[
  {
    "path": ".github/workflows/deploy.yml",
    "content": "name: Deploy Docs Pages\n\non:\n  push:\n    #分支名字\n    branches: [master]\n\n# 设置tokenn访问权限\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\n# 只允许同时进行一次部署，跳过正在运行和最新队列之间的运行队列\n# 但是，不要取消正在进行的运行，因为我们希望允许这些生产部署完成\nconcurrency:\n  group: pages\n  cancel-in-progress: false\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0 # 如果未启用 lastUpdated，则不需要\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v2 # 安装pnpm并添加到环境变量\n        with:\n          version: 10.10.0 # 指定 pnpm 版本\n      - name: Setup Pages\n        uses: actions/configure-pages@v4  # 在工作流程自动配置GithubPages\n      - name: Install dependencies\n        run: |\n          cd docs\n          pnpm install # 安装依赖\n      - name: Build with VitePress\n        run: |\n          cd docs\n          pnpm run build # 启动项目\n          touch .vitepress/dist/.nojekyll  # 通知githubpages不要使用Jekyll处理这个站点\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v3  # 上传构建产物\n        with:\n          path: docs/.vitepress/dist # 指定上传的路径\n\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }} # 从后续的输出中获取部署后的页面URL\n    needs: build    # 在build后面完成\n    runs-on: ubuntu-latest  # 运行在最新版本的ubuntu系统上\n    name: Deploy\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment  # 指定id\n        uses: actions/deploy-pages@v4 # 将之前的构建产物部署到github pages中"
  },
  {
    "path": ".gitignore",
    "content": "HELP.md\ntarget/\ntarget/*\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**\n!**/src/test/**\n*.pdf\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.ipr\n*.iws\n*.iml\n**/.idea\n**/*.iml\nrebel.xml\n\n### IntelliJ IDEA Local ###\ntarget\n*.log\n*.log.*\nlogs\n.DS_Store\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n\n### VS Code ###\n.vscode/\n/logs/\n\n**/node_modules\n**/.umi\ntemp\n\n### java ###\n*.class\n\n/docs/.vitepress/dist\n/docs/.vitepress/cache\n/docs/package-lock.json\n/docs/pnpm-lock.yaml\n\nlefthook.yml"
  },
  {
    "path": "LICENSE",
    "content": " \nMIT License (MIT)\n\nCopyright © 2025 HiAuth\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and \nassociated documentation files (the “Software”), to deal in the Software without restriction, \nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, \nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, \nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial \nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT \nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. \nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE \nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">Hi Auth</h1>\n\n<div align=\"center\">\n\nHiAuth是一个开源的基于OAuth2.0协议的认证、授权系统，除了标准的OAuth2.0授权流程功能外，还提供了应用管理、用户管理、权限管理等相关功能。\n\n[![Star](https://img.shields.io/github/stars/bestaone/HiAuth?color=42b883&logo=github&style=flat-square)](https://github.com/bestaone/HiAuth/stargazers)\n[![Fork](https://img.shields.io/github/forks/bestaone/HiAuth?color=42b883&logo=github&style=flat-square)](https://github.com/bestaone/HiAuth/network/members)\n[![Language](https://img.shields.io/badge/%E8%AF%AD%E8%A8%80-Java%20%7C%20Springboot%20%7C%20Vue3-red?style=flat-square&color=42b883)](https://github.com/bestaone/HiAuth)\n[![License](https://img.shields.io/github/license/bestaone/HiAuth?color=42b883&style=flat-square)](https://github.com/bestaone/HiAuth/blob/master/LICENSE)\n[![Author](https://img.shields.io/badge/作者-码道功臣-orange.svg)](https://github.com/bestaone)\n\n</div>\n\n## 介绍\n除了认证相关功能外，还提供了`/example/demo`、`/example/himall`项目，供用户参考如何集成。\n\n- 参考`demo`实例，你可以几分钟之内快速验证如何集成HiAuth；\n- 参考`himall`实例，你可以快速的启动一个带页面的实例；\n\n### LIVE\n- HiAuth Docs：http://docs.hiauth.cn\n- HiAuth Admin：http://auth.hiauth.cn/admin\n- HiAuth 授权页：http://auth.hiauth.cn\n\n### 目录结构\n```\n├─cicd                              持续集成\n├─docs                              开发文档\n├─example                           样例\n│ ├─demo                            基础样例\n│ ├─hiauth-client                   使用hiauth-client-spring-boot-starter集成hiauth的样例\n│ ├─hiauth-client-exp               hiauth-client的简易版，用于做实验\n│ ├─hiauth-server-exp               hiauth-server的简易版，用于做实验\n│ ├─himall                          带有页面的样例\n│ ├─resource                        资源服务样例\n│ ├─spring-cloud                    spring-cloud微服务集成样例，原生集成\n│ ├─spring-cloud-with-hiauth-client spring-cloud微服务集成样例，使用starter集成\n│ ├─wechat-login                    微信登录样例\n├─hiauth-client-starter             hiauth-client SDK\n│ ├─hiauth-client-commons                       基础包\n│ ├─hiauth-client-spring-boot-starter           适用于SpringBoot直接集成\n│ ├─hiauth-client-session-spring-boot-starter   SpringCloud架构中，业务服务中的session管理SDK\n│ ├─hiauth-client-spring-cloud-gateway-starter  SpringCloudGateway中集成认证授权\n├─hiauth-front                      管理端前端项目\n├─hiauth-server                     HiAuth服务端\n├─other                             其他内容，数据库脚本等\n```\n## 效果图\n- 认证中心登录页\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/github/%E8%AE%A4%E8%AF%81%E7%99%BB%E5%BD%95%E9%A1%B5.jpg\">\n</p>\n\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/github/wechat_login.jpg\">\n</p>\n\n- 管理后台登录页\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/github/%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%E7%99%BB%E5%BD%95%E9%A1%B5.jpg\">\n</p>\n\n- 超级管理员-用户管理页\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/github/%E8%B6%85%E7%BA%A7%E7%AE%A1%E7%90%86%E5%91%98-%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86%E9%A1%B5.jpg\">\n</p>\n\n- 企业管理员-部门列表页\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/github/%E4%BC%81%E4%B8%9A%E7%AE%A1%E7%90%86%E5%91%98-%E9%83%A8%E9%97%A8%E5%88%97%E8%A1%A8%E9%A1%B5.jpg\">\n</p>\n\n- 企业管理员-员工列表页\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/github/%E4%BC%81%E4%B8%9A%E7%AE%A1%E7%90%86%E5%91%98-%E5%91%98%E5%B7%A5%E5%88%97%E8%A1%A8%E9%A1%B5.jpg\">\n</p>\n\n**如果你觉得此项目对你有帮助，请给我点个star，谢谢！**\n\n## 快速尝试\n\n### 环境要求\n- Git\n- JDK17+\n- Maven 3.8+\n\n### 下载源码\n```sh\n$ git clone https://github.com/bestaone/HiAuth.git\n```\n### 构建、启动\n```sh\n# 启动himall实例\n$ cd HiAuth/example/himall\n$ mvn clean install\n$ mvn spring-boot:run\n```\n\n### 验证\n\n- 访问HiMall：http://127.0.0.1:9000 点击`Login`按钮，登录账号：`corpadmin/123456`\n\n> 注意：`127.0.0.1`不能使用`localhost`代替，因为数据库中配置了回调地址为`http://127.0.0.1:9000`。\n\n## 认证模式\n\n**authorization_code模式：**\n- 访问授权端点获取`授权码`: http://auth.hiauth.cn/oauth2/authorize?response_type=code&client_id=himall&scope=openid%20profile&redirect_uri=http://127.0.0.1:9000/login/oauth2/code/hiauth-code\n- 用户登录并授权后，重定向到`redirect_uri`并附带`授权码`，如下（注意：浏览器开发模式下，网络控制台中，url的参数code值）：\n```shell\nhttp://127.0.0.1:9000/login/oauth2/code/hiauth-code?code=R4vhO65LvdsNqQ9A3KHwjb...\n```\n- 使用`授权码`换取访问`令牌`\n```shell\n# 最后的YourCode替换为上面步骤获取的授权码\n$ curl --location --request POST 'http://auth.hiauth.cn/oauth2/token' \\\n--header 'Content-Type: application/x-www-form-urlencoded' \\\n--header 'Authorization: Basic aGltYWxsOnNlY3JldA==' \\\n--data-urlencode 'grant_type=authorization_code' \\\n--data-urlencode 'redirect_uri=http://127.0.0.1:9000/login/oauth2/code/hiauth-code' \\\n--data-urlencode 'code=YourCode'\n\n# 或者\n$ curl --location --request POST 'http://auth.hiauth.cn/oauth2/token' \\\n--header 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8' \\\n--header 'Authorization: Basic aGltYWxsOnNlY3JldA==' \\\n--data 'grant_type=authorization_code&redirect_uri=http://127.0.0.1:9000/login/oauth2/code/hiauth-code&client_id=himall&client_secret=secret&code=YourCode'\n```\n> 上述“Authorization: Basic aGltYWxsOnNlY3JldA==”中的值“aGltYWxsOnNlY3JldA==”，\n> 计算方式为：Base64.encode(client_id:client_secret)，\n> 例如：client_id=himall,client_secret=secret时，base64解码为：Base64.encode(\"himall:secret\")\n\n返回结果：\n```json\n{\n    \"access_token\": \"eyJraWQiOiJkZTYxMjVmNi0wYTQ5LTQwMGYtYWMzMC02M2U2Zm\",\n    \"refresh_token\": \"8WS6liiSW0gmUy8yudFAPIHGor3Hf6yBtaBTUNjj3-q9y4JXRlBZ\",\n    \"scope\": \"openid profile\",\n    \"token_type\": \"Bearer\",\n    \"expires_in\": 35999\n}\n```\n\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/github/hiauth-1.jpg\">\n</p>\n\n**client_credentials模式：**\n```shell\n$ curl --location --request POST 'http://auth.hiauth.cn/oauth2/token' \\\n--header 'Content-Type: application/x-www-form-urlencoded' \\\n--data-urlencode 'grant_type=client_credentials' \\\n--data-urlencode 'client_id=himall' \\\n--data-urlencode 'client_secret=secret' \\\n--data-urlencode 'scope=profile'\n\n# 或者\n$ curl --location --request POST 'http://auth.hiauth.cn/oauth2/token' \\\n--header 'Content-Type: application/x-www-form-urlencoded' \\\n--data 'grant_type=client_credentials&client_id=himall&client_secret=secret&scope=profile'\n```\n返回结果：\n```json\n{\n  \"access_token\": \"eyJraWQiOiJkZTYxMjVmNi0wYTQ5LTQwMGYtYWMzMC02M2U2Zm\",\n  \"scope\": \"profile user\",\n  \"token_type\": \"Bearer\",\n  \"expires_in\": 35999\n}\n```\n\n**用户信息获取：**\n```shell\n# 将accessToken替换为上面步骤获取的访问令牌\n$ curl --location --request POST 'http://auth.hiauth.cn/userinfo' \\\n--header 'Accept: application/json' \\\n--header 'Authorization: Bearer accessToken'\n```\n> 注意：只在code码模式`grant_type=authorization_code`下生效。\n\n返回结果：\n```shell\n{\n    \"sub\": \"corpadmin\",\n    \"empId\": 1,\n    \"avatarUrl\": \"/unpapi/image/2c924149ddfe4bd181959ee9bede10c0.jpeg\",\n    \"appId\": 91,\n    \"name\": \"企业管理员\",\n    \"phoneNum\": \"13400000001\",\n    \"userId\": 11,\n    \"authorities\": [],\n    \"cid\": 1,\n    \"username\": \"corpadmin\"\n}\n```\n\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/github/hiauth-2.jpg\">\n</p>\n\n**scop权限：**\n- 在授权请求中包含所需scope\n- 获取的访问令牌将包含授予的scope\n- 资源服务器验证请求的scope是否匹配\n```java\n@PreAuthorize(\"hasAuthority('SCOPE_profile')\")\n@GetMapping(\"/protected\")\npublic String protectedResource() {\n    return \"Accessed protected resource\";\n}\n```\n\n### 其他\n- 获取认证服务器配置信息：http://auth.hiauth.cn/.well-known/openid-configuration\n\n### 更多集成方式\n- 云端SaaS版集成，[参考文档](http://docs.hiauth.cn/guide/saas)；\n- 本地Docker版集成，[参考文档](http://docs.hiauth.cn/guide/docker)；\n- 源码编译安装集成，[参考文档](http://docs.hiauth.cn/guide/sourcecode)；\n\n## 社区与作者\n<p align=\"center\">\n  <img width=\"900\" src=\"https://hiauth.oss-cn-zhangjiakou.aliyuncs.com/community_wechat.jpg\">\n</p>\n\n>如果群二维码失效了，请先添加我的微信，然我我拉你入群。\n\n## 授权协议\n本项目执行 [MIT](https://github.com/bestaone/HiAuth/blob/master/LICENSE) 协议"
  },
  {
    "path": "cicd/Dockerfile",
    "content": "FROM ubuntu:jdk21-ng-24\n\n# 设置语言\nENV LANG en_US.UTF-8\nENV LANG C.UTF-8\nENV LC_ALL C.UTF-8\n\n# 设置地理位置\nENV TZ=Asia/Shanghai\n\n# 设置时区\nRUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone\n\n# 安装工具\nRUN apt-get update && apt-get install -y curl && apt-get clean\n\n# 挂在目录\nVOLUME /data\n\n# 安装jar包\nADD ./hiauth-server/target/hiauth-server.jar /hiauth/app.jar\nCOPY ./cicd/hiauth.properties /hiauth/conf/hiauth.properties\n\n# 安装前端\nADD ./hiauth-front/apps/web-auth/dist.zip dist.zip\nRUN mkdir -p /html && chmod a+rwx -R /html\nRUN unzip dist.zip -d /html/admin\n\n# 安装文档\n# COPY ./docs/.vitepress/dist /html/docs\n\n# 配置nginx\nCOPY ./cicd/nginx.conf /etc/nginx/nginx.conf\n\n# 配置启动脚本\nRUN echo \"#!/bin/bash\" > /hiauth/run.sh\nRUN echo \"java -jar /hiauth/app.jar & nginx -g 'daemon off;'\" >> /hiauth/run.sh\n\n# 设置权限\nRUN chmod +x /hiauth/run.sh\n\n# 暴露端口\nEXPOSE 80 8080\n\n# 设置容器启动时执行的命令\nENTRYPOINT [\"/hiauth/run.sh\"]"
  },
  {
    "path": "cicd/Jenkinsfile",
    "content": "pipeline {\n\n    agent any\n\n    // 设置环境变量\n    environment {\n        BUILD_VERSION = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()\n        CONFIG_FILE = '/var/jenkins_home/hiauth/conf/hiauth.properties'\n    }\n\n    // 设置参数, 设置后，构建时会提示填写\n//     parameters {\n//         string(name: 'DEPLOY_ENV', defaultValue: 'dev', description: 'Environment to deploy to')\n//     }\n\n    stages {\n\n        stage('Check Env') {\n            steps {\n                sh 'echo ${BUILD_VERSION}'\n                sh 'docker -v'\n                sh 'java -version'\n                sh 'mvn -v'\n                sh 'node -v'\n                sh 'pnpm -v'\n            }\n        }\n\n        stage('Install') {\n            steps {\n                sh \"mvn clean install -Dmaven.test.skip=false\"\n                sh \"cd hiauth-front && pnpm install --no-frozen-lockfile && pnpm build:auth\"\n                // sh \"cd docs && pnpm install && pnpm run build\"\n                sh 'docker stop hiauth || true'\n                sh 'docker rm -f hiauth || true'\n                sh \"docker rmi -f bestaone/hiauth:3.0.0 || true\"\n                sh \"docker build -f ./cicd/Dockerfile -t bestaone/hiauth:3.0.0 .\"\n                sh \"\"\"\n                    docker run -d \\\n                      --restart=always \\\n                      -p 9080:80 \\\n                      -v /opt/install/hiauth/conf:/hiauth/conf \\\n                      -v /opt/install/hiauth/logs:/hiauth/logs \\\n                      --name hiauth bestaone/hiauth:3.0.0\n                \"\"\"\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "cicd/hiauth.properties",
    "content": "\n# login page title, default:\nloginPage.title=\\u7edf\\u4e00\\u8ba4\\u8bc1\\u4e2d\\u5fc3\n# login page static file name\nloginPage.path=login\n# login page default username\nloginPage.username=corpadmin\n# login page default password\nloginPage.password=123456\n# login page username placeholder\nloginPage.usernamePlaceholder=\\u4f01\\u4e1a\\u7ba1\\u7406\\u5458\\uff1acorpadmin\\u3001\\u7cfb\\u7edf\\u7ba1\\u7406\\u5458\\uff1aadmin\n# login page password placeholder\nloginPage.passwordPlaceholder=123456\n# login types\nloginPage.loginTypes=phone,account,wechat\n\n# aliyun sms\naliyun.sms.accessKeyId=abcdefghi\naliyun.sms.accessKeySecret=jklmnopqrstuvwxyz\naliyun.sms.sign=HiAuth\naliyun.sms.smsTemplateCode=SMS_00000001\naliyun.sms.superSmsCode=888888\n\n# supported wechat qrcode login, config in wx open platform\nwechat.open.appid=wx9b04c3f125a24962\nwechat.open.appSecret=abcdefghijklmnopqrstuvwxyz\nwechat.open.redirectUri=http://127.0.0.1:8080/wechat/doLogin\nwechat.open.style=black\nwechat.open.href=\n\n# only supported postgresql\ndatasource.type=com.alibaba.druid.pool.DruidDataSource\ndatasource.driverClassName=org.postgresql.Driver\ndatasource.url=jdbc:postgresql://127.0.0.1:5432/hiauth?stringtype=unspecified\ndatasource.username=test\ndatasource.password=123456\n\n# redis\nredis.host=127.0.0.1\nredis.port=6379\nredis.database=0\nredis.username=\nredis.password="
  },
  {
    "path": "cicd/nginx.conf",
    "content": "worker_processes auto;\npid /run/nginx.pid;\ninclude /etc/nginx/modules-enabled/*.conf;\n\nevents {\n    worker_connections 768;\n    # multi_accept on;\n}\n\nhttp {\n\n    sendfile on;\n    tcp_nopush on;\n    tcp_nodelay on;\n    keepalive_timeout 65;\n    types_hash_max_size 2048;\n    # server_tokens off;\n\n    # server_names_hash_bucket_size 64;\n    # server_name_in_redirect off;\n\n    include /etc/nginx/mime.types;\n    default_type application/octet-stream;\n\n    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE\n    ssl_prefer_server_ciphers on;\n\n    access_log /var/log/nginx/access.log;\n    error_log /var/log/nginx/error.log;\n\n    gzip on;\n\n    # gzip_vary on;\n    # gzip_proxied any;\n    # gzip_comp_level 6;\n    # gzip_buffers 16 8k;\n    # gzip_http_version 1.1;\n    # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    server {\n\n        listen 80;\n\n        # hiauth授权服务\n        location / {\n            proxy_set_header Host $http_host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_pass http://127.0.0.1:8080/;\n        }\n\n        # hiauth管理后台静态页面\n        location /admin {\n            root /html;\n            index  index.html index.htm;\n            try_files $uri $uri/ /index.html;\n        }\n\n        # hiauth管理后台接口服务\n        location /gateway/ {\n            proxy_set_header Host $http_host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_pass http://127.0.0.1:8080/;\n            rewrite \"^/gateway/(.*)$\" /$1 break;\n        }\n\n        # 文档\n#        location /docs {\n#            root /html;\n#            index  index.html index.htm;\n#            try_files $uri $uri/ /index.html;\n#        }\n\n    }\n\n}\n"
  },
  {
    "path": "docs/.postcssrc.json",
    "content": "{\n  \"plugins\": {\n    \"postcss-rtlcss\": {\n      \"ltrPrefix\": \":where([dir=\\\"ltr\\\"])\",\n      \"rtlPrefix\": \":where([dir=\\\"rtl\\\"])\"\n    }\n  }\n}\n"
  },
  {
    "path": "docs/.vitepress/config/en.ts",
    "content": "import { createRequire } from 'module'\nimport { defineConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('../../package.json')\n\nexport const en = defineConfig({\n  lang: 'en-US',\n  description: 'Vite & Vue powered static site generator.',\n\n  themeConfig: {\n    nav: nav(),\n\n    sidebar: {\n      '/en/guide/': { base: '/en/guide/', items: sidebarGuide() },\n      '/en/other/': { base: '/en/other/', items: sidebarOther() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/bestaone/HiAuth/edit/main/docs/:path',\n      text: 'Edit this page on GitHub'\n    },\n\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: `Copyright © 2024-${new Date().getFullYear()} Earven`\n    }\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: 'Guide',\n      link: '/en/guide/what-is-hiauth',\n      activeMatch: '/en/guide/'\n    },\n    {\n      text: 'Other',\n      link: '/en/other/support',\n      activeMatch: '/en/other/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: 'Changelog',\n          link: 'https://github.com/bestaone/HiAuth/blob/main/CHANGELOG.md'\n        },\n        {\n          text: 'Contributing',\n          link: 'https://github.com/bestaone/HiAuth/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Introduction',\n      collapsed: false,\n      items: [\n        { text: 'What is HiAuth', link: 'what-is-hiauth' },\n        { text: 'Quick Start', link: 'quick-start' }\n      ]\n    },\n    {\n      text: 'Deployment & Integration',\n      collapsed: false,\n      items: [\n        { text: 'SaaS Edition', link: 'saas' },\n        { text: 'Docker Edition', link: 'docker' },\n        { text: 'Source Code Edition', link: 'sourcecode' },\n        { text: 'hiauth-client Integration', link: 'hiauth-client' },\n        { text: 'Deploying on K8S', link: 'k8s' },\n        { text: 'Integration Testing', link: 'test' }\n      ]\n    },\n    {\n      text: 'Secondary Development',\n      collapsed: false,\n      items: [\n        { text: 'Project Structure', link: 'project' },\n        { text: 'Front-end Development', link: 'frontend' },\n        { text: 'Backend Development', link: 'backend' }\n      ]\n    },\n    {\n      text: 'Other',\n      collapsed: false,\n      items: [\n        { text: 'About Topic', link: 'about-topic' },\n        { text: 'Issue', link: 'issue' }\n      ]\n    }\n  ]\n}\n\nfunction sidebarOther(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'other',\n      items: [\n        { text: 'support', link: 'support' },\n        { text: 'community', link: 'community' }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/.vitepress/config/index.ts",
    "content": "import { defineConfig } from 'vitepress'\nimport { shared } from './shared'\nimport { en } from './en'\nimport { zh } from './zh'\n\nexport default defineConfig({\n  ...shared,\n  locales: {\n    root: { label: '简体中文', ...zh },\n    en: { label: 'English', ...en }\n  }\n})\n"
  },
  {
    "path": "docs/.vitepress/config/shared.ts",
    "content": "import {defineConfig} from 'vitepress'\nimport {groupIconMdPlugin, groupIconVitePlugin, localIconLoader} from 'vitepress-plugin-group-icons'\nimport {search as zhSearch} from './zh'\n\nexport const shared = defineConfig({\n  title: 'HiAuth',\n  base: \"/\",\n  rewrites: {\n    'zh/:rest*': ':rest*'\n  },\n\n  lastUpdated: true,\n  cleanUrls: true,\n  metaChunk: true,\n\n  markdown: {\n    math: true,\n    codeTransformers: [\n      // We use `[!!code` in demo to prevent transformation, here we revert it back.\n      {\n        postprocess(code) {\n          return code.replace(/\\[\\!\\!code/g, '[!code')\n        }\n      }\n    ],\n    config(md) {\n      // TODO: remove when https://github.com/vuejs/vitepress/issues/4431 is fixed\n      const fence = md.renderer.rules.fence!\n      md.renderer.rules.fence = function (tokens, idx, options, env, self) {\n        const { localeIndex = 'root' } = env\n        const codeCopyButtonTitle = (() => {\n          switch (localeIndex) {\n            case 'zh':\n              return '复制代码'\n            case 'en':\n              return 'Copy code'\n            default:\n              return 'Copy code'\n          }\n        })()\n        return fence(tokens, idx, options, env, self).replace(\n          '<button title=\"Copy Code\" class=\"copy\"></button>',\n          `<button title=\"${codeCopyButtonTitle}\" class=\"copy\"></button>`\n        )\n      }\n      md.use(groupIconMdPlugin)\n    }\n  },\n\n  sitemap: {\n    hostname: 'http://docs.hiauth.cn',\n    transformItems(items) {\n      return items.filter((item) => !item.url.includes('migration'))\n    }\n  },\n\n  /* prettier-ignore */\n  head: [\n    ['link', { rel: 'icon', type: 'image/svg+xml', href: '/hiauth-logo-mini.svg' }],\n    ['link', { rel: 'icon', type: 'image/png', href: '/hiauth-logo-mini.png' }],\n    ['meta', { name: 'theme-color', content: '#5f67ee' }],\n    ['meta', { property: 'og:type', content: 'website' }],\n    ['meta', { property: 'og:locale', content: 'zh' }],\n    ['meta', { property: 'og:title', content: 'HiAuth | 基于OAuth2.0协议的认证授权服务' }],\n    ['meta', { property: 'og:site_name', content: 'VitePress' }],\n    ['meta', { property: 'og:image', content: 'https://vitepress.dev/vitepress-og.jpg' }],\n    ['meta', { property: 'og:url', content: 'http://docs.hiauth.cn' }],\n    ['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }]\n  ],\n\n  themeConfig: {\n    logo: { src: '/hiauth-logo-mini.svg', width: 24, height: 24 },\n\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/bestaone/HiAuth' }\n    ],\n\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '8J64VVRP8K',\n        apiKey: '52f578a92b88ad6abde815aae2b0ad7c',\n        indexName: 'vitepress',\n        locales: {\n          ...zhSearch\n        }\n      }\n    },\n\n    carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' }\n  },\n  vite: {\n    plugins: [\n      groupIconVitePlugin({\n        customIcon: {\n          vitepress: localIconLoader(\n            import.meta.url,\n            '../../public/hiauth-logo-mini.svg'\n          ),\n          firebase: 'logos:firebase'\n        }\n      })\n    ]\n  }\n})\n"
  },
  {
    "path": "docs/.vitepress/config/zh.ts",
    "content": "import { createRequire } from 'module'\nimport { defineConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('../../package.json')\n\nexport const zh = defineConfig({\n  lang: 'zh-Hans',\n  description: '基于OAuth2.0协议的认证授权服务',\n\n  themeConfig: {\n    nav: nav(),\n\n    sidebar: {\n      '/guide/': { base: '/guide/', items: sidebarGuide() },\n      '/other/': { base: '/other/', items: sidebarOther() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/bestaone/HiAuth/edit/main/docs/:path',\n      text: '在 GitHub 上编辑此页面'\n    },\n\n    footer: {\n      message: '基于 MIT 许可发布',\n      copyright: `版权所有 © 2024-${new Date().getFullYear()} 张国圣`\n    },\n\n    docFooter: {\n      prev: '上一页',\n      next: '下一页'\n    },\n\n    outline: {\n      label: '页面导航'\n    },\n\n    lastUpdated: {\n      text: '最后更新于',\n      formatOptions: {\n        dateStyle: 'short',\n        timeStyle: 'medium'\n      }\n    },\n\n    langMenuLabel: '多语言',\n    returnToTopLabel: '回到顶部',\n    sidebarMenuLabel: '菜单',\n    darkModeSwitchLabel: '主题',\n    lightModeSwitchTitle: '切换到浅色模式',\n    darkModeSwitchTitle: '切换到深色模式',\n    skipToContentLabel: '跳转到内容'\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: '文档',\n      link: '/guide/what-is-hiauth',\n      activeMatch: '/guide/'\n    },\n    {\n      text: '其他',\n      link: '/other/support',\n      activeMatch: '/other/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '更新日志',\n          link: 'https://github.com/bestaone/HiAuth/blob/main/CHANGELOG.md'\n        },\n        {\n          text: '参与贡献',\n          link: 'https://github.com/bestaone/HiAuth/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: '简介',\n      collapsed: false,\n      items: [\n        { text: '什么是HiAuth', link: 'what-is-hiauth' },\n        { text: '快速体验', link: 'quick-start' }\n      ]\n    },\n    {\n      text: '部署&集成',\n      collapsed: false,\n      items: [\n        { text: 'SaaS版', link: 'saas' },\n        { text: 'Docker版', link: 'docker' },\n        { text: '源码版', link: 'sourcecode' },\n        { text: 'hiauth-client集成', link: 'hiauth-client' },\n        { text: 'K8S上部署', link: 'k8s' },\n        { text: '集成测试', link: 'test' }\n      ]\n    },\n    {\n      text: '二次开发',\n      collapsed: false,\n      items: [\n        { text: '项目结构', link: 'project' },\n        { text: '前端开发', link: 'frontend' },\n        { text: '后端开发', link: 'backend' }\n      ]\n    },\n    {\n      text: '其他',\n      collapsed: false,\n      items: [\n        { text: '相关资料', link: 'about-topic' },\n        { text: '问题', link: 'issue' }\n      ]\n    }\n  ]\n}\n\nfunction sidebarOther(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: '其他',\n      items: [\n        { text: '技术支持', link: 'support' },\n        { text: '社区', link: 'community' }\n      ]\n    }\n  ]\n}\n\nexport const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {\n  zh: {\n    placeholder: '搜索文档',\n    translations: {\n      button: {\n        buttonText: '搜索文档',\n        buttonAriaLabel: '搜索文档'\n      },\n      modal: {\n        searchBox: {\n          resetButtonTitle: '清除查询条件',\n          resetButtonAriaLabel: '清除查询条件',\n          cancelButtonText: '取消',\n          cancelButtonAriaLabel: '取消'\n        },\n        startScreen: {\n          recentSearchesTitle: '搜索历史',\n          noRecentSearchesText: '没有搜索历史',\n          saveRecentSearchButtonTitle: '保存至搜索历史',\n          removeRecentSearchButtonTitle: '从搜索历史中移除',\n          favoriteSearchesTitle: '收藏',\n          removeFavoriteSearchButtonTitle: '从收藏中移除'\n        },\n        errorScreen: {\n          titleText: '无法获取结果',\n          helpText: '你可能需要检查你的网络连接'\n        },\n        footer: {\n          selectText: '选择',\n          navigateText: '切换',\n          closeText: '关闭',\n          searchByText: '搜索提供者'\n        },\n        noResultsScreen: {\n          noResultsText: '无法找到相关结果',\n          suggestedQueryText: '你可以尝试查询',\n          reportMissingResultsText: '你认为该查询应该有结果？',\n          reportMissingResultsLinkText: '点击反馈'\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/.vitepress/theme/index.ts",
    "content": "import Theme from 'vitepress/theme'\nimport 'virtual:group-icons.css'\nimport './styles.css'\n\nexport default Theme\n"
  },
  {
    "path": "docs/.vitepress/theme/styles.css",
    "content": "@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100..900&display=swap');\n\n:root:where(:lang(fa)) {\n  --vp-font-family-base:\n    'Vazirmatn', 'Inter', ui-sans-serif, system-ui, sans-serif,\n    'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n}\n\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(\n    120deg,\n    #bd34fe 30%,\n    #41d1ff\n  );\n  --vp-home-hero-image-background-image: linear-gradient(\n    -45deg,\n    #bd34fe 50%,\n    #47caff 50%\n  );\n  --vp-home-hero-image-filter: blur(44px);\n}\n\n@media (min-width: 640px) {\n  :root {\n    --vp-home-hero-image-filter: blur(56px);\n  }\n}\n\n@media (min-width: 960px) {\n  :root {\n    --vp-home-hero-image-filter: blur(68px);\n  }\n}\n\n/* used in reference/default-theme-search */\nimg[src='/search.png'] {\n  width: 100%;\n  aspect-ratio: 1 / 1;\n}\n\n/* 屏蔽更新时间 */\n.last-updated {\n  display: none !important;\n}"
  },
  {
    "path": "docs/en/guide/about-topic.md",
    "content": "edit..."
  },
  {
    "path": "docs/en/guide/backend.md",
    "content": "edit..."
  },
  {
    "path": "docs/en/guide/docker.md",
    "content": "# Docker Edition {#docker}\n\nThe integration process for the Docker edition is similar to the SaaS edition, except that before integration, we need to deploy a Docker version of HiAuth. The local installation and deployment of the Docker edition rely on `PostgreSQL 16+` and `Redis`. If you need to run the HiAuth demo, you will also need a `JDK 17` and `Maven 3.8+` environment.\n\n## Installation and Integration Steps:\n- Check the server environment\n- Initialize the HiAuth database by executing SQL scripts\n- Configure the HiAuth startup configuration file\n- Download the image and start the service\n- Verify using the HiAuth source code demo\n\n### Check the Server Environment {#check-env}\n```shell\n# Check the git version\n$ git --version\ngit version 1.8.3.1\n\n# Check the Docker version\n$ docker -v\nDocker version 26.1.4, build 5650f9b\n\n# Check the JDK version\n$ java -version\nopenjdk version \"17.0.5\" 2022-10-18\n\n# Check the Maven version\n$ mvn -v\nApache Maven 3.8.6 (36645f6c9b5079805ea5009217e36f2cffd34256)\n```\n\n### Initialize the HiAuth Database by Executing SQL Scripts {#init-db}\n- Install `PostgreSQL 16+`;\n- Create a database named `hiauth`;\n- Execute the initialization script `HiAuth/other/hiauth.sql`;\n\n### Configure the HiAuth Startup Configuration File {#config-file}\n- Create the configuration file `/opt/install/hiauth/conf/hiauth.properties` and configure the correct parameters;\n```properties [hiauth.properties]\n# login page title, default:\nloginPage.title=Welcome Login\n# login page static file name\nloginPage.path=login\n# login page default username\nloginPage.username=\n# login page default password\nloginPage.password=\n# login page username placeholder\nloginPage.usernamePlaceholder=\n# login page password placeholder\nloginPage.passwordPlaceholder=\n# login types\nloginPage.loginTypes=phone,account,wechat\n\n# aliyun sms\naliyun.sms.accessKeyId=abcdefghi\naliyun.sms.accessKeySecret=abcdefghi\naliyun.sms.sign=HiAuth\naliyun.sms.smsTemplateCode=SMS_00000001\naliyun.sms.superSmsCode=888888\n\n# supported wechat qrcode login, config in wx open platform\nwechat.open.appid=wx123456789\nwechat.open.appSecret=abcdefghijklmnopqrstuvwxyz\nwechat.open.redirectUri=http://127.0.0.1:8080/wechat/doLogin\nwechat.open.style=black\nwechat.open.href=\n\n# only supported postgresql\ndatasource.type=com.alibaba.druid.pool.DruidDataSource\ndatasource.driverClassName=org.postgresql.Driver\ndatasource.url=jdbc:postgresql://db_host:5432/hiauth?stringtype=unspecified\ndatasource.username=test\ndatasource.password=123456\n\n# redis\nredis.host=redis_host\nredis.port=6379\nredis.database=0\nredis.username=test\nredis.password=123456\n```\n> Configuration reference: [hiauth.properties](https://github.com/bestaone/HiAuth/blob/master/other/hiauth.properties)\n\n### Download the Image and Start the Service {#download-image}\n```shell\n# You need to be able to access the Docker Hub central repository, which may require a proxy.\n$ docker run -d \\\n  --restart=always \\\n  -p 9080:80 -p 8080:8080 \\\n  -v /opt/install/hiauth/conf:/hiauth/conf \\\n  -v /opt/install/hiauth/logs:/hiauth/logs \\\n  --name hiauth bestaone/hiauth:3.0.0\n  \n# If you cannot access the Docker Hub central repository, you can download the image from the Alibaba Cloud repository.\n$ docker run -d \\\n  --restart=always \\\n  -p 9080:80 -p 8080:8080 \\\n  -v /opt/install/hiauth/conf:/hiauth/conf \\\n  -v /opt/install/hiauth/logs:/hiauth/logs \\\n  --name hiauth registry.cn-zhangjiakou.aliyuncs.com/bestaone/hiauth:3.0.0\n  \n# Check the images  \n$ docker images\nREPOSITORY                                                 TAG           IMAGE ID       CREATED         SIZE\nbestaone/hiauth                                            3.0.0         c5e4140bd5aa   3 hours ago     810MB\nregistry-vpc.cn-zhangjiakou.aliyuncs.com/bestaone/hiauth   3.0.0         c5e4140bd5aa   3 hours ago     810MB\n\n# Check the services\n$ docker ps\nCONTAINER ID   IMAGE                   COMMAND                  CREATED        STATUS       PORTS                                                  NAMES\n3ea0fdb8a165   bestaone/hiauth:3.0.0   \"/hiauth/run.sh\"         3 hours ago    Up 3 hours   8080/tcp, 0.0.0.0:9080->80/tcp, :::9080->80/tcp        hiauth\n\n# Check the logs\n$ docker logs 3ea0fdb8a165\n...\nINFO 7 [main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer Tomcat started on port 8080 (http) with context path '/'\nINFO 7 [main] cn.hiauth.server.ServerStarter Started ServerStarter in 10.094 seconds (process running for 11.107)\n...\n\n# Access the service\n$ curl http://127.0.0.1:9080\n{ \"code\": 50000, \"message\": \"Invalid or expired token\" }\n```\n- The authorization address for the Docker edition of HiAuth is: http://127.0.0.1:9080\n- The management address for the Docker edition of HiAuth is: http://127.0.0.1:9080/admin\n\n### Verify Using the HiAuth Source Code Demo {#hiauth-himall}\n- Download the source code\n```shell\n$ git clone https://github.com/bestaone/HiAuth.git\n```\n- Modify the configuration `HiAuth/example/himall/src/main/resources/application.yml`\n```yaml\n...\nspring.security.oauth2.client:\n  provider:\n    hiauth-server:\n      # Change the value of issuer-uri from http://auth.hiauth.cn to http://127.0.0.1:9080\n      issuer-uri: http://auth.hiauth.cn\n...\n```\n- Compile and run\n```shell\n$ cd HiAuth/example/himall\n$ mvn clean install\n$ mvn spring-boot:run\n```\n\n### Verification\n- Open a browser and visit: http://127.0.0.1:9000\n- Click the `Login` button, and you will be redirected to the unified authentication system. Enter the account: `corpadmin`, password: `123456`\n- After successful login, you will see the home page and the logged-in user information!\n\n## Video Tutorial\n<iframe src=\"//player.bilibili.com/player.html?bvid=BV14hZEYmEEq&page=1\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/en/guide/frontend.md",
    "content": "edit..."
  },
  {
    "path": "docs/en/guide/hiauth-client.md",
    "content": "edit..."
  },
  {
    "path": "docs/en/guide/issue.md",
    "content": "edit..."
  },
  {
    "path": "docs/en/guide/k8s.md",
    "content": "edit..."
  },
  {
    "path": "docs/en/guide/quick-start.md",
    "content": "# Quick Start {#quick-start}\n\n## Admin Console {#admin}\n\nExperience it on the [Admin End](http://auth.hiauth.cn/admin).\n- **System Administrator Account**: `admin\\123456`. This account can view all configurations. By switching tenants, you can view the configurations of the current tenant. To prevent unauthorized changes, this account has read-only access.\n- **Corporate Administrator Account**: `corpadmin\\123456`. This account can view all configurations within the tenant. To prevent unauthorized changes, this account has read-only access.\n\n## Unified Authentication System {#auth}\n\nExperience the [Authentication End](http://auth.hiauth.cn) for application login authorization. After integrating with third-party applications, you will be redirected to this page for authentication.\n\n## Documentation {#docs}\n\nGet help from the [Documentation](http://hiauth.cn)."
  },
  {
    "path": "docs/en/guide/saas.md",
    "content": "# SaaS Edition {#saas}\n\nTo integrate the SaaS edition, users need to sign up for an account on HiAuth, add applications, and perform relevant settings. Then, they can use the obtained `client-id` and `client-secret` for integration. For a quick validation, we will use the demo account provided in the system for integration. After completing the validation, users can replace it with their own account.\n\n- The HiAuth authorization address is: http://auth.hiauth.cn\n- The HiAuth management address is: http://auth.hiauth.cn/admin\n\n## Example of Integrating with a SpringBoot Project\n- Create a SpringBoot project\n- Add dependencies\n- Add configurations\n- Add a home page\n\nIntegration with the SaaS edition can be completed with just these simple steps.\n\n## Running the HiAuth Source Code Demo {#hiauth-demo}\n### Environment Requirements\n- Git\n- JDK 17+\n- Maven 3.8+\n\n### Running Script\n```shell\n# Download HiAuth source code\n$ git clone https://github.com/bestaone/HiAuth.git\n# Enter the demo directory\n$ cd HiAuth/example/himall\n# Compile and install\n$ mvn clean install\n# Run\n$ mvn spring-boot:run\n```\n### Verification\n- Open a browser and visit: http://127.0.0.1:9000\n- Click the `Login` button, and you will be redirected to the unified authentication system. Enter the account: `corpadmin`, password: `123456`\n- After successful login, you will see the home page and the logged-in user information!\n\n## Step-by-Step Integration {#hand-by-hand}\n### Environment Requirements\n- JDK 17+\n- Maven 3.8+\n\n### Create an Empty SpringBoot Project\n\nUse [Spring Initializr](https://start.spring.io/) to create an empty SpringBoot project. The `pom.xml` file is as follows:\n\n```xml [pom.xml]\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" \n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 \n\thttps://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    \n\t<modelVersion>4.0.0</modelVersion>\n    \n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>3.4.5</version>\n\t\t<relativePath/>\n\t</parent>\n    \n\t<groupId>cn.hiauth</groupId>\n\t<artifactId>demo</artifactId>\n\t<version>0.0.1-SNAPSHOT</version>\n\t<name>demo</name>\n\t<description>Demo project for Spring Boot</description>\n    \n\t<properties>\n\t\t<java.version>17</java.version>\n\t</properties>\n    \n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n```\n\n### Add Dependencies\n```xml [pom.xml]\n<dependency>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-oauth2-client</artifactId>\n</dependency>\n```\n\n### Add Configurations\n```yml [application.yml]\nserver.port: 9000\nspring.security.oauth2.client:\n  provider:\n    # Authentication server information\n    hiauth-server:\n      # If you have deployed HiAuth privately, replace this address with the private deployment authentication server address\n      issuer-uri: http://auth.hiauth.cn\n      authorizationUri: http://auth.hiauth.cn/oauth2/authorize\n      # Token acquisition address\n      tokenUri: http://auth.hiauth.cn/oauth2/token\n      userInfoUri: http://auth.hiauth.cn/userinfo\n      jwkSetUri: http://auth.hiauth.cn/oauth2/jwks\n      #userNameAttribute: name\n  registration:\n    hiauth-code:\n      # Authentication provider, indicating which authentication server to use for authentication, associated with the above hiauth-server\n      provider: hiauth-server\n      # Client name\n      client-name: himall\n      # Client ID, obtained from the authentication platform\n      client-id: himall\n      # Client secret\n      client-secret: secret\n      # Client authentication method client_secret_basic\\client_secret_post\n      client-authentication-method: client_secret_basic\n      # Use authorization code mode to obtain token\n      authorization-grant-type: authorization_code\n      # Callback address after authentication, this address needs to be registered in the oauth2_registered_client table,\n      # otherwise the callback will be rejected\n      redirect-uri: http://127.0.0.1:9000/login/oauth2/code/hiauth-code\n      scope:\n        - profile\n        - openid\n```\n> Note: After adding the `application.yml` file, delete the `application.properties` file.\n\n### Add a Controller\n```java [IndexController.java]\npackage cn.hiauth.demo;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClient;\nimport org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;\nimport org.springframework.ui.Model;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.client.RestTemplate;\n\nimport java.util.Map;\n\n@RestController\npublic class IndexController {\n\n    private final RestTemplate restTemplate = new RestTemplate();\n\n    @Value(\"${spring.security.oauth2.client.provider.hiauth-server.userInfoUri}\")\n    private String userInfoUri;\n\n    @GetMapping(\"/\")\n    public Map<?, ?> index(Model model, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oAuth2AuthorizedClient) {\n        // After authentication, the accessToken will be obtained\n        String accessToken = oAuth2AuthorizedClient.getAccessToken().getTokenValue();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        // Set the request header and include the accessToken in it\n        headers.add(\"Authorization\", \"Bearer \" + accessToken);\n        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);\n        // Request the authentication server to obtain user information\n        return restTemplate.postForObject(this.userInfoUri, entity, Map.class);\n    }\n\n}\n```\n\n### Verification\n\n- Start the project and visit: http://127.0.0.1:9000. The system will detect that you are not logged in and redirect you to the unified authentication system;\n- Enter the account: `corpadmin`, password: `123456`. After successful login, you will be redirected back to the application;\n- In this demo, the home page directly outputs the logged-in user information in `json` format;\n```json\n{\n  \"sub\": \"corpadmin\",\n  \"empId\": 1,\n  \"avatarUrl\": \"/unpapi/image/2c924149ddfe4bd181959ee9bede10c0.jpeg\",\n  \"appId\": 91,\n  \"name\": \"Corporate Administrator\",\n  \"phoneNum\": \"13400000001\",\n  \"userId\": 11,\n  \"authorities\": [],\n  \"cid\": 1,\n  \"username\": \"corpadmin\"\n}\n```\n\n## Video Tutorial\n<iframe src=\"//player.bilibili.com/player.html?bvid=BV1KhZEYmEf1&page=1\" scrolling=\"no\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/en/guide/sourcecode.md",
    "content": "# Source Code Edition {#sourcecode}\nThe integration process for the source code edition is similar to the Docker edition, except that the Docker version of HiAuth is replaced with a source code compilation and startup.\n\n## Environment Requirements {#env-demand}\n- Git\n- JDK 17+\n- Maven 3.8+\n- Node.js v20.15+\n- pnpm 10.10+\n- PostgreSQL 16+\n- Redis\n\n## Installation and Integration Steps\n- Check the server environment\n- Download the source code\n- Initialize the HiAuth database by executing SQL scripts\n- Configure the HiAuth startup configuration file\n- Compile the source code and start the service\n- Verify using the HiAuth source code demo\n\n### Check the Server Environment {#check-env}\n```shell\n# Check the git version\n$ git --version\ngit version 1.8.3.1\n\n# Check the JDK version\n$ java -version\nopenjdk version \"17.0.5\" 2022-10-18\n\n# Check the Maven version\n$ mvn -v\nApache Maven 3.8.6 (36645f6c9b5079805ea5009217e36f2cffd34256)\n\n# Check the Node.js version\n$ node -v\nv20.15.0\n\n# Check the pnpm version\n$ pnpm -v\n9.14.2\n```\n\n### Download the Source Code {#download-source}\n```shell\n$ git clone https://github.com/bestaone/HiAuth.git\n```\n\n### Initialize the HiAuth Database by Executing SQL Scripts {#init-db}\n- Install `PostgreSQL 16+`;\n- Create a database named `hiauth`;\n- Execute the initialization script `HiAuth/other/hiauth.sql`;\n\n### Configure the HiAuth Startup Configuration File {#config-file}\n- Modify the configuration file `HiAuth/cicd/hiauth.properties` to your own settings;\n```properties [hiauth.properties]\n# Only PostgreSQL is supported\ndatasource.type=com.alibaba.druid.pool.DruidDataSource\ndatasource.driverClassName=org.postgresql.Driver\ndatasource.url=jdbc:postgresql://db_host:5432/hiauth\ndatasource.username=test\ndatasource.password=123456\n\nredis.host=redis_host\nredis.port=6379\nredis.database=0\nredis.username=test\nredis.password=123456\n```\n- Apply the configuration file by modifying `HiAuth/hiauth-server/src/main/resources/application.yml`;\n```yaml\n...\n# Replace `/hiauth/conf/hiauth.properties` with the file path you configured above\nspring.config.import: ${CONFIG_FILE:optional:/hiauth/conf/hiauth.properties}\n...\n```\n\n### Compile the Source Code and Start the Service {#compile-start}\n```shell\n# Compile and start the backend service\n$ cd HiAuth/hiauth-server\n$ mvn clean install\n$ mvn spring-boot:run\n\n# Compile and start the frontend service\n$ cd HiAuth/hiauth-front\n$ pnpm install\n$ pnpm dev:auth\n\n# Access the service\n$ curl http://127.0.0.1:8080\n{ \"code\": 50000, \"message\": \"Invalid or expired token\" }\n```\n- Check the backend service: http://127.0.0.1:8080\n- Check the frontend service: http://127.0.0.1:5666/admin (The port may change, please check the console)\n\n### Verify Using the HiAuth Source Code Demo {#hiauth-himall}\n- Modify the configuration `HiAuth/example/himall/src/main/resources/application.yml`\n```yaml\n...\nspring.security.oauth2.client:\n  provider:\n    hiauth-server:\n      # Change the value of issuer-uri from http://auth.hiauth.cn to http://127.0.0.1:8080\n      issuer-uri: http://auth.hiauth.cn\n...\n```\n- Compile and run\n```shell\n$ cd HiAuth/example/himall\n$ mvn clean install\n$ mvn spring-boot:run\n```\n\n### Verification\n- Open a browser and visit: http://127.0.0.1:9000\n- Click the `Login` button, and you will be redirected to the unified authentication system. Enter the account: `corpadmin`, password: `123456`\n- After successful login, you will see the home page and the logged-in user information!\n\n## Video Tutorial\n<iframe src=\"//player.bilibili.com/player.html?bvid=BV1KhZEYmERF&page=1\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/en/guide/test.md",
    "content": "edit..."
  },
  {
    "path": "docs/en/guide/what-is-hiauth.md",
    "content": "# What is HiAuth? {#what-is-hiauth}\n\nHiAuth is an authentication and authorization system based on the OAuth2.0 protocol. By integrating the HiAuth system, you can quickly enable authentication and authorization functions for your application. HiAuth supports SaaS mode, Docker private deployment mode, and source code compilation installation mode. Moreover, it is completely free and open-source.\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\nWant to give it a try? Jump to [Quick Start](./quick-start).\n\n</div>\n\n## Functions {#function}\n\n### **1. Authentication**\nBased on the `OAuth2.0` authorization protocol, it allows third-party applications to access user resources with user authorization, without sharing user credentials.\n- **Core Process**:\n    - **Authorization Code Mode**: Suitable for web applications, obtaining an access token through an authorization code exchange (most secure).\n    - **Implicit Mode**: Suitable for Single Page Applications (SPAs), directly returning an access token (no refresh token).\n    - **Password Mode**: Users directly provide their account and password to the client (for use only in trusted scenarios).\n    - **Client Credentials Mode**: Applications obtain tokens directly with their own identity (for service-to-service communication).\n- **Token Management**:\n    - Access Token is used for resource access, with a relatively short validity period.\n    - Refresh Token is used to obtain a new access token and must be securely stored.\n- **Security**:\n    - Enforces HTTPS transmission to prevent token leakage.\n    - Token Binding to prevent man-in-the-middle attacks.\n\n### **2. Access Authorization**\nAccess authorization (`Authorization`) determines whether users/applications can perform specific operations or access resources. It is based on `RBAC` (Role-Based Access Control), assigning permissions through roles (e.g., administrator, regular user).\n\n### **3. Application Management**\nManages the integration and lifecycle of third-party or internal applications.\n- **Core Functions**:\n    - **Application Registration**: Assigns unique `ClientID`/`ClientSecret`, defining permission scopes.\n    - **Key Rotation**: Regularly updates `ClientSecret` to prevent leakage risks.\n    - **Permission Control**: Limits the API or data scope that applications can access.\n- **Security Auditing**:\n    - Logs application behavior (e.g., API call frequency).\n    - Reviews application permission requests to ensure the principle of least privilege.\n\n### **4. Organization Management**\nManages the hierarchical structure and member relationships of enterprises or teams.\n- **Functions**:\n    - **Multi-level Architecture**: Supports nested structures such as departments, teams, and project groups.\n    - **Multi-tenancy Support**: Isolates data and permissions of different organizations (e.g., in SaaS scenarios).\n    - **Administrator Assignment**: Sets organization administrators to manage members and permissions.\n\n### **5. Permission Management**\nDefines and manages the operations that users or roles can perform.\n- **Core Mechanism**:\n    - **Permission Granularity**: Supports control at the API level, functional level, or data field level.\n    - **Permission Groups**: Packages permissions into templates (e.g., \"Finance Approval Group\").\n    - **Permission Inheritance and Overrides**: Sub-roles inherit permissions from parent roles, with the ability to make local adjustments.\n- **Audit and Compliance**:\n    - Permission change logs: Records who modified permissions and when.\n    - Regularly reviews permission assignments to avoid redundancy or excessive authorization.\n\n### **6. User Management**\nManages user identities, authentication, and lifecycle.\n- **Core Functions**:\n    - **Identity Storage**: Supports local databases.\n    - **Lifecycle Management**: User registration, disabling, deletion, and profile updates.\n    - **Authentication Enhancement**: Multi-Factor Authentication (MFA), Single Sign-On (SSO).\n\n\n## Video Tutorial\n<iframe src=\"//player.bilibili.com/player.html?bvid=BV1KhZEYmEU9&page=1\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/en/index.md",
    "content": "---\nlayout: home\n\ntitle: HiAuth\ntitleTemplate: Authentication and Authorization Service Based on OAuth2.0 Protocol\n\nhero:\n  name: HiAuth\n  text: Authentication and Authorization Service Based on OAuth2.0 Protocol\n  tagline: With just a few simple steps, you can integrate into your application\n  actions:\n    - theme: brand\n      text: Quick Start ->\n      link: /zh/guide/what-is-vitepress\n    - theme: alt\n      text: Online Preview\n      link: http://auth.hiauth.cn\n    - theme: alt\n      text: GitHub\n      link: https://github.com/bestaone/HiAuth\n  image:\n    src: /hiauth-large.png\n    alt: HiAuth\n\nfeatures:\n  - icon: 📝\n    title: Login authentication\n    details: Single sign on, multi login, single end login, mutually exclusive login, no login Multiple login strategies can be configured.\n  - icon: 🔐\n    title: Rights Management\n    details: Permission authentication, role management, permission management, menu management, session management, interface authentication Multiple flexible authentication schemes.\n  - icon: 🌐\n    title: OAuth2.0 protocol\n    details: Authentication service based on OAuth2.0 protocol, supporting four authorization modes for easy integration with different development language environments.\n  - icon: 🚀\n    title: Out of box\n    details: Provide SAAS version, one click deployment Docker version, and source code local deployment version, which can be developed based on source code for secondary development.\n---\n"
  },
  {
    "path": "docs/lunaria.config.json",
    "content": "{\n  \"$schema\": \"./node_modules/@lunariajs/core/config.schema.json\",\n  \"repository\": {\n    \"name\": \"bestaone/HiAuth\",\n    \"rootDir\": \"docs\"\n  },\n  \"files\": [\n    {\n      \"location\": \".vitepress/config/{en,zh,pt,ru,es,ko,fa}.ts\",\n      \"pattern\": \".vitepress/config/@lang.ts\",\n      \"type\": \"universal\"\n    },\n    {\n      \"location\": \"**/*.md\",\n      \"pattern\": \"@lang/@path\",\n      \"type\": \"universal\"\n    }\n  ],\n  \"defaultLocale\": {\n    \"label\": \"简体中文\",\n    \"lang\": \"zh\"\n  },\n  \"locales\": [\n    {\n      \"label\": \"English\",\n      \"lang\": \"en\"\n    }\n  ],\n  \"outDir\": \".vitepress/dist/_translations\",\n  \"ignoreKeywords\": [\"lunaria-ignore\"]\n}\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"docs\",\n  \"version\": \"3.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vitepress dev\",\n    \"build\": \"vitepress build\",\n    \"preview\": \"vitepress preview\",\n    \"lunaria:build\": \"lunaria build\",\n    \"lunaria:open\": \"open-cli .vitepress/dist/_translations/index.html\"\n  },\n  \"devDependencies\": {\n    \"@lunariajs/core\": \"^0.1.1\",\n    \"markdown-it-mathjax3\": \"^4.3.2\",\n    \"open-cli\": \"^8.0.0\",\n    \"postcss-rtlcss\": \"^5.6.0\",\n    \"vitepress\": \"2.0.0-alpha.3\",\n    \"vitepress-plugin-group-icons\": \"^1.3.6\"\n  }\n}\n"
  },
  {
    "path": "docs/public/pure.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <title>Plain HTML page | VitePress</title>\n    <meta charset=\"utf-8\" />\n    <meta name=\"robots\" content=\"noindex, nofollow\" />\n  </head>\n  <body>\n    <h1>Not part of the main VitePress docs site</h1>\n    <div>This page is plain HTML in the <code>public</code> directory.</div>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/zh/guide/about-topic.md",
    "content": "编辑中..."
  },
  {
    "path": "docs/zh/guide/backend.md",
    "content": "编辑中...\n"
  },
  {
    "path": "docs/zh/guide/docker.md",
    "content": "# Docker版 {#docker}\nDocker版的集成过程和SaaS版类似，只不过在集成前，我们需要部署一个Docker版本的HiAuth。Docker版的本地安装部署，依赖`PostgreSQL16+`、`Redis`，如果需要运行HiAuth自带的Demo的话，还需要 `JDK17` 和 `Maven 3.8+`环境。\n\n## 安装及集成步骤：\n- 检查服务器环境\n- 初始化HiAuth数据库，执行SQL脚本\n- 配置HiAuth的启动配置文件\n- 下载镜像、启动服务\n- 使用HiAuth源码Demo验证\n\n### 检查服务器环境 {#check-env}\n```shell\n# 检查git版本\n$ git --version\ngit version 1.8.3.1\n\n# 检查daocker版本\n$ docker -v\nDocker version 26.1.4, build 5650f9b\n\n# 检查JDK版本\n$ java -version\nopenjdk version \"17.0.5\" 2022-10-18\n\n# 检查maven版本\n$ mvn -v\nApache Maven 3.8.6 (36645f6c9b5079805ea5009217e36f2cffd34256)\n```\n\n### 初始化HiAuth数据库，执行SQL脚本 {#init-db}\n- 安装`PostgreSQL16+`；\n- 创建数据库`hiauth`；\n- 执行初始化脚本 `HiAuth/other/hiauth.sql` ；\n\n### 配置HiAuth的启动配置文件 {#config-file}\n- 创建配置文件 `/opt/install/hiauth/conf/hiauth.properties`，并配置正确的参数;\n```properties [hiauth.properties]\n# login page title, default:\nloginPage.title=Welcome Login\n# login page static file name\nloginPage.path=login\n# login page default username\nloginPage.username=\n# login page default password\nloginPage.password=\n# login page username placeholder\nloginPage.usernamePlaceholder=\n# login page password placeholder\nloginPage.passwordPlaceholder=\n# login types\nloginPage.loginTypes=phone,account,wechat\n\n# aliyun sms\naliyun.sms.accessKeyId=abcdefghi\naliyun.sms.accessKeySecret=abcdefghi\naliyun.sms.sign=HiAuth\naliyun.sms.smsTemplateCode=SMS_00000001\naliyun.sms.superSmsCode=888888\n\n# supported wechat qrcode login, config in wx open platform\nwechat.open.appid=wx123456789\nwechat.open.appSecret=abcdefghijklmnopqrstuvwxyz\nwechat.open.redirectUri=http://127.0.0.1:8080/wechat/doLogin\nwechat.open.style=black\nwechat.open.href=\n\n# only supported postgresql\ndatasource.type=com.alibaba.druid.pool.DruidDataSource\ndatasource.driverClassName=org.postgresql.Driver\ndatasource.url=jdbc:postgresql://db_host:5432/hiauth?stringtype=unspecified\ndatasource.username=test\ndatasource.password=123456\n\n# redis\nredis.host=redis_host\nredis.port=6379\nredis.database=0\nredis.username=test\nredis.password=123456\n```\n> 配置参考：[hiauth.properties](https://github.com/bestaone/HiAuth/blob/master/other/hiauth.properties)\n\n### 下载镜像、启动服务 {#download-image}\n```shell\n# 需要能够访问dockerhub中央仓库，可能需要梯子\n$ docker run -d \\\n  --restart=always \\\n  -p 9080:80 -p 8080:8080 \\\n  -v /opt/install/hiauth/conf:/hiauth/conf \\\n  -v /opt/install/hiauth/logs:/hiauth/logs \\\n  --name hiauth bestaone/hiauth:3.0.0\n  \n# 如果无法访问dockerhub中央仓库，可以从阿里云仓库下载镜像\n$ docker run -d \\\n  --restart=always \\\n  -p 9080:80 -p 8080:8080 \\\n  -v /opt/install/hiauth/conf:/hiauth/conf \\\n  -v /opt/install/hiauth/logs:/hiauth/logs \\\n  --name hiauth registry.cn-zhangjiakou.aliyuncs.com/bestaone/hiauth:3.0.0\n  \n# 查看镜像  \n$ docker images\nREPOSITORY                                                 TAG           IMAGE ID       CREATED         SIZE\nbestaone/hiauth                                            3.0.0         c5e4140bd5aa   3 hours ago     810MB\nregistry-vpc.cn-zhangjiakou.aliyuncs.com/bestaone/hiauth   3.0.0         c5e4140bd5aa   3 hours ago     810MB\n\n# 查看服务\n$ docker ps\nCONTAINER ID   IMAGE                   COMMAND                  CREATED        STATUS       PORTS                                                  NAMES\n3ea0fdb8a165   bestaone/hiauth:3.0.0   \"/hiauth/run.sh\"         3 hours ago    Up 3 hours   8080/tcp, 0.0.0.0:9080->80/tcp, :::9080->80/tcp        hiauth\n\n# 查看日志\n$ docker logs 3ea0fdb8a165\n...\nINFO 7 [main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer Tomcat started on port 8080 (http) with context path '/'\nINFO 7 [main] cn.hiauth.server.ServerStarter Started ServerStarter in 10.094 seconds (process running for 11.107)\n...\n\n# 访问服务\n$ curl http://127.0.0.1:9080\n{ \"code\": 50000, \"message\": \"令牌无效或已过期\" }\n```\n- Docker 版 HiAuth 授权地址为：http://127.0.0.1:9080\n- Docker 版 HiAuth 管理地址为：http://127.0.0.1:9080/admin\n\n### 使用HiAuth源码Demo验证 {#hiauth-himall}\n- 下载源码\n```shell\n$ git clone https://github.com/bestaone/HiAuth.git\n```\n- 修改配置`HiAuth/example/himall/src/main/resources/application.yml`\n```yaml\n...\nspring.security.oauth2.client:\n  provider:\n    hiauth-server:\n      # 将 issuer-uri 的值从 http://auth.hiauth.cn 改为 http://127.0.0.1:9080\n      issuer-uri: http://auth.hiauth.cn\n...\n```\n- 编译运行\n```shell\n$ cd HiAuth/example/himall\n$ mvn clean install\n$ mvn spring-boot:run\n```\n\n### 验证\n- 浏览器访问: http://127.0.0.1:9000\n- 点击`Login`按钮，会被重定向到统一认证系统，输入账号：`corpadmin`，密码：`123456`\n- 登录成功后，会看到首页及登录用户信息!\n\n## 视频教程\n<iframe src=\"//player.bilibili.com/player.html?bvid=BV14hZEYmEEq&page=1\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/zh/guide/frontend.md",
    "content": "编辑中..."
  },
  {
    "path": "docs/zh/guide/hiauth-client.md",
    "content": "编辑中..."
  },
  {
    "path": "docs/zh/guide/issue.md",
    "content": "编辑中...\n"
  },
  {
    "path": "docs/zh/guide/k8s.md",
    "content": "编辑中..."
  },
  {
    "path": "docs/zh/guide/quick-start.md",
    "content": "# 快速体验 {#quikc-start}\n\n## 管理后台 {#admin}\n\n在 [Admin端](http://auth.hiauth.cn/admin) 上体验。\n- 系统管理员账号：admin\\123456，可以看到所有的配置。通过切换租户，可以查看到当前租户的配置。为了防止乱改数据，此账号只有只读权限。\n- 企业管理员账号：corpadmin\\123456，可以看到租户内所有的配置。为了防止乱改数据，此账号只有只读权限。\n\n## 统一认证系统 {#auth}\n\n体验 [认证端](http://auth.hiauth.cn) 授权应用登录。三方应用集成后，会被重定向到此页面进行登录认证。\n\n## 文档 {#docs}\n\n在 [文档](http://hiauth.cn) 中获取帮助。"
  },
  {
    "path": "docs/zh/guide/saas.md",
    "content": "# SaaS版 {#saas}\n\nSaaS版的集成，需要用户在HiAuth上开通账号、添加应，并进行相关的设置后，使用你获取的 `client-id` 和 `client-secret` 进行集成。这里为了快速验证，我们使用系统中提供的demo账号来进行集成。等完成验证后，用户可以替换成自己的账号即可。\n\n- HiAuth 授权地址为：http://auth.hiauth.cn\n- HiAuth 管理地址为：http://auth.hiauth.cn/admin\n\n## 以SpringBoot项目为例，我们的集成需要以下几步：\n- 创建一个SpringBoot项目\n- 添加依赖\n- 添加配置\n- 添加一个首页\n\n只需以上简单几步就可以完成集成SaaS版。\n\n## 运行HiAuth源码自带demo {#hiauth-demo}\n### 环境要求\n- Git\n- JDK 17+\n- Maven 3.8+\n\n### 运行脚本\n```shell\n# 下载HiAuth源码\n$ git clone https://github.com/bestaone/HiAuth.git\n# 进入demo\n$ cd HiAuth/example/himall\n# 编译和安装\n$ mvn clean install\n# 运行\n$ mvn spring-boot:run\n```\n### 验证\n- 浏览器访问: http://127.0.0.1:9000\n- 点击`Login`按钮，会被重定向到统一认证系统，输入账号：`corpadmin`，密码：`123456`\n- 登录成功后，会看到首页及登录用户信息!\n\n## 手把手集成 {#hand-by-hand}\n### 环境要求\n- JDK 17+\n- Maven 3.8+\n\n### 创建一个空的SpringBoot项目\n\n使用 [Spring Initializr](https://start.spring.io/) 创建一个空的SpringBoot项目。pom.xml 文件如下：\n\n```xml [pom.xml]\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" \n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 \n\thttps://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    \n\t<modelVersion>4.0.0</modelVersion>\n    \n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>3.4.5</version>\n\t\t<relativePath/>\n\t</parent>\n    \n\t<groupId>cn.hiauth</groupId>\n\t<artifactId>demo</artifactId>\n\t<version>0.0.1-SNAPSHOT</version>\n\t<name>demo</name>\n\t<description>Demo project for Spring Boot</description>\n    \n\t<properties>\n\t\t<java.version>17</java.version>\n\t</properties>\n    \n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n```\n\n### 添加依赖\n```xml [pom.xml]\n<dependency>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-oauth2-client</artifactId>\n</dependency>\n```\n\n### 添加配置\n```yml [application.yml]\nserver.port: 9000\nspring.security.oauth2.client:\n  provider:\n    #认证服务器信息\n    hiauth-server:\n      # 如果你私有化部署了 HiAuth服务，请将此地址替换为私有部署的认证服务器地址\n      issuer-uri: http://auth.hiauth.cn\n      authorizationUri: http://auth.hiauth.cn/oauth2/authorize\n      #令牌获取地址\n      tokenUri: http://auth.hiauth.cn/oauth2/token\n      userInfoUri: http://auth.hiauth.cn/userinfo\n      jwkSetUri: http://auth.hiauth.cn/oauth2/jwks\n      #userNameAttribute: name\n  registration:\n    hiauth-code:\n      #认证提供者，标识由哪个认证服务器进行认证，和上面的hiauth-server进行关联\n      provider: hiauth-server\n      #客户端名称\n      client-name: himall\n      #客户端id，从认证平台申请的客户端id\n      client-id: himall\n      #客户端秘钥\n      client-secret: secret\n      #客户端认证方式 client_secret_basic\\client_secret_post\n      client-authentication-method: client_secret_basic\n      #使用授权码模式获取令牌（token）\n      authorization-grant-type: authorization_code\n      # 认证完成后回调的地址，需要在数据库表oauth2_registered_client中登记这个地址，\n      # 否则会拒绝回调\n      redirect-uri: http://127.0.0.1:9000/login/oauth2/code/hiauth-code\n      scope:\n        - profile\n        - openid\n```\n> 注意：添加完成 `application.yml` 文件后，将 `application.properties` 文件删除掉\n\n### 添加一个Controller\n```java [IndexController.java]\npackage cn.hiauth.demo;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClient;\nimport org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;\nimport org.springframework.ui.Model;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.client.RestTemplate;\n\nimport java.util.Map;\n\n@RestController\npublic class IndexController {\n\n    private final RestTemplate restTemplate = new RestTemplate();\n\n    @Value(\"${spring.security.oauth2.client.provider.hiauth-server.userInfoUri}\")\n    private String userInfoUri;\n\n    @GetMapping(\"/\")\n    public Map<?, ?> index(Model model, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oAuth2AuthorizedClient) {\n        // 认证完后会获取到 accessToken\n        String accessToken = oAuth2AuthorizedClient.getAccessToken().getTokenValue();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        // 设置请求头，将 accessToken 放入请求头中\n        headers.add(\"Authorization\", \"Bearer \" + accessToken);\n        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);\n        // 请求认证服务器获取用户信息\n        return restTemplate.postForObject(this.userInfoUri, entity, Map.class);\n    }\n\n}\n```\n\n### 验证\n\n- 启动项目，访问: http://127.0.0.1:9000，系统检测到未登录，会被重定向到统一认证系统；\n- 输入账号：`corpadmin`，密码：`123456`，登录成功后，会跳转回应用；\n- 这个demo中。首页直接输出了登录用户信息，以`json`格式；\n```json\n{\n  \"sub\": \"corpadmin\",\n  \"empId\": 1,\n  \"avatarUrl\": \"/unpapi/image/2c924149ddfe4bd181959ee9bede10c0.jpeg\",\n  \"appId\": 91,\n  \"name\": \"企业管理员\",\n  \"phoneNum\": \"13400000001\",\n  \"userId\": 11,\n  \"authorities\": [],\n  \"cid\": 1,\n  \"username\": \"corpadmin\"\n}\n```\n\n## 视频教程\n<iframe src=\"//player.bilibili.com/player.html?bvid=BV1KhZEYmEf1&page=1\" scrolling=\"no\" allowfullscreen></iframe>\n\n"
  },
  {
    "path": "docs/zh/guide/sourcecode.md",
    "content": "# 源码版 {#sourcecode}\n源码版的集成过程和Docker版类似，只不过将Docker版本的HiAuth改为源码编译启动。\n\n## 环境要求 {#env-demand}\n- Git\n- JDK 17+\n- Maven 3.8+\n- Nodejs v20.15+\n- pnpm 10.10+\n- PostgreSQL16+\n- Redis\n\n## 安装及集成步骤\n- 检查服务器环境\n- 下载源码\n- 初始化HiAuth数据库，执行SQL脚本\n- 配置HiAuth的启动配置文件\n- 编译源码、启动服务\n- 使用HiAuth源码Demo验证\n\n### 检查服务器环境 {#check-env}\n```shell\n# 检查git版本\n$ git --version\ngit version 1.8.3.1\n\n# 检查JDK版本\n$ java -version\nopenjdk version \"17.0.5\" 2022-10-18\n\n# 检查maven版本\n$ mvn -v\nApache Maven 3.8.6 (36645f6c9b5079805ea5009217e36f2cffd34256)\n\n# 检查node版本\n$ node -v\nv20.15.0\n\n# 检查pnpm版本\n$ pnpm -v\n9.14.2\n```\n\n### 下载源码 {#download-source}\n```shell\n$ git clone https://github.com/bestaone/HiAuth.git\n```\n\n### 初始化HiAuth数据库，执行SQL脚本 {#init-db}\n- 安装`PostgreSQL16+`；\n- 创建数据库`hiauth`；\n- 执行初始化脚本 `HiAuth/other/hiauth.sql` ；\n\n### 配置HiAuth的启动配置文件 {#config-file}\n- 修改配置文件 `HiAuth/cicd/hiauth.properties`，改成你自己的配置;\n```properties [hiauth.properties]\n# only supported postgresql\ndatasource.type=com.alibaba.druid.pool.DruidDataSource\ndatasource.driverClassName=org.postgresql.Driver\ndatasource.url=jdbc:postgresql://db_host:5432/hiauth\ndatasource.username=test\ndatasource.password=123456\n\nredis.host=redis_host\nredis.port=6379\nredis.database=0\nredis.username=test\nredis.password=123456\n```\n- 应用配置文件，修改`HiAuth/hiauth-server/src/main/resources/application.yml`;\n```yaml\n...\n# 将 /hiauth/conf/hiauth.properties 替换为你上面配置的文件路径\nspring.config.import: ${CONFIG_FILE:optional:/hiauth/conf/hiauth.properties}\n...\n```\n\n### 编译源码、启动服务 {#compile-start}\n```shell\n# 编译、启动服务端\n$ cd HiAuth/hiauth-server\n$ mvn clean install\n$ mvn spring-boot:run\n\n# 编译、启动前端\n$ cd HiAuth/hiauth-front\n$ pnpm install\n$ pnpm dev:auth\n\n# 访问服务\n$ curl http://127.0.0.1:8080\n{ \"code\": 50000, \"message\": \"令牌无效或已过期\" }\n```\n- 检查后端服务：http://127.0.0.1:8080\n- 检查前端服务：http://127.0.0.1:5666/admin (端口可能会变化，请自行查看控制台)\n\n### 使用HiAuth源码Demo验证 {#hiauth-himall}\n- 修改配置`HiAuth/example/himall/src/main/resources/application.yml`\n```yaml\n...\nspring.security.oauth2.client:\n  provider:\n    hiauth-server:\n      # 将 issuer-uri 的值从 http://auth.hiauth.cn 改为 http://127.0.0.1:8080\n      issuer-uri: http://auth.hiauth.cn\n...\n```\n- 编译运行\n```shell\n$ cd HiAuth/example/himall\n$ mvn clean install\n$ mvn spring-boot:run\n```\n\n### 验证\n- 浏览器访问: http://127.0.0.1:9000\n- 点击`Login`按钮，会被重定向到统一认证系统，输入账号：`corpadmin`，密码：`123456`\n- 登录成功后，会看到首页及登录用户信息!\n\n## 视频教程\n<iframe src=\"//player.bilibili.com/player.html?bvid=BV1KhZEYmERF&page=1\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/zh/guide/test.md",
    "content": "编辑中..."
  },
  {
    "path": "docs/zh/guide/what-is-hiauth.md",
    "content": "# HiAuth是什么？ {#what-is-hiauth}\n\nHiAuth是一个基于OAuth2.0协议的认证授权系统，通过集成HiAuth系统可以快速的开启应用的认证和授权功能。HiAuth支持SaaS模式、Docker私有化部署模式、源码编译安装模式。而且完全免费，完全开源。\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\n想尝试一下？跳到 [快速开始](./quick-start)。\n\n</div>\n\n## 功能 {#function}\n\n### **1. 登录认证**\n基于`OAuth2.0`授权协议，允许第三方应用在用户授权下访问其资源，而无需共享用户凭证。\n- **核心流程**：\n    - **授权码模式**：适用于Web应用，通过授权码交换访问令牌（最安全）。\n    - **隐式模式**：适用于单页应用（SPA），直接返回访问令牌（无刷新令牌）。\n    - **密码模式**：用户直接提供账号密码给客户端（仅信任场景使用）。\n    - **客户端凭证模式**：应用直接以自身身份获取令牌（用于服务间通信）。\n- **令牌管理**：\n    - 访问令牌（Access Token）用于资源访问，有效期较短。\n    - 刷新令牌（Refresh Token）用于获取新访问令牌，需安全存储。\n- **安全性**：\n    - 强制HTTPS传输，防止令牌泄露。\n    - 令牌绑定（Token Binding）防止中间人攻击。\n\n### **2. 访问授权**\n访问授权（`Authorization`）决定用户/应用能否执行特定操作或访问资源。基于`RBAC`（基于角色的访问控制），通过角色分配权限（如管理员、普通用户）。\n\n### **3. 应用管理**\n管理第三方或内部应用的接入与生命周期。\n- **核心功能**：\n    - **应用注册**：分配唯一`ClientID`/`ClientSecret`，定义权限范围`Scopes`。\n    - **密钥轮换**：定期更新`ClientSecret`，防止泄露风险。\n    - **权限控制**：限制应用可访问的API或数据范围。\n- **安全审计**：\n    - 记录应用行为日志（如API调用频率）。\n    - 审核应用权限申请，确保最小权限原则。\n\n### **4. 组织管理**\n管理企业或团队的层级结构与成员关系。\n- **功能**：\n    - **多层级架构**：支持部门、团队、项目组等嵌套结构。\n    - **多租户支持**：隔离不同组织的数据与权限（如SaaS场景）。\n    - **管理员分配**：设置组织管理员，管理成员与权限。\n\n### **5. 权限管理**\n定义和管理用户或角色可执行的操作。\n- **核心机制**：\n    - **权限粒度**：支持API级、功能级或数据字段级控制。\n    - **权限组**：将权限打包为模板（如“财务审批组”）。\n    - **权限继承与覆盖**：子角色继承父角色权限，可局部调整。\n- **审计与合规**：\n    - 权限变更日志：记录谁在何时修改了权限。\n    - 定期审查权限分配，避免冗余或过度授权。\n\n### **6. 用户管理**\n管理用户身份、认证与生命周期。\n- **核心功能**：\n    - **身份存储**：支持本地数据库。\n    - **生命周期管理**：用户注册、禁用、删除及资料更新。\n    - **认证增强**：多因素认证（MFA）、单点登录（SSO）。\n\n\n## 视频教程\n<iframe src=\"//player.bilibili.com/player.html?bvid=BV1KhZEYmEU9&page=1\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/zh/index.md",
    "content": "---\nlayout: home\n\ntitle: HiAuth\ntitleTemplate: 基于OAuth2.0协议的认证授权服务\n\nhero:\n  name: HiAuth\n  text: 基于OAuth2.0协议的认证授权服务\n  tagline: 只需简单几步，即可将认证授权功能集成到你的应用中\n  actions:\n    - theme: brand\n      text: 快速开始 ->\n      link: /guide/what-is-hiauth\n    - theme: alt\n      text: 在线预览\n      link: http://auth.hiauth.cn/admin\n    - theme: alt\n      text: GitHub\n      link: https://github.com/bestaone/HiAuth\n  image:\n      src: /hiauth-large.png\n      alt: HiAuth\n\nfeatures:\n  - icon: 📝\n    title: 登录认证\n    details: 单点登录、多端登录、单端登录、互斥登录、免登录... 多种登录策略可配置。\n  - icon: 🔐\n    title: 权限管理\n    details: 权限认证、角色管理、权限管理、菜单管理、会话管理、接口鉴权... 多种方案灵活鉴权。\n  - icon: 🌐\n    title: OAuth2.0协议\n    details: 基于OAuth2.0协议的认证服务，支持四种授权模式，方便与不同开发语言环境对接。\n  - icon: 🚀\n    title: 开箱即用\n    details: 提供SaaS版、一键部署Docker版、源码本地部署版，可以基于源码二次开发，免费、开源。\n---\n"
  },
  {
    "path": "example/demo/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.4.5</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>demo</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>demo</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-oauth2-client</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/demo/src/main/java/cn/hiauth/demo/DemoApplication.java",
    "content": "package cn.hiauth.demo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class DemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/demo/src/main/java/cn/hiauth/demo/IndexController.java",
    "content": "package cn.hiauth.demo;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.core.annotation.AuthenticationPrincipal;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClient;\nimport org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;\nimport org.springframework.security.oauth2.core.oidc.user.OidcUser;\nimport org.springframework.ui.Model;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.client.RestTemplate;\n\nimport java.util.Map;\n\n@RestController\npublic class IndexController {\n\n    private final RestTemplate restTemplate = new RestTemplate();\n\n    @Value(\"${spring.security.oauth2.client.provider.hiauth-server.userInfoUri}\")\n    private String userInfoUri;\n\n    @GetMapping(\"/\")\n    public Map<?, ?> index(Model model, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oAuth2AuthorizedClient, @AuthenticationPrincipal OidcUser oidcUser) {\n        // 认证完后会获取到 accessToken\n        String accessToken = oAuth2AuthorizedClient.getAccessToken().getTokenValue();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        // 设置请求头，将 accessToken 放入请求头中\n        headers.add(\"Authorization\", \"Bearer \" + accessToken);\n        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);\n        // 请求认证服务器获取用户信息\n        return restTemplate.postForObject(this.userInfoUri, entity, Map.class);\n    }\n\n}"
  },
  {
    "path": "example/demo/src/main/resources/application.yml",
    "content": "server.port: 9000\n\nlogging.level:\n  root: DEBUG\n\nspring.security.oauth2.client:\n  provider:\n    #认证服务器信息\n    hiauth-server:\n      # 如果你私有化部署了 HiAuth服务，请将此地址替换为私有部署的认证服务器地址\n      issuer-uri: http://auth.hiauth.cn\n      authorizationUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/authorize\n      tokenUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/token\n      userInfoUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/userinfo\n      jwkSetUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/jwks\n      #userNameAttribute: name\n  registration:\n    hiauth-code:\n      #认证提供者，标识由哪个认证服务器进行认证，和上面的hiauth-server进行关联\n      provider: hiauth-server\n      client-name: himall\n      client-id: himall\n      client-secret: secret\n      #客户端认证方式 client_secret_basic\\client_secret_post\n      client-authentication-method: client_secret_basic\n      #使用授权码模式获取令牌（token）\n      authorization-grant-type: authorization_code\n      # 认证完成后回调的地址，需要在数据库表oauth2_registered_client中登记这个地址，\n      # 否则会拒绝回调\n      redirect-uri: http://127.0.0.1:9000/login/oauth2/code/hiauth-code\n      scope: openid,profile"
  },
  {
    "path": "example/hiauth-client/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.4.5</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-client</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <name>hiauth-client</name>\n    <description>集成HiAuth认证系统</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>webjars-locator-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>bootstrap</artifactId>\n            <version>3.3.7</version>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>jquery</artifactId>\n            <version>3.6.3</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.hiauth</groupId>\n            <artifactId>hiauth-client-spring-boot-starter</artifactId>\n            <version>1.0.9</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>hiauth-client</finalName>\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n                <filtering>true</filtering>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-resources-plugin</artifactId>\n                <configuration>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/hiauth-client/src/main/java/cn/hiauth/hiauthclient/HiauthClientStarter.java",
    "content": "package cn.hiauth.hiauthclient;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\n\n@ComponentScan(basePackages = {\"cn.hiauth.client\", \"cn.hiauth.hiauthclient\"})\n@SpringBootApplication\npublic class HiauthClientStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(HiauthClientStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-client/src/main/java/cn/hiauth/hiauthclient/config/WebMvcConfig.java",
    "content": "package cn.hiauth.hiauthclient.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.CacheControl;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport java.util.concurrent.TimeUnit;\n\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/static/**\", \"/webjars/**\")\n                .addResourceLocations(\"classpath:/static/\", \"classpath:/META-INF/resources/webjars/\")\n                .setCacheControl(CacheControl.maxAge(0, TimeUnit.HOURS).cachePrivate());\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-client/src/main/java/cn/hiauth/hiauthclient/controller/ApiController.java",
    "content": "package cn.hiauth.hiauthclient.controller;\n\nimport cn.hiauth.client.Authentication;\nimport cn.hiauth.client.SessionContextHolder;\nimport cn.webestar.scms.commons.R;\nimport jakarta.servlet.http.HttpServletRequest;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@Slf4j\n@Validated\n@RestController\n@RequestMapping(\"/api\")\npublic class ApiController {\n\n    @GetMapping(\"/getAuth\")\n    public R<Authentication> getAuth(HttpServletRequest request) {\n        Authentication auth = SessionContextHolder.getAuthentication();\n        return R.success(auth);\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-client/src/main/java/cn/hiauth/hiauthclient/controller/IndexController.java",
    "content": "package cn.hiauth.hiauthclient.controller;\n\nimport cn.hiauth.client.Authentication;\nimport cn.hiauth.client.Constant;\nimport cn.hiauth.client.SessionContextHolder;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.GetMapping;\n\nimport java.time.LocalDateTime;\n\n@Slf4j\n@Controller\npublic class IndexController {\n\n    @GetMapping({\"/\", \"/index\"})\n    public String index(HttpServletRequest request, HttpServletResponse response, Model model) {\n        // 这个为了简单就直接判断accessToken了，实际情况应该判断 SessionContextHolder.getContext().getAuth()\n        String accessToken = request.getParameter(Constant.PARAMETER_TOKEN_KEY);\n        if (StringUtils.hasText(accessToken)) {\n            request.getSession().setAttribute(\"isAuth\", true);\n            model.addAttribute(Constant.PARAMETER_TOKEN_KEY, accessToken);\n        } else {\n            request.getSession().setAttribute(\"isAuth\", false);\n        }\n        return \"index\";\n    }\n\n    @GetMapping(\"/api/profile\")\n    public String profile(HttpServletRequest request, Model model) {\n        Authentication auth = SessionContextHolder.getContext().getAuth();\n        model.addAttribute(Constant.PARAMETER_TOKEN_KEY, request.getParameter(Constant.PARAMETER_TOKEN_KEY));\n        model.addAttribute(\"name\", auth.getName());\n        model.addAttribute(\"username\", auth.getUsername());\n        model.addAttribute(\"tel\", auth.getPhoneNum());\n        model.addAttribute(\"lastLoginTime\", LocalDateTime.now());\n        request.getSession().setAttribute(\"isAuth\", true);\n        return \"profile\";\n    }\n\n}"
  },
  {
    "path": "example/hiauth-client/src/main/resources/application.yml",
    "content": "server.port: 9000\n\nlogging.level:\n  root: INFO\n  cn.hiauth: DEBUG\n\nspring.security.oauth2.client:\n  provider:\n    #认证服务器信息\n    hiauth-server:\n      # 如果你私有化部署了 HiAuth服务，请将此地址替换为私有部署的认证服务器地址\n      issuer-uri: http://auth.hiauth.cn\n      authorizationUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/authorize\n      tokenUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/token\n      userInfoUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/userinfo\n      jwkSetUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/jwks\n      #userNameAttribute: name\n  registration:\n    hiauth-code:\n      #认证提供者，标识由哪个认证服务器进行认证，和上面的hiauth-server进行关联\n      provider: hiauth-server\n      client-name: himall\n      client-id: himall\n      client-secret: secret\n      #客户端认证方式 client_secret_basic\\client_secret_post\n      client-authentication-method: client_secret_basic\n      #使用授权码模式获取令牌（token）\n      authorization-grant-type: authorization_code\n      # 认证完成后回调的地址，需要在数据库表oauth2_registered_client中登记这个地址，否则会拒绝回调\n      redirect-uri: http://127.0.0.1:9000/oauth2/token/redirect\n      scope: openid,profile\n\napp.security.enable: true\n\nhiauth.client:\n  cachePrefix: hiauthclient\n  checkPermission: false\n  authSuccessRedirectUri: http://127.0.0.1:9000\n  authUris:\n    - /api/**\n  ignoreUris:\n    - /unpapi/**\n\nspring.data.redis:\n  host: 192.168.3.143\n  port: 26379\n  database: 0\n  username:\n  password: Vking1357!\n  timeout: 10000\n  connect-timeout: 10000"
  },
  {
    "path": "example/hiauth-client/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"hiauth-client.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/hiauth-client/src/main/resources/static/css/index.css",
    "content": "/* Space out content a bit */\nbody {\n  padding-top: 20px;\n  padding-bottom: 20px;\n}\n\n/* Everything but the jumbotron gets side spacing for mobile first views */\n.header,\n.marketing,\n.footer {\n  padding-right: 15px;\n  padding-left: 15px;\n}\n\n/* Custom page header */\n.header {\n  padding-bottom: 20px;\n  border-bottom: 1px solid #e5e5e5;\n}\n/* Make the masthead heading the same height as the navigation */\n.header h3 {\n  margin-top: 0;\n  margin-bottom: 0;\n  line-height: 40px;\n}\n\n/* Custom page footer */\n.footer {\n  padding-top: 19px;\n  color: #777;\n  border-top: 1px solid #e5e5e5;\n}\n\n/* Customize container */\n@media (min-width: 768px) {\n  .container {\n    max-width: 730px;\n  }\n}\n.container-narrow > hr {\n  margin: 30px 0;\n}\n\n/* Main marketing message and sign up button */\n.jumbotron {\n  text-align: center;\n  border-bottom: 1px solid #e5e5e5;\n}\n.jumbotron .btn {\n  padding: 14px 24px;\n  font-size: 21px;\n}\n\n/* Supporting marketing content */\n.marketing {\n  margin: 40px 0;\n}\n.marketing p + h4 {\n  margin-top: 28px;\n}\n\n/* Responsive: Portrait tablets and up */\n@media screen and (min-width: 768px) {\n  /* Remove the padding we set earlier */\n  .header,\n  .marketing,\n  .footer {\n    padding-right: 0;\n    padding-left: 0;\n  }\n  /* Space out the masthead */\n  .header {\n    margin-bottom: 30px;\n  }\n  /* Remove the bottom border on the jumbotron for visual effect */\n  .jumbotron {\n    border-bottom: 0;\n  }\n}\n"
  },
  {
    "path": "example/hiauth-client/src/main/resources/templates/demo.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"https://www.thymeleaf.org\" xmlns:sec=\"https://www.thymeleaf.org/thymeleaf-extras-springsecurity5\">\n    <head>\n        <title>Spring Security OAuth 2.0 Sample</title>\n        <meta charset=\"utf-8\" />\n        <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n        <link th:rel=\"stylesheet\" th:href=\"@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css} \">\n    </head>\n    <body>\n        <div th:fragment=\"header\">\n            <nav class=\"navbar navbar-default\">\n                <div class=\"container\">\n                    <div class=\"container-fluid\">\n                        <div class=\"navbar-collapse collapse\" id=\"navbar\">\n                        </div>\n                    </div>\n                </div>\n            </nav>\n        </div>\n        <div class=\"container\">\n            <div th:if=\"${error}\" class=\"alert alert-danger alert-dismissible\" role=\"alert\">\n                <button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\n                <h4 th:text=\"${error}\" class=\"text-center\"></h4>\n            </div>\n            <div class=\"panel panel-default\">\n                <div class=\"panel-heading\">\n                    <h3 class=\"panel-title\">Authorize the client using <span style=\"font-family:monospace\">grant_type</span>:</h3>\n                </div>\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <a href=\"/authorize?grant_type=authorization_code\" th:href=\"@{/authorize?grant_type=authorization_code}\"><span style=\"font-size:medium\">Authorization Code</span>&nbsp;&nbsp;<small class=\"text-muted\">(Login to Spring Authorization Server using: user1/password)</small></a>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <a href=\"/authorize?grant_type=client_credentials\" th:href=\"@{/authorize?grant_type=client_credentials}\"><span style=\"font-size:medium\">Client Credentials</span></a>\n                    </li>\n                </ul>\n                <div th:if=\"${messages}\" class=\"panel-footer\">\n                    <h4>Messages:</h4>\n                    <table class=\"table table-condensed\">\n                        <tbody>\n                            <tr class=\"row\" th:each=\"message : ${messages}\">\n                                <td th:text=\"${message}\">message</td>\n                            </tr>\n                        </tbody>\n                    </table>\n                </div>\n            </div>\n        </div>\n        <script src=\"/webjars/jquery/jquery.min.js\" th:src=\"@{/webjars/jquery/3.6.3/jquery.min.js}\"></script>\n        <script th:src=\"@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}\"></script>\n    </body>\n</html>\n"
  },
  {
    "path": "example/hiauth-client/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>HiMall</title>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n    <link rel=\"icon\" th:href=\"@{/static/favicon.ico}\">\n    <link th:rel=\"stylesheet\" th:href=\"@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css} \">\n    <link th:href=\"@{/static/css/index.css}\" rel=\"stylesheet\">\n</head>\n<body>\n\n<div class=\"container\">\n    <div class=\"header clearfix\">\n        <nav>\n            <ul class=\"nav nav-pills pull-right\">\n                <li role=\"presentation\" class=\"active\"><a th:href=\"'/?accessToken=' + ${accessToken}\">Home</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\"><a th:href=\"'/api/profile?accessToken=' + ${accessToken}\">Profile</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? !session.isAuth : true}\"><a th:href=\"'/oauth2/login?accessToken=' + ${accessToken}\">Login</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\"><a th:href=\"'/oauth2/logout?accessToken=' + ${accessToken}\">Logout</a></li>\n            </ul>\n        </nav>\n        <h3 class=\"text-muted\">HIMALL</h3>\n    </div>\n\n    <div class=\"jumbotron\">\n        <h1>HiMall Example</h1>\n        <p class=\"lead\">This example is a quick exercise to illustrate how Integrate HiAuth by Oauth2, an integrated instance of microservices is also included here, so you can find some best practices.</p>\n        <p><a class=\"btn btn-lg btn-success\" href=\"https://github.com/bestaone/HiAuth\" role=\"button\">View HiMall docs</a></p>\n    </div>\n\n    <div class=\"row marketing\">\n        <div class=\"col-lg-6\"></div>\n        <div class=\"col-lg-6\"></div>\n    </div>\n\n    <footer class=\"footer\">\n        <p>&copy; HiMall system for hiauth.com, by 码道功臣@webestar.cn</p>\n    </footer>\n\n</div>\n\n<script th:src=\"@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "example/hiauth-client/src/main/resources/templates/profile.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>HiMall</title>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n    <link rel=\"icon\" th:href=\"@{/static/favicon.ico}\">\n    <link th:rel=\"stylesheet\" th:href=\"@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css} \">\n    <link th:href=\"@{/static/css/index.css}\" rel=\"stylesheet\">\n</head>\n<body>\n\n<div class=\"container\">\n    <div class=\"header clearfix\">\n        <nav>\n            <ul class=\"nav nav-pills pull-right\">\n                <li role=\"presentation\"><a th:href=\"'/?accessToken=' + ${accessToken}\">Home</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\" class=\"active\"><a th:href=\"'/api/profile?accessToken=' + ${accessToken}\">Profile</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? !session.isAuth : true}\"><a th:href=\"'/oauth2/login?accessToken=' + ${accessToken}\">Login</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\"><a th:href=\"'/oauth2/logout?accessToken=' + ${accessToken}\">Logout</a></li>\n            </ul>\n        </nav>\n        <h3 class=\"text-muted\">HIMALL</h3>\n    </div>\n\n    <div style=\"margin-top: 30px;\"><span class=\"glyphicon glyphicon-user\" aria-hidden=\"true\"></span> 用户信息</div>\n    <div class=\"row\">\n        <div class=\"col-md-2 title\">用户姓名：</div><div class=\"col-md-4 text\" th:text=\"${name}\"></div>\n        <div class=\"col-md-2 title\">用户账号：</div><div class=\"col-md-4 text\" th:text=\"${username}\"></div>\n        <div class=\"col-md-2 title\">手机号码：</div><div class=\"col-md-4 text\" th:text=\"${tel}\"></div>\n        <div class=\"col-md-2 title\">最近登录：</div><div class=\"col-md-4 text\" th:text=\"${lastLoginTime}\"></div>\n    </div>\n\n    <div style=\"margin-top: 30px;\"><span class=\"glyphicon glyphicon-list-alt\" aria-hidden=\"true\"></span> 我的订单</div>\n    <div class=\"row\">\n        <div class=\"col-md-2 title\">订单编号：</div><div class=\"col-md-4 text\" th:text=\"${orderNo}\"></div>\n        <div class=\"col-md-2 title\">订单标题：</div><div class=\"col-md-4 text\" th:text=\"${orderTitle}\"></div>\n        <div class=\"col-md-2 title\">创建时间：</div><div class=\"col-md-4 text\" th:text=\"${orderCreateTime}\"></div>\n        <div class=\"col-md-2 title\">订单总额：</div><div class=\"col-md-4 text\" th:text=\"${orderTotalAmount}\"></div>\n    </div>\n\n    <div class=\"row\" style=\"margin-top: 30px; padding: 0px 15px;\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">商品列表</div>\n            <table class=\"table\">\n                <thead>\n                    <tr>\n                        <th>#</th>\n                        <th>商品名称</th>\n                        <th>单价（元）</th>\n                        <th>库存（个）</th>\n                        <th>上架时间</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr th:each=\"goods,stat : ${goodsList}\">\n                        <th scope=\"row\" th:text=\"${stat.index + 1}\"></th>\n                        <td th:text=\"${goods.title}\"></td>\n                        <td th:text=\"${goods.price}\"></td>\n                        <td th:text=\"${goods.amount}\"></td>\n                        <td th:text=\"${goods.createTime}\"></td>\n                    </tr>\n                </tbody>\n            </table>\n\n        </div>\n    </div>\n\n    <footer class=\"footer\">\n        <p>&copy; HiMall system for hiauth.com, by 码道功臣@webestar.cn.</p>\n    </footer>\n\n</div>\n\n<script th:src=\"@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "example/hiauth-client-exp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.4.5</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-client-exp</artifactId>\n    <version>3.0.0-SNAPSHOT</version>\n    <name>hiauth-server</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencies>\n        <!-- Spring Boot Starters -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-oauth2-client</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>hiauth-client-exp</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.graalvm.buildtools</groupId>\n                <artifactId>native-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <excludes>\n                        <exclude>\n                            <groupId>org.projectlombok</groupId>\n                            <artifactId>lombok</artifactId>\n                        </exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/hiauth-client-exp/src/main/java/cn/hiauth/client/ClientStarter.java",
    "content": "package cn.hiauth.client;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class ClientStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ClientStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-client-exp/src/main/java/cn/hiauth/client/config/BeanConfig.java",
    "content": "package cn.hiauth.client.config;\n\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class BeanConfig {\n\n}\n"
  },
  {
    "path": "example/hiauth-client-exp/src/main/java/cn/hiauth/client/config/SecurityConfig.java",
    "content": "package cn.hiauth.client.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\n\n@Configuration\n@EnableWebSecurity\npublic class SecurityConfig {\n\n}"
  },
  {
    "path": "example/hiauth-client-exp/src/main/java/cn/hiauth/client/config/WebMvcConfig.java",
    "content": "package cn.hiauth.client.config;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.CacheControl;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport java.util.concurrent.TimeUnit;\n\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n\n    @Value(\"${app.cacheControl.maxAge:0}\")\n    private Integer maxAge;\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/static/**\", \"/webjars/**\")\n                .addResourceLocations(\"classpath:/static/\", \"classpath:/META-INF/resources/webjars/\")\n                .setCacheControl(CacheControl.maxAge(maxAge, TimeUnit.HOURS).cachePrivate());\n    }\n\n}"
  },
  {
    "path": "example/hiauth-client-exp/src/main/java/cn/hiauth/client/controller/ClientController.java",
    "content": "package cn.hiauth.client.controller;\n\nimport org.springframework.stereotype.Controller;\n\n@Controller\npublic class ClientController {\n\n}\n"
  },
  {
    "path": "example/hiauth-client-exp/src/main/resources/application.yml",
    "content": "server.port: 9000\n\nspring.security.oauth2.client:\n  provider:\n    hiauth-code:\n      issuer-uri: http://localhost:8080\n      authorizationUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/authorize\n      tokenUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/token\n      userInfoUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/userinfo\n      jwkSetUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/jwks\n      user-name-attribute: sub\n  registration:\n    hiauth-code:\n      client-name: HiAuth Authorization Server\n      client-id: himall\n      client-secret: secret\n      authorization-grant-type: authorization_code\n      redirect-uri: http://127.0.0.1:9000/login/oauth2/code/hiauth-code\n      scope: openid,profile"
  },
  {
    "path": "example/hiauth-client-exp/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\"\n              value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\"/>\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\"\n              value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\"/>\n    <property name=\"LOG_FILE\" value=\"./hiauth/logs/client.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\"/>\n    <conversionRule conversionWord=\"wex\"\n                    converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\"/>\n    <conversionRule conversionWord=\"wEx\"\n                    converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\"/>\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/hiauth-client-exp/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>OAuth2 Client Demo</title>\n    <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n</head>\n<body>\nindex\n</body>\n</html>"
  },
  {
    "path": "example/hiauth-server-exp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.4.5</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-server-exp</artifactId>\n    <version>3.0.0-SNAPSHOT</version>\n    <name>hiauth-server</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencies>\n        <!-- 开发支持：热启动等 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <scope>runtime</scope>\n            <optional>true</optional>\n        </dependency>\n        <!-- web服务必选 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- authorization server -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>\n        </dependency>\n        <!-- Spring Boot验证依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n        <!-- thymeleaf -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n        <!-- redis session 如果客户端session出现问题可以尝试打开\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.session</groupId>\n            <artifactId>spring-session-data-redis</artifactId>\n        </dependency>\n        -->\n        <!-- hutool -->\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.38</version>\n        </dependency>\n        <!-- lombok -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <!-- scms -->\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>commons</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <!-- 数据库 -->\n        <dependency>\n            <groupId>org.postgresql</groupId>\n            <artifactId>postgresql</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.2.24</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-oauth2-client</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>hiauth-server</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.graalvm.buildtools</groupId>\n                <artifactId>native-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <excludes>\n                        <exclude>\n                            <groupId>org.projectlombok</groupId>\n                            <artifactId>lombok</artifactId>\n                        </exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/ServerStarter.java",
    "content": "package cn.hiauth.server;\n\nimport cn.webestar.scms.commons.Constant;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\n\n@ComponentScan(basePackages = {\"cn.hiauth.server\", Constant.SCMS_BASIC_PKG})\n@SpringBootApplication\npublic class ServerStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ServerStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/config/AuthServerConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport cn.hiauth.server.federation.FederatedIdentityIdTokenCustomizer;\nimport cn.hiauth.server.mapper.SimpleJdbcRegisteredClientRepository;\nimport cn.hiauth.server.utils.jose.Jwks;\nimport com.nimbusds.jose.jwk.JWKSet;\nimport com.nimbusds.jose.jwk.RSAKey;\nimport com.nimbusds.jose.jwk.source.JWKSource;\nimport com.nimbusds.jose.proc.SecurityContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.MediaType;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;\nimport org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;\nimport org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\nimport org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;\nimport org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;\nimport org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;\n\n@Configuration(proxyBeanMethods = false)\npublic class AuthServerConfig {\n\n    /**\n     * Spring Authorization Server 相关配置\n     * 主要配置OAuth 2.1和OpenID Connect 1.0\n     */\n    @Bean\n    @Order(Ordered.HIGHEST_PRECEDENCE)\n    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {\n        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer();\n        http\n                .securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())\n                .with(authorizationServerConfigurer, (authorizationServer) ->\n                        authorizationServer\n                                .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint.consentPage(\"/oauth2/consent\"))\n                                .oidc(Customizer.withDefaults())\n                )\n                .authorizeHttpRequests((authorize) ->\n                        authorize.anyRequest().authenticated()\n                )\n                .exceptionHandling((exceptions) -> exceptions\n                        .defaultAuthenticationEntryPointFor(\n                                new LoginUrlAuthenticationEntryPoint(\"/login\"),\n                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)\n                        )\n                )\n                .oauth2ResourceServer((resourceServer) -> resourceServer.jwt(Customizer.withDefaults()));\n        return http.build();\n    }\n\n    /**\n     * 客户端信息\n     * 对应表：oauth2_registered_client\n     */\n    @Bean\n    public SimpleJdbcRegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {\n        return new SimpleJdbcRegisteredClientRepository(jdbcTemplate);\n    }\n\n    @Bean\n    public JdbcOAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {\n        return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);\n    }\n\n    @Bean\n    public JdbcOAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {\n        return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);\n    }\n\n    @Bean\n    public OAuth2TokenCustomizer<JwtEncodingContext> idTokenCustomizer() {\n        return new FederatedIdentityIdTokenCustomizer();\n    }\n\n    @Bean\n    public JWKSource<SecurityContext> jwkSource() {\n        RSAKey rsaKey = Jwks.generateRsa();\n        JWKSet jwkSet = new JWKSet(rsaKey);\n        return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);\n    }\n\n    @Bean\n    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {\n        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);\n    }\n\n    @Bean\n    public AuthorizationServerSettings authorizationServerSettings() {\n        return AuthorizationServerSettings.builder().build();\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/config/BeanConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.context.annotation.Configuration;\n\n@Slf4j\n@Configuration\npublic class BeanConfig {\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/config/SecurityConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport cn.hiauth.server.federation.FederatedIdentityAuthenticationSuccessHandler;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;\nimport org.springframework.security.core.session.SessionRegistry;\nimport org.springframework.security.core.session.SessionRegistryImpl;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.authentication.AuthenticationSuccessHandler;\nimport org.springframework.security.web.session.HttpSessionEventPublisher;\n\n@EnableWebSecurity\n@Configuration(proxyBeanMethods = true)\n@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)\npublic class SecurityConfig {\n\n    @Bean\n    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {\n        http\n                .authorizeHttpRequests((authorize) -> authorize\n                        .anyRequest().authenticated()\n                )\n                .cors(Customizer.withDefaults())\n                .csrf(AbstractHttpConfigurer::disable)\n                .formLogin(Customizer.withDefaults());\n        return http.build();\n    }\n\n    @Bean\n    public UserDetailsService userDetailsService() {\n        UserDetails userDetails = User.withDefaultPasswordEncoder()\n                .username(\"user\")\n                .password(\"123456\")\n                .roles(\"USER\")\n                .build();\n        return new InMemoryUserDetailsManager(userDetails);\n    }\n\n    private AuthenticationSuccessHandler authenticationSuccessHandler() {\n        return new FederatedIdentityAuthenticationSuccessHandler();\n    }\n\n    @Bean\n    public SessionRegistry sessionRegistry() {\n        return new SessionRegistryImpl();\n    }\n\n    @Bean\n    public HttpSessionEventPublisher httpSessionEventPublisher() {\n        return new HttpSessionEventPublisher();\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/config/WebMvcConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.CacheControl;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport java.util.concurrent.TimeUnit;\n\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n\n    @Value(\"${app.cacheControl.maxAge:0}\")\n    private Integer maxAge;\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/static/**\", \"/webjars/**\")\n                .addResourceLocations(\"classpath:/static/\", \"classpath:/META-INF/resources/webjars/\")\n                .setCacheControl(CacheControl.maxAge(maxAge, TimeUnit.HOURS).cachePrivate());\n    }\n\n}"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/controller/IndexController.java",
    "content": "package cn.hiauth.server.controller;\n\nimport org.springframework.stereotype.Controller;\n\n@Controller\npublic class IndexController {\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/controller/LoginController.java",
    "content": "package cn.hiauth.server.controller;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Controller;\n\n@Slf4j\n@Controller\npublic class LoginController {\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/federation/FederatedIdentityAuthenticationSuccessHandler.java",
    "content": "/*\n * Copyright 2020-2025 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.hiauth.server.federation;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;\nimport org.springframework.security.oauth2.core.oidc.user.OidcUser;\nimport org.springframework.security.oauth2.core.user.OAuth2User;\nimport org.springframework.security.web.authentication.AuthenticationSuccessHandler;\nimport org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;\n\nimport java.io.IOException;\nimport java.util.function.Consumer;\n\n/**\n * An {@link AuthenticationSuccessHandler} for capturing the {@link OidcUser} or\n * {@link OAuth2User} for Federated Account Linking or JIT Account Provisioning.\n *\n * @author Steve Riesenberg\n * @since 1.1\n */\npublic final class FederatedIdentityAuthenticationSuccessHandler implements AuthenticationSuccessHandler {\n\n    private final AuthenticationSuccessHandler delegate = new SavedRequestAwareAuthenticationSuccessHandler();\n\n    private Consumer<OAuth2User> oauth2UserHandler = (user) -> {\n    };\n\n    private Consumer<OidcUser> oidcUserHandler = (user) -> this.oauth2UserHandler.accept(user);\n\n    @Override\n    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {\n        if (authentication instanceof OAuth2AuthenticationToken) {\n            if (authentication.getPrincipal() instanceof OidcUser oidcUser) {\n                this.oidcUserHandler.accept(oidcUser);\n            } else if (authentication.getPrincipal() instanceof OAuth2User oauth2User) {\n                this.oauth2UserHandler.accept(oauth2User);\n            }\n        }\n\n        this.delegate.onAuthenticationSuccess(request, response, authentication);\n    }\n\n    public void setOAuth2UserHandler(Consumer<OAuth2User> oauth2UserHandler) {\n        this.oauth2UserHandler = oauth2UserHandler;\n    }\n\n    public void setOidcUserHandler(Consumer<OidcUser> oidcUserHandler) {\n        this.oidcUserHandler = oidcUserHandler;\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/federation/FederatedIdentityIdTokenCustomizer.java",
    "content": "/*\n * Copyright 2020-2025 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.hiauth.server.federation;\n\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;\nimport org.springframework.security.oauth2.core.oidc.OidcIdToken;\nimport org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;\nimport org.springframework.security.oauth2.core.oidc.user.OidcUser;\nimport org.springframework.security.oauth2.core.user.OAuth2User;\nimport org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;\nimport org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;\n\nimport java.util.*;\n\n/**\n * An {@link OAuth2TokenCustomizer} to map claims from a federated identity to\n * the {@code id_token} produced by this authorization server.\n *\n * @author Steve Riesenberg\n * @since 1.1\n */\npublic final class FederatedIdentityIdTokenCustomizer implements OAuth2TokenCustomizer<JwtEncodingContext> {\n\n    private static final Set<String> ID_TOKEN_CLAIMS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(\n            IdTokenClaimNames.ISS,\n            IdTokenClaimNames.SUB,\n            IdTokenClaimNames.AUD,\n            IdTokenClaimNames.EXP,\n            IdTokenClaimNames.IAT,\n            IdTokenClaimNames.AUTH_TIME,\n            IdTokenClaimNames.NONCE,\n            IdTokenClaimNames.ACR,\n            IdTokenClaimNames.AMR,\n            IdTokenClaimNames.AZP,\n            IdTokenClaimNames.AT_HASH,\n            IdTokenClaimNames.C_HASH\n    )));\n\n    @Override\n    public void customize(JwtEncodingContext context) {\n        if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) {\n            Map<String, Object> thirdPartyClaims = extractClaims(context.getPrincipal());\n            context.getClaims().claims(existingClaims -> {\n                // Remove conflicting claims set by this authorization server\n                existingClaims.keySet().forEach(thirdPartyClaims::remove);\n\n                // Remove standard id_token claims that could cause problems with clients\n                ID_TOKEN_CLAIMS.forEach(thirdPartyClaims::remove);\n\n                // Add all other claims directly to id_token\n                existingClaims.putAll(thirdPartyClaims);\n            });\n        }\n    }\n\n    private Map<String, Object> extractClaims(Authentication principal) {\n        Map<String, Object> claims;\n        if (principal.getPrincipal() instanceof OidcUser oidcUser) {\n            OidcIdToken idToken = oidcUser.getIdToken();\n            claims = idToken.getClaims();\n        } else if (principal.getPrincipal() instanceof OAuth2User oauth2User) {\n            claims = oauth2User.getAttributes();\n        } else {\n            claims = Collections.emptyMap();\n        }\n        return new HashMap<>(claims);\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/mapper/SimpleJdbcRegisteredClientRepository.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jdbc.core.namedparam.MapSqlParameterSource;\nimport org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\n\nimport java.util.List;\nimport java.util.Set;\n\npublic class SimpleJdbcRegisteredClientRepository extends JdbcRegisteredClientRepository {\n\n    private static final String TABLE_NAME = \"oauth2_registered_client\";\n\n    private static final String COLUMN_NAMES = \"id, \"\n            + \"client_id, \"\n            + \"client_id_issued_at, \"\n            + \"client_secret, \"\n            + \"client_secret_expires_at, \"\n            + \"client_name, \"\n            + \"client_authentication_methods, \"\n            + \"authorization_grant_types, \"\n            + \"redirect_uris, \"\n            + \"post_logout_redirect_uris, \"\n            + \"scopes, \"\n            + \"client_settings,\"\n            + \"token_settings\";\n\n    private static final String LOAD_REGISTERED_CLIENT_SQL = \"SELECT \" + COLUMN_NAMES + \" FROM \" + TABLE_NAME + \" WHERE \";\n\n    public SimpleJdbcRegisteredClientRepository(JdbcOperations jdbcOperations) {\n        super(jdbcOperations);\n    }\n\n    public List<RegisteredClient> findByClientIds(Set<String> clientIds) {\n        MapSqlParameterSource parameters = new MapSqlParameterSource();\n        parameters.addValue(\"clientIds\", clientIds);\n        StringBuilder sb = new StringBuilder();\n        sb.append(LOAD_REGISTERED_CLIENT_SQL).append(\"client_id IN (\");\n        clientIds.forEach(i -> sb.append(\"'\").append(i).append(\"',\"));\n        sb.deleteCharAt(sb.length() - 1);\n        sb.append(\")\");\n        List<RegisteredClient> result = this.getJdbcOperations().query(sb.toString(), this.getRegisteredClientRowMapper());\n        return !result.isEmpty() ? result : null;\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/utils/jose/Jwks.java",
    "content": "/*\n * Copyright 2020-2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.hiauth.server.utils.jose;\n\nimport com.nimbusds.jose.jwk.Curve;\nimport com.nimbusds.jose.jwk.ECKey;\nimport com.nimbusds.jose.jwk.OctetSequenceKey;\nimport com.nimbusds.jose.jwk.RSAKey;\n\nimport javax.crypto.SecretKey;\nimport java.security.KeyPair;\nimport java.security.interfaces.ECPrivateKey;\nimport java.security.interfaces.ECPublicKey;\nimport java.security.interfaces.RSAPrivateKey;\nimport java.security.interfaces.RSAPublicKey;\nimport java.util.UUID;\n\n/**\n * @author Joe Grandja\n * @since 1.1\n */\npublic final class Jwks {\n\n    private Jwks() {\n    }\n\n    public static RSAKey generateRsa() {\n        KeyPair keyPair = KeyGeneratorUtils.generateRsaKey();\n        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();\n        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();\n        // @formatter:off\n\t\treturn new RSAKey.Builder(publicKey)\n\t\t\t\t.privateKey(privateKey)\n\t\t\t\t.keyID(UUID.randomUUID().toString())\n\t\t\t\t.build();\n\t\t// @formatter:on\n    }\n\n    public static ECKey generateEc() {\n        KeyPair keyPair = KeyGeneratorUtils.generateEcKey();\n        ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();\n        ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();\n        Curve curve = Curve.forECParameterSpec(publicKey.getParams());\n        // @formatter:off\n\t\treturn new ECKey.Builder(curve, publicKey)\n\t\t\t\t.privateKey(privateKey)\n\t\t\t\t.keyID(UUID.randomUUID().toString())\n\t\t\t\t.build();\n\t\t// @formatter:on\n    }\n\n    public static OctetSequenceKey generateSecret() {\n        SecretKey secretKey = KeyGeneratorUtils.generateSecretKey();\n        // @formatter:off\n\t\treturn new OctetSequenceKey.Builder(secretKey)\n\t\t\t\t.keyID(UUID.randomUUID().toString())\n\t\t\t\t.build();\n\t\t// @formatter:on\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/utils/jose/KeyGeneratorUtils.java",
    "content": "/*\n * Copyright 2020-2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.hiauth.server.utils.jose;\n\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport java.math.BigInteger;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.spec.ECFieldFp;\nimport java.security.spec.ECParameterSpec;\nimport java.security.spec.ECPoint;\nimport java.security.spec.EllipticCurve;\n\n/**\n * @author Joe Grandja\n * @since 1.1\n */\nfinal class KeyGeneratorUtils {\n\n    private KeyGeneratorUtils() {\n    }\n\n    static SecretKey generateSecretKey() {\n        SecretKey hmacKey;\n        try {\n            hmacKey = KeyGenerator.getInstance(\"HmacSha256\").generateKey();\n        } catch (Exception ex) {\n            throw new IllegalStateException(ex);\n        }\n        return hmacKey;\n    }\n\n    static KeyPair generateRsaKey() {\n        KeyPair keyPair;\n        try {\n            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"RSA\");\n            keyPairGenerator.initialize(2048);\n            keyPair = keyPairGenerator.generateKeyPair();\n        } catch (Exception ex) {\n            throw new IllegalStateException(ex);\n        }\n        return keyPair;\n    }\n\n    static KeyPair generateEcKey() {\n        EllipticCurve ellipticCurve = new EllipticCurve(\n                new ECFieldFp(\n                        new BigInteger(\"115792089210356248762697446949407573530086143415290314195533631308867097853951\")),\n                new BigInteger(\"115792089210356248762697446949407573530086143415290314195533631308867097853948\"),\n                new BigInteger(\"41058363725152142129326129780047268409114441015993725554835256314039467401291\"));\n        ECPoint ecPoint = new ECPoint(\n                new BigInteger(\"48439561293906451759052585252797914202762949526041747995844080717082404635286\"),\n                new BigInteger(\"36134250956749795798585127919587881956611106672985015071877198253568414405109\"));\n        ECParameterSpec ecParameterSpec = new ECParameterSpec(\n                ellipticCurve,\n                ecPoint,\n                new BigInteger(\"115792089210356248762697446949407573529996955224135760342422259061068512044369\"),\n                1);\n\n        KeyPair keyPair;\n        try {\n            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"EC\");\n            keyPairGenerator.initialize(ecParameterSpec);\n            keyPair = keyPairGenerator.generateKeyPair();\n        } catch (Exception ex) {\n            throw new IllegalStateException(ex);\n        }\n        return keyPair;\n    }\n\n}\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/java/cn/hiauth/server/utils/package-info.java",
    "content": "package cn.hiauth.server.utils;"
  },
  {
    "path": "example/hiauth-server-exp/src/main/resources/application-hiauth.yml",
    "content": "server.port: 8080\n\nlogging.level:\n  root: INFO\n  cn.hiauth: DEBUG\n  com.alibaba.nacos: INFO\n  org.springframework.data.redis: INFO\n  io.lettuce.core: INFO\n\nspring.datasource:\n  type: ${datasource.type}\n  driver-class-name: ${datasource.driverClassName}\n  url: ${datasource.url}\n  username: ${datasource.username}\n  password: ${datasource.password}\n\nspring.session.timeout: 600m\nspring.session.redis:\n  # 支持发布session事件，默认值不支持发布session事件\n  repository-type: indexed\n  namespace: \"hiauth:session\"\n  # 每次保存或更新 session 时立即将数据同步到 Redis\n  flush-mode: on_save\n  # 每次请求结束时都保存 session\n  save-mode: always\n  # 关闭Spring Session的自动配置检查,否则在使用aliyun redis（Tair）时会报错\n  # 报错内容为：NOPERM this user has no permissions to run the 'config|get' command\n  configure-action: none\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/resources/application-redis.yml",
    "content": "# 单节点写法\nspring.data.redis:\n  host: ${redis.host}\n  port: ${redis.port}\n  database: ${redis.database}\n  username: ${redis.username}\n  password: ${redis.password}\n  timeout: 10000\n  connect-timeout: 10000\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/resources/application.yml",
    "content": "app.version: '@project.version@'\napp.build.timestamp: '@app.build.timestamp@'\nspring.application.name: hiauth-server\n\n# 加载模块化配置\nspring.profiles.active: hiauth,redis\n\n# 加载外部配置文件，覆盖内置配置文件\nspring.config.import: ${CONFIG_FILE:optional:/hiauth/conf/hiauth.properties}\n\ndatasource:\n  type: com.alibaba.druid.pool.DruidDataSource\n  driverClassName: org.postgresql.Driver\n  url: jdbc:mysql://${DB_HOST:127.0.0.1}:3306/hiauth\n  username: ${DB_USER:test}\n  password: ${DB_pwd:123456}\n\nredis:\n  host: ${REDIS_HOST:127.0.0.1}\n  username: ${REDIS_USERNAME:}\n  password: ${REDIS_PWD:}\n  port: 6379\n  database: 0\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"./hiauth/logs/server.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/hiauth-server-exp/src/main/resources/templates/index.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n</head>\n<body>\nindex\n<a class=\"dropdown-item\" href=\"/logout\">退出</a>\n</body>\n</html>\n"
  },
  {
    "path": "example/himall/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.4.5</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>himall</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <name>himall</name>\n    <description>集成HiAuth认证系统</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>webjars-locator-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>bootstrap</artifactId>\n            <version>3.3.7</version>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>jquery</artifactId>\n            <version>3.6.3</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-oauth2-client</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>himall</finalName>\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n                <filtering>true</filtering>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-resources-plugin</artifactId>\n                <configuration>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/himall/src/main/java/cn/hiauth/himall/HiMallStarter.java",
    "content": "package cn.hiauth.himall;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class HiMallStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(HiMallStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/himall/src/main/java/cn/hiauth/himall/config/SecurityConfig.java",
    "content": "package cn.hiauth.himall.config;\n\nimport org.springframework.boot.web.client.RestTemplateBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@EnableWebSecurity\n@Configuration(proxyBeanMethods = true)\npublic class SecurityConfig {\n\n    @Bean\n    public RestTemplate restTemplate(RestTemplateBuilder builder) {\n        return builder.build();\n    }\n\n    @Bean\n    WebSecurityCustomizer webSecurityCustomizer() {\n        return web -> web.ignoring().requestMatchers(\"/static/**\", \"/webjars/**\");\n    }\n\n    @Bean\n    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n        http\n                .authorizeHttpRequests(authorize ->\n                        authorize.requestMatchers(\"/\", \"/index\").permitAll().anyRequest().authenticated()\n                )\n                .oauth2Login(oauth2Login -> oauth2Login.failureUrl(\"/login?error\"))\n                .logout(logout -> logout\n                        .logoutRequestMatcher(new AntPathRequestMatcher(\"/logout\"))\n                        .invalidateHttpSession(true)\n                        .clearAuthentication(true)\n                        .deleteCookies(\"JSESSIONID\")\n                )\n                .oauth2Client(withDefaults());\n        return http.build();\n    }\n\n}\n"
  },
  {
    "path": "example/himall/src/main/java/cn/hiauth/himall/config/WebMvcConfig.java",
    "content": "package cn.hiauth.himall.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.CacheControl;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport java.util.concurrent.TimeUnit;\n\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/static/**\", \"/webjars/**\")\n                .addResourceLocations(\"classpath:/static/\", \"classpath:/META-INF/resources/webjars/\")\n                .setCacheControl(CacheControl.maxAge(0, TimeUnit.HOURS).cachePrivate());\n    }\n\n}\n"
  },
  {
    "path": "example/himall/src/main/java/cn/hiauth/himall/controller/AuthController.java",
    "content": "package cn.hiauth.himall.controller;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClient;\nimport org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class AuthController {\n\n    @ResponseBody\n    @GetMapping(\"/api/client\")\n    public OAuth2AuthorizedClient client(HttpServletRequest request, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oAuth2AuthorizedClient) {\n        // 通过OAuth2AuthorizedClient对象获取到客户端和令牌相关的信息，然后直接返回给前端页面\n        request.getSession().setAttribute(\"isAuth\", true);\n        return oAuth2AuthorizedClient;\n    }\n\n}\n"
  },
  {
    "path": "example/himall/src/main/java/cn/hiauth/himall/controller/IndexController.java",
    "content": "package cn.hiauth.himall.controller;\n\nimport jakarta.servlet.http.Cookie;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.core.annotation.AuthenticationPrincipal;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClient;\nimport org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;\nimport org.springframework.security.oauth2.core.oidc.user.OidcUser;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.client.RestTemplate;\n\nimport java.time.LocalDateTime;\nimport java.util.Map;\n\n@Slf4j\n@Controller\npublic class IndexController {\n\n    @Autowired\n    private RestTemplate restTemplate;\n\n    @Value(\"${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}\")\n    private String issuerUri;\n\n    @Value(\"${spring.security.oauth2.client.provider.hiauth-server.userInfoUri}\")\n    private String userInfoUri;\n\n    @GetMapping({\"/\", \"/index\"})\n    public String index(HttpServletRequest request, HttpServletResponse response) {\n        return \"index\";\n    }\n\n    @GetMapping(\"/user/logout\")\n    public String logout(HttpServletRequest request, HttpServletResponse response) {\n        SecurityContextHolder.clearContext();\n        Cookie cookie = new Cookie(\"JSESSIONID\", null);\n        cookie.setMaxAge(0);\n        cookie.setPath(\"/\");\n        response.addCookie(cookie);\n        return \"redirect:\" + issuerUri + \"/unpapi/logoutWithRedirect?redirect_uri=http://127.0.0.1:9000\";\n    }\n\n    @GetMapping(\"/profile\")\n    public String profile(HttpServletRequest request, Model model, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oAuth2AuthorizedClient, @AuthenticationPrincipal OidcUser oidcUser) {\n        String accessToken = oAuth2AuthorizedClient.getAccessToken().getTokenValue();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        headers.add(\"Authorization\", \"Bearer \" + accessToken);\n        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n        HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);\n        Map<?, ?> res = restTemplate.postForObject(this.userInfoUri, entity, Map.class);\n        log.info(\"res:{}\", res);\n        model.addAttribute(\"name\", res.get(\"name\"));\n        model.addAttribute(\"username\", res.get(\"username\"));\n        model.addAttribute(\"tel\", res.get(\"phoneNum\"));\n        model.addAttribute(\"lastLoginTime\", LocalDateTime.now());\n        request.getSession().setAttribute(\"isAuth\", true);\n        return \"profile\";\n    }\n\n}"
  },
  {
    "path": "example/himall/src/main/resources/application.yml",
    "content": "server.port: 9000\n\nlogging.level:\n  root: DEBUG\n  cn.hiauth: DEBUG\n\nspring.security.oauth2.client:\n  provider:\n    #认证服务器信息\n    hiauth-server:\n      # 如果你私有化部署了 HiAuth服务，请将此地址替换为私有部署的认证服务器地址\n      #issuer-uri: http://localhost:8080\n      issuer-uri: http://auth.hiauth.cn\n      authorizationUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/authorize\n      #令牌获取地址\n      tokenUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/token\n      userInfoUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/userinfo\n      jwkSetUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/jwks\n      #userNameAttribute: name\n  registration:\n    hiauth-code:\n      #认证提供者，标识由哪个认证服务器进行认证，和上面的hiauth-server进行关联\n      provider: hiauth-server\n      client-name: himall\n      client-id: himall\n      client-secret: secret\n      #客户端认证方式 client_secret_basic\\client_secret_post\n      client-authentication-method: client_secret_basic\n      #使用授权码模式获取令牌（token）\n      authorization-grant-type: authorization_code\n      # 认证完成后回调的地址，需要在数据库表oauth2_registered_client中登记这个地址，否则会拒绝回调\n      redirect-uri: http://127.0.0.1:9000/login/oauth2/code/hiauth-code\n      scope: openid,profile"
  },
  {
    "path": "example/himall/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"himall.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/himall/src/main/resources/static/css/index.css",
    "content": "/* Space out content a bit */\nbody {\n  padding-top: 20px;\n  padding-bottom: 20px;\n}\n\n/* Everything but the jumbotron gets side spacing for mobile first views */\n.header,\n.marketing,\n.footer {\n  padding-right: 15px;\n  padding-left: 15px;\n}\n\n/* Custom page header */\n.header {\n  padding-bottom: 20px;\n  border-bottom: 1px solid #e5e5e5;\n}\n/* Make the masthead heading the same height as the navigation */\n.header h3 {\n  margin-top: 0;\n  margin-bottom: 0;\n  line-height: 40px;\n}\n\n/* Custom page footer */\n.footer {\n  padding-top: 19px;\n  color: #777;\n  border-top: 1px solid #e5e5e5;\n}\n\n/* Customize container */\n@media (min-width: 768px) {\n  .container {\n    max-width: 730px;\n  }\n}\n.container-narrow > hr {\n  margin: 30px 0;\n}\n\n/* Main marketing message and sign up button */\n.jumbotron {\n  text-align: center;\n  border-bottom: 1px solid #e5e5e5;\n}\n.jumbotron .btn {\n  padding: 14px 24px;\n  font-size: 21px;\n}\n\n/* Supporting marketing content */\n.marketing {\n  margin: 40px 0;\n}\n.marketing p + h4 {\n  margin-top: 28px;\n}\n\n/* Responsive: Portrait tablets and up */\n@media screen and (min-width: 768px) {\n  /* Remove the padding we set earlier */\n  .header,\n  .marketing,\n  .footer {\n    padding-right: 0;\n    padding-left: 0;\n  }\n  /* Space out the masthead */\n  .header {\n    margin-bottom: 30px;\n  }\n  /* Remove the bottom border on the jumbotron for visual effect */\n  .jumbotron {\n    border-bottom: 0;\n  }\n}\n"
  },
  {
    "path": "example/himall/src/main/resources/templates/demo.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"https://www.thymeleaf.org\" xmlns:sec=\"https://www.thymeleaf.org/thymeleaf-extras-springsecurity5\">\n    <head>\n        <title>Spring Security OAuth 2.0 Sample</title>\n        <meta charset=\"utf-8\" />\n        <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n        <link th:rel=\"stylesheet\" th:href=\"@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css} \">\n    </head>\n    <body>\n        <div th:fragment=\"header\">\n            <nav class=\"navbar navbar-default\">\n                <div class=\"container\">\n                    <div class=\"container-fluid\">\n                        <div class=\"navbar-collapse collapse\" id=\"navbar\">\n                        </div>\n                    </div>\n                </div>\n            </nav>\n        </div>\n        <div class=\"container\">\n            <div th:if=\"${error}\" class=\"alert alert-danger alert-dismissible\" role=\"alert\">\n                <button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\n                <h4 th:text=\"${error}\" class=\"text-center\"></h4>\n            </div>\n            <div class=\"panel panel-default\">\n                <div class=\"panel-heading\">\n                    <h3 class=\"panel-title\">Authorize the client using <span style=\"font-family:monospace\">grant_type</span>:</h3>\n                </div>\n                <ul class=\"list-group\">\n                    <li class=\"list-group-item\">\n                        <a href=\"/authorize?grant_type=authorization_code\" th:href=\"@{/authorize?grant_type=authorization_code}\"><span style=\"font-size:medium\">Authorization Code</span>&nbsp;&nbsp;<small class=\"text-muted\">(Login to Spring Authorization Server using: user1/password)</small></a>\n                    </li>\n                    <li class=\"list-group-item\">\n                        <a href=\"/authorize?grant_type=client_credentials\" th:href=\"@{/authorize?grant_type=client_credentials}\"><span style=\"font-size:medium\">Client Credentials</span></a>\n                    </li>\n                </ul>\n                <div th:if=\"${messages}\" class=\"panel-footer\">\n                    <h4>Messages:</h4>\n                    <table class=\"table table-condensed\">\n                        <tbody>\n                            <tr class=\"row\" th:each=\"message : ${messages}\">\n                                <td th:text=\"${message}\">message</td>\n                            </tr>\n                        </tbody>\n                    </table>\n                </div>\n            </div>\n        </div>\n        <script src=\"/webjars/jquery/jquery.min.js\" th:src=\"@{/webjars/jquery/3.6.3/jquery.min.js}\"></script>\n        <script th:src=\"@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}\"></script>\n    </body>\n</html>\n"
  },
  {
    "path": "example/himall/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>HiMall</title>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n    <link rel=\"icon\" th:href=\"@{/static/favicon.ico}\">\n    <link th:rel=\"stylesheet\" th:href=\"@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css} \">\n    <link th:href=\"@{/static/css/index.css}\" rel=\"stylesheet\">\n</head>\n<body>\n\n<div class=\"container\">\n    <div class=\"header clearfix\">\n        <nav>\n            <ul class=\"nav nav-pills pull-right\">\n                <li role=\"presentation\" class=\"active\"><a th:href=\"@{/}\">Home</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\"><a th:href=\"@{/profile}\">Profile</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\"><a th:href=\"@{/api/client}\">Client</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? !session.isAuth : true}\"><a th:href=\"@{/profile}\">Login</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\"><a th:href=\"@{/user/logout}\">Logout</a></li>\n            </ul>\n        </nav>\n        <h3 class=\"text-muted\">HIMALL</h3>\n    </div>\n\n    <div class=\"jumbotron\">\n        <h1>HiMall Example</h1>\n        <p class=\"lead\">This example is a quick exercise to illustrate how Integrate HiAuth by Oauth2, an integrated instance of microservices is also included here, so you can find some best practices.</p>\n        <p><a class=\"btn btn-lg btn-success\" href=\"https://github.com/bestaone/HiAuth\" role=\"button\">View HiMall docs</a></p>\n    </div>\n\n    <div class=\"row marketing\">\n        <div class=\"col-lg-6\"></div>\n        <div class=\"col-lg-6\"></div>\n    </div>\n\n    <footer class=\"footer\">\n        <p>&copy; HiMall system for hiauth.com, by 码道功臣@webestar.cn</p>\n    </footer>\n\n</div>\n\n<script th:src=\"@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "example/himall/src/main/resources/templates/profile.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>HiMall</title>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n    <link rel=\"icon\" th:href=\"@{/static/favicon.ico}\">\n    <link th:rel=\"stylesheet\" th:href=\"@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css} \">\n    <link th:href=\"@{/static/css/index.css}\" rel=\"stylesheet\">\n</head>\n<body>\n\n<div class=\"container\">\n    <div class=\"header clearfix\">\n        <nav>\n            <ul class=\"nav nav-pills pull-right\">\n                <li role=\"presentation\"><a th:href=\"@{/}\">Home</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\" class=\"active\"><a th:href=\"@{/profile}\">Profile</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\"><a th:href=\"@{/api/client}\">Client</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? !session.isAuth : true}\"><a th:href=\"@{/signin}\">Login</a></li>\n                <li role=\"presentation\" th:if=\"${session.isAuth!=null ? session.isAuth : false}\"><a th:href=\"@{/user/logout}\">Logout</a></li>\n            </ul>\n        </nav>\n        <h3 class=\"text-muted\">HIMALL</h3>\n    </div>\n\n    <div style=\"margin-top: 30px;\"><span class=\"glyphicon glyphicon-user\" aria-hidden=\"true\"></span> 用户信息</div>\n    <div class=\"row\">\n        <div class=\"col-md-2 title\">用户姓名：</div><div class=\"col-md-4 text\" th:text=\"${name}\"></div>\n        <div class=\"col-md-2 title\">用户账号：</div><div class=\"col-md-4 text\" th:text=\"${username}\"></div>\n        <div class=\"col-md-2 title\">手机号码：</div><div class=\"col-md-4 text\" th:text=\"${tel}\"></div>\n        <div class=\"col-md-2 title\">最近登录：</div><div class=\"col-md-4 text\" th:text=\"${lastLoginTime}\"></div>\n    </div>\n\n    <div style=\"margin-top: 30px;\"><span class=\"glyphicon glyphicon-list-alt\" aria-hidden=\"true\"></span> 我的订单</div>\n    <div class=\"row\">\n        <div class=\"col-md-2 title\">订单编号：</div><div class=\"col-md-4 text\" th:text=\"${orderNo}\"></div>\n        <div class=\"col-md-2 title\">订单标题：</div><div class=\"col-md-4 text\" th:text=\"${orderTitle}\"></div>\n        <div class=\"col-md-2 title\">创建时间：</div><div class=\"col-md-4 text\" th:text=\"${orderCreateTime}\"></div>\n        <div class=\"col-md-2 title\">订单总额：</div><div class=\"col-md-4 text\" th:text=\"${orderTotalAmount}\"></div>\n    </div>\n\n    <div class=\"row\" style=\"margin-top: 30px; padding: 0px 15px;\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">商品列表</div>\n            <table class=\"table\">\n                <thead>\n                    <tr>\n                        <th>#</th>\n                        <th>商品名称</th>\n                        <th>单价（元）</th>\n                        <th>库存（个）</th>\n                        <th>上架时间</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr th:each=\"goods,stat : ${goodsList}\">\n                        <th scope=\"row\" th:text=\"${stat.index + 1}\"></th>\n                        <td th:text=\"${goods.title}\"></td>\n                        <td th:text=\"${goods.price}\"></td>\n                        <td th:text=\"${goods.amount}\"></td>\n                        <td th:text=\"${goods.createTime}\"></td>\n                    </tr>\n                </tbody>\n            </table>\n\n        </div>\n    </div>\n\n    <footer class=\"footer\">\n        <p>&copy; HiMall system for hiauth.com, by 码道功臣@webestar.cn.</p>\n    </footer>\n\n</div>\n\n<script th:src=\"@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "example/resource/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.4.5</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>resource</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>demo</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>commons</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/ResourceStarter.java",
    "content": "package cn.hiauth.resource;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class ResourceStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ResourceStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/config/ResourceServerConfig.java",
    "content": "package cn.hiauth.resource.config;\n\nimport cn.hiauth.resource.config.auth.SimpleAccessDeniedHandler;\nimport cn.hiauth.resource.config.auth.SimpleAuthenticationEntryPoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration\n@EnableWebSecurity\n@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)\npublic class ResourceServerConfig {\n\n    @Bean\n    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n        http\n                .authorizeHttpRequests(authorize -> authorize\n                        .requestMatchers(\"/unpapi/**\").permitAll()\n                        .anyRequest().authenticated()\n                )\n                .oauth2ResourceServer(oauth2ResourceServer -> oauth2ResourceServer\n                        .jwt(Customizer.withDefaults())\n                        .authenticationEntryPoint(new SimpleAuthenticationEntryPoint())\n                        .accessDeniedHandler(new SimpleAccessDeniedHandler())\n                );\n        return http.build();\n    }\n\n}\n"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/config/auth/SimpleAccessDeniedHandler.java",
    "content": "package cn.hiauth.resource.config.auth;\n\nimport cn.hiauth.resource.utils.ResponseTools;\nimport cn.webestar.scms.commons.R;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;\nimport org.springframework.security.web.access.AccessDeniedHandler;\n\nimport java.io.IOException;\n\npublic class SimpleAccessDeniedHandler implements AccessDeniedHandler {\n\n    @Override\n    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException, ServletException {\n        if (request.getUserPrincipal() instanceof AbstractOAuth2TokenAuthenticationToken) {\n            ResponseTools.write(response, R.fail(10403, \"没有权限访问\"));\n        } else {\n            ResponseTools.write(response, R.fail(10403, exception.getMessage()));\n        }\n    }\n\n}\n"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/config/auth/SimpleAuthenticationEntryPoint.java",
    "content": "package cn.hiauth.resource.config.auth;\n\nimport cn.hiauth.resource.utils.ResponseTools;\nimport cn.webestar.scms.commons.R;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.authentication.InsufficientAuthenticationException;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;\nimport org.springframework.security.web.AuthenticationEntryPoint;\nimport org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;\n\nimport java.io.IOException;\n\npublic class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint {\n\n    @Override\n    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {\n        if (exception instanceof InsufficientAuthenticationException) {\n            String accept = request.getHeader(\"accept\");\n            if (accept.contains(MediaType.TEXT_HTML_VALUE)) {\n                //如果是html请求类型，则返回登录页\n                LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(\"/login\");\n                loginUrlAuthenticationEntryPoint.commence(request, response, exception);\n            } else {\n                //如果是api请求类型，则返回json\n                ResponseTools.write(response, R.fail(10401, \"缺少访问令牌\"));\n            }\n        } else if (exception instanceof InvalidBearerTokenException) {\n            ResponseTools.write(response, R.fail(10401, \"令牌无效或过期\"));\n        } else {\n            ResponseTools.write(response, R.fail(10401, exception.getMessage()));\n        }\n    }\n\n}\n"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/controller/IndexController.java",
    "content": "package cn.hiauth.resource.controller;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class IndexController {\n\n    @GetMapping(\"/\")\n    public String index() {\n        return \"index\";\n    }\n\n}"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/controller/ProfileController.java",
    "content": "package cn.hiauth.resource.controller;\n\nimport cn.webestar.scms.commons.R;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@PreAuthorize(\"hasAuthority('SCOPE_profile')\")\n@RestController\n@RequestMapping(\"/api/profile\")\npublic class ProfileController {\n\n    @GetMapping(\"/info\")\n    public R<String> info() {\n        return R.success(\"profile:superman\");\n    }\n\n}"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/controller/UnpapiController.java",
    "content": "package cn.hiauth.resource.controller;\n\nimport cn.webestar.scms.commons.R;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n@RestController\n@RequestMapping(\"/unpapi\")\npublic class UnpapiController {\n\n    @GetMapping(\"/metadata\")\n    public R<Map<String, Object>> metadata() {\n        Map<String, Object> data = new HashMap<>(5);\n        data.put(\"name\", \"hiauth-resource\");\n        data.put(\"description\", \"hiauth-resource\");\n        data.put(\"version\", \"1.0.0\");\n        return R.success(data);\n    }\n\n}"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/controller/UserController.java",
    "content": "package cn.hiauth.resource.controller;\n\nimport cn.webestar.scms.commons.R;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@PreAuthorize(\"hasAuthority('SCOPE_user')\")\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @GetMapping(\"/info\")\n    public R<String> info() {\n        return R.success(\"user:zhangsan\");\n    }\n\n}"
  },
  {
    "path": "example/resource/src/main/java/cn/hiauth/resource/utils/ResponseTools.java",
    "content": "package cn.hiauth.resource.utils;\n\nimport cn.webestar.scms.commons.R;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\n\npublic class ResponseTools {\n\n    private static final ObjectMapper om = new ObjectMapper();\n\n    static {\n        om.setSerializationInclusion(JsonInclude.Include.NON_NULL);\n    }\n\n    public static void write(HttpServletResponse response, R<?> r) throws IOException {\n        // 设置响应头\n        response.setStatus(HttpServletResponse.SC_OK);\n        response.setContentType(\"application/json;charset=UTF-8\");\n        response.setCharacterEncoding(\"UTF-8\");\n        // 序列化并写入响应\n        try {\n            String jsonResponse = om.writeValueAsString(r);\n            response.getWriter().write(jsonResponse);\n            response.getWriter().flush();\n        } catch (IOException e) {\n            // 如果JSON序列化失败，使用简单文本响应\n            response.setContentType(\"text/plain;charset=UTF-8\");\n            response.getWriter().write(\"错误处理失败: \" + e.getMessage());\n        }\n    }\n\n}"
  },
  {
    "path": "example/resource/src/main/resources/application.yml",
    "content": "server.port: 9002\n\nlogging.level:\n  root: DEBUG\n\nspring.jackson:\n  default-property-inclusion: NON_NULL\n  serialization:\n    indent-output: true\n\nspring.security.oauth2.resourceServer:\n  jwt:\n    issuerUri: http://auth.hiauth.cn\n    jwkSetUri: ${spring.security.oauth2.resourceServer.jwt.issuerUri}/oauth2/jwks\n"
  },
  {
    "path": "example/resource/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"resource.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/spring-cloud/README.md",
    "content": "- 访问：http://auth.hiauth.cn，如果是登录状态，先退出登录\n- 然后访问：http://127.0.0.1:9000/ordersvc"
  },
  {
    "path": "example/spring-cloud/gateway/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>gateway</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>gateway</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>3.3.10</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>2023.0.6</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.cloud</groupId>\n                <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n                <version>2023.0.3.3</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <!-- 开发支持：热启动等 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <scope>runtime</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-webflux</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-actuator</artifactId>\n        </dependency>\n        <!-- 网关 -->\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-gateway</artifactId>\n        </dependency>\n        <!--注册中心客户端-->\n        <dependency>\n            <groupId>com.alibaba.cloud</groupId>\n            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-loadbalancer</artifactId>\n        </dependency>\n        <!-- OAuth2 Client -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-oauth2-client</artifactId>\n        </dependency>\n        <!-- Spring Security -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/spring-cloud/gateway/src/main/java/cn/hiauth/gateway/ApiController.java",
    "content": "package cn.hiauth.gateway;\n\nimport org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;\nimport org.springframework.security.oauth2.core.user.OAuth2User;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@RequestMapping(\"/api/common\")\npublic class ApiController {\n\n    @GetMapping(\"/userinfo\")\n    public OAuth2User userinfo(OAuth2AuthenticationToken authentication) {\n        return authentication.getPrincipal();\n    }\n\n}"
  },
  {
    "path": "example/spring-cloud/gateway/src/main/java/cn/hiauth/gateway/GatewayStarter.java",
    "content": "package cn.hiauth.gateway;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class GatewayStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(GatewayStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/spring-cloud/gateway/src/main/java/cn/hiauth/gateway/IndexController.java",
    "content": "package cn.hiauth.gateway;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class IndexController {\n\n    @GetMapping(\"/\")\n    public String index() {\n        return \"gateway\";\n    }\n\n    @GetMapping(\"/home\")\n    public String home() {\n        return \"home\";\n    }\n\n}"
  },
  {
    "path": "example/spring-cloud/gateway/src/main/java/cn/hiauth/gateway/SecurityConfig.java",
    "content": "package cn.hiauth.gateway;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.security.web.server.WebFilterExchange;\nimport org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;\nimport org.springframework.security.web.server.authentication.logout.LogoutWebFilter;\nimport org.springframework.security.web.server.authentication.logout.ServerLogoutSuccessHandler;\nimport org.springframework.security.web.server.authentication.logout.WebSessionServerLogoutHandler;\nimport reactor.core.publisher.Mono;\n\n@Configuration\n@EnableWebFluxSecurity\npublic class SecurityConfig {\n\n    @Bean\n    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {\n        return http\n                .authorizeExchange(exchanges -> exchanges\n                        .pathMatchers(\"/login\", \"logout\", \"/oauth2/**\").permitAll()\n                        .anyExchange().authenticated()\n                )\n                .oauth2Login(oauth2 -> oauth2\n                        .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler(\"/home\"))\n                )\n                .logout(logout -> logout\n                        .logoutUrl(\"/logout\") // 退出登录端点\n                        .logoutHandler(new WebSessionServerLogoutHandler()) // 清除会话\n                        .logoutSuccessHandler(logoutSuccessHandler()) // 退出成功处理\n                )\n                .csrf(ServerHttpSecurity.CsrfSpec::disable)\n                .build();\n    }\n\n    @Bean\n    public ServerLogoutSuccessHandler logoutSuccessHandler() {\n        return new ServerLogoutSuccessHandler() {\n            @Override\n            public Mono<Void> onLogoutSuccess(WebFilterExchange exchange, Authentication authentication) {\n                // 重定向到登录页面或首页\n                return Mono.fromRunnable(() -> {\n                    exchange.getExchange().getResponse().setStatusCode(org.springframework.http.HttpStatus.FOUND);\n                    exchange.getExchange().getResponse().getHeaders().setLocation(java.net.URI.create(\"/login?logout\"));\n                });\n            }\n        };\n    }\n\n    /**\n     * 可选：添加自定义的LogoutWebFilter\n     */\n    @Bean\n    public LogoutWebFilter logoutWebFilter() {\n        return new LogoutWebFilter();\n    }\n\n}"
  },
  {
    "path": "example/spring-cloud/gateway/src/main/resources/application.yml",
    "content": "server.port: 9000\nspring.application.name: gateway\nlogging.level.root: INFO\n\n# Nacos注册中心配置\nspring.cloud.nacos.discovery.server-addr: 192.168.1.250:8848\n\n# 网关路由配置\nspring.cloud.gateway.routes:\n  - id: ordersvc\n    uri: lb://ordersvc/\n    predicates:\n      - Path=/ordersvc/**\n    filters:\n      - StripPrefix=1\n      - TokenRelay=\n\n# oauth2客户端配置\nspring.security.oauth2.client:\n  provider:\n    #认证服务器信息\n    hiauth-server:\n      # 如果你私有化部署了 HiAuth服务，请将此地址替换为私有部署的认证服务器地址\n      issuer-uri: http://auth.hiauth.cn\n      authorizationUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/authorize\n      #令牌获取地址\n      tokenUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/token\n      userInfoUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/userinfo\n      jwkSetUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/jwks\n      #userNameAttribute: name\n  registration:\n    hiauth-code:\n      #认证提供者，标识由哪个认证服务器进行认证，和上面的hiauth-server进行关联\n      provider: hiauth-server\n      client-name: himall\n      client-id: himall\n      client-secret: secret\n      #客户端认证方式 client_secret_basic\\client_secret_post\n      client-authentication-method: client_secret_basic\n      #使用授权码模式获取令牌（token）\n      authorization-grant-type: authorization_code\n      # 认证完成后回调的地址，需要在数据库表oauth2_registered_client中登记这个地址，否则会拒绝回调\n      redirect-uri: http://127.0.0.1:9000/login/oauth2/code/hiauth-code\n      #redirect-uri: http://127.0.0.1:9000/home\n      scope: openid,profile"
  },
  {
    "path": "example/spring-cloud/gateway/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"gateway.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/spring-cloud/ordersvc/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.3.10</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>ordersvc</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>ordersvc</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>2023.0.6</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.cloud</groupId>\n                <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n                <version>2023.0.3.3</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <!-- 开发支持：热启动等 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <scope>runtime</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--注册中心客户端-->\n        <dependency>\n            <groupId>com.alibaba.cloud</groupId>\n            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/spring-cloud/ordersvc/src/main/java/cn/hiauth/gateway/IndexController.java",
    "content": "package cn.hiauth.gateway;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestHeader;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class IndexController {\n\n    @GetMapping(\"/\")\n    public String index(@RequestHeader(\"Authorization\") String authHeader) {\n        return \"ordersvc\" + authHeader;\n    }\n\n}"
  },
  {
    "path": "example/spring-cloud/ordersvc/src/main/java/cn/hiauth/gateway/OrderStarter.java",
    "content": "package cn.hiauth.gateway;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\n\n@EnableDiscoveryClient\n@SpringBootApplication\npublic class OrderStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(OrderStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/spring-cloud/ordersvc/src/main/resources/application.yml",
    "content": "server.port: 9001\nspring.application.name: ordersvc\nlogging.level.root: INFO\n\n# Nacos注册中心配置\nspring.cloud.nacos.discovery.server-addr: 192.168.1.250:8848"
  },
  {
    "path": "example/spring-cloud/ordersvc/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"ordersvc.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/spring-cloud/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>spring-cloud</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>gateway</module>\n        <module>ordersvc</module>\n    </modules>\n\n</project>\n"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/README.md",
    "content": "- 清空登录状态：访问 http://auth.hiauth.cn，如果是登录状态，先退出登录；\n- 登录授权：访问 http://127.0.0.1:9000/unpapi/himall/oauth2/login\n- 访问接口：登录成功后，浏览器会自动跳转到配置文件中指定的地址，并在参数中携带accessToken；\n- 退出：访问 http://127.0.0.1:9000/unpapi/himall/oauth2/logout"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/gateway1/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>gateway1</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>gateway</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>3.3.10</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>2023.0.6</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.cloud</groupId>\n                <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n                <version>2023.0.3.3</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <!-- 必须得启动以来 -->\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-bootstrap</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-webflux</artifactId>\n        </dependency>\n        <!--注册中心客户端-->\n        <dependency>\n            <groupId>com.alibaba.cloud</groupId>\n            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>\n        </dependency>\n        <!-- 网关 -->\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-gateway</artifactId>\n        </dependency>\n        <!-- 由于Nacos2020版之后不支持Ribbon所以通过服务名访问路由将会失败，需要引入以下依赖 -->\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-loadbalancer</artifactId>\n        </dependency>\n        <!-- 开发支持：热启动等 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-actuator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-resolver-dns-native-macos</artifactId>\n            <version>4.1.112.Final</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.hiauth</groupId>\n            <artifactId>hiauth-client-spring-cloud-gateway-starter</artifactId>\n            <version>1.0.8</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/gateway1/src/main/java/cn/hiauth/gateway/ApiController.java",
    "content": "package cn.hiauth.gateway;\n\nimport cn.hiauth.client.Authentication;\nimport cn.hiauth.client.SessionContextHolder;\nimport cn.hiauth.client.UserinfoVo;\nimport cn.webestar.scms.commons.R;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@RequestMapping(\"/api/common\")\npublic class ApiController {\n\n    @ResponseBody\n    @GetMapping(value = \"/api/userinfo\")\n    public R<UserinfoVo> userinfo() {\n        Authentication auth = SessionContextHolder.getContext().getAuth();\n        return R.success(UserinfoVo.toVo(auth));\n    }\n\n}"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/gateway1/src/main/java/cn/hiauth/gateway/GatewayStarter.java",
    "content": "package cn.hiauth.gateway;\n\nimport cn.hiauth.client.Constant;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\n\n@SpringBootApplication\n@ComponentScan(basePackages = {Constant.HIAUTH_BASIC_PKG, \"cn.hiauth.gateway\"})\npublic class GatewayStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(GatewayStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/gateway1/src/main/java/cn/hiauth/gateway/IndexController.java",
    "content": "package cn.hiauth.gateway;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class IndexController {\n\n    @GetMapping(\"/\")\n    public String index() {\n        return \"gateway\";\n    }\n\n    @GetMapping(\"/home\")\n    public String home() {\n        return \"home\";\n    }\n\n}"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/gateway1/src/main/resources/application.yml",
    "content": "server.port: 9000\nspring.application.name: gateway\nlogging.level.root: INFO\n\n# 网关启动方式\nspring.main.web-application-type: reactive\n\n# Nacos注册中心配置\nspring.cloud.nacos.discovery.server-addr: 192.168.1.250:8848\n\n# 网关路由配置\nspring.cloud.gateway.routes:\n  - id: ordersvc\n    uri: lb://ordersvc/\n    predicates:\n      - Path=/ordersvc/**\n    filters:\n      - StripPrefix=1\n\n# HiAuth客户端配置\nhiauth.client.gateway:\n  issuerUri: http://auth.hiauth.cn\n  authorizationUri: ${hiauth.client.gateway.issuerUri}/oauth2/authorize\n  tokenUri: ${hiauth.client.gateway.issuerUri}/oauth2/token\n  userInfoUri: ${hiauth.client.gateway.issuerUri}/userinfo\n  clients:\n    himall:\n      clientId: himall\n      clientSecret: secret\n      scope: profile,openid\n      redirectUri: http://127.0.0.1:9000/unpapi/himall/oauth2/token/redirect\n      # 登录成功后会将accessToken通过这个地址返回给前端\n      authSuccessRedirectUri: http://127.0.0.1:9000/ordersvc/api/info\n      cachePrefix: himall\n      cacheExpire: 2592000\n      checkPermission: false\n\n# Redis配置\nspring.data.redis:\n  host: 192.168.3.143\n  port: 26379\n  database: 5\n  username:\n  password: Vking1357!\n  timeout: 10000\n  connect-timeout: 10000\n"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/gateway1/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"gateway.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/ordersvc1/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.3.10</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>ordersvc1</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>ordersvc</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>2023.0.6</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.cloud</groupId>\n                <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n                <version>2023.0.3.3</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <!-- 开发支持：热启动等 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <scope>runtime</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--注册中心客户端-->\n        <dependency>\n            <groupId>com.alibaba.cloud</groupId>\n            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.hiauth</groupId>\n            <artifactId>hiauth-client-session-spring-boot-starter</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/ordersvc1/src/main/java/cn/hiauth/gateway/IndexController.java",
    "content": "package cn.hiauth.gateway;\n\nimport cn.hiauth.client.Authentication;\nimport cn.hiauth.client.SessionContextHolder;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestHeader;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class IndexController {\n\n    @GetMapping(\"/api/info\")\n    public Authentication index(@RequestHeader(value = \"Authorization\", required = false) String authHeader) {\n        Authentication auth = SessionContextHolder.getContext().getAuth();\n        return auth;\n    }\n\n}"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/ordersvc1/src/main/java/cn/hiauth/gateway/OrderStarter.java",
    "content": "package cn.hiauth.gateway;\n\nimport cn.hiauth.client.Constant;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\nimport org.springframework.context.annotation.ComponentScan;\n\n@EnableDiscoveryClient\n@SpringBootApplication\n@ComponentScan(basePackages = {Constant.HIAUTH_BASIC_PKG, \"cn.hiauth.gateway\"})\npublic class OrderStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(OrderStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/ordersvc1/src/main/resources/application.yml",
    "content": "server.port: 9001\nspring.application.name: ordersvc\nlogging.level.root: INFO\n\n# Nacos注册中心配置\nspring.cloud.nacos.discovery.server-addr: 192.168.1.250:8848\n\n# HiAuth Client 配置\napp.security.enable: true\nhiauth.client.cachePrefix: himall\n\n# Redis配置\nspring.data.redis:\n  host: 192.168.3.143\n  port: 26379\n  database: 5\n  username:\n  password: Vking1357!\n  timeout: 10000\n  connect-timeout: 10000"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/ordersvc1/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"ordersvc.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/spring-cloud-with-hiauth-client/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>spring-cloud-with-hiauth-client</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>gateway1</module>\n        <module>ordersvc1</module>\n    </modules>\n\n</project>\n"
  },
  {
    "path": "example/wechat-login/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.4.5</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>wechat-login</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <name>wechat-login</name>\n    <description>wechat-login</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <scope>runtime</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>wechat-login</finalName>\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n                <filtering>true</filtering>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-resources-plugin</artifactId>\n                <configuration>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/WechatLoginStarter.java",
    "content": "package cn.hiauth.wechatlogin;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class WechatLoginStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(WechatLoginStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/SecurityConfig.java",
    "content": "package cn.hiauth.wechatlogin.config;\n\nimport cn.hiauth.wechatlogin.config.web.security.phone.SmsCodeAuthenticationFilter;\nimport cn.hiauth.wechatlogin.config.web.security.phone.SmsCodeAuthenticationProvider;\nimport cn.hiauth.wechatlogin.config.web.security.wechat.QrCodeAuthenticationFilter;\nimport cn.hiauth.wechatlogin.config.web.security.wechat.QrCodeAuthenticationProvider;\nimport cn.hiauth.wechatlogin.service.CustomUserDetailsService;\nimport org.springframework.boot.web.client.RestTemplateBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.authentication.ProviderManager;\nimport org.springframework.security.authentication.dao.DaoAuthenticationProvider;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;\nimport org.springframework.security.web.context.DelegatingSecurityContextRepository;\nimport org.springframework.security.web.context.HttpSessionSecurityContextRepository;\nimport org.springframework.security.web.context.RequestAttributeSecurityContextRepository;\nimport org.springframework.security.web.context.SecurityContextRepository;\nimport org.springframework.web.client.RestTemplate;\n\n@EnableWebSecurity\n@Configuration(proxyBeanMethods = true)\npublic class SecurityConfig {\n\n    @Bean\n    public PasswordEncoder passwordEncoder() {\n        return new BCryptPasswordEncoder();\n    }\n\n    @Bean\n    public CustomUserDetailsService customUserDetailsService() {\n        return new CustomUserDetailsService(passwordEncoder());\n    }\n\n    @Bean\n    public RestTemplate restTemplate(RestTemplateBuilder builder) {\n        return builder.build();\n    }\n\n    @Bean\n    WebSecurityCustomizer webSecurityCustomizer() {\n        return web -> web.ignoring().requestMatchers(\"/static/**\", \"/webjars/**\");\n    }\n\n    /**\n     * 定义securityContextRepository，加入两种securityContextRepository\n     */\n    @Bean\n    public SecurityContextRepository securityContextRepository() {\n        HttpSessionSecurityContextRepository httpSecurityRepository = new HttpSessionSecurityContextRepository();\n        return new DelegatingSecurityContextRepository(httpSecurityRepository, new RequestAttributeSecurityContextRepository());\n    }\n\n    @Bean\n    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n        http.authorizeHttpRequests(auth -> auth\n                        .requestMatchers(\"/login\").permitAll()\n                        .anyRequest().authenticated()\n                )\n                .formLogin(Customizer.withDefaults())\n                // 用户名密码登录配置\n                .formLogin(form -> form\n                        .loginPage(\"/login\")\n                        .loginProcessingUrl(\"/account/doLogin\")\n                        .defaultSuccessUrl(\"/index\", true)\n                        .permitAll()\n                )\n                // 添加手机验证码认证过滤器\n                .addFilterBefore(smsCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)\n                .addFilterBefore(qrCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)\n                // 设置全局authenticationManager\n                .authenticationManager(authenticationManager())\n                // 设置全局securityContextRepository\n                .securityContext(c -> c.securityContextRepository(securityContextRepository()));\n        // .csrf(AbstractHttpConfigurer::disable)\n        return http.build();\n    }\n\n    @Bean\n    public SmsCodeAuthenticationFilter smsCodeAuthenticationFilter() {\n        // 手机验证码登录过滤器\n        SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();\n        smsCodeAuthenticationFilter.setAuthenticationManager(authenticationManager());\n        smsCodeAuthenticationFilter.setSecurityContextRepository(securityContextRepository());\n        return smsCodeAuthenticationFilter;\n    }\n\n    @Bean\n    public QrCodeAuthenticationFilter qrCodeAuthenticationFilter() {\n        QrCodeAuthenticationFilter qrCodeAuthenticationFilter = new QrCodeAuthenticationFilter();\n        qrCodeAuthenticationFilter.setAuthenticationManager(authenticationManager());\n        qrCodeAuthenticationFilter.setSecurityContextRepository(securityContextRepository());\n        return qrCodeAuthenticationFilter;\n    }\n\n    @Bean\n    public AuthenticationManager authenticationManager() {\n        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();\n        daoAuthenticationProvider.setUserDetailsService(customUserDetailsService());\n        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());\n        SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider(customUserDetailsService());\n        QrCodeAuthenticationProvider qrCodeAuthenticationProvider = new QrCodeAuthenticationProvider(customUserDetailsService());\n        return new ProviderManager(daoAuthenticationProvider, smsCodeAuthenticationProvider, qrCodeAuthenticationProvider);\n    }\n\n}\n\n\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/WebMvcConfig.java",
    "content": "package cn.hiauth.wechatlogin.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.CacheControl;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport java.util.concurrent.TimeUnit;\n\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/static/**\", \"/webjars/**\")\n                .addResourceLocations(\"classpath:/static/\", \"classpath:/META-INF/resources/webjars/\")\n                .setCacheControl(CacheControl.maxAge(0, TimeUnit.HOURS).cachePrivate());\n    }\n\n}\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/web/auth/package-info.java",
    "content": "package cn.hiauth.wechatlogin.config.web.auth;"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/web/security/phone/SmsCodeAuthenticationFilter.java",
    "content": "package cn.hiauth.wechatlogin.config.web.security.phone;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.authentication.AuthenticationServiceException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\n\npublic class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {\n\n    public SmsCodeAuthenticationFilter() {\n        super(new AntPathRequestMatcher(\"/phone/doLogin\", HttpMethod.POST.name()));\n    }\n\n    @Override\n    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {\n        String method = request.getMethod();\n        if (!HttpMethod.POST.name().equalsIgnoreCase(method)) {\n            throw new AuthenticationServiceException(\"Authentication method not supported: \" + request.getMethod());\n        } else {\n            String phone = request.getParameter(\"phone\");\n            String code = request.getParameter(\"code\");\n            SmsCodeAuthenticationToken authenticationToken = new SmsCodeAuthenticationToken(phone, code);\n            return this.getAuthenticationManager().authenticate(authenticationToken);\n        }\n    }\n\n}"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/web/security/phone/SmsCodeAuthenticationProvider.java",
    "content": "package cn.hiauth.wechatlogin.config.web.security.phone;\n\nimport cn.hiauth.wechatlogin.service.CustomUserDetailsService;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.authentication.BadCredentialsException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.core.userdetails.UserDetails;\n\npublic class SmsCodeAuthenticationProvider implements AuthenticationProvider {\n\n    private final CustomUserDetailsService userDetailsService;\n\n    public SmsCodeAuthenticationProvider(CustomUserDetailsService userDetailsService) {\n        this.userDetailsService = userDetailsService;\n    }\n\n    @Override\n    public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;\n\n        String mobile = (String) authenticationToken.getPrincipal();\n        String code = (String) authenticationToken.getCredentials();\n\n        // 这里应该添加验证码校验逻辑，验证手机号和验证码是否匹配\n        // 示例中简化处理，实际应用中应该调用短信验证服务验证code是否正确\n\n        UserDetails userDetails = userDetailsService.loadUserByMobile(mobile);\n        if (userDetails == null) {\n            throw new BadCredentialsException(\"手机号未注册\");\n        }\n\n        // 验证通过后，返回认证成功的令牌\n        SmsCodeAuthenticationToken token = new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());\n        token.setDetails(authenticationToken.getDetails());\n\n        return token;\n    }\n\n    @Override\n    public boolean supports(Class<?> authentication) {\n        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);\n    }\n}\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/web/security/phone/SmsCodeAuthenticationToken.java",
    "content": "package cn.hiauth.wechatlogin.config.web.security.phone;\n\nimport org.springframework.security.authentication.AbstractAuthenticationToken;\nimport org.springframework.security.core.GrantedAuthority;\n\nimport java.util.Collection;\n\npublic class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {\n\n    private static final long serialVersionUID = 1L;\n    private final Object principal;\n    private String code;\n\n    public SmsCodeAuthenticationToken(String mobile, String code) {\n        super(null);\n        this.principal = mobile;\n        this.code = code;\n        setAuthenticated(false);\n    }\n\n    public SmsCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {\n        super(authorities);\n        this.principal = principal;\n        super.setAuthenticated(true);\n    }\n\n    @Override\n    public Object getCredentials() {\n        return code;\n    }\n\n    @Override\n    public Object getPrincipal() {\n        return principal;\n    }\n\n}\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/web/security/wechat/QrCodeAuthenticationFilter.java",
    "content": "package cn.hiauth.wechatlogin.config.web.security.wechat;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\n\npublic class QrCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {\n\n    public QrCodeAuthenticationFilter() {\n        super(new AntPathRequestMatcher(\"/wechat/qrcode/doLogin\"));\n    }\n\n    @Override\n    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {\n        String code = request.getParameter(\"code\");\n        QrCodeAuthenticationToken authenticationToken = new QrCodeAuthenticationToken(code);\n        return this.getAuthenticationManager().authenticate(authenticationToken);\n    }\n\n}"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/web/security/wechat/QrCodeAuthenticationProvider.java",
    "content": "package cn.hiauth.wechatlogin.config.web.security.wechat;\n\nimport cn.hiauth.wechatlogin.service.CustomUserDetailsService;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.authentication.BadCredentialsException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.core.userdetails.UserDetails;\n\npublic class QrCodeAuthenticationProvider implements AuthenticationProvider {\n\n    private final CustomUserDetailsService userDetailsService;\n\n    public QrCodeAuthenticationProvider(CustomUserDetailsService userDetailsService) {\n        this.userDetailsService = userDetailsService;\n    }\n\n    @Override\n    public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n        QrCodeAuthenticationToken authenticationToken = (QrCodeAuthenticationToken) authentication;\n\n        String code = (String) authenticationToken.getPrincipal();\n\n        // 这里应该添加验证码校验逻辑，验证手机号和验证码是否匹配\n        // 示例中简化处理，实际应用中应该调用短信验证服务验证code是否正确\n\n        UserDetails userDetails = userDetailsService.loadUserWeChatCode(code);\n        if (userDetails == null) {\n            throw new BadCredentialsException(\"手机号未注册\");\n        }\n\n        // 验证通过后，返回认证成功的令牌\n        QrCodeAuthenticationToken token = new QrCodeAuthenticationToken(userDetails, userDetails.getAuthorities());\n        token.setDetails(authenticationToken.getDetails());\n\n        return token;\n    }\n\n    @Override\n    public boolean supports(Class<?> authentication) {\n        return QrCodeAuthenticationToken.class.isAssignableFrom(authentication);\n    }\n}\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/config/web/security/wechat/QrCodeAuthenticationToken.java",
    "content": "package cn.hiauth.wechatlogin.config.web.security.wechat;\n\nimport org.springframework.security.authentication.AbstractAuthenticationToken;\nimport org.springframework.security.core.GrantedAuthority;\n\nimport java.util.Collection;\n\npublic class QrCodeAuthenticationToken extends AbstractAuthenticationToken {\n\n    private static final long serialVersionUID = 1L;\n    private final Object principal;\n    private String code;\n\n    public QrCodeAuthenticationToken(String code) {\n        super(null);\n        this.principal = code;\n        this.code = code;\n        setAuthenticated(false);\n    }\n\n    public QrCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {\n        super(authorities);\n        this.principal = principal;\n        super.setAuthenticated(true);\n    }\n\n    @Override\n    public Object getCredentials() {\n        return code;\n    }\n\n    @Override\n    public Object getPrincipal() {\n        return principal;\n    }\n\n}\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/controller/AuthController.java",
    "content": "package cn.hiauth.wechatlogin.controller;\n\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class AuthController {\n\n}\n"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/controller/IndexController.java",
    "content": "package cn.hiauth.wechatlogin.controller;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.GetMapping;\n\n@Slf4j\n@Controller\npublic class IndexController {\n\n    @GetMapping(\"/login\")\n    public String login() {\n        return \"login\";\n    }\n\n    @GetMapping({\"/\", \"/index\"})\n    public String index(HttpServletRequest request, HttpServletResponse response, Model model) {\n        Authentication auth = SecurityContextHolder.getContext().getAuthentication();\n        model.addAttribute(\"token\", auth);\n        return \"index\";\n    }\n\n    @GetMapping({\"/home\"})\n    public String home() {\n        Authentication auth = SecurityContextHolder.getContext().getAuthentication();\n        return \"home\";\n    }\n\n}"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/entity/CustomUserDetails.java",
    "content": "package cn.hiauth.wechatlogin.entity;\n\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.userdetails.UserDetails;\n\nimport java.util.Collection;\n\npublic class CustomUserDetails implements UserDetails {\n\n    private final String username;\n    private final String password;\n    private final boolean enabled;\n    private final Collection<? extends GrantedAuthority> authorities;\n\n    public CustomUserDetails(String username, String password, boolean enabled,\n                             Collection<? extends GrantedAuthority> authorities) {\n        this.username = username;\n        this.password = password;\n        this.enabled = enabled;\n        this.authorities = authorities;\n    }\n\n    @Override\n    public Collection<? extends GrantedAuthority> getAuthorities() {\n        return authorities;\n    }\n\n    @Override\n    public String getPassword() {\n        return password;\n    }\n\n    @Override\n    public String getUsername() {\n        return username;\n    }\n\n    @Override\n    public boolean isAccountNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isAccountNonLocked() {\n        return true;\n    }\n\n    @Override\n    public boolean isCredentialsNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return enabled;\n    }\n}"
  },
  {
    "path": "example/wechat-login/src/main/java/cn/hiauth/wechatlogin/service/CustomUserDetailsService.java",
    "content": "package cn.hiauth.wechatlogin.service;\n\nimport cn.hiauth.wechatlogin.entity.CustomUserDetails;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.security.crypto.password.PasswordEncoder;\n\nimport java.util.Collections;\n\npublic class CustomUserDetailsService implements UserDetailsService {\n\n    private PasswordEncoder passwordEncoder;\n\n    public CustomUserDetailsService(PasswordEncoder passwordEncoder) {\n        this.passwordEncoder = passwordEncoder;\n    }\n\n    @Override\n    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {\n        if (\"admin\".equals(username)) {\n            return new CustomUserDetails(\n                    \"admin\",\n                    passwordEncoder.encode(\"123456\"),\n                    true,\n                    Collections.singletonList(() -> \"ROLE_ADMIN\")\n            );\n        } else if (\"user\".equals(username)) {\n            return new CustomUserDetails(\n                    \"user\",\n                    passwordEncoder.encode(\"123456\"),\n                    true,\n                    Collections.singletonList(() -> \"ROLE_USER\")\n            );\n        }\n        throw new UsernameNotFoundException(\"User not found: \" + username);\n    }\n\n    public UserDetails loadUserByMobile(String mobile) throws UsernameNotFoundException {\n        if (\"1388888888\".equals(mobile)) {\n            return new CustomUserDetails(\n                    \"admin\",\n                    passwordEncoder.encode(\"123456\"),\n                    true,\n                    Collections.singletonList(() -> \"ROLE_ADMIN\")\n            );\n        }\n        throw new UsernameNotFoundException(\"User not found: \" + mobile);\n    }\n\n    public UserDetails loadUserWeChatCode(String code) {\n        return new CustomUserDetails(\n                \"admin\",\n                passwordEncoder.encode(\"123456\"),\n                true,\n                Collections.singletonList(() -> \"ROLE_ADMIN\")\n        );\n    }\n}"
  },
  {
    "path": "example/wechat-login/src/main/resources/application.yml",
    "content": "server.port: 9000\n\nlogging.level:\n  root: INFO\n  cn.hiauth: DEBUG\n"
  },
  {
    "path": "example/wechat-login/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"wechat.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "example/wechat-login/src/main/resources/templates/home.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>HiMall</title>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n</head>\n<body>\nHOME\n</body>\n</html>\n"
  },
  {
    "path": "example/wechat-login/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>HiMall</title>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n</head>\n<body>\nINDEX\n<div th:text=\"${token}\"></div>\n<form th:action=\"@{/logout}\" method=\"post\">\n<!--    <input type=\"hidden\" th:name=\"${_csrf.parameterName}\" th:value=\"${_csrf.token}\"/>-->\n    <button type=\"submit\">退出登录</button>\n</form>\n</body>\n</html>\n"
  },
  {
    "path": "example/wechat-login/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Custom Login Page</title>\n</head>\n<body>\n<h2>Account Login</h2>\n<form th:action=\"@{/account/doLogin}\" method=\"post\">\n<!--    <input name=\"_csrf\" type=\"hidden\" th:value=\"${_csrf.token}\">-->\n    <div>\n        <label for=\"username\">Username:</label>\n        <input type=\"text\" id=\"username\" name=\"username\" value=\"user\"/>\n    </div>\n    <div>\n        <label for=\"password\">Password:</label>\n        <input type=\"password\" id=\"password\" name=\"password\" value=\"123456\"/>\n    </div>\n    <div>\n        <button type=\"submit\">Log In</button>\n    </div>\n</form>\n<h2>Phone Login</h2>\n<form th:action=\"@{/phone/doLogin}\" method=\"post\">\n<!--    <input name=\"_csrf\" type=\"hidden\" th:value=\"${_csrf.token}\">-->\n    <div>\n        <label for=\"phone\">Phone:</label>\n        <input type=\"text\" id=\"phone\" name=\"phone\" value=\"1388888888\"/>\n    </div>\n    <div>\n        <label for=\"code\">Code:</label>\n        <input type=\"text\" id=\"code\" name=\"code\" value=\"1234\"/>\n    </div>\n    <div>\n        <button type=\"submit\">Log In</button>\n    </div>\n</form>\n<h2>WeChat Login POST</h2>\n<form th:action=\"@{/wechat/qrcode/doLogin}\" method=\"post\">\n    <!--    <input name=\"_csrf\" type=\"hidden\" th:value=\"${_csrf.token}\">-->\n    <div>\n        <label for=\"wxcode\">Code:</label>\n        <input type=\"text\" id=\"wxcode\" name=\"code\" value=\"1234\"/>\n    </div>\n    <div>\n        <button type=\"submit\">Log In</button>\n    </div>\n</form>\n<h2>WeChat Login GET</h2>\n<form th:action=\"@{/wechat/qrcode/doLogin}\" method=\"get\">\n    <!--    <input name=\"_csrf\" type=\"hidden\" th:value=\"${_csrf.token}\">-->\n    <div>\n        <label for=\"wxcode1\">Code:</label>\n        <input type=\"text\" id=\"wxcode1\" name=\"code\" value=\"1234\"/>\n    </div>\n    <div>\n        <button type=\"submit\">Log In</button>\n    </div>\n</form>\n</body>\n</html>"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-client-commons</artifactId>\n    <version>1.0.0</version>\n    <packaging>jar</packaging>\n    <name>hiauth-client-commons</name>\n    <description>hiauth-client-commons</description>\n    <url>https://github.com/bestaone/hiauth</url>\n\n    <properties>\n        <maven.compiler.source>17</maven.compiler.source>\n        <maven.compiler.target>17</maven.compiler.target>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>3.4.5</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.30</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.38</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n            <scope>compile</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.13.0</version>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>3.3.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.3.0</version>\n                <configuration>\n                    <source>17</source>\n                    <encoding>UTF-8</encoding>\n                    <additionalJOptions>\n                        <additionalJOption>-Xdoclint:none</additionalJOption>\n                    </additionalJOptions>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- 如果要往中央仓库推，需要把下面两个插件打开 -->\n            <!--  必须配置GPG插件用于使用以下配置对组件进行签名 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>3.2.0</version>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--新账号的配置：将组件部署到OSSRH并将其发布到Central Repository-->\n            <plugin>\n                <groupId>org.sonatype.central</groupId>\n                <artifactId>central-publishing-maven-plugin</artifactId>\n                <version>0.4.0</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <publishingServerId>ossrh</publishingServerId>\n                    <tokenAuth>true</tokenAuth>\n                    <deploymentName>${project.groupId}:${project.artifactId}:${project.version}</deploymentName>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <scm>\n        <url>https://gitee.com/bestaone/scms</url>\n        <connection>scm:git:https://github.com/bestaone/scms.git</connection>\n        <developerConnection>scm:git:https://github.com/bestaone/hiauth.git</developerConnection>\n    </scm>\n\n    <developers>\n        <developer>\n            <name>zgs</name>\n            <email>bestaone@163.com</email>\n            <url>https://github.com/bestaone/hiauth</url>\n            <timezone>+8</timezone>\n        </developer>\n    </developers>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n        </license>\n    </licenses>\n\n</project>\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/Authentication.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Data\npublic class Authentication {\n\n    private Long appId;\n    private Long cid;\n    private Long userId;\n    private Long empId;\n    private String name;\n    private String username;\n    private String phoneNum;\n    private String avatarUrl;\n    private List<Map<String, String>> authorities;\n    private SecurityUser principal;\n    private Boolean isCorpAdmin;\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/Client.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\n\n@Data\npublic class Client {\n\n    private String clientId;\n    private String clientSecret;\n    private String[] scope;\n    private String redirectUri;\n    /**\n     * TODO 登录成功后会将accessToken通过这个地址返回给前端\n     * 这里需优化，accessToken不能直接给到前端，存在安全隐患\n     */\n    private String authSuccessRedirectUri;\n    private Boolean checkPermission;\n    private String cachePrefix;\n    private Integer cacheExpire = 60 * 60 * 5;\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/Constant.java",
    "content": "package cn.hiauth.client;\n\npublic class Constant {\n\n    public final static String RESULT_JSON = \"{ \\\"code\\\": %d, \\\"message\\\": \\\"%s\\\" }\";\n\n    public final static String HIAUTH_BASIC_PKG = \"cn.hiauth.client\";\n\n    public final static String PARAMETER_TOKEN_KEY = \"accessToken\";\n\n    public final static String TOKEN_HEADER = \"Authorization\";\n\n    public final static String TOKEN_PREFIX = \"Bearer\";\n\n    public final static String IGNORE_METHOD = \"OPTIONS\";\n\n    /**\n     * token 有效期\n     */\n//    public final static Integer ACCESS_TOKEN_EXPIRE = 60 * 60 * 5;\n//\n//    /**\n//     * refresh_token 有效期\n//     */\n//    public final static Integer REFRESH_TOKEN_EXPIRE = 60 * 60 * 24 * 3;\n\n    /**\n     * token key 的key格式\n     */\n    public final static String ACCESS_TOKEN_CACHE_KEY = \"%s:security:accessToken:%s:%s\";\n\n    /**\n     * refresh_token 的key格式\n     */\n    public final static String REFRESH_TOKEN_CACHE_KEY = \"%s:security:refreshToken:%s:%s\";\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/HiAuthToken.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\n\n@Data\npublic class HiAuthToken {\n\n    private String accessToken;\n    private String refreshToken;\n    private String scope;\n    private LocalDateTime expire;\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/JwtUtils.java",
    "content": "package cn.hiauth.client;\n\nimport cn.hutool.jwt.JWT;\nimport cn.hutool.jwt.JWTPayload;\nimport cn.hutool.jwt.JWTUtil;\n\nimport java.time.LocalDateTime;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class JwtUtils {\n\n    public static final String SUB_KEY = \"sub\";\n    /**\n     * 10小时\n     */\n//    public static final Integer EXPIRE = 60 * 60 * 10;\n    private static final String KEY = \"jwtsecret\";\n\n//    public static String generateToken(String sub) {\n//        return generateToken(sub, EXPIRE);\n//    }\n\n    public static String generateToken(String sub, Integer expire) {\n\n        Map<String, Object> payload = new HashMap<>(2);\n        payload.put(SUB_KEY, sub);\n\n        //过期时间\n        LocalDateTime now = LocalDateTime.now();\n        LocalDateTime expireTime = now.plusSeconds(expire);\n        payload.put(JWTPayload.EXPIRES_AT, expireTime);\n\n        //签发时间\n        payload.put(JWTPayload.ISSUED_AT, now);\n\n        //生效时间\n        payload.put(JWTPayload.NOT_BEFORE, now);\n\n        return generateToken(payload);\n    }\n\n    private static String generateToken(Map<String, Object> payload) {\n        return JWTUtil.createToken(payload, KEY.getBytes());\n    }\n\n    public static JWT parseToken(String token) {\n        return JWT.of(token);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/SecurityCorp.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\n\n@Data\npublic class SecurityCorp {\n\n    private Long id;\n    private String name;\n\n    public SecurityCorp(Long id, String name) {\n        this.id = id;\n        this.name = name;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/SecurityService.java",
    "content": "package cn.hiauth.client;\n\nimport java.util.List;\n\n/**\n * @author zgs\n */\npublic interface SecurityService {\n\n    SecurityUser loadSecurityUser(Authentication auth);\n\n    /**\n     * 根据用户ID查询所属租户列表，按照最近登录时间排序\n     */\n    List<SecurityCorp> loadUserCorps(Long userId);\n\n    /**\n     * 切换租户\n     */\n    Boolean switchCorp(Long id);\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/SecurityUser.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\n\n@Data\npublic class SecurityUser {\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/SessionContext.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\n\nimport java.io.Serializable;\nimport java.time.LocalDateTime;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author zgs\n */\n@Data\npublic class SessionContext implements Serializable {\n\n    private String clientName;\n    private String cachePrefix;\n    private Integer cacheExpire;\n    private String accessToken;\n    private String refreshToken;\n    private LocalDateTime expire;\n    private Authentication auth;\n    private HiAuthToken token;\n    private Map<String, String> extend = new HashMap<>();\n\n    public SessionContext(String clientName, String cachePrefix, Integer cacheExpire) {\n        this.clientName = clientName;\n        this.cachePrefix = cachePrefix;\n        this.cacheExpire = cacheExpire;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/SessionContextHolder.java",
    "content": "package cn.hiauth.client;\n\nimport cn.hutool.json.JSONUtil;\nimport org.springframework.data.redis.core.RedisTemplate;\n\nimport java.time.LocalDateTime;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author zgs\n */\npublic class SessionContextHolder {\n\n    private static final InheritableThreadLocal<SessionContext> contexts = new InheritableThreadLocal<>();\n    private static RedisTemplate<String, String> redisTemplate;\n\n    public static void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {\n        SessionContextHolder.redisTemplate = redisTemplate;\n    }\n\n    public static SessionContext getContext() {\n        return contexts.get();\n    }\n\n    public static void setContext(SessionContext context) {\n        contexts.set(context);\n    }\n\n    public static Authentication getAuthentication() {\n        SessionContext context = getContext();\n        return context == null ? null : context.getAuth();\n    }\n\n    public static SecurityUser getPrincipal() {\n        Authentication auth = getAuthentication();\n        return auth == null ? null : auth.getPrincipal();\n    }\n\n    public static void refresh() {\n        SessionContext context = contexts.get();\n        String tokenKey = String.format(Constant.ACCESS_TOKEN_CACHE_KEY, context.getCachePrefix(), context.getAuth().getUserId(), context.getAccessToken());\n        String refreshTokenKey = String.format(Constant.REFRESH_TOKEN_CACHE_KEY, context.getCachePrefix(), context.getAuth().getUserId(), context.getRefreshToken());\n        String json = JSONUtil.toJsonStr(context);\n        redisTemplate.opsForValue().set(tokenKey, json, context.getCacheExpire(), TimeUnit.SECONDS);\n        redisTemplate.expire(refreshTokenKey, context.getCacheExpire() * 2, TimeUnit.SECONDS);\n    }\n\n    public static SessionContext auth(String clientName, String cachePrefix, Integer cacheExpire, Authentication authentication) {\n        SessionContext context = new SessionContext(clientName, cachePrefix, cacheExpire);\n        context.setAuth(authentication);\n        return auth(context);\n    }\n\n    public static SessionContext auth(SessionContext context) {\n        return auth(context, context.getCachePrefix(), context.getCacheExpire());\n    }\n\n    public static SessionContext auth(SessionContext context, String cachePrefix, Integer expire) {\n\n        String userId = context.getAuth().getUserId().toString();\n        String accessToken = JwtUtils.generateToken(userId, expire);\n        String refreshToken = UUID.randomUUID().toString().replace(\"-\", \"\");\n        context.setAccessToken(accessToken);\n        context.setRefreshToken(refreshToken);\n        context.setExpire(LocalDateTime.now().plusMinutes(expire));\n\n        SessionContextHolder.setContext(context);\n        String json = JSONUtil.toJsonStr(context);\n        redisTemplate.opsForValue().set(String.format(Constant.ACCESS_TOKEN_CACHE_KEY, cachePrefix, userId, accessToken), json, expire, TimeUnit.SECONDS);\n        redisTemplate.opsForValue().set(String.format(Constant.REFRESH_TOKEN_CACHE_KEY, cachePrefix, userId, refreshToken), accessToken, expire * 2, TimeUnit.SECONDS);\n\n        return context;\n    }\n\n    public static void logout() {\n        SessionContext context = SessionContextHolder.getContext();\n        String username = context.getAuth().getUsername();\n        String accessToken = context.getAccessToken();\n        String refreshToken = context.getRefreshToken();\n        if (redisTemplate != null) {\n            redisTemplate.expire(String.format(Constant.ACCESS_TOKEN_CACHE_KEY, context.getCachePrefix(), username, accessToken), 0, TimeUnit.SECONDS);\n            redisTemplate.expire(String.format(Constant.REFRESH_TOKEN_CACHE_KEY, context.getCachePrefix(), username, refreshToken), 0, TimeUnit.SECONDS);\n        }\n    }\n\n}"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/TokenVo.java",
    "content": "package cn.hiauth.client;\n\npublic class TokenVo {\n\n    private String accessToken;\n    private Integer expireIn;\n    private String refreshToken;\n\n    private String scope;\n\n    public TokenVo() {\n    }\n\n    public TokenVo(String accessToken, String refreshToken, Integer expireIn, String scope) {\n        this.accessToken = accessToken;\n        this.expireIn = expireIn;\n        this.refreshToken = refreshToken;\n        this.scope = scope;\n    }\n\n    public String getScope() {\n        return scope;\n    }\n\n    public void setScope(String scope) {\n        this.scope = scope;\n    }\n\n    public String getAccessToken() {\n        return accessToken;\n    }\n\n    public void setAccessToken(String accessToken) {\n        this.accessToken = accessToken;\n    }\n\n    public Integer getExpireIn() {\n        return expireIn;\n    }\n\n    public void setExpireIn(Integer expireIn) {\n        this.expireIn = expireIn;\n    }\n\n    public String getRefreshToken() {\n        return refreshToken;\n    }\n\n    public void setRefreshToken(String refreshToken) {\n        this.refreshToken = refreshToken;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-commons/src/main/java/cn/hiauth/client/UserinfoVo.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Data\npublic class UserinfoVo {\n\n    private Long cid;\n    private Long appId;\n    private Long userId;\n    private Long empId;\n    private String name;\n    private String username;\n    private String phoneNum;\n    private String avatarUrl;\n    private List<String> authorities;\n    private Boolean isCorpAdmin;\n\n    public static UserinfoVo toVo(Authentication auth) {\n        UserinfoVo vo = new UserinfoVo();\n        vo.setCid(auth.getCid());\n        vo.setAppId(auth.getAppId());\n        vo.setUserId(auth.getUserId());\n        vo.setEmpId(auth.getEmpId());\n        vo.setName(auth.getName());\n        vo.setUsername(auth.getUsername());\n        vo.setPhoneNum(auth.getPhoneNum());\n        vo.setAvatarUrl(auth.getAvatarUrl());\n        if (auth.getAuthorities() != null && !auth.getAuthorities().isEmpty()) {\n            vo.setAuthorities(new ArrayList<>());\n            auth.getAuthorities().forEach(item -> vo.getAuthorities().add(item.get(\"code\")));\n        }\n        vo.setIsCorpAdmin(auth.getIsCorpAdmin());\n        return vo;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-resource-spring-boot-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-client-resource-spring-boot-starter</artifactId>\n    <version>1.0.0</version>\n    <packaging>jar</packaging>\n    <name>hiauth-client-resource-spring-boot-starter</name>\n    <description>hiauth-client-resource-spring-boot-starter</description>\n    <url>https://github.com/bestaone/hiauth</url>\n\n    <properties>\n        <maven.compiler.source>17</maven.compiler.source>\n        <maven.compiler.target>17</maven.compiler.target>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>3.4.5</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <!-- 自动装配 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.38</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>commons</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hiauth</groupId>\n            <artifactId>hiauth-client-commons</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.13.0</version>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>3.3.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.3.0</version>\n                <configuration>\n                    <source>17</source>\n                    <encoding>UTF-8</encoding>\n                    <additionalJOptions>\n                        <additionalJOption>-Xdoclint:none</additionalJOption>\n                    </additionalJOptions>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- 如果要往中央仓库推，需要把下面两个插件打开 -->\n            <!--  必须配置GPG插件用于使用以下配置对组件进行签名 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>3.2.0</version>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--新账号的配置：将组件部署到OSSRH并将其发布到Central Repository-->\n            <plugin>\n                <groupId>org.sonatype.central</groupId>\n                <artifactId>central-publishing-maven-plugin</artifactId>\n                <version>0.4.0</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <publishingServerId>ossrh</publishingServerId>\n                    <tokenAuth>true</tokenAuth>\n                    <deploymentName>${project.groupId}:${project.artifactId}:${project.version}</deploymentName>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <scm>\n        <url>https://gitee.com/bestaone/scms</url>\n        <connection>scm:git:https://github.com/bestaone/scms.git</connection>\n        <developerConnection>scm:git:https://github.com/bestaone/hiauth.git</developerConnection>\n    </scm>\n\n    <developers>\n        <developer>\n            <name>zgs</name>\n            <email>bestaone@163.com</email>\n            <url>https://github.com/bestaone/hiauth</url>\n            <timezone>+8</timezone>\n        </developer>\n    </developers>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n        </license>\n    </licenses>\n\n</project>\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-resource-spring-boot-starter/src/main/java/cn/hiauth/client/resource/HiAuthClientResourceAutoConfig.java",
    "content": "package cn.hiauth.client.resource;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @author zgs\n */\n@Slf4j\n@Configuration\n@EnableConfigurationProperties({HiAuthClientResourceProperties.class})\npublic class HiAuthClientResourceAutoConfig {\n\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-resource-spring-boot-starter/src/main/java/cn/hiauth/client/resource/HiAuthClientResourceProperties.java",
    "content": "package cn.hiauth.client.resource;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.io.Serializable;\n\n@Data\n@ConfigurationProperties(\"hiauth.client.resource\")\npublic class HiAuthClientResourceProperties implements Serializable {\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-resource-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": {\n    \"hiauth.client.resource.url\": {\n      \"description\": \"授权服务端地址\",\n      \"type\": \"string\"\n    }\n  }\n}"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-resource-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hiauth.client.resource.HiAuthClientResourceAutoConfig"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-client-session-spring-boot-starter</artifactId>\n    <version>1.0.0</version>\n    <packaging>jar</packaging>\n    <name>hiauth-client-session-spring-boot-starter</name>\n    <description>hiauth-client-session-spring-boot-starter</description>\n    <url>https://github.com/bestaone/hiauth</url>\n\n    <properties>\n        <maven.compiler.source>17</maven.compiler.source>\n        <maven.compiler.target>17</maven.compiler.target>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>3.4.5</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <!-- 自动装配 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.38</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>commons</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hiauth</groupId>\n            <artifactId>hiauth-client-commons</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.13.0</version>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>3.3.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.3.0</version>\n                <configuration>\n                    <source>17</source>\n                    <encoding>UTF-8</encoding>\n                    <additionalJOptions>\n                        <additionalJOption>-Xdoclint:none</additionalJOption>\n                    </additionalJOptions>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- 如果要往中央仓库推，需要把下面两个插件打开 -->\n            <!--  必须配置GPG插件用于使用以下配置对组件进行签名 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>3.2.0</version>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--新账号的配置：将组件部署到OSSRH并将其发布到Central Repository-->\n            <plugin>\n                <groupId>org.sonatype.central</groupId>\n                <artifactId>central-publishing-maven-plugin</artifactId>\n                <version>0.4.0</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <publishingServerId>ossrh</publishingServerId>\n                    <tokenAuth>true</tokenAuth>\n                    <deploymentName>${project.groupId}:${project.artifactId}:${project.version}</deploymentName>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <scm>\n        <url>https://gitee.com/bestaone/scms</url>\n        <connection>scm:git:https://github.com/bestaone/scms.git</connection>\n        <developerConnection>scm:git:https://github.com/bestaone/hiauth.git</developerConnection>\n    </scm>\n\n    <developers>\n        <developer>\n            <name>zgs</name>\n            <email>bestaone@163.com</email>\n            <url>https://github.com/bestaone/hiauth</url>\n            <timezone>+8</timezone>\n        </developer>\n    </developers>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n        </license>\n    </licenses>\n\n</project>\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/src/main/java/cn/hiauth/client/session/AuthFilter.java",
    "content": "package cn.hiauth.client.session;\n\nimport cn.hiauth.client.Constant;\nimport cn.hiauth.client.JwtUtils;\nimport cn.hiauth.client.SessionContext;\nimport cn.hiauth.client.SessionContextHolder;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.jwt.JWT;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.CommonException;\nimport jakarta.servlet.*;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.StringUtils;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * @author zgs\n */\n@Slf4j\npublic class AuthFilter implements Filter {\n\n    private final AntPathMatcher matcher = new AntPathMatcher();\n\n    private final RedisTemplate<String, String> redisTemplate;\n\n    private final HiAuthClientSessionProperties properties;\n\n    public AuthFilter(HiAuthClientSessionProperties properties, RedisTemplate<String, String> redisTemplate) {\n        this.properties = properties;\n        this.redisTemplate = redisTemplate;\n    }\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n        Filter.super.init(filterConfig);\n    }\n\n    @Override\n    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) {\n        final HttpServletRequest request = (HttpServletRequest) servletRequest;\n        final HttpServletResponse response = (HttpServletResponse) servletResponse;\n        try {\n            doIt(request, response, chain);\n        } catch (Exception e) {\n            printError(request, response, e);\n        }\n    }\n\n    private void doIt(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws Exception {\n\n        if (Constant.IGNORE_METHOD.equalsIgnoreCase(request.getMethod())) {\n            chain.doFilter(request, response);\n        } else if (matcherUrl(request.getRequestURI())) {\n            SessionContext context = getSessionContext(request);\n            Assert.notNull(context, 10401, \"request fail\");\n            SessionContextHolder.setContext(context);\n            chain.doFilter(request, response);\n        } else {\n            chain.doFilter(request, response);\n        }\n    }\n\n    private SessionContext getSessionContext(HttpServletRequest request) throws Exception {\n\n        String accessToken = null;\n\n        String authHeader = request.getHeader(Constant.TOKEN_HEADER);\n        if (StringUtils.hasText(authHeader)) {\n            authHeader = URLDecoder.decode(authHeader, StandardCharsets.UTF_8);\n            Assert.isTrue(authHeader.startsWith(Constant.TOKEN_PREFIX), 10401, \"miss bearer\");\n            accessToken = authHeader.substring(Constant.TOKEN_PREFIX.length()).trim();\n        }\n\n        if (!StringUtils.hasText(accessToken)) {\n            accessToken = request.getParameter(Constant.PARAMETER_TOKEN_KEY);\n        }\n        Assert.notNull(accessToken, 10401, \"miss token\");\n\n        JWT jwt = JwtUtils.parseToken(accessToken);\n        Assert.notNull(jwt, 10401, \"invalid token\");\n\n        String username = (String) jwt.getPayload(JwtUtils.SUB_KEY);\n        Assert.notNull(username, 10401, \"invalid token\");\n\n        String accessTokenKey = String.format(Constant.ACCESS_TOKEN_CACHE_KEY, properties.getCachePrefix(), username, accessToken);\n        String json = redisTemplate.opsForValue().get(accessTokenKey);\n        Assert.notNull(json, 10401, \"invalid token\");\n        SessionContext context = JSONUtil.toBean(json, SessionContext.class);\n        Assert.notNull(context, 10401, \"invalid token\");\n\n        return context;\n    }\n\n    public boolean matcherUrl(String uri) {\n        for (String authUrl : properties.getAuthUris()) {\n            if (matcher.match(authUrl, uri)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public boolean ignoreUrl(String uri) {\n        for (String ignoreUrl : properties.getIgnoreUris()) {\n            if (matcher.match(ignoreUrl, uri)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private void printError(HttpServletRequest request, HttpServletResponse response, Exception e) {\n\n        log.error(e.getMessage(), e);\n\n        response.setContentType(\"application/json;charset=utf-8\");\n        response.setStatus(HttpServletResponse.SC_OK);\n\n        Integer code = 50000;\n        String msg;\n\n        if (e instanceof CommonException ce) {\n            code = ce.getCode();\n            msg = e.getMessage();\n        } else {\n            msg = \"系统异常\";\n        }\n\n        PrintWriter out = null;\n        try {\n            out = response.getWriter();\n            out.write(String.format(Constant.RESULT_JSON, code, msg));\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        } finally {\n            if (out != null) {\n                out.flush();\n                out.close();\n            }\n        }\n\n    }\n\n    @Override\n    public void destroy() {\n        Filter.super.destroy();\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/src/main/java/cn/hiauth/client/session/HiAuthClientSessionAutoConfig.java",
    "content": "package cn.hiauth.client.session;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.core.RedisTemplate;\n\n/**\n * @author zgs\n */\n@Slf4j\n@Configuration\n@EnableConfigurationProperties({HiAuthClientSessionProperties.class})\npublic class HiAuthClientSessionAutoConfig {\n\n    @Autowired\n    private HiAuthClientSessionProperties hiAuthClientSessionProperties;\n\n    @Autowired\n    private RedisTemplate<String, String> redisTemplate;\n\n    @Bean\n    @ConditionalOnMissingBean\n    @ConditionalOnExpression(\"${app.security.enable:false}\")\n    public FilterRegistrationBean<AuthFilter> authFilterRegister() {\n        FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();\n        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);\n        registration.setFilter(new AuthFilter(hiAuthClientSessionProperties, redisTemplate));\n        registration.setName(\"authFilter\");\n        registration.addUrlPatterns(\"/*\");\n        log.info(\"Register AuthFilter,url=/*\");\n        return registration;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/src/main/java/cn/hiauth/client/session/HiAuthClientSessionCacheConfig.java",
    "content": "package cn.hiauth.client.session;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.SerializationFeature;\nimport com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;\nimport com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\n@Slf4j\n@Configuration\npublic class HiAuthClientSessionCacheConfig {\n\n    @Bean\n    @ConditionalOnMissingBean\n    public RedisTemplate<String, ?> redisTemplate(RedisConnectionFactory factory) {\n        log.info(\"[cache-spring-boot-starter]:Init RedisTemplate\");\n        ObjectMapper om = new ObjectMapper();\n        // 支持 LocalDate、LocalDateTime的序列号\n        om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);\n        om.registerModule(new JavaTimeModule());\n        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);\n\n        RedisTemplate<String, ?> template = new RedisTemplate<>();\n        template.setConnectionFactory(factory);\n        Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(om, Object.class);\n        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();\n        // key采用String的序列化方式\n        template.setKeySerializer(stringRedisSerializer);\n        // hash的key也采用String的序列化方式\n        template.setHashKeySerializer(stringRedisSerializer);\n        // value序列化方式采用jackson\n        template.setValueSerializer(jackson2JsonRedisSerializer);\n        // hash的value序列化方式采用jackson\n        template.setHashValueSerializer(jackson2JsonRedisSerializer);\n        template.afterPropertiesSet();\n        return template;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/src/main/java/cn/hiauth/client/session/HiAuthClientSessionController.java",
    "content": "package cn.hiauth.client.session;\n\nimport cn.hiauth.client.*;\nimport cn.webestar.scms.commons.R;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n@Slf4j\n@Controller\n@RequestMapping(\"/\")\npublic class HiAuthClientSessionController {\n\n    @Autowired(required = false)\n    private SecurityService securityService;\n\n    @ResponseBody\n    @GetMapping(value = \"/api/common/user/info\")\n    public R<UserinfoVo> userInfo() {\n        Authentication auth = SessionContextHolder.getContext().getAuth();\n        return R.success(UserinfoVo.toVo(auth));\n    }\n\n    @ResponseBody\n    @PostMapping(value = \"/api/common/myCorps\")\n    public R<List<SecurityCorp>> myCorps() {\n        Authentication auth = SessionContextHolder.getContext().getAuth();\n        List<SecurityCorp> corps = securityService.loadUserCorps(auth.getUserId());\n        return R.success(corps);\n    }\n\n    @ResponseBody\n    @PostMapping(value = \"/api/common/switchCorp\")\n    public R<Boolean> switchCorp(@RequestParam(\"id\") Long id) {\n        return R.success(securityService.switchCorp(id));\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/src/main/java/cn/hiauth/client/session/HiAuthClientSessionProperties.java",
    "content": "package cn.hiauth.client.session;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.io.Serializable;\nimport java.util.Set;\n\n@Data\n@ConfigurationProperties(\"hiauth.client\")\npublic class HiAuthClientSessionProperties implements Serializable {\n\n    /**\n     * 缓存前缀\n     */\n    private String cachePrefix = \"hiauth\";\n\n    /**\n     * 无需登录也无需鉴权的接口(暂时未启用)\n     */\n    private Set<String> ignoreUris = Set.of(\"/unpapi/**\");\n\n    /**\n     * 需要登录，并且需要拥有权限，才可访问的接口\n     */\n    private Set<String> authUris = Set.of(\"/api/**\");\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/src/main/java/cn/hiauth/client/session/HiAuthClientSessionRunner.java",
    "content": "package cn.hiauth.client.session;\n\nimport cn.hiauth.client.SessionContextHolder;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author zgs\n */\n@Slf4j\n@Component\npublic class HiAuthClientSessionRunner implements ApplicationRunner {\n\n    @Autowired\n    private RedisTemplate<String, String> redisTemplate;\n\n    @Override\n    public void run(ApplicationArguments args) {\n        SessionContextHolder.setRedisTemplate(redisTemplate);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": {\n    \"app.security.enable\": {\n      \"description\": \"开启安全拦截。默认值：false\",\n      \"type\": \"boolean\"\n    },\n    \"hiauth.client.cachePrefix\": {\n      \"description\": \"缓存前缀。默认值：hiauth\",\n      \"type\": \"string\"\n    },\n    \"hiauth.client.authUris\": {\n      \"description\": \"需要登录，并且需要拥有权限，才可访问的接口。默认值：/api/**\",\n      \"type\": \"string[]\"\n    },\n    \"hiauth.client.ignoreUris\": {\n      \"description\": \"无需登录也无需鉴权的接口(暂时未启用)。默认值：/unpapi/**\",\n      \"type\": \"string[]\"\n    }\n  }\n}"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-session-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hiauth.client.session.HiAuthClientSessionAutoConfig"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/docs/apisvc-oms.yml",
    "content": "server.port: 9003\n\nlogging.level:\n  root: INFO\n  com.vking: DEBUG\n\napp.cache.prefix: uavs:oms\napp.security.enable: true\n\nspring.security.oauth2.client:\n  provider:\n    hiauth-server:\n      issuer-uri: ${AUTH_URI:http://auth-dev.vking.fun:31000}\n      authorizationUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/authorize\n      tokenUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/token\n      userInfoUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/userinfo\n      jwkSetUri: ${spring.security.oauth2.client.provider.hiauth-server.issuer-uri}/oauth2/jwks\n      # userNameAttribute: name\n  registration:\n    hiauth-code:\n      # 认证提供者，标识由哪个认证服务器进行认证，和上面的auth-server进行关联\n      provider: hiauth-server\n      client-name: uavs-oms\n      client-id: uavs-oms\n      client-secret: 123456\n      # 客户端认证方式 client_secret_basic\\client_secret_post\n      client-authentication-method: client_secret_basic\n      authorization-grant-type: authorization_code\n      # 回调地址，接收认证服务器回传code的接口地址，之前我们是使用http://www.baidu.com代替\n      # 注意：和认证服务器配置的回调地址要一致 '{baseUrl}/{action}/oauth2/code/{registrationId}'\n      redirect-uri: ${REDIRECT_URI:http://oms-dev.mayizhifei.com:30281/gateway/apisvc-oms/oauth2/token/redirect}\n      scope: profile,openid\n\nhiauth.client:\n  cachePrefix: ${app.cache.prefix}\n  checkPermission: false\n  authSuccessRedirectUri: ${AUTH_SUCCESS_REDIRECT_URI:http://oms-dev.mayizhifei.com:30281}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-client-spring-boot-starter</artifactId>\n    <version>1.0.9</version>\n    <packaging>jar</packaging>\n    <name>hiauth-client-spring-boot-starter</name>\n    <description>hiauth-client-spring-boot-starter</description>\n    <url>https://github.com/bestaone/hiauth</url>\n\n    <properties>\n        <maven.compiler.source>17</maven.compiler.source>\n        <maven.compiler.target>17</maven.compiler.target>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>3.4.5</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <!-- 自动装配 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <!-- 网关会依赖此服务，但是网关使用的是webflux(依赖web模块会报错)，所以这里需要使用scope=compile -->\n        <!-- 或者使用配置 spring.main.web-application-type=reactive -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.38</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>commons</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hiauth</groupId>\n            <artifactId>hiauth-client-commons</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.13.0</version>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>3.3.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.3.0</version>\n                <configuration>\n                    <source>17</source>\n                    <encoding>UTF-8</encoding>\n                    <additionalJOptions>\n                        <additionalJOption>-Xdoclint:none</additionalJOption>\n                    </additionalJOptions>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- 如果要往中央仓库推，需要把下面两个插件打开 -->\n            <!--  必须配置GPG插件用于使用以下配置对组件进行签名 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>3.2.0</version>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--新账号的配置：将组件部署到OSSRH并将其发布到Central Repository-->\n            <plugin>\n                <groupId>org.sonatype.central</groupId>\n                <artifactId>central-publishing-maven-plugin</artifactId>\n                <version>0.4.0</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <publishingServerId>ossrh</publishingServerId>\n                    <tokenAuth>true</tokenAuth>\n                    <deploymentName>${project.groupId}:${project.artifactId}:${project.version}</deploymentName>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <scm>\n        <url>https://gitee.com/bestaone/scms</url>\n        <connection>scm:git:https://github.com/bestaone/scms.git</connection>\n        <developerConnection>scm:git:https://github.com/bestaone/hiauth.git</developerConnection>\n    </scm>\n\n    <developers>\n        <developer>\n            <name>zgs</name>\n            <email>bestaone@163.com</email>\n            <url>https://github.com/bestaone/hiauth</url>\n            <timezone>+8</timezone>\n        </developer>\n    </developers>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n        </license>\n    </licenses>\n\n</project>\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/AuthFilter.java",
    "content": "package cn.hiauth.client;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.jwt.JWT;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.CommonException;\nimport cn.webestar.scms.commons.SysCode;\nimport jakarta.servlet.*;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.StringUtils;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author zgs\n */\n@Slf4j\npublic class AuthFilter implements Filter {\n\n    private final static String ERROR_RESULT = \"{ \\\"code\\\": %d, \\\"message\\\": \\\"%s\\\" }\";\n\n    private final AntPathMatcher matcher = new AntPathMatcher();\n\n    private final RedisTemplate<String, String> redisTemplate;\n\n    private final HiAuthClientProperties properties;\n\n    public AuthFilter(HiAuthClientProperties properties, RedisTemplate<String, String> redisTemplate) {\n        this.properties = properties;\n        this.redisTemplate = redisTemplate;\n    }\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n        Filter.super.init(filterConfig);\n    }\n\n    @Override\n    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) {\n        final HttpServletRequest request = (HttpServletRequest) servletRequest;\n        final HttpServletResponse response = (HttpServletResponse) servletResponse;\n        try {\n            doIt(request, response, chain);\n        } catch (Exception e) {\n            printError(request, response, e);\n        }\n    }\n\n    private void doIt(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws Exception {\n\n//        String cid = request.getHeader(\"_CID_\");\n//        if(StringUtils.hasText(cid)){\n//            RequestContext context = new RequestContext();\n//            context.setCid(Long.parseLong(cid));\n//            ApiRequestContextHolder.setContext(context);\n//        } else {\n//            ApiRequestContextHolder.setContext(null);\n//        }\n\n        if (Constant.IGNORE_METHOD.equalsIgnoreCase(request.getMethod())) {\n            chain.doFilter(request, response);\n        } else if (matcherUrl(request.getRequestURI())) {\n            SessionContext context = getSessionContext(request);\n            Assert.notNull(context, 10401, \"request fail\");\n            SessionContextHolder.setContext(context);\n            checkPermissions(request, context.getAuth().getAuthorities());\n            chain.doFilter(request, response);\n        } else {\n            chain.doFilter(request, response);\n        }\n    }\n\n    private void checkPermissions(HttpServletRequest request, List<Map<String, String>> authorities) {\n        //是否开启了权限检查\n        if (!properties.isCheckPermission()) {\n            return;\n        }\n        String uri = request.getRequestURI();\n        //检查是否为无需权限的api\n        for (String api : properties.getIgnorePermissionUris()) {\n            if (StringUtils.hasText(api) && StringUtils.hasText(uri) && matcher.match(api, uri)) {\n                return;\n            }\n        }\n        //检查是否分配了权限\n        for (Map<String, String> o : authorities) {\n            String api = o.get(\"api\");\n            if (StringUtils.hasText(api) && StringUtils.hasText(uri) && matcher.match(api, uri)) {\n                return;\n            }\n        }\n        throw new CommonException(SysCode.FORBIDDEN.getCode(), \"没有权限\");\n    }\n\n    private SessionContext getSessionContext(HttpServletRequest request) throws Exception {\n\n        String accessToken = null;\n\n        String authHeader = request.getHeader(Constant.TOKEN_HEADER);\n        if (StringUtils.hasText(authHeader)) {\n            authHeader = URLDecoder.decode(authHeader, StandardCharsets.UTF_8);\n            Assert.isTrue(authHeader.startsWith(Constant.TOKEN_PREFIX), 10401, \"miss bearer\");\n            accessToken = authHeader.substring(Constant.TOKEN_PREFIX.length()).trim();\n        }\n\n        if (!StringUtils.hasText(accessToken)) {\n            accessToken = request.getParameter(Constant.PARAMETER_TOKEN_KEY);\n        }\n        Assert.notNull(accessToken, 10401, \"miss token\");\n\n        JWT jwt = JwtUtils.parseToken(accessToken);\n        Assert.notNull(jwt, 10401, \"invalid token\");\n\n        String username = (String) jwt.getPayload(JwtUtils.SUB_KEY);\n        Assert.notNull(username, 10401, \"invalid token\");\n\n        String accessTokenKey = String.format(Constant.ACCESS_TOKEN_CACHE_KEY, properties.getCachePrefix(), username, accessToken);\n        String json = redisTemplate.opsForValue().get(accessTokenKey);\n        Assert.notNull(json, 10401, \"invalid token\");\n        SessionContext context = JSONUtil.toBean(json, SessionContext.class);\n        Assert.notNull(context, 10401, \"invalid token\");\n\n        return context;\n    }\n\n    public boolean matcherUrl(String uri) {\n        for (String authUrl : properties.getAuthUris()) {\n            if (matcher.match(authUrl, uri)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public boolean ignoreUrl(String uri) {\n        for (String ignoreUrl : properties.getIgnoreUris()) {\n            if (matcher.match(ignoreUrl, uri)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private void printError(HttpServletRequest request, HttpServletResponse response, Exception e) {\n\n        log.error(e.getMessage(), e);\n\n        response.setContentType(\"application/json;charset=utf-8\");\n        response.setStatus(HttpServletResponse.SC_OK);\n\n        Integer code = 50000;\n        String msg;\n\n        if (e instanceof CommonException ce) {\n            code = ce.getCode();\n            msg = e.getMessage();\n        } else {\n            msg = \"系统异常\";\n        }\n\n        PrintWriter out = null;\n        try {\n            out = response.getWriter();\n            out.write(String.format(ERROR_RESULT, code, msg));\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        } finally {\n            if (out != null) {\n                out.flush();\n                out.close();\n            }\n        }\n\n    }\n\n    @Override\n    public void destroy() {\n        Filter.super.destroy();\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/HiAuthCacheConfig.java",
    "content": "package cn.hiauth.client;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.SerializationFeature;\nimport com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;\nimport com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\n@Slf4j\n@Configuration\npublic class HiAuthCacheConfig {\n\n    @Bean\n    @ConditionalOnMissingBean\n    public RedisTemplate<String, ?> redisTemplate(RedisConnectionFactory factory) {\n        log.info(\"[cache-spring-boot-starter]:Init RedisTemplate\");\n        ObjectMapper om = new ObjectMapper();\n        // 支持 LocalDate、LocalDateTime的序列号\n        om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);\n        om.registerModule(new JavaTimeModule());\n        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);\n\n        RedisTemplate<String, ?> template = new RedisTemplate<>();\n        template.setConnectionFactory(factory);\n        Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(om, Object.class);\n        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();\n        // key采用String的序列化方式\n        template.setKeySerializer(stringRedisSerializer);\n        // hash的key也采用String的序列化方式\n        template.setHashKeySerializer(stringRedisSerializer);\n        // value序列化方式采用jackson\n        template.setValueSerializer(jackson2JsonRedisSerializer);\n        // hash的value序列化方式采用jackson\n        template.setHashValueSerializer(jackson2JsonRedisSerializer);\n        template.afterPropertiesSet();\n        return template;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/HiAuthClientAutoConfig.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * @author zgs\n */\n@Slf4j\n@Configuration\n@EnableConfigurationProperties({HiAuthClientProviderProperties.class, HiAuthClientRegistrationProperties.class, HiAuthClientProperties.class})\npublic class HiAuthClientAutoConfig {\n\n    @Autowired\n    private HiAuthClientProperties authClientProperties;\n\n    @Autowired\n    private RedisTemplate<String, String> redisTemplate;\n\n    @Bean\n    @ConditionalOnMissingBean(RestTemplate.class)\n    public RestTemplate restTemplate() {\n        return new RestTemplate();\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    @ConditionalOnExpression(\"${app.security.enable:false}\")\n    public FilterRegistrationBean<AuthFilter> authFilterRegister() {\n        FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>();\n        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);\n        registration.setFilter(new AuthFilter(authClientProperties, redisTemplate));\n        registration.setName(\"authFilter\");\n        registration.addUrlPatterns(\"/*\");\n        log.info(\"Register AuthFilter,url=/*\");\n        return registration;\n    }\n\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/HiAuthClientController.java",
    "content": "package cn.hiauth.client;\n\nimport cn.hiauth.client.api.TokenVo;\nimport cn.hiauth.client.api.UserPwdUpdateDto;\nimport cn.hutool.core.codec.Base64;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport jakarta.servlet.http.HttpServletRequest;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.client.HttpClientErrorException;\nimport org.springframework.web.client.RestTemplate;\n\nimport java.time.LocalDateTime;\nimport java.time.temporal.ChronoUnit;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@Slf4j\n@Controller\n@RequestMapping(\"/\")\npublic class HiAuthClientController {\n\n    @Autowired\n    private HiAuthClientProviderProperties authClientProviderProperties;\n\n    @Autowired\n    private HiAuthClientRegistrationProperties authClientRegistrationProperties;\n\n    @Autowired\n    private HiAuthClientProperties authClientProperties;\n\n    @Autowired\n    private RestTemplate restTemplate;\n\n    @Autowired(required = false)\n    private SecurityService securityService;\n\n    @GetMapping(\"/oauth2/login\")\n    public String login(HttpServletRequest request) {\n        String authUrl = authClientProviderProperties.getAuthorizationUri() +\n                \"?response_type=code\" +\n                \"&client_id=\" + authClientRegistrationProperties.getClientId() +\n                \"&scope=\" + String.join(\" \", authClientRegistrationProperties.getScope()) +\n                \"&redirect_uri=\" + authClientRegistrationProperties.getRedirectUri();\n        return \"redirect:\" + authUrl;\n    }\n\n    @GetMapping(\"/oauth2/logout\")\n    public String logout(HttpServletRequest request) {\n        String redirectUri = authClientProperties.getAuthSuccessRedirectUri();\n        if (!StringUtils.hasText(redirectUri)) {\n            redirectUri = authClientRegistrationProperties.getRedirectUri();\n        }\n        String logoutUrl = authClientProviderProperties.getIssuerUri() + \"/unpapi/logoutWithRedirect?redirect_uri=\" + redirectUri;\n        return \"redirect:\" + logoutUrl;\n    }\n\n    @ResponseBody\n    @GetMapping(value = \"/oauth2/token\")\n    public R<TokenVo> getTokenJson(HttpServletRequest request, @RequestParam(\"code\") String code) {\n        SessionContext context = auth(code);\n        long expireIn = ChronoUnit.SECONDS.between(LocalDateTime.now(), context.getExpire());\n        TokenVo vo = new TokenVo();\n        vo.setAccessToken(context.getAccessToken());\n        vo.setRefreshToken(context.getRefreshToken());\n        vo.setExpireIn((int) expireIn);\n        return R.success(vo);\n    }\n\n    @GetMapping(value = \"/oauth2/token/redirect\")\n    public String getTokenHtml(HttpServletRequest request, @RequestParam(\"code\") String code) {\n        Assert.notNull(authClientProperties.getAuthSuccessRedirectUri(), SysCode.biz(1), \"请先配置参数:hiauth.client.authSuccessRedirectUri\");\n        String customAuthSuccessRedirectUri = request.getHeader(\"dev-auth-success-redirect-uri\");\n        String authSuccessRedirectUri = customAuthSuccessRedirectUri != null ? customAuthSuccessRedirectUri : authClientProperties.getAuthSuccessRedirectUri();\n        try {\n            SessionContext context = auth(code);\n            log.debug(\"REDIRECT-URI:{}?accessToken={}\", authSuccessRedirectUri, context.getAccessToken());\n            return \"redirect:\" + authSuccessRedirectUri + \"?accessToken=\" + context.getAccessToken();\n        } catch (HttpClientErrorException e) {\n            log.debug(\"权限不足，退出重新登陆。\");\n            return logout(request);\n        }\n    }\n\n    private SessionContext auth(String code) throws HttpClientErrorException {\n        Assert.notEmpty(code, 300001, \"code不能为空。\");\n\n        Map<?, ?> tokenMap = getTokenByOauthServer(code);\n        assert tokenMap != null;\n        Assert.isTrue(tokenMap.containsKey(\"access_token\"), 300002, \"无法获取accessToken。\");\n        String accessToken = (String) tokenMap.get(\"access_token\");\n        String refreshToken = (String) tokenMap.get(\"refresh_token\");\n        String scope = (String) tokenMap.get(\"scope\");\n        Integer expireIn = (Integer) tokenMap.get(\"expires_in\");\n\n        Map<?, ?> userinfoMap = getUserInfoByOauthServer(accessToken);\n\n        Long appId = Long.parseLong(userinfoMap.get(\"appId\").toString());\n        Long cid = Long.parseLong(userinfoMap.get(\"cid\").toString());\n        Long userId = Long.parseLong(userinfoMap.get(\"userId\").toString());\n        Long empId = Long.parseLong(userinfoMap.get(\"empId\").toString());\n        String username = (String) userinfoMap.get(\"username\");\n        String phoneNum = (String) userinfoMap.get(\"phoneNum\");\n        String avatarUrl = (String) userinfoMap.get(\"avatarUrl\");\n        String name = (String) userinfoMap.get(\"name\");\n        List<Map<String, String>> authorities = (List<Map<String, String>>) userinfoMap.get(\"authorities\");\n\n        Boolean isCorpAdmin = null;\n        if (userinfoMap.containsKey(\"isCorpAdmin\")) {\n            isCorpAdmin = (Boolean) userinfoMap.get(\"isCorpAdmin\");\n        }\n\n        HiAuthToken token = new HiAuthToken();\n        token.setAccessToken(accessToken);\n        token.setRefreshToken(refreshToken);\n        token.setScope(scope);\n        token.setExpire(LocalDateTime.now().plusSeconds(expireIn));\n\n        //设置认证信息\n        Authentication auth = new Authentication();\n        auth.setAppId(appId);\n        auth.setCid(cid);\n        auth.setUserId(userId);\n        auth.setUsername(username);\n        auth.setPhoneNum(phoneNum);\n        auth.setAvatarUrl(avatarUrl);\n        auth.setEmpId(empId);\n        auth.setName(name);\n        auth.setAuthorities(authorities);\n        auth.setIsCorpAdmin(isCorpAdmin);\n        //设置用户扩展信息\n        if (securityService != null) {\n            SecurityUser principal = securityService.loadSecurityUser(auth);\n            auth.setPrincipal(principal);\n        }\n\n        SessionContext context = new SessionContext(null, authClientProperties.getCachePrefix(), authClientProperties.getCacheExpire());\n        context.setToken(token);\n        context.setAuth(auth);\n\n        return SessionContextHolder.auth(context);\n    }\n\n    @ResponseBody\n    @GetMapping(value = \"/api/common/userinfo\")\n    public R<UserinfoVo> userinfo(HttpServletRequest request) {\n        Authentication auth = SessionContextHolder.getContext().getAuth();\n        return R.success(UserinfoVo.toVo(auth));\n    }\n\n    @ResponseBody\n    @PostMapping(value = \"/api/common/updatePwd\")\n    public Map<?, ?> updatePwd(@RequestBody UserPwdUpdateDto body) {\n        SessionContext context = SessionContextHolder.getContext();\n        HiAuthToken hiAuthToken = context.getToken();\n        return updatePwdByOauthServer(hiAuthToken.getAccessToken(), body.getRawPwd(), body.getNewPwd());\n    }\n\n    @ResponseBody\n    @PostMapping(value = \"/api/common/myCorps\")\n    public R<List<SecurityCorp>> myCorps() {\n        Authentication auth = SessionContextHolder.getContext().getAuth();\n        List<SecurityCorp> corps = securityService.loadUserCorps(auth.getUserId());\n        return R.success(corps);\n    }\n\n    @ResponseBody\n    @PostMapping(value = \"/api/common/switchCorp\")\n    public R<Boolean> switchCorp(@RequestParam(\"id\") Long id) {\n        return R.success(securityService.switchCorp(id));\n    }\n\n    private Map<?, ?> getTokenByOauthServer(String code) {\n        String basicStr = authClientRegistrationProperties.getClientId() + \":\" + authClientRegistrationProperties.getClientSecret();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        headers.add(\"Authorization\", \"Basic \" + Base64.encode(basicStr.getBytes()));\n        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n        map.add(\"grant_type\", \"authorization_code\");\n        map.add(\"code\", code);\n        map.add(\"redirect_uri\", authClientRegistrationProperties.getRedirectUri());\n        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);\n        return restTemplate.postForObject(authClientProviderProperties.getTokenUri(), request, Map.class);\n    }\n\n    private Map<?, ?> getUserInfoByOauthServer(String accessToken) throws HttpClientErrorException {\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        headers.add(\"Authorization\", \"Bearer \" + accessToken);\n        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);\n        return restTemplate.postForObject(authClientProviderProperties.getUserInfoUri(), request, Map.class);\n    }\n\n    private Map<?, ?> updatePwdByOauthServer(String accessToken, String rawPwd, String newPwd) {\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_JSON);\n        headers.add(\"Authorization\", \"Bearer \" + accessToken);\n        Map<String, String> map = new HashMap<>(2);\n        map.put(\"rawPwd\", rawPwd);\n        map.put(\"pwd\", newPwd);\n        HttpEntity<Map<String, String>> request = new HttpEntity<>(map, headers);\n        return restTemplate.postForObject(authClientProviderProperties.getIssuerUri() + \"/oauth2/user/updatePwd\", request, Map.class);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/HiAuthClientProperties.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.io.Serializable;\nimport java.util.Set;\n\n@Data\n@ConfigurationProperties(\"hiauth.client\")\npublic class HiAuthClientProperties implements Serializable {\n\n    /**\n     * 认证完成后跳转的页面\n     */\n    private String authSuccessRedirectUri;\n\n    /**\n     * 缓存前缀\n     */\n    private String cachePrefix = \"hiauth\";\n\n    /**\n     * 缓存过期时间（秒），默认值：10天\n     */\n    private Integer cacheExpire = 60 * 60 * 24 * 10;\n\n    /**\n     * 是否开启检查权限\n     */\n    private boolean checkPermission = true;\n\n    /**\n     * 无需登录也无需鉴权的接口(暂时未启用)\n     */\n    private Set<String> ignoreUris = Set.of(\"/unpapi/**\");\n\n    /**\n     * 需要登录，并且需要拥有权限，才可访问的接口\n     */\n    private Set<String> authUris = Set.of(\"/api/**\");\n\n    /**\n     * 需要登录，无需分配权限，就能访问的接口（需要时authUris的子路径）\n     */\n    private Set<String> ignorePermissionUris = Set.of(\"/api/common/**\");\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/HiAuthClientProviderProperties.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.io.Serializable;\n\n@Data\n@ConfigurationProperties(\"spring.security.oauth2.client.provider.hiauth-server\")\npublic class HiAuthClientProviderProperties implements Serializable {\n\n    private String issuerUri;\n    private String authorizationUri;\n    private String tokenUri;\n    private String userInfoUri;\n    private String jwkSetUri;\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/HiAuthClientRegistrationProperties.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.io.Serializable;\nimport java.util.Set;\n\n@Data\n@ConfigurationProperties(\"spring.security.oauth2.client.registration.hiauth-code\")\npublic class HiAuthClientRegistrationProperties implements Serializable {\n\n    private String provider;\n    private String clientName;\n    private String clientId;\n    private String clientSecret;\n    private String clientAuthenticationMethod;\n    private String authorizationGrantType;\n    private String redirectUri;\n    private Set<String> scope;\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/HiAuthClientRunner.java",
    "content": "package cn.hiauth.client;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author zgs\n */\n@Slf4j\n@Component\npublic class HiAuthClientRunner implements ApplicationRunner {\n\n    @Autowired\n    private RedisTemplate<String, String> redisTemplate;\n\n    @Override\n    public void run(ApplicationArguments args) {\n        SessionContextHolder.setRedisTemplate(redisTemplate);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/api/TokenVo.java",
    "content": "package cn.hiauth.client.api;\n\npublic class TokenVo {\n\n    private String accessToken;\n    private Integer expireIn;\n    private String refreshToken;\n\n    private String scope;\n\n    public TokenVo() {\n    }\n\n    public TokenVo(String accessToken, String refreshToken, Integer expireIn, String scope) {\n        this.accessToken = accessToken;\n        this.expireIn = expireIn;\n        this.refreshToken = refreshToken;\n        this.scope = scope;\n    }\n\n    public String getScope() {\n        return scope;\n    }\n\n    public void setScope(String scope) {\n        this.scope = scope;\n    }\n\n    public String getAccessToken() {\n        return accessToken;\n    }\n\n    public void setAccessToken(String accessToken) {\n        this.accessToken = accessToken;\n    }\n\n    public Integer getExpireIn() {\n        return expireIn;\n    }\n\n    public void setExpireIn(Integer expireIn) {\n        this.expireIn = expireIn;\n    }\n\n    public String getRefreshToken() {\n        return refreshToken;\n    }\n\n    public void setRefreshToken(String refreshToken) {\n        this.refreshToken = refreshToken;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/java/cn/hiauth/client/api/UserPwdUpdateDto.java",
    "content": "package cn.hiauth.client.api;\n\nimport lombok.Data;\n\n@Data\npublic class UserPwdUpdateDto {\n\n    private String newPwd;\n    private String rawPwd;\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": {\n    \"app.security.enable\": {\n      \"description\": \"是否启用安全拦截。默认值：false\",\n      \"type\": \"boolean\"\n    },\n    \"hiauth.client.cachePrefix\": {\n      \"description\": \"缓存前缀。默认值：hiauth\",\n      \"type\": \"string\"\n    },\n    \"hiauth.client.checkPermission\": {\n      \"description\": \"是否需要检查权限。默认值：hiauth\",\n      \"type\": \"boolean\"\n    },\n    \"hiauth.client.authSuccessRedirectUri\": {\n      \"description\": \"认证完成后跳转的页面。无默认值\",\n      \"type\": \"string\"\n    },\n    \"hiauth.client.authUris\": {\n      \"description\": \"需要登录，并且需要拥有权限，才可访问的接口。默认值：/api/**\",\n      \"type\": \"string[]\"\n    },\n    \"hiauth.client.ignoreUris\": {\n      \"description\": \"无需登录也无需鉴权的接口(暂时未启用)。默认值：/unpapi/**\",\n      \"type\": \"string[]\"\n    },\n    \"spring.security.oauth2.client.provider.hiauth-server\": {\n      \"description\": \"HiAuth授权服务端地址\",\n      \"type\": \"string\"\n    },\n    \"spring.security.oauth2.client.registration.hiauth-code\": {\n      \"description\": \"HiAuth客户端注册\",\n      \"type\": \"string\"\n    }\n  }\n}"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hiauth.client.HiAuthClientAutoConfig"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-client-spring-cloud-gateway-starter</artifactId>\n    <version>1.0.8</version>\n    <packaging>jar</packaging>\n    <name>hiauth-client-spring-cloud-gateway-starter</name>\n    <description>hiauth-client-spring-cloud-gateway-starter</description>\n    <url>https://github.com/bestaone/hiauth</url>\n\n    <properties>\n        <maven.compiler.source>17</maven.compiler.source>\n        <maven.compiler.target>17</maven.compiler.target>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>3.4.5</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>2023.0.5</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <!-- 自动装配 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-gateway-server</artifactId>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.38</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>commons</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hiauth</groupId>\n            <artifactId>hiauth-client-commons</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.13.0</version>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>3.3.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.3.0</version>\n                <configuration>\n                    <source>17</source>\n                    <encoding>UTF-8</encoding>\n                    <additionalJOptions>\n                        <additionalJOption>-Xdoclint:none</additionalJOption>\n                    </additionalJOptions>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- 如果要往中央仓库推，需要把下面两个插件打开 -->\n            <!--  必须配置GPG插件用于使用以下配置对组件进行签名 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>3.2.0</version>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--新账号的配置：将组件部署到OSSRH并将其发布到Central Repository-->\n            <plugin>\n                <groupId>org.sonatype.central</groupId>\n                <artifactId>central-publishing-maven-plugin</artifactId>\n                <version>0.4.0</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <publishingServerId>ossrh</publishingServerId>\n                    <tokenAuth>true</tokenAuth>\n                    <deploymentName>${project.groupId}:${project.artifactId}:${project.version}</deploymentName>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <scm>\n        <url>https://gitee.com/bestaone/scms</url>\n        <connection>scm:git:https://github.com/bestaone/scms.git</connection>\n        <developerConnection>scm:git:https://github.com/bestaone/hiauth.git</developerConnection>\n    </scm>\n\n    <developers>\n        <developer>\n            <name>zgs</name>\n            <email>bestaone@163.com</email>\n            <url>https://github.com/bestaone/hiauth</url>\n            <timezone>+8</timezone>\n        </developer>\n    </developers>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n        </license>\n    </licenses>\n\n</project>\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/src/main/java/cn/hiauth/client/gateway/AuthGatewayFilterFactory.java",
    "content": "package cn.hiauth.client.gateway;\n\nimport cn.hiauth.client.*;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.jwt.JWT;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.CommonException;\nimport lombok.Data;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.cloud.gateway.filter.GatewayFilter;\nimport org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;\nimport org.springframework.core.io.buffer.DataBuffer;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.web.server.ServerWebExchange;\nimport reactor.core.publisher.Mono;\n\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * @author zgs\n */\n@Slf4j\npublic class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config> {\n\n    private final AntPathMatcher matcher = new AntPathMatcher();\n    private final HiAuthClientGatewayProperties hiAuthClientGatewayProperties;\n    private final RedisTemplate<String, String> redisTemplate;\n\n    public AuthGatewayFilterFactory(HiAuthClientGatewayProperties hiAuthClientGatewayProperties, RedisTemplate<String, String> redisTemplate) {\n        super(Config.class);\n        this.hiAuthClientGatewayProperties = hiAuthClientGatewayProperties;\n        this.redisTemplate = redisTemplate;\n    }\n\n    @Override\n    public GatewayFilter apply(Config config) {\n        return (exchange, chain) -> {\n            Client client = hiAuthClientGatewayProperties.getClients().get(config.getClientName());\n            try {\n                // 检查是否已认证\n                checkAuth(exchange, client.getCachePrefix());\n                //TODO 检查是否已授权\n            } catch (Exception e) {\n                return handleException(exchange, e);\n            }\n            return chain.filter(exchange).then(Mono.fromRunnable(() -> {\n            })).then();\n        };\n    }\n\n    private void checkAuth(ServerWebExchange exchange, String cachePrefix) {\n        ServerHttpRequest request = exchange.getRequest();\n        final String url = request.getPath().pathWithinApplication().value();\n        final String method = exchange.getRequest().getMethod().name();\n        if (Constant.IGNORE_METHOD.equalsIgnoreCase(method) || !matcherAuthUrl(url)) {\n            return;\n        }\n        SessionContext context = getSessionContext(request, cachePrefix);\n        Assert.notNull(context, 10401, \"request fail\");\n        Assert.notNull(cachePrefix, 10401, \"cachePrefix is null\");\n        //Assert.isTrue(cachePrefix.equals(context.getCachePrefix()), 10401, \"invalid token\");\n        SessionContextHolder.setContext(context);\n    }\n\n    public boolean matcherAuthUrl(String uri) {\n        for (String authUrl : hiAuthClientGatewayProperties.getAuthUris()) {\n            if (matcher.match(authUrl, uri)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private SessionContext getSessionContext(ServerHttpRequest request, String cachePrefix) {\n\n        String authHeader = request.getHeaders().getFirst(Constant.TOKEN_HEADER);\n        Assert.notNull(authHeader, 10401, \"miss token\");\n\n        authHeader = URLDecoder.decode(authHeader, StandardCharsets.UTF_8);\n        Assert.isTrue(authHeader.startsWith(Constant.TOKEN_PREFIX), 10401, \"miss bearer\");\n\n        String accessToken = authHeader.substring(Constant.TOKEN_PREFIX.length()).trim();\n        JWT jwt = JwtUtils.parseToken(accessToken);\n        Assert.notNull(jwt, 10401, \"invalid token\");\n\n        String username = (String) jwt.getPayload(JwtUtils.SUB_KEY);\n        Assert.notNull(username, 10401, \"invalid token\");\n\n        String accessTokenKey = String.format(Constant.ACCESS_TOKEN_CACHE_KEY, cachePrefix, username, accessToken);\n        String json = redisTemplate.opsForValue().get(accessTokenKey);\n        Assert.notNull(json, 10401, \"invalid token\");\n        SessionContext context = JSONUtil.toBean(json, SessionContext.class);\n        Assert.notNull(context, 10401, \"invalid token\");\n\n        return context;\n    }\n\n    private Mono<Void> handleException(ServerWebExchange exchange, Throwable ex) {\n        // 设置响应状态码\n        exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);\n        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);\n\n        Integer code = 50000;\n        String msg;\n\n        if (ex instanceof CommonException ce) {\n            code = ce.getCode();\n            msg = ex.getMessage();\n        } else {\n            msg = \"系统异常\";\n        }\n\n        byte[] bytes = String.format(Constant.RESULT_JSON, code, msg).getBytes();\n        DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);\n        return exchange.getResponse().writeWith(Mono.just(buffer));\n    }\n\n    @Override\n    public List<String> shortcutFieldOrder() {\n        return Arrays.asList(\"clientName\", \"enabled\");\n    }\n\n    @Data\n    public static class Config {\n        private String clientName;\n        private boolean enabled;\n    }\n\n}"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/src/main/java/cn/hiauth/client/gateway/HiAuthClientGatewayAutoConfig.java",
    "content": "package cn.hiauth.client.gateway;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.SerializationFeature;\nimport com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;\nimport com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * @author zgs\n */\n@Slf4j\n@Configuration\n@EnableConfigurationProperties(HiAuthClientGatewayProperties.class)\npublic class HiAuthClientGatewayAutoConfig {\n\n    @Autowired\n    private HiAuthClientGatewayProperties hiAuthClientGatewayProperties;\n\n    @Bean\n    public AuthGatewayFilterFactory authGatewayFilterFactory(RedisTemplate<String, String> redisTemplate) {\n        return new AuthGatewayFilterFactory(hiAuthClientGatewayProperties, redisTemplate);\n    }\n\n    @Bean\n    @ConditionalOnMissingBean(RestTemplate.class)\n    public RestTemplate restTemplate() {\n        return new RestTemplate();\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    public RedisTemplate<String, ?> redisTemplate(RedisConnectionFactory factory) {\n        log.info(\"[cache-spring-boot-starter]:Init RedisTemplate\");\n        ObjectMapper om = new ObjectMapper();\n        // 支持 LocalDate、LocalDateTime的序列号\n        om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);\n        om.registerModule(new JavaTimeModule());\n        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);\n\n        RedisTemplate<String, ?> template = new RedisTemplate<>();\n        template.setConnectionFactory(factory);\n        Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(om, Object.class);\n        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();\n        // key采用String的序列化方式\n        template.setKeySerializer(stringRedisSerializer);\n        // hash的key也采用String的序列化方式\n        template.setHashKeySerializer(stringRedisSerializer);\n        // value序列化方式采用jackson\n        template.setValueSerializer(jackson2JsonRedisSerializer);\n        // hash的value序列化方式采用jackson\n        template.setHashValueSerializer(jackson2JsonRedisSerializer);\n        template.afterPropertiesSet();\n        return template;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/src/main/java/cn/hiauth/client/gateway/HiAuthClientGatewayController.java",
    "content": "package cn.hiauth.client.gateway;\n\nimport cn.hiauth.client.*;\nimport cn.hutool.core.codec.Base64;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.client.HttpClientErrorException;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.util.UriComponentsBuilder;\nimport reactor.core.publisher.Mono;\n\nimport java.time.LocalDateTime;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@Slf4j\n@Controller\n@RequestMapping(\"/\")\npublic class HiAuthClientGatewayController {\n\n    @Autowired\n    private RestTemplate restTemplate;\n\n    @Autowired(required = false)\n    private SecurityService securityService;\n\n    @Autowired\n    private HiAuthClientGatewayProperties hiauthClientProperties;\n\n    @GetMapping(\"/unpapi/{clientName}/oauth2/login\")\n    public Mono<Void> login(@PathVariable(\"clientName\") String clientName, ServerWebExchange exchange) {\n        Client client = hiauthClientProperties.getClients().get(clientName);\n        UriComponentsBuilder uriBuilder = UriComponentsBuilder\n                .fromUriString(hiauthClientProperties.getAuthorizationUri())\n                .queryParam(\"response_type\", \"code\")\n                .queryParam(\"client_id\", client.getClientId())\n                .queryParam(\"scope\", String.join(\" \", client.getScope()))\n                .queryParam(\"redirect_uri\", client.getRedirectUri());\n        exchange.getResponse().setStatusCode(HttpStatus.TEMPORARY_REDIRECT);\n        exchange.getResponse().getHeaders().setLocation(uriBuilder.build().toUri());\n        return exchange.getResponse().setComplete();\n    }\n\n    @GetMapping(value = \"/unpapi/{clientName}/oauth2/token/redirect\")\n    public Mono<Void> getTokenHtml(@PathVariable(\"clientName\") String clientName, @RequestParam(\"code\") String code, ServerWebExchange exchange) {\n        Client client = hiauthClientProperties.getClients().get(clientName);\n        Assert.notNull(client.getAuthSuccessRedirectUri(), SysCode.biz(1), \"请先配置参数:hiauth.client.authSuccessRedirectUri\");\n        String customAuthSuccessRedirectUri = exchange.getRequest().getHeaders().getFirst(\"dev-auth-success-redirect-uri\");\n        String authSuccessRedirectUri = customAuthSuccessRedirectUri != null ? customAuthSuccessRedirectUri : client.getAuthSuccessRedirectUri();\n        try {\n            SessionContext context = auth(clientName, client, code);\n            log.debug(\"REDIRECT-URI:{}?accessToken={}\", authSuccessRedirectUri, context.getAccessToken());\n            UriComponentsBuilder uriBuilder = UriComponentsBuilder\n                    .fromUriString(authSuccessRedirectUri)\n                    .queryParam(\"accessToken\", context.getAccessToken());\n            exchange.getResponse().setStatusCode(HttpStatus.TEMPORARY_REDIRECT);\n            exchange.getResponse().getHeaders().setLocation(uriBuilder.build().toUri());\n            return exchange.getResponse().setComplete();\n        } catch (HttpClientErrorException e) {\n            log.debug(\"权限不足，退出重新登陆。\");\n            return logout(clientName, exchange);\n        }\n    }\n\n    @GetMapping(\"/unpapi/{clientName}/oauth2/logout\")\n    public Mono<Void> logout(@PathVariable(\"clientName\") String clientName, ServerWebExchange exchange) {\n        Client client = hiauthClientProperties.getClients().get(clientName);\n        UriComponentsBuilder uriBuilder = UriComponentsBuilder\n                .fromUriString(hiauthClientProperties.getIssuerUri() + \"/unpapi/logoutWithRedirect\")\n                .queryParam(\"redirect_uri\", client.getAuthSuccessRedirectUri());\n        exchange.getResponse().setStatusCode(HttpStatus.TEMPORARY_REDIRECT);\n        exchange.getResponse().getHeaders().setLocation(uriBuilder.build().toUri());\n        return exchange.getResponse().setComplete();\n    }\n\n    @ResponseBody\n    @GetMapping(value = \"/api/common/userinfo\")\n    public R<UserinfoVo> userinfo() {\n        Authentication auth = SessionContextHolder.getContext().getAuth();\n        return R.success(UserinfoVo.toVo(auth));\n    }\n\n    @ResponseBody\n    @PostMapping(value = \"/api/common/updatePwd\")\n    public Map<?, ?> updatePwd(@RequestBody UserPwdUpdateDto body) {\n        SessionContext context = SessionContextHolder.getContext();\n        HiAuthToken token = context.getToken();\n        return updatePwdByOauthServer(token.getAccessToken(), body.getRawPwd(), body.getNewPwd());\n    }\n\n    private SessionContext auth(String clientName, Client client, String code) throws HttpClientErrorException {\n        Assert.notEmpty(code, 300001, \"code不能为空。\");\n        Map<?, ?> tokenMap = getTokenByOauthServer(client, code);\n        assert tokenMap != null;\n        Assert.isTrue(tokenMap.containsKey(\"access_token\"), 300002, \"无法获取accessToken。\");\n        String accessToken = (String) tokenMap.get(\"access_token\");\n        String refreshToken = (String) tokenMap.get(\"refresh_token\");\n        String scope = (String) tokenMap.get(\"scope\");\n        Integer expireIn = (Integer) tokenMap.get(\"expires_in\");\n\n        Map<?, ?> userinfoMap = getUserInfoByOauthServer(accessToken);\n\n        Long appId = Long.parseLong(userinfoMap.get(\"appId\").toString());\n        Long cid = Long.parseLong(userinfoMap.get(\"cid\").toString());\n        Long userId = Long.parseLong(userinfoMap.get(\"userId\").toString());\n        Long empId = Long.parseLong(userinfoMap.get(\"empId\").toString());\n        String username = (String) userinfoMap.get(\"username\");\n        String phoneNum = (String) userinfoMap.get(\"phoneNum\");\n        String avatarUrl = (String) userinfoMap.get(\"avatarUrl\");\n        String name = (String) userinfoMap.get(\"name\");\n        List<Map<String, String>> authorities = (List<Map<String, String>>) userinfoMap.get(\"authorities\");\n\n        Boolean isCorpAdmin = null;\n        if (userinfoMap.containsKey(\"isCorpAdmin\")) {\n            isCorpAdmin = (Boolean) userinfoMap.get(\"isCorpAdmin\");\n        }\n\n        HiAuthToken token = new HiAuthToken();\n        token.setAccessToken(accessToken);\n        token.setRefreshToken(refreshToken);\n        token.setScope(scope);\n        token.setExpire(LocalDateTime.now().plusSeconds(expireIn));\n\n        //设置认证信息\n        Authentication auth = new Authentication();\n        auth.setAppId(appId);\n        auth.setCid(cid);\n        auth.setUserId(userId);\n        auth.setUsername(username);\n        auth.setPhoneNum(phoneNum);\n        auth.setAvatarUrl(avatarUrl);\n        auth.setEmpId(empId);\n        auth.setName(name);\n        auth.setAuthorities(authorities);\n        auth.setIsCorpAdmin(isCorpAdmin);\n        //设置用户扩展信息\n        if (securityService != null) {\n            SecurityUser principal = securityService.loadSecurityUser(auth);\n            auth.setPrincipal(principal);\n        }\n\n        SessionContext context = new SessionContext(clientName, client.getCachePrefix(), client.getCacheExpire());\n        context.setToken(token);\n        context.setAuth(auth);\n\n        return SessionContextHolder.auth(context);\n    }\n\n    private Map<?, ?> getTokenByOauthServer(Client client, String code) {\n        String basicStr = client.getClientId() + \":\" + client.getClientSecret();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        headers.add(\"Authorization\", \"Basic \" + Base64.encode(basicStr.getBytes()));\n        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n        map.add(\"grant_type\", \"authorization_code\");\n        map.add(\"code\", code);\n        map.add(\"redirect_uri\", client.getRedirectUri());\n        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);\n        return restTemplate.postForObject(hiauthClientProperties.getTokenUri(), request, Map.class);\n    }\n\n    private Map<?, ?> getUserInfoByOauthServer(String accessToken) throws HttpClientErrorException {\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        headers.add(\"Authorization\", \"Bearer \" + accessToken);\n        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);\n        return restTemplate.postForObject(hiauthClientProperties.getUserInfoUri(), request, Map.class);\n    }\n\n    private Map<?, ?> updatePwdByOauthServer(String accessToken, String rawPwd, String newPwd) {\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_JSON);\n        headers.add(\"Authorization\", \"Bearer \" + accessToken);\n        Map<String, String> map = new HashMap<>(2);\n        map.put(\"rawPwd\", rawPwd);\n        map.put(\"pwd\", newPwd);\n        HttpEntity<Map<String, String>> request = new HttpEntity<>(map, headers);\n        return restTemplate.postForObject(hiauthClientProperties.getIssuerUri() + \"/oauth2/user/updatePwd\", request, Map.class);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/src/main/java/cn/hiauth/client/gateway/HiAuthClientGatewayProperties.java",
    "content": "package cn.hiauth.client.gateway;\n\nimport cn.hiauth.client.Client;\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n@Data\n@ConfigurationProperties(\"hiauth.client.gateway\")\npublic class HiAuthClientGatewayProperties {\n\n    private String issuerUri;\n    private String authorizationUri;\n    private String tokenUri;\n    private String userInfoUri;\n    private Map<String, Client> clients = new HashMap<>();\n\n    /**\n     * 无需登录也无需鉴权的接口(暂时未启用)\n     */\n    private Set<String> ignoreUris = Set.of(\"/unpapi/**\");\n\n    /**\n     * 需要登录，并且需要拥有权限，才可访问的接口\n     */\n    private Set<String> authUris = Set.of(\"/api/**\");\n\n    /**\n     * 需要登录，无需分配权限，就能访问的接口（需要时authUris的子路径）\n     */\n    private Set<String> ignorePermissionUris = Set.of(\"/api/common/**\");\n\n}"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/src/main/java/cn/hiauth/client/gateway/HiAuthClientGatewayRunner.java",
    "content": "package cn.hiauth.client.gateway;\n\nimport cn.hiauth.client.SessionContextHolder;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author zgs\n */\n@Slf4j\n@Component\npublic class HiAuthClientGatewayRunner implements ApplicationRunner {\n\n    @Autowired\n    private RedisTemplate<String, String> redisTemplate;\n\n    @Override\n    public void run(ApplicationArguments args) {\n        SessionContextHolder.setRedisTemplate(redisTemplate);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/src/main/java/cn/hiauth/client/gateway/UserPwdUpdateDto.java",
    "content": "package cn.hiauth.client.gateway;\n\nimport lombok.Data;\n\n@Data\npublic class UserPwdUpdateDto {\n\n    private String newPwd;\n    private String rawPwd;\n\n}\n"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": {\n    \"hiauth.client.gateway.issuerUri\": {\n      \"description\": \"HiAuth认证服务地址。\",\n      \"type\": \"string\"\n    },\n    \"hiauth.client.gateway.authorizationUri\": {\n      \"description\": \"authorization端点地址\",\n      \"type\": \"string\"\n    },\n    \"hiauth.client.gateway.tokenUri\": {\n      \"description\": \"token端点地址\",\n      \"type\": \"string\"\n    },\n    \"hiauth.client.gateway.userInfoUri\": {\n      \"description\": \"userInfo端点地址\",\n      \"type\": \"string\"\n    },\n    \"hiauth.client.gateway.clients\": {\n      \"description\": \"客户端配置\",\n      \"type\": \"[]\"\n    },\n    \"hiauth.client.gateway.ignoreUris\": {\n      \"description\": \"无需登录也无需鉴权的接口(暂时未启用)。默认值：/unpapi/**\",\n      \"type\": \"string[]\"\n    },\n    \"hiauth.client.gateway.authUris\": {\n      \"description\": \"需要登录，并且需要拥有权限，才可访问的接口。默认值：/api/**\",\n      \"type\": \"string[]\"\n    }\n  }\n}"
  },
  {
    "path": "hiauth-client-starter/hiauth-client-spring-cloud-gateway-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hiauth.client.gateway.HiAuthClientGatewayAutoConfig"
  },
  {
    "path": "hiauth-client-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-client-starter</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>hiauth-client-commons</module>\n        <module>hiauth-client-spring-boot-starter</module>\n        <module>hiauth-client-session-spring-boot-starter</module>\n        <module>hiauth-client-spring-cloud-gateway-starter</module>\n        <module>hiauth-client-resource-spring-boot-starter</module>\n    </modules>\n\n</project>\n"
  },
  {
    "path": "hiauth-front/.browserslistrc",
    "content": "> 1%\nlast 2 versions\nnot dead\nnot ie 11\n"
  },
  {
    "path": "hiauth-front/.changeset/README.md",
    "content": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets)\n\nWe have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)\n"
  },
  {
    "path": "hiauth-front/.changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@3.0.0/schema.json\",\n  \"changelog\": [\n    \"@changesets/changelog-github\",\n    { \"repo\": \"vbenjs/vue-vben-admin\" }\n  ],\n  \"commit\": false,\n  \"fixed\": [[\"@vben-core/*\", \"@vben/*\"]],\n  \"snapshot\": {\n    \"prereleaseTemplate\": \"{tag}-{datetime}\"\n  },\n  \"privatePackages\": { \"version\": true, \"tag\": true },\n  \"linked\": [],\n  \"access\": \"public\",\n  \"baseBranch\": \"main\",\n  \"updateInternalDependencies\": \"patch\",\n  \"ignore\": []\n}\n"
  },
  {
    "path": "hiauth-front/.commitlintrc.js",
    "content": "export { default } from '@vben/commitlint-config';\n"
  },
  {
    "path": "hiauth-front/.dockerignore",
    "content": "node_modules\n.git\n.gitignore\n*.md\ndist\n.turbo\ndist.zip\n"
  },
  {
    "path": "hiauth-front/.editorconfig",
    "content": "root = true\n\n[*]\ncharset=utf-8\nend_of_line=lf\ninsert_final_newline=true\nindent_style=space\nindent_size=2\nmax_line_length = 100\ntrim_trailing_whitespace = true\nquote_type = single\n\n[*.{yml,yaml,json}]\nindent_style = space\nindent_size = 2\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": "hiauth-front/.gitattributes",
    "content": "# https://docs.github.com/cn/get-started/getting-started-with-git/configuring-git-to-handle-line-endings\n\n# Automatically normalize line endings (to LF) for all text-based files.\n* text=auto eol=lf\n\n# Declare files that will always have CRLF line endings on checkout.\n*.{cmd,[cC][mM][dD]} text eol=crlf\n*.{bat,[bB][aA][tT]} text eol=crlf\n\n# Denote all files that are truly binary and should not be modified.\n*.{ico,png,jpg,jpeg,gif,webp,svg,woff,woff2} binary"
  },
  {
    "path": "hiauth-front/.gitconfig",
    "content": "[core]\n    ignorecase = false\n"
  },
  {
    "path": "hiauth-front/.gitignore",
    "content": "node_modules\n.DS_Store\ndist\ndist-ssr\ndist.zip\ndist.tar\ndist.war\n.nitro\n.output\n*-dist.zip\n*-dist.tar\n*-dist.war\ncoverage\n*.local\n**/.vitepress/cache\n.cache\n.turbo\n.temp\ndev-dist\n.stylelintcache\nyarn.lock\npackage-lock.json\n.VSCodeCounter\n**/backend-mock/data\n\n# local env files\n.env.local\n.env.*.local\n.eslintcache\n\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\nvite.config.mts.*\nvite.config.mjs.*\nvite.config.js.*\nvite.config.ts.*\n\n# Editor directories and files\n.idea\n# .vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n.history\n.cursor\n"
  },
  {
    "path": "hiauth-front/.gitpod.yml",
    "content": "ports:\n  - port: 5555\n    onOpen: open-preview\ntasks:\n  - init: npm i -g corepack && pnpm install\n    command: pnpm run dev:play\n"
  },
  {
    "path": "hiauth-front/.node-version",
    "content": "22.1.0\n"
  },
  {
    "path": "hiauth-front/.npmrc",
    "content": "registry = \"https://registry.npmmirror.com\"\npublic-hoist-pattern[]=lefthook\npublic-hoist-pattern[]=eslint\npublic-hoist-pattern[]=prettier\npublic-hoist-pattern[]=prettier-plugin-tailwindcss\npublic-hoist-pattern[]=stylelint\npublic-hoist-pattern[]=*postcss*\npublic-hoist-pattern[]=@commitlint/*\npublic-hoist-pattern[]=czg\n\nstrict-peer-dependencies=false\nauto-install-peers=true\ndedupe-peer-dependents=true\n"
  },
  {
    "path": "hiauth-front/.prettierignore",
    "content": "dist\ndev-dist\n.local\n.output.js\nnode_modules\n.nvmrc\ncoverage\nCODEOWNERS\n.nitro\n.output\n\n\n**/*.svg\n**/*.sh\n\npublic\n.npmrc\n*-lock.yaml\n"
  },
  {
    "path": "hiauth-front/.prettierrc.mjs",
    "content": "export { default } from '@vben/prettier-config';\n"
  },
  {
    "path": "hiauth-front/.stylelintignore",
    "content": "dist\npublic\n__tests__\ncoverage\n"
  },
  {
    "path": "hiauth-front/Dockerfile",
    "content": "FROM harbor.vking.fun/vking/nginx:1.25.5\n\nVOLUME /tmp\n\n# 设置语言\nENV LANG en_US.UTF-8\n\n# 设置地理位置\nENV TZ=Asia/Shanghai\n\nRUN mkdir -p /html && chmod a+rwx -R /html\n\nADD ./apps/web-auth/dist.zip front-auth.zip\nRUN unzip front-auth.zip -d /html/front-auth\n\nEXPOSE 80\nEXPOSE 443\n"
  },
  {
    "path": "hiauth-front/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2024-present, Vben\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "hiauth-front/README.ja-JP.md",
    "content": "<div align=\"center\">\n  <a href=\"https://github.com/anncwb/vue-vben-admin\">\n    <img alt=\"VbenAdmin Logo\" width=\"215\" src=\"https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp\">\n  </a>\n  <br>\n  <br>\n\n[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)\n\n  <h1>Vue Vben Admin</h1>\n</div>\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)\n\n**日本語** | [English](./README.md) | [中文](./README.zh-CN.md)\n\n## 紹介\n\nVue Vben Adminは、最新の`vue3`、`vite`、`TypeScript`などの主流技術を使用して開発された、無料でオープンソースの中・後端テンプレートです。すぐに使える中・後端のフロントエンドソリューションとして、学習の参考にもなります。\n\n## アップグレード通知\n\nこれは最新バージョン `5.0` であり、以前のバージョンとは互換性がありません。新しいプロジェクトを開始する場合は、最新バージョンを使用することをお勧めします。古いバージョンを表示したい場合は、[v2ブランチ](https://github.com/vbenjs/vue-vben-admin/tree/v2)を使用してください。\n\n## 特徴\n\n- **最新技術スタック**：Vue 3やViteなどの最先端フロントエンド技術で開発\n- **TypeScript**：アプリケーション規模のJavaScriptのための言語\n- **テーマ**：複数のテーマカラーが利用可能で、カスタマイズオプションも豊富\n- **国際化**：完全な内蔵国際化サポート\n- **権限管理**：動的ルートベースの権限生成ソリューションを内蔵\n\n## プレビュー\n\n- [Vben Admin](https://vben.pro/) - フルバージョンの中国語サイト\n\nテストアカウント：vben/123456\n\n<div align=\"center\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview1.png\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview2.png\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview3.png\">\n</div>\n\n### Gitpodを使用\n\nGitpod（GitHub用の無料オンライン開発環境）でプロジェクトを開き、すぐにコーディングを開始します。\n\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)\n\n## ドキュメント\n\n[ドキュメント](https://doc.vben.pro/)\n\n## インストールと使用\n\n1. プロジェクトコードを取得\n\n```bash\ngit clone https://github.com/vbenjs/vue-vben-admin.git\n```\n\n2. 依存関係のインストール\n\n```bash\ncd vue-vben-admin\nnpm i -g corepack\npnpm install\n```\n\n3. 実行\n\n```bash\npnpm dev\n```\n\n4. ビルド\n\n```bash\npnpm build\n```\n\n## 変更ログ\n\n[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)\n\n## 貢献方法\n\nご参加をお待ちしております！[Issueを提出](https://github.com/anncwb/vue-vben-admin/issues/new/choose)するか、Pull Requestを送信してください。\n\n**Pull Request プロセス：**\n\n1. コードをフォーク\n2. 自分のブランチを作成：`git checkout -b feat/xxxx`\n3. 変更をコミット：`git commit -am 'feat(function): add xxxxx'`\n4. ブランチをプッシュ：`git push origin feat/xxxx`\n5. `pull request`を送信\n\n## Git貢献提出規則\n\n参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 規則 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))\n\n- `feat` 新機能の追加\n- `fix` 問題/バグの修正\n- `style` コードスタイルに関連し、実行結果に影響しない\n- `perf` 最適化/パフォーマンス向上\n- `refactor` リファクタリング\n- `revert` 変更の取り消し\n- `test` テスト関連\n- `docs` ドキュメント/注釈\n- `chore` 依存関係の更新/スキャフォールディング設定の変更など\n- `ci` 継続的インテグレーション\n- `types` 型定義ファイルの変更\n\n## ブラウザサポート\n\nローカル開発には `Chrome 80+` ブラウザを推奨します\n\nモダンブラウザをサポートし、IEはサポートしません\n\n| [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\" alt=\"Edge\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Safari |\n| :-: | :-: | :-: | :-: |\n| 最新2バージョン | 最新2バージョン | 最新2バージョン | 最新2バージョン |\n\n## メンテナー\n\n[@Vben](https://github.com/anncwb)\n\n## スター歴史\n\n[![Star History Chart](https://api.star-history.com/svg?repos=vbenjs/vue-vben-admin&type=Date)](https://star-history.com/#vbenjs/vue-vben-admin&Date)\n\n## 寄付\n\nこのプロジェクトが役に立つと思われた場合、作者にコーヒーを一杯おごってサポートを示すことができます！\n\n![donate](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png)\n\n<a style=\"display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;\" href=\"https://www.paypal.com/paypalme/cvvben\">Paypal Me</a>\n\n## 貢献者\n\n<a href=\"https://openomy.app/github/vbenjs/vue-vben-admin\" target=\"_blank\" style=\"display: block; width: 100%;\" align=\"center\">\n  <img src=\"https://openomy.app/svg?repo=vbenjs/vue-vben-admin&chart=bubble&latestMonth=3\" target=\"_blank\" alt=\"Contribution Leaderboard\" style=\"display: block; width: 100%;\" />\n </a>\n\n<a href=\"https://github.com/vbenjs/vue-vben-admin/graphs/contributors\">\n  <img alt=\"Contributors\" src=\"https://contrib.rocks/image?repo=vbenjs/vue-vben-admin\" />\n</a>\n\n## Discord\n\n- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)\n\n## ライセンス\n\n[MIT © Vben-2020](./LICENSE)\n"
  },
  {
    "path": "hiauth-front/README.md",
    "content": "<div align=\"center\">\n  <a href=\"https://github.com/anncwb/vue-vben-admin\">\n    <img alt=\"VbenAdmin Logo\" width=\"215\" src=\"https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp\">\n  </a>\n  <br>\n  <br>\n\n[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)\n\n  <h1>Vue Vben Admin</h1>\n</div>\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)\n\n**English** | [中文](./README.zh-CN.md) | [日本語](./README.ja-JP.md)\n\n## Introduction\n\nVue Vben Admin is a free and open source middle and back-end template. Using the latest `vue3`, `vite`, `TypeScript` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference.\n\n## Upgrade Notice\n\nThis is the latest version, 5.0, and it is not compatible with previous versions. If you are starting a new project, it is recommended to use the latest version. If you wish to view the old version, please use the [v2 branch](https://github.com/vbenjs/vue-vben-admin/tree/v2).\n\n## Features\n\n- **Latest Technology Stack**: Developed with cutting-edge front-end technologies like Vue 3 and Vite\n- **TypeScript**: A language for application-scale JavaScript\n- **Themes**: Multiple theme colors available with customizable options\n- **Internationalization**: Comprehensive built-in internationalization support\n- **Permissions**: Built-in solution for dynamic route-based permission generation\n\n## Preview\n\n- [Vben Admin](https://vben.pro/) - Full version Chinese site\n\nTest Account: vben/123456\n\n<div align=\"center\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview1.png\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview2.png\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview3.png\">\n</div>\n\n### Use Gitpod\n\nOpen the project in Gitpod (free online dev environment for GitHub) and start coding immediately.\n\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)\n\n## Documentation\n\n[Document](https://doc.vben.pro/)\n\n## Install and Use\n\n1. Get the project code\n\n```bash\ngit clone https://github.com/vbenjs/vue-vben-admin.git\n```\n\n2. Install dependencies\n\n```bash\ncd vue-vben-admin\nnpm i -g corepack\npnpm install\n```\n\n3. Run\n\n```bash\npnpm dev\n```\n\n4. Build\n\n```bash\npnpm build\n```\n\n## Change Log\n\n[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)\n\n## How to Contribute\n\nYou are very welcome to join! [Raise an issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) or submit a Pull Request.\n\n**Pull Request Process:**\n\n1. Fork the code\n2. Create your branch: `git checkout -b feat/xxxx`\n3. Submit your changes: `git commit -am 'feat(function): add xxxxx'`\n4. Push your branch: `git push origin feat/xxxx`\n5. Submit `pull request`\n\n## Git Contribution Submission Specification\n\nReference [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) specification ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))\n\n- `feat` Add new features\n- `fix` Fix the problem/BUG\n- `style` The code style is related and does not affect the running result\n- `perf` Optimization/performance improvement\n- `refactor` Refactor\n- `revert` Undo edit\n- `test` Test related\n- `docs` Documentation/notes\n- `chore` Dependency update/scaffolding configuration modification etc.\n- `ci` Continuous integration\n- `types` Type definition file changes\n\n## Browser Support\n\nThe `Chrome 80+` browser is recommended for local development\n\nSupport modern browsers, not IE\n\n| [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\" alt=\"Edge\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Safari |\n| :-: | :-: | :-: | :-: |\n| last 2 versions | last 2 versions | last 2 versions | last 2 versions |\n\n## Maintainer\n\n[@Vben](https://github.com/anncwb)\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=vbenjs/vue-vben-admin&type=Date)](https://star-history.com/#vbenjs/vue-vben-admin&Date)\n\n## Donate\n\nIf you think this project is helpful to you, you can help the author buy a cup of coffee to show your support!\n\n![donate](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png)\n\n<a style=\"display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aee;border-radius: 4px;\" href=\"https://www.paypal.com/paypalme/cvvben\">Paypal Me</a>\n\n## Contributors\n\n<a href=\"https://openomy.app/github/vbenjs/vue-vben-admin\" target=\"_blank\" style=\"display: block; width: 100%;\" align=\"center\">\n  <img src=\"https://openomy.app/svg?repo=vbenjs/vue-vben-admin&chart=bubble&latestMonth=3\" target=\"_blank\" alt=\"Contribution Leaderboard\" style=\"display: block; width: 100%;\" />\n </a>\n\n<a href=\"https://github.com/vbenjs/vue-vben-admin/graphs/contributors\">\n  <img alt=\"Contributors\" src=\"https://contrib.rocks/image?repo=vbenjs/vue-vben-admin\" />\n</a>\n\n## Discord\n\n- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)\n\n## License\n\n[MIT © Vben-2020](./LICENSE)\n"
  },
  {
    "path": "hiauth-front/README.zh-CN.md",
    "content": "<div align=\"center\">\n  <a href=\"https://github.com/anncwb/vue-vben-admin\">\n    <img alt=\"VbenAdmin Logo\" width=\"215\" src=\"https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp\">\n  </a>\n  <br>\n  <br>\n\n[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)\n\n  <h1>Vue Vben Admin</h1>\n</div>\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)\n\n**中文** | [English](./README.md) | [日本語](./README.ja-JP.md)\n\n## 简介\n\nVue Vben Admin 是 Vue Vben Admin 的升级版本。作为一个免费开源的中后台模板，它采用了最新的 Vue 3、Vite、TypeScript 等主流技术开发，开箱即用，可用于中后台前端开发，也适合学习参考。\n\n## 升级提示\n\n该版本为最新版本 `5.0`，与其他版本不兼容，如果你是新项目，建议使用最新版本。如果你想查看旧版本，请使用 [v2 分支](https://github.com/vbenjs/vue-vben-admin/tree/v2)\n\n## 特性\n\n- **最新技术栈**：使用 Vue3/vite 等前端前沿技术开发\n- **TypeScript**：应用程序级 JavaScript 的语言\n- **主题**：提供多套主题色彩，可配置自定义主题\n- **国际化**：内置完善的国际化方案\n- **权限**：内置完善的动态路由权限生成方案\n\n## 预览\n\n- [Vben Admin](https://vben.pro/) - 完整版中文站点\n\n测试账号：vben/123456\n\n<div align=\"center\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview1.png\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview2.png\">\n  <img alt=\"VbenAdmin Logo\" width=\"100%\" src=\"https://anncwb.github.io/anncwb/images/preview3.png\">\n</div>\n\n### 使用 Gitpod\n\n在 Gitpod（适用于 GitHub 的免费在线开发环境）中打开项目，并立即开始编码。\n\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)\n\n## 文档\n\n[文档地址](https://doc.vben.pro/)\n\n## 安装使用\n\n1. 获取项目代码\n\n```bash\ngit clone https://github.com/vbenjs/vue-vben-admin.git\n```\n\n2. 安装依赖\n\n```bash\ncd vue-vben-admin\nnpm i -g corepack\npnpm install\n```\n\n3. 运行\n\n```bash\npnpm dev\n```\n\n4. 打包\n\n```bash\npnpm build\n```\n\n## 更新日志\n\n[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)\n\n## 如何贡献\n\n非常欢迎你的加入！[提一个 Issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) 或者提交一个 Pull Request。\n\n**Pull Request 流程：**\n\n1. Fork 代码\n2. 创建自己的分支：`git checkout -b feature/xxxx`\n3. 提交你的修改：`git commit -am 'feat(function): add xxxxx'`\n4. 推送您的分支：`git push origin feature/xxxx`\n5. 提交 `pull request`\n\n## Git 贡献提交规范\n\n参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 规范 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))\n\n- `feat` 增加新功能\n- `fix` 修复问题/BUG\n- `style` 代码风格相关无影响运行结果的\n- `perf` 优化/性能提升\n- `refactor` 重构\n- `revert` 撤销修改\n- `test` 测试相关\n- `docs` 文档/注释\n- `chore` 依赖更新/脚手架配置修改等\n- `ci` 持续集成\n- `types` 类型定义文件更改\n\n## 浏览器支持\n\n本地开发推荐使用 `Chrome 80+` 浏览器\n\n支持现代浏览器，不支持 IE\n\n| [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\" alt=\"Edge\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Safari |\n| :-: | :-: | :-: | :-: |\n| last 2 versions | last 2 versions | last 2 versions | last 2 versions |\n\n## 维护者\n\n[@Vben](https://github.com/anncwb)\n\n## Star 历史\n\n[![Star History Chart](https://api.star-history.com/svg?repos=vbenjs/vue-vben-admin&type=Date)](https://star-history.com/#vbenjs/vue-vben-admin&Date)\n\n## 捐赠\n\n如果你觉得这个项目对你有帮助，你可以帮作者买一杯咖啡表示支持！\n\n![donate](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png)\n\n<a style=\"display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;\" href=\"https://www.paypal.com/paypalme/cvvben\">Paypal Me</a>\n\n## 贡献者\n\n<a href=\"https://openomy.app/github/vbenjs/vue-vben-admin\" target=\"_blank\" style=\"display: block; width: 100%;\" align=\"center\">\n  <img src=\"https://openomy.app/svg?repo=vbenjs/vue-vben-admin&chart=bubble&latestMonth=3\" target=\"_blank\" alt=\"Contribution Leaderboard\" style=\"display: block; width: 100%;\" />\n </a>\n\n<a href=\"https://github.com/vbenjs/vue-vben-admin/graphs/contributors\">\n  <img alt=\"Contributors\" src=\"https://contrib.rocks/image?repo=vbenjs/vue-vben-admin\" />\n</a>\n\n## Discord\n\n- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)\n\n## 许可证\n\n[MIT © Vben-2020](./LICENSE)\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/README.md",
    "content": "# @vben/backend-mock\n\n## Description\n\nVben Admin 数据 mock 服务，没有对接任何的数据库，所有数据都是模拟的，用于前端开发时提供数据支持。线上环境不再提供 mock 集成，可自行部署服务或者对接真实数据，由于 `mock.js` 等工具有一些限制，比如上传文件不行、无法模拟复杂的逻辑等，所以这里使用了真实的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务，但是这样可以更好的模拟真实环境。该服务不需要手动启动，已经集成在 vite 插件内，随应用一起启用。\n\n## Running the app\n\n```bash\n# development\n$ pnpm run start\n\n# production mode\n$ pnpm run build\n```\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/auth/codes.ts",
    "content": "import { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { MOCK_CODES } from '~/utils/mock-data';\nimport { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';\n\nexport default eventHandler((event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n\n  const codes =\n    MOCK_CODES.find((item) => item.username === userinfo.username)?.codes ?? [];\n\n  return useResponseSuccess(codes);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/auth/login.post.ts",
    "content": "import { defineEventHandler, readBody, setResponseStatus } from 'h3';\nimport {\n  clearRefreshTokenCookie,\n  setRefreshTokenCookie,\n} from '~/utils/cookie-utils';\nimport { generateAccessToken, generateRefreshToken } from '~/utils/jwt-utils';\nimport { MOCK_USERS } from '~/utils/mock-data';\nimport {\n  forbiddenResponse,\n  useResponseError,\n  useResponseSuccess,\n} from '~/utils/response';\n\nexport default defineEventHandler(async (event) => {\n  const { password, username } = await readBody(event);\n  if (!password || !username) {\n    setResponseStatus(event, 400);\n    return useResponseError(\n      'BadRequestException',\n      'Username and password are required',\n    );\n  }\n\n  const findUser = MOCK_USERS.find(\n    (item) => item.username === username && item.password === password,\n  );\n\n  if (!findUser) {\n    clearRefreshTokenCookie(event);\n    return forbiddenResponse(event, 'Username or password is incorrect.');\n  }\n\n  const accessToken = generateAccessToken(findUser);\n  const refreshToken = generateRefreshToken(findUser);\n\n  setRefreshTokenCookie(event, refreshToken);\n\n  return useResponseSuccess({\n    ...findUser,\n    accessToken,\n  });\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/auth/logout.post.ts",
    "content": "import { defineEventHandler } from 'h3';\nimport {\n  clearRefreshTokenCookie,\n  getRefreshTokenFromCookie,\n} from '~/utils/cookie-utils';\nimport { useResponseSuccess } from '~/utils/response';\n\nexport default defineEventHandler(async (event) => {\n  const refreshToken = getRefreshTokenFromCookie(event);\n  if (!refreshToken) {\n    return useResponseSuccess('');\n  }\n\n  clearRefreshTokenCookie(event);\n\n  return useResponseSuccess('');\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/auth/refresh.post.ts",
    "content": "import { defineEventHandler } from 'h3';\nimport {\n  clearRefreshTokenCookie,\n  getRefreshTokenFromCookie,\n  setRefreshTokenCookie,\n} from '~/utils/cookie-utils';\nimport { generateAccessToken, verifyRefreshToken } from '~/utils/jwt-utils';\nimport { MOCK_USERS } from '~/utils/mock-data';\nimport { forbiddenResponse } from '~/utils/response';\n\nexport default defineEventHandler(async (event) => {\n  const refreshToken = getRefreshTokenFromCookie(event);\n  if (!refreshToken) {\n    return forbiddenResponse(event);\n  }\n\n  clearRefreshTokenCookie(event);\n\n  const userinfo = verifyRefreshToken(refreshToken);\n  if (!userinfo) {\n    return forbiddenResponse(event);\n  }\n\n  const findUser = MOCK_USERS.find(\n    (item) => item.username === userinfo.username,\n  );\n  if (!findUser) {\n    return forbiddenResponse(event);\n  }\n  const accessToken = generateAccessToken(findUser);\n\n  setRefreshTokenCookie(event, refreshToken);\n\n  return accessToken;\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/demo/bigint.ts",
    "content": "import { eventHandler, setHeader } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { unAuthorizedResponse } from '~/utils/response';\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n  const data = `\n  {\n    \"code\": 0,\n    \"message\": \"success\",\n    \"data\": [\n              {\n                \"id\": 123456789012345678901234567890123456789012345678901234567890,\n                \"name\": \"John Doe\",\n                \"age\": 30,\n                \"email\": \"john-doe@demo.com\"\n                },\n                {\n                \"id\": 987654321098765432109876543210987654321098765432109876543210,\n                \"name\": \"Jane Smith\",\n                \"age\": 25,\n                \"email\": \"jane@demo.com\"\n                }\n            ]\n  }\n  `;\n  setHeader(event, 'Content-Type', 'application/json');\n  return data;\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/menu/all.ts",
    "content": "import { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { MOCK_MENUS } from '~/utils/mock-data';\nimport { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n\n  const menus =\n    MOCK_MENUS.find((item) => item.username === userinfo.username)?.menus ?? [];\n  return useResponseSuccess(menus);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/status.ts",
    "content": "import { eventHandler, getQuery, setResponseStatus } from 'h3';\nimport { useResponseError } from '~/utils/response';\n\nexport default eventHandler((event) => {\n  const { status } = getQuery(event);\n  setResponseStatus(event, Number(status));\n  return useResponseError(`${status}`);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/system/dept/.post.ts",
    "content": "import { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport {\n  sleep,\n  unAuthorizedResponse,\n  useResponseSuccess,\n} from '~/utils/response';\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n  await sleep(600);\n  return useResponseSuccess(null);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/system/dept/[id].delete.ts",
    "content": "import { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport {\n  sleep,\n  unAuthorizedResponse,\n  useResponseSuccess,\n} from '~/utils/response';\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n  await sleep(1000);\n  return useResponseSuccess(null);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/system/dept/[id].put.ts",
    "content": "import { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport {\n  sleep,\n  unAuthorizedResponse,\n  useResponseSuccess,\n} from '~/utils/response';\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n  await sleep(2000);\n  return useResponseSuccess(null);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/system/dept/list.ts",
    "content": "import { faker } from '@faker-js/faker';\nimport { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';\n\nconst formatterCN = new Intl.DateTimeFormat('zh-CN', {\n  timeZone: 'Asia/Shanghai',\n  year: 'numeric',\n  month: '2-digit',\n  day: '2-digit',\n  hour: '2-digit',\n  minute: '2-digit',\n  second: '2-digit',\n});\n\nfunction generateMockDataList(count: number) {\n  const dataList = [];\n\n  for (let i = 0; i < count; i++) {\n    const dataItem: Record<string, any> = {\n      id: faker.string.uuid(),\n      pid: 0,\n      name: faker.commerce.department(),\n      status: faker.helpers.arrayElement([0, 1]),\n      createTime: formatterCN.format(\n        faker.date.between({ from: '2021-01-01', to: '2022-12-31' }),\n      ),\n      remark: faker.lorem.sentence(),\n    };\n    if (faker.datatype.boolean()) {\n      dataItem.children = Array.from(\n        { length: faker.number.int({ min: 1, max: 5 }) },\n        () => ({\n          id: faker.string.uuid(),\n          pid: dataItem.id,\n          name: faker.commerce.department(),\n          status: faker.helpers.arrayElement([0, 1]),\n          createTime: formatterCN.format(\n            faker.date.between({ from: '2023-01-01', to: '2023-12-31' }),\n          ),\n          remark: faker.lorem.sentence(),\n        }),\n      );\n    }\n    dataList.push(dataItem);\n  }\n\n  return dataList;\n}\n\nconst mockData = generateMockDataList(10);\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n\n  const listData = structuredClone(mockData);\n\n  return useResponseSuccess(listData);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/system/menu/list.ts",
    "content": "import { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { MOCK_MENU_LIST } from '~/utils/mock-data';\nimport { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n\n  return useResponseSuccess(MOCK_MENU_LIST);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/system/menu/name-exists.ts",
    "content": "import { eventHandler, getQuery } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { MOCK_MENU_LIST } from '~/utils/mock-data';\nimport { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';\n\nconst namesMap: Record<string, any> = {};\n\nfunction getNames(menus: any[]) {\n  menus.forEach((menu) => {\n    namesMap[menu.name] = String(menu.id);\n    if (menu.children) {\n      getNames(menu.children);\n    }\n  });\n}\ngetNames(MOCK_MENU_LIST);\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n  const { id, name } = getQuery(event);\n\n  return (name as string) in namesMap &&\n    (!id || namesMap[name as string] !== String(id))\n    ? useResponseSuccess(true)\n    : useResponseSuccess(false);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/system/menu/path-exists.ts",
    "content": "import { eventHandler, getQuery } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { MOCK_MENU_LIST } from '~/utils/mock-data';\nimport { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';\n\nconst pathMap: Record<string, any> = { '/': 0 };\n\nfunction getPaths(menus: any[]) {\n  menus.forEach((menu) => {\n    pathMap[menu.path] = String(menu.id);\n    if (menu.children) {\n      getPaths(menu.children);\n    }\n  });\n}\ngetPaths(MOCK_MENU_LIST);\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n  const { id, path } = getQuery(event);\n\n  return (path as string) in pathMap &&\n    (!id || pathMap[path as string] !== String(id))\n    ? useResponseSuccess(true)\n    : useResponseSuccess(false);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/system/role/list.ts",
    "content": "import { faker } from '@faker-js/faker';\nimport { eventHandler, getQuery } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { getMenuIds, MOCK_MENU_LIST } from '~/utils/mock-data';\nimport { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';\n\nconst formatterCN = new Intl.DateTimeFormat('zh-CN', {\n  timeZone: 'Asia/Shanghai',\n  year: 'numeric',\n  month: '2-digit',\n  day: '2-digit',\n  hour: '2-digit',\n  minute: '2-digit',\n  second: '2-digit',\n});\n\nconst menuIds = getMenuIds(MOCK_MENU_LIST);\n\nfunction generateMockDataList(count: number) {\n  const dataList = [];\n\n  for (let i = 0; i < count; i++) {\n    const dataItem: Record<string, any> = {\n      id: faker.string.uuid(),\n      name: faker.commerce.product(),\n      status: faker.helpers.arrayElement([0, 1]),\n      createTime: formatterCN.format(\n        faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),\n      ),\n      permissions: faker.helpers.arrayElements(menuIds),\n      remark: faker.lorem.sentence(),\n    };\n\n    dataList.push(dataItem);\n  }\n\n  return dataList;\n}\n\nconst mockData = generateMockDataList(100);\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n\n  const {\n    page = 1,\n    pageSize = 20,\n    name,\n    id,\n    remark,\n    startTime,\n    endTime,\n    status,\n  } = getQuery(event);\n  let listData = structuredClone(mockData);\n  if (name) {\n    listData = listData.filter((item) =>\n      item.name.toLowerCase().includes(String(name).toLowerCase()),\n    );\n  }\n  if (id) {\n    listData = listData.filter((item) =>\n      item.id.toLowerCase().includes(String(id).toLowerCase()),\n    );\n  }\n  if (remark) {\n    listData = listData.filter((item) =>\n      item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),\n    );\n  }\n  if (startTime) {\n    listData = listData.filter((item) => item.createTime >= startTime);\n  }\n  if (endTime) {\n    listData = listData.filter((item) => item.createTime <= endTime);\n  }\n  if (['0', '1'].includes(status as string)) {\n    listData = listData.filter((item) => item.status === Number(status));\n  }\n  return usePageResponseSuccess(page as string, pageSize as string, listData);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/table/list.ts",
    "content": "import { faker } from '@faker-js/faker';\nimport { eventHandler, getQuery } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport {\n  sleep,\n  unAuthorizedResponse,\n  usePageResponseSuccess,\n} from '~/utils/response';\n\nfunction generateMockDataList(count: number) {\n  const dataList = [];\n\n  for (let i = 0; i < count; i++) {\n    const dataItem = {\n      id: faker.string.uuid(),\n      imageUrl: faker.image.avatar(),\n      imageUrl2: faker.image.avatar(),\n      open: faker.datatype.boolean(),\n      status: faker.helpers.arrayElement(['success', 'error', 'warning']),\n      productName: faker.commerce.productName(),\n      price: faker.commerce.price(),\n      currency: faker.finance.currencyCode(),\n      quantity: faker.number.int({ min: 1, max: 100 }),\n      available: faker.datatype.boolean(),\n      category: faker.commerce.department(),\n      releaseDate: faker.date.past(),\n      rating: faker.number.float({ min: 1, max: 5 }),\n      description: faker.commerce.productDescription(),\n      weight: faker.number.float({ min: 0.1, max: 10 }),\n      color: faker.color.human(),\n      inProduction: faker.datatype.boolean(),\n      tags: Array.from({ length: 3 }, () => faker.commerce.productAdjective()),\n    };\n\n    dataList.push(dataItem);\n  }\n\n  return dataList;\n}\n\nconst mockData = generateMockDataList(100);\n\nexport default eventHandler(async (event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n\n  await sleep(600);\n\n  const { page, pageSize, sortBy, sortOrder } = getQuery(event);\n  // 规范化分页参数，处理 string[]\n  const pageRaw = Array.isArray(page) ? page[0] : page;\n  const pageSizeRaw = Array.isArray(pageSize) ? pageSize[0] : pageSize;\n  const pageNumber = Math.max(\n    1,\n    Number.parseInt(String(pageRaw ?? '1'), 10) || 1,\n  );\n  const pageSizeNumber = Math.min(\n    100,\n    Math.max(1, Number.parseInt(String(pageSizeRaw ?? '10'), 10) || 10),\n  );\n  const listData = structuredClone(mockData);\n\n  // 规范化 query 入参，兼容 string[]\n  const sortKeyRaw = Array.isArray(sortBy) ? sortBy[0] : sortBy;\n  const sortOrderRaw = Array.isArray(sortOrder) ? sortOrder[0] : sortOrder;\n  // 检查 sortBy 是否是 listData 元素的合法属性键\n  if (\n    typeof sortKeyRaw === 'string' &&\n    listData[0] &&\n    Object.prototype.hasOwnProperty.call(listData[0], sortKeyRaw)\n  ) {\n    // 定义数组元素的类型\n    type ItemType = (typeof listData)[0];\n    const sortKey = sortKeyRaw as keyof ItemType; // 将 sortBy 断言为合法键\n    const isDesc = sortOrderRaw === 'desc';\n    listData.sort((a, b) => {\n      const aValue = a[sortKey] as unknown;\n      const bValue = b[sortKey] as unknown;\n\n      let result = 0;\n\n      if (typeof aValue === 'number' && typeof bValue === 'number') {\n        result = aValue - bValue;\n      } else if (aValue instanceof Date && bValue instanceof Date) {\n        result = aValue.getTime() - bValue.getTime();\n      } else if (typeof aValue === 'boolean' && typeof bValue === 'boolean') {\n        if (aValue === bValue) {\n          result = 0;\n        } else {\n          result = aValue ? 1 : -1;\n        }\n      } else {\n        const aStr = String(aValue);\n        const bStr = String(bValue);\n        const aNum = Number(aStr);\n        const bNum = Number(bStr);\n        result =\n          Number.isFinite(aNum) && Number.isFinite(bNum)\n            ? aNum - bNum\n            : aStr.localeCompare(bStr, undefined, {\n                numeric: true,\n                sensitivity: 'base',\n              });\n      }\n\n      return isDesc ? -result : result;\n    });\n  }\n\n  return usePageResponseSuccess(\n    String(pageNumber),\n    String(pageSizeNumber),\n    listData,\n  );\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/test.get.ts",
    "content": "import { defineEventHandler } from 'h3';\n\nexport default defineEventHandler(() => 'Test get handler');\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/test.post.ts",
    "content": "import { defineEventHandler } from 'h3';\n\nexport default defineEventHandler(() => 'Test post handler');\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/upload.ts",
    "content": "import { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';\n\nexport default eventHandler((event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n  return useResponseSuccess({\n    url: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n  });\n  // return useResponseError(\"test\")\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/api/user/info.ts",
    "content": "import { eventHandler } from 'h3';\nimport { verifyAccessToken } from '~/utils/jwt-utils';\nimport { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';\n\nexport default eventHandler((event) => {\n  const userinfo = verifyAccessToken(event);\n  if (!userinfo) {\n    return unAuthorizedResponse(event);\n  }\n  return useResponseSuccess(userinfo);\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/error.ts",
    "content": "import type { NitroErrorHandler } from 'nitropack';\n\nconst errorHandler: NitroErrorHandler = function (error, event) {\n  event.node.res.end(`[Error Handler] ${error.stack}`);\n};\n\nexport default errorHandler;\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/middleware/1.api.ts",
    "content": "import { defineEventHandler } from 'h3';\nimport { forbiddenResponse, sleep } from '~/utils/response';\n\nexport default defineEventHandler(async (event) => {\n  event.node.res.setHeader(\n    'Access-Control-Allow-Origin',\n    event.headers.get('Origin') ?? '*',\n  );\n  if (event.method === 'OPTIONS') {\n    event.node.res.statusCode = 204;\n    event.node.res.statusMessage = 'No Content.';\n    return 'OK';\n  } else if (\n    ['DELETE', 'PATCH', 'POST', 'PUT'].includes(event.method) &&\n    event.path.startsWith('/api/system/')\n  ) {\n    await sleep(Math.floor(Math.random() * 2000));\n    return forbiddenResponse(event, '演示环境，禁止修改');\n  }\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/nitro.config.ts",
    "content": "import errorHandler from './error';\n\nprocess.env.COMPATIBILITY_DATE = new Date().toISOString();\nexport default defineNitroConfig({\n  devErrorHandler: errorHandler,\n  errorHandler: '~/error',\n  routeRules: {\n    '/api/**': {\n      cors: true,\n      headers: {\n        'Access-Control-Allow-Credentials': 'true',\n        'Access-Control-Allow-Headers':\n          'Accept, Authorization, Content-Length, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With',\n        'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',\n        'Access-Control-Allow-Origin': '*',\n        'Access-Control-Expose-Headers': '*',\n      },\n    },\n  },\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/package.json",
    "content": "{\n  \"name\": \"@vben/backend-mock\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"private\": true,\n  \"license\": \"MIT\",\n  \"author\": \"\",\n  \"scripts\": {\n    \"build\": \"nitro build\",\n    \"start\": \"nitro dev\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"catalog:\",\n    \"jsonwebtoken\": \"catalog:\",\n    \"nitropack\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/jsonwebtoken\": \"catalog:\",\n    \"h3\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/routes/[...].ts",
    "content": "import { defineEventHandler } from 'h3';\n\nexport default defineEventHandler(() => {\n  return `\n<h1>Hello Vben Admin</h1>\n<h2>Mock service is starting</h2>\n<ul>\n<li><a href=\"/api/user\">/api/user/info</a></li>\n<li><a href=\"/api/menu\">/api/menu/all</a></li>\n<li><a href=\"/api/auth/codes\">/api/auth/codes</a></li>\n<li><a href=\"/api/auth/login\">/api/auth/login</a></li>\n<li><a href=\"/api/upload\">/api/upload</a></li>\n</ul>\n`;\n});\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/tsconfig.json",
    "content": "{\n  \"extends\": \"./.nitro/types/tsconfig.json\"\n}\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/utils/cookie-utils.ts",
    "content": "import type { EventHandlerRequest, H3Event } from 'h3';\n\nimport { deleteCookie, getCookie, setCookie } from 'h3';\n\nexport function clearRefreshTokenCookie(event: H3Event<EventHandlerRequest>) {\n  deleteCookie(event, 'jwt', {\n    httpOnly: true,\n    sameSite: 'none',\n    secure: true,\n  });\n}\n\nexport function setRefreshTokenCookie(\n  event: H3Event<EventHandlerRequest>,\n  refreshToken: string,\n) {\n  setCookie(event, 'jwt', refreshToken, {\n    httpOnly: true,\n    maxAge: 24 * 60 * 60, // unit: seconds\n    sameSite: 'none',\n    secure: true,\n  });\n}\n\nexport function getRefreshTokenFromCookie(event: H3Event<EventHandlerRequest>) {\n  const refreshToken = getCookie(event, 'jwt');\n  return refreshToken;\n}\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/utils/jwt-utils.ts",
    "content": "import type { EventHandlerRequest, H3Event } from 'h3';\n\nimport type { UserInfo } from './mock-data';\n\nimport { getHeader } from 'h3';\nimport jwt from 'jsonwebtoken';\n\nimport { MOCK_USERS } from './mock-data';\n\n// TODO: Replace with your own secret key\nconst ACCESS_TOKEN_SECRET = 'access_token_secret';\nconst REFRESH_TOKEN_SECRET = 'refresh_token_secret';\n\nexport interface UserPayload extends UserInfo {\n  iat: number;\n  exp: number;\n}\n\nexport function generateAccessToken(user: UserInfo) {\n  return jwt.sign(user, ACCESS_TOKEN_SECRET, { expiresIn: '7d' });\n}\n\nexport function generateRefreshToken(user: UserInfo) {\n  return jwt.sign(user, REFRESH_TOKEN_SECRET, {\n    expiresIn: '30d',\n  });\n}\n\nexport function verifyAccessToken(\n  event: H3Event<EventHandlerRequest>,\n): null | Omit<UserInfo, 'password'> {\n  const authHeader = getHeader(event, 'Authorization');\n  if (!authHeader?.startsWith('Bearer')) {\n    return null;\n  }\n\n  const tokenParts = authHeader.split(' ');\n  if (tokenParts.length !== 2) {\n    return null;\n  }\n  const token = tokenParts[1] as string;\n  try {\n    const decoded = jwt.verify(\n      token,\n      ACCESS_TOKEN_SECRET,\n    ) as unknown as UserPayload;\n\n    const username = decoded.username;\n    const user = MOCK_USERS.find((item) => item.username === username);\n    if (!user) {\n      return null;\n    }\n    const { password: _pwd, ...userinfo } = user;\n    return userinfo;\n  } catch {\n    return null;\n  }\n}\n\nexport function verifyRefreshToken(\n  token: string,\n): null | Omit<UserInfo, 'password'> {\n  try {\n    const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET) as UserPayload;\n    const username = decoded.username;\n    const user = MOCK_USERS.find(\n      (item) => item.username === username,\n    ) as UserInfo;\n    if (!user) {\n      return null;\n    }\n    const { password: _pwd, ...userinfo } = user;\n    return userinfo;\n  } catch {\n    return null;\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/utils/mock-data.ts",
    "content": "export interface UserInfo {\n  id: number;\n  password: string;\n  realName: string;\n  roles: string[];\n  username: string;\n  homePath?: string;\n}\n\nexport const MOCK_USERS: UserInfo[] = [\n  {\n    id: 0,\n    password: '123456',\n    realName: 'Vben',\n    roles: ['super'],\n    username: 'vben',\n  },\n  {\n    id: 1,\n    password: '123456',\n    realName: 'Admin',\n    roles: ['admin'],\n    username: 'admin',\n    homePath: '/workspace',\n  },\n  {\n    id: 2,\n    password: '123456',\n    realName: 'Jack',\n    roles: ['user'],\n    username: 'jack',\n    homePath: '/analytics',\n  },\n];\n\nexport const MOCK_CODES = [\n  // super\n  {\n    codes: ['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010'],\n    username: 'vben',\n  },\n  {\n    // admin\n    codes: ['AC_100010', 'AC_100020', 'AC_100030'],\n    username: 'admin',\n  },\n  {\n    // user\n    codes: ['AC_1000001', 'AC_1000002'],\n    username: 'jack',\n  },\n];\n\nconst dashboardMenus = [\n  {\n    meta: {\n      order: -1,\n      title: 'page.dashboard.title',\n    },\n    name: 'Dashboard',\n    path: '/dashboard',\n    redirect: '/analytics',\n    children: [\n      {\n        name: 'Analytics',\n        path: '/analytics',\n        component: '/dashboard/analytics/index',\n        meta: {\n          affixTab: true,\n          title: 'page.dashboard.analytics',\n        },\n      },\n      {\n        name: 'Workspace',\n        path: '/workspace',\n        component: '/dashboard/workspace/index',\n        meta: {\n          title: 'page.dashboard.workspace',\n        },\n      },\n    ],\n  },\n];\n\nconst createDemosMenus = (role: 'admin' | 'super' | 'user') => {\n  const roleWithMenus = {\n    admin: {\n      component: '/demos/access/admin-visible',\n      meta: {\n        icon: 'mdi:button-cursor',\n        title: 'demos.access.adminVisible',\n      },\n      name: 'AccessAdminVisibleDemo',\n      path: '/demos/access/admin-visible',\n    },\n    super: {\n      component: '/demos/access/super-visible',\n      meta: {\n        icon: 'mdi:button-cursor',\n        title: 'demos.access.superVisible',\n      },\n      name: 'AccessSuperVisibleDemo',\n      path: '/demos/access/super-visible',\n    },\n    user: {\n      component: '/demos/access/user-visible',\n      meta: {\n        icon: 'mdi:button-cursor',\n        title: 'demos.access.userVisible',\n      },\n      name: 'AccessUserVisibleDemo',\n      path: '/demos/access/user-visible',\n    },\n  };\n\n  return [\n    {\n      meta: {\n        icon: 'ic:baseline-view-in-ar',\n        keepAlive: true,\n        order: 1000,\n        title: 'demos.title',\n      },\n      name: 'Demos',\n      path: '/demos',\n      redirect: '/demos/access',\n      children: [\n        {\n          name: 'AccessDemos',\n          path: '/demosaccess',\n          meta: {\n            icon: 'mdi:cloud-key-outline',\n            title: 'demos.access.backendPermissions',\n          },\n          redirect: '/demos/access/page-control',\n          children: [\n            {\n              name: 'AccessPageControlDemo',\n              path: '/demos/access/page-control',\n              component: '/demos/access/index',\n              meta: {\n                icon: 'mdi:page-previous-outline',\n                title: 'demos.access.pageAccess',\n              },\n            },\n            {\n              name: 'AccessButtonControlDemo',\n              path: '/demos/access/button-control',\n              component: '/demos/access/button-control',\n              meta: {\n                icon: 'mdi:button-cursor',\n                title: 'demos.access.buttonControl',\n              },\n            },\n            {\n              name: 'AccessMenuVisible403Demo',\n              path: '/demos/access/menu-visible-403',\n              component: '/demos/access/menu-visible-403',\n              meta: {\n                authority: ['no-body'],\n                icon: 'mdi:button-cursor',\n                menuVisibleWithForbidden: true,\n                title: 'demos.access.menuVisible403',\n              },\n            },\n            roleWithMenus[role],\n          ],\n        },\n      ],\n    },\n  ];\n};\n\nexport const MOCK_MENUS = [\n  {\n    menus: [...dashboardMenus, ...createDemosMenus('super')],\n    username: 'vben',\n  },\n  {\n    menus: [...dashboardMenus, ...createDemosMenus('admin')],\n    username: 'admin',\n  },\n  {\n    menus: [...dashboardMenus, ...createDemosMenus('user')],\n    username: 'jack',\n  },\n];\n\nexport const MOCK_MENU_LIST = [\n  {\n    id: 1,\n    name: 'Workspace',\n    status: 1,\n    type: 'menu',\n    icon: 'mdi:dashboard',\n    path: '/workspace',\n    component: '/dashboard/workspace/index',\n    meta: {\n      icon: 'carbon:workspace',\n      title: 'page.dashboard.workspace',\n      affixTab: true,\n      order: 0,\n    },\n  },\n  {\n    id: 2,\n    meta: {\n      icon: 'carbon:settings',\n      order: 9997,\n      title: 'system.title',\n      badge: 'new',\n      badgeType: 'normal',\n      badgeVariants: 'primary',\n    },\n    status: 1,\n    type: 'catalog',\n    name: 'System',\n    path: '/system',\n    children: [\n      {\n        id: 201,\n        pid: 2,\n        path: '/system/menu',\n        name: 'SystemMenu',\n        authCode: 'System:Menu:List',\n        status: 1,\n        type: 'menu',\n        meta: {\n          icon: 'carbon:menu',\n          title: 'system.menu.title',\n        },\n        component: '/system/menu/list',\n        children: [\n          {\n            id: 20_101,\n            pid: 201,\n            name: 'SystemMenuCreate',\n            status: 1,\n            type: 'button',\n            authCode: 'System:Menu:Create',\n            meta: { title: 'common.create' },\n          },\n          {\n            id: 20_102,\n            pid: 201,\n            name: 'SystemMenuEdit',\n            status: 1,\n            type: 'button',\n            authCode: 'System:Menu:Edit',\n            meta: { title: 'common.edit' },\n          },\n          {\n            id: 20_103,\n            pid: 201,\n            name: 'SystemMenuDelete',\n            status: 1,\n            type: 'button',\n            authCode: 'System:Menu:Delete',\n            meta: { title: 'common.delete' },\n          },\n        ],\n      },\n      {\n        id: 202,\n        pid: 2,\n        path: '/system/dept',\n        name: 'SystemDept',\n        status: 1,\n        type: 'menu',\n        authCode: 'System:Dept:List',\n        meta: {\n          icon: 'carbon:container-services',\n          title: 'system.dept.title',\n        },\n        component: '/system/dept/list',\n        children: [\n          {\n            id: 20_401,\n            pid: 201,\n            name: 'SystemDeptCreate',\n            status: 1,\n            type: 'button',\n            authCode: 'System:Dept:Create',\n            meta: { title: 'common.create' },\n          },\n          {\n            id: 20_402,\n            pid: 201,\n            name: 'SystemDeptEdit',\n            status: 1,\n            type: 'button',\n            authCode: 'System:Dept:Edit',\n            meta: { title: 'common.edit' },\n          },\n          {\n            id: 20_403,\n            pid: 201,\n            name: 'SystemDeptDelete',\n            status: 1,\n            type: 'button',\n            authCode: 'System:Dept:Delete',\n            meta: { title: 'common.delete' },\n          },\n        ],\n      },\n    ],\n  },\n  {\n    id: 9,\n    meta: {\n      badgeType: 'dot',\n      order: 9998,\n      title: 'demos.vben.title',\n      icon: 'carbon:data-center',\n    },\n    name: 'Project',\n    path: '/vben-admin',\n    type: 'catalog',\n    status: 1,\n    children: [\n      {\n        id: 901,\n        pid: 9,\n        name: 'VbenDocument',\n        path: '/vben-admin/document',\n        component: 'IFrameView',\n        type: 'embedded',\n        status: 1,\n        meta: {\n          icon: 'carbon:book',\n          iframeSrc: 'https://doc.vben.pro',\n          title: 'demos.vben.document',\n        },\n      },\n      {\n        id: 902,\n        pid: 9,\n        name: 'VbenGithub',\n        path: '/vben-admin/github',\n        component: 'IFrameView',\n        type: 'link',\n        status: 1,\n        meta: {\n          icon: 'carbon:logo-github',\n          link: 'https://github.com/vbenjs/vue-vben-admin',\n          title: 'Github',\n        },\n      },\n      {\n        id: 903,\n        pid: 9,\n        name: 'VbenAntdv',\n        path: '/vben-admin/antdv',\n        component: 'IFrameView',\n        type: 'link',\n        status: 0,\n        meta: {\n          icon: 'carbon:hexagon-vertical-solid',\n          badgeType: 'dot',\n          link: 'https://ant.vben.pro',\n          title: 'demos.vben.antdv',\n        },\n      },\n    ],\n  },\n  {\n    id: 10,\n    component: '_core/about/index',\n    type: 'menu',\n    status: 1,\n    meta: {\n      icon: 'lucide:copyright',\n      order: 9999,\n      title: 'demos.vben.about',\n    },\n    name: 'About',\n    path: '/about',\n  },\n];\n\nexport function getMenuIds(menus: any[]) {\n  const ids: number[] = [];\n  menus.forEach((item) => {\n    ids.push(item.id);\n    if (item.children && item.children.length > 0) {\n      ids.push(...getMenuIds(item.children));\n    }\n  });\n  return ids;\n}\n"
  },
  {
    "path": "hiauth-front/apps/backend-mock/utils/response.ts",
    "content": "import type { EventHandlerRequest, H3Event } from 'h3';\n\nimport { setResponseStatus } from 'h3';\n\nexport function useResponseSuccess<T = any>(data: T) {\n  return {\n    code: 0,\n    data,\n    error: null,\n    message: 'ok',\n  };\n}\n\nexport function usePageResponseSuccess<T = any>(\n  page: number | string,\n  pageSize: number | string,\n  list: T[],\n  { message = 'ok' } = {},\n) {\n  const pageData = pagination(\n    Number.parseInt(`${page}`),\n    Number.parseInt(`${pageSize}`),\n    list,\n  );\n\n  return {\n    ...useResponseSuccess({\n      items: pageData,\n      total: list.length,\n    }),\n    message,\n  };\n}\n\nexport function useResponseError(message: string, error: any = null) {\n  return {\n    code: -1,\n    data: null,\n    error,\n    message,\n  };\n}\n\nexport function forbiddenResponse(\n  event: H3Event<EventHandlerRequest>,\n  message = 'Forbidden Exception',\n) {\n  setResponseStatus(event, 403);\n  return useResponseError(message, message);\n}\n\nexport function unAuthorizedResponse(event: H3Event<EventHandlerRequest>) {\n  setResponseStatus(event, 401);\n  return useResponseError('Unauthorized Exception', 'Unauthorized Exception');\n}\n\nexport function sleep(ms: number) {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function pagination<T = any>(\n  pageNo: number,\n  pageSize: number,\n  array: T[],\n): T[] {\n  const offset = (pageNo - 1) * Number(pageSize);\n  return offset + Number(pageSize) >= array.length\n    ? array.slice(offset)\n    : array.slice(offset, offset + Number(pageSize));\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/index.html",
    "content": "<!doctype html>\n<html lang=\"zh\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n    <meta name=\"renderer\" content=\"webkit\" />\n    <meta name=\"description\" content=\"A Modern Back-end Management System\" />\n    <meta name=\"keywords\" content=\"Vben Admin Vue3 Vite\" />\n    <meta name=\"author\" content=\"Vben\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0\"\n    />\n    <!-- 由 vite 注入 VITE_APP_TITLE 变量，在 .env 文件内配置 -->\n    <title><%= VITE_APP_TITLE %></title>\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <script>\n      // 生产环境下注入百度统计\n      if (window._VBEN_ADMIN_PRO_APP_CONF_) {\n        var _hmt = _hmt || [];\n        (function () {\n          var hm = document.createElement('script');\n          hm.src =\n            'https://hm.baidu.com/hm.js?b38e689f40558f20a9a686d7f6f33edf';\n          var s = document.getElementsByTagName('script')[0];\n          s.parentNode.insertBefore(hm, s);\n        })();\n      }\n    </script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/package.json",
    "content": "{\n  \"name\": \"@vben/web-antd\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://vben.pro\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"apps/web-antd\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"vben\",\n    \"email\": \"ann.vben@gmail.com\",\n    \"url\": \"https://github.com/anncwb\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm vite build --mode production\",\n    \"build:analyze\": \"pnpm vite build --mode analyze\",\n    \"dev\": \"pnpm vite --mode development\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"vue-tsc --noEmit --skipLibCheck\"\n  },\n  \"imports\": {\n    \"#/*\": \"./src/*\"\n  },\n  \"dependencies\": {\n    \"@vben/access\": \"workspace:*\",\n    \"@vben/common-ui\": \"workspace:*\",\n    \"@vben/constants\": \"workspace:*\",\n    \"@vben/hooks\": \"workspace:*\",\n    \"@vben/icons\": \"workspace:*\",\n    \"@vben/layouts\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/plugins\": \"workspace:*\",\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/request\": \"workspace:*\",\n    \"@vben/stores\": \"workspace:*\",\n    \"@vben/styles\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"ant-design-vue\": \"catalog:\",\n    \"dayjs\": \"catalog:\",\n    \"pinia\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/adapter/component/index.ts",
    "content": "/**\n * 通用组件共同的使用的基础组件，原先放在 adapter/form 内部，限制了使用范围，这里提取出来，方便其他地方使用\n * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,\n */\n\nimport type { Component } from 'vue';\n\nimport type { BaseFormComponentType } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { defineAsyncComponent, defineComponent, h, ref } from 'vue';\n\nimport { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { notification } from 'ant-design-vue';\n\nconst AutoComplete = defineAsyncComponent(\n  () => import('ant-design-vue/es/auto-complete'),\n);\nconst Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));\nconst Checkbox = defineAsyncComponent(\n  () => import('ant-design-vue/es/checkbox'),\n);\nconst CheckboxGroup = defineAsyncComponent(() =>\n  import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),\n);\nconst DatePicker = defineAsyncComponent(\n  () => import('ant-design-vue/es/date-picker'),\n);\nconst Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));\nconst Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));\nconst InputNumber = defineAsyncComponent(\n  () => import('ant-design-vue/es/input-number'),\n);\nconst InputPassword = defineAsyncComponent(() =>\n  import('ant-design-vue/es/input').then((res) => res.InputPassword),\n);\nconst Mentions = defineAsyncComponent(\n  () => import('ant-design-vue/es/mentions'),\n);\nconst Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));\nconst RadioGroup = defineAsyncComponent(() =>\n  import('ant-design-vue/es/radio').then((res) => res.RadioGroup),\n);\nconst RangePicker = defineAsyncComponent(() =>\n  import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),\n);\nconst Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));\nconst Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));\nconst Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));\nconst Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));\nconst Textarea = defineAsyncComponent(() =>\n  import('ant-design-vue/es/input').then((res) => res.Textarea),\n);\nconst TimePicker = defineAsyncComponent(\n  () => import('ant-design-vue/es/time-picker'),\n);\nconst TreeSelect = defineAsyncComponent(\n  () => import('ant-design-vue/es/tree-select'),\n);\nconst Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));\n\nconst withDefaultPlaceholder = <T extends Component>(\n  component: T,\n  type: 'input' | 'select',\n  componentProps: Recordable<any> = {},\n) => {\n  return defineComponent({\n    name: component.name,\n    inheritAttrs: false,\n    setup: (props: any, { attrs, expose, slots }) => {\n      const placeholder =\n        props?.placeholder ||\n        attrs?.placeholder ||\n        $t(`ui.placeholder.${type}`);\n      // 透传组件暴露的方法\n      const innerRef = ref();\n      expose(\n        new Proxy(\n          {},\n          {\n            get: (_target, key) => innerRef.value?.[key],\n            has: (_target, key) => key in (innerRef.value || {}),\n          },\n        ),\n      );\n      return () =>\n        h(\n          component,\n          { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },\n          slots,\n        );\n    },\n  });\n};\n\n// 这里需要自行根据业务组件库进行适配，需要用到的组件都需要在这里类型说明\nexport type ComponentType =\n  | 'ApiSelect'\n  | 'ApiTreeSelect'\n  | 'AutoComplete'\n  | 'Checkbox'\n  | 'CheckboxGroup'\n  | 'DatePicker'\n  | 'DefaultButton'\n  | 'Divider'\n  | 'IconPicker'\n  | 'Input'\n  | 'InputNumber'\n  | 'InputPassword'\n  | 'Mentions'\n  | 'PrimaryButton'\n  | 'Radio'\n  | 'RadioGroup'\n  | 'RangePicker'\n  | 'Rate'\n  | 'Select'\n  | 'Space'\n  | 'Switch'\n  | 'Textarea'\n  | 'TimePicker'\n  | 'TreeSelect'\n  | 'Upload'\n  | BaseFormComponentType;\n\nasync function initComponentAdapter() {\n  const components: Partial<Record<ComponentType, Component>> = {\n    // 如果你的组件体积比较大，可以使用异步加载\n    // Button: () =>\n    // import('xxx').then((res) => res.Button),\n    ApiSelect: withDefaultPlaceholder(\n      {\n        ...ApiComponent,\n        name: 'ApiSelect',\n      },\n      'select',\n      {\n        component: Select,\n        loadingSlot: 'suffixIcon',\n        visibleEvent: 'onDropdownVisibleChange',\n        modelPropName: 'value',\n      },\n    ),\n    ApiTreeSelect: withDefaultPlaceholder(\n      {\n        ...ApiComponent,\n        name: 'ApiTreeSelect',\n      },\n      'select',\n      {\n        component: TreeSelect,\n        fieldNames: { label: 'label', value: 'value', children: 'children' },\n        loadingSlot: 'suffixIcon',\n        modelPropName: 'value',\n        optionsPropName: 'treeData',\n        visibleEvent: 'onVisibleChange',\n      },\n    ),\n    AutoComplete,\n    Checkbox,\n    CheckboxGroup,\n    DatePicker,\n    // 自定义默认按钮\n    DefaultButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'default' }, slots);\n    },\n    Divider,\n    IconPicker: withDefaultPlaceholder(IconPicker, 'select', {\n      iconSlot: 'addonAfter',\n      inputComponent: Input,\n      modelValueProp: 'value',\n    }),\n    Input: withDefaultPlaceholder(Input, 'input'),\n    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),\n    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),\n    Mentions: withDefaultPlaceholder(Mentions, 'input'),\n    // 自定义主要按钮\n    PrimaryButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'primary' }, slots);\n    },\n    Radio,\n    RadioGroup,\n    RangePicker,\n    Rate,\n    Select: withDefaultPlaceholder(Select, 'select'),\n    Space,\n    Switch,\n    Textarea: withDefaultPlaceholder(Textarea, 'input'),\n    TimePicker,\n    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),\n    Upload,\n  };\n\n  // 将组件注册到全局共享状态中\n  globalShareState.setComponents(components);\n\n  // 定义全局共享状态中的消息提示\n  globalShareState.defineMessage({\n    // 复制成功消息提示\n    copyPreferencesSuccess: (title, content) => {\n      notification.success({\n        description: content,\n        message: title,\n        placement: 'bottomRight',\n      });\n    },\n  });\n}\n\nexport { initComponentAdapter };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/adapter/form.ts",
    "content": "import type {\n  VbenFormSchema as FormSchema,\n  VbenFormProps,\n} from '@vben/common-ui';\n\nimport type { ComponentType } from './component';\n\nimport { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nasync function initSetupVbenForm() {\n  setupVbenForm<ComponentType>({\n    config: {\n      // ant design vue组件库默认都是 v-model:value\n      baseModelPropName: 'value',\n\n      // 一些组件是 v-model:checked 或者 v-model:fileList\n      modelPropNameMap: {\n        Checkbox: 'checked',\n        Radio: 'checked',\n        Switch: 'checked',\n        Upload: 'fileList',\n      },\n    },\n    defineRules: {\n      // 输入项目必填国际化适配\n      required: (value, _params, ctx) => {\n        if (value === undefined || value === null || value.length === 0) {\n          return $t('ui.formRules.required', [ctx.label]);\n        }\n        return true;\n      },\n      // 选择项目必填国际化适配\n      selectRequired: (value, _params, ctx) => {\n        if (value === undefined || value === null) {\n          return $t('ui.formRules.selectRequired', [ctx.label]);\n        }\n        return true;\n      },\n    },\n  });\n}\n\nconst useVbenForm = useForm<ComponentType>;\n\nexport { initSetupVbenForm, useVbenForm, z };\n\nexport type VbenFormSchema = FormSchema<ComponentType>;\nexport type { VbenFormProps };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/adapter/vxe-table.ts",
    "content": "import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';\n\nimport { h } from 'vue';\n\nimport { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';\n\nimport { Button, Image } from 'ant-design-vue';\n\nimport { useVbenForm } from './form';\n\nsetupVbenVxeTable({\n  configVxeTable: (vxeUI) => {\n    vxeUI.setConfig({\n      grid: {\n        align: 'center',\n        border: false,\n        columnConfig: {\n          resizable: true,\n        },\n        minHeight: 180,\n        formConfig: {\n          // 全局禁用vxe-table的表单配置，使用formOptions\n          enabled: false,\n        },\n        proxyConfig: {\n          autoLoad: true,\n          response: {\n            result: 'items',\n            total: 'total',\n            list: 'items',\n          },\n          showActiveMsg: true,\n          showResponseMsg: false,\n        },\n        round: true,\n        showOverflow: true,\n        size: 'small',\n      } as VxeTableGridOptions,\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellImage' },\n    vxeUI.renderer.add('CellImage', {\n      renderTableDefault(_renderOpts, params) {\n        const { column, row } = params;\n        return h(Image, { src: row[column.field] });\n      },\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellLink' },\n    vxeUI.renderer.add('CellLink', {\n      renderTableDefault(renderOpts) {\n        const { props } = renderOpts;\n        return h(\n          Button,\n          { size: 'small', type: 'link' },\n          { default: () => props?.text },\n        );\n      },\n    });\n\n    // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化\n    // vxeUI.formats.add\n  },\n  useVbenForm,\n});\n\nexport { useVbenVxeGrid };\n\nexport type * from '@vben/plugins/vxe-table';\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/api/core/auth.ts",
    "content": "import { baseRequestClient, requestClient } from '#/api/request';\n\nexport namespace AuthApi {\n  /** 登录接口参数 */\n  export interface LoginParams {\n    password?: string;\n    username?: string;\n  }\n\n  /** 登录接口返回值 */\n  export interface LoginResult {\n    accessToken: string;\n  }\n\n  export interface RefreshTokenResult {\n    data: string;\n    status: number;\n  }\n}\n\n/**\n * 登录\n */\nexport async function loginApi(data: AuthApi.LoginParams) {\n  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);\n}\n\n/**\n * 刷新accessToken\n */\nexport async function refreshTokenApi() {\n  return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {\n    withCredentials: true,\n  });\n}\n\n/**\n * 退出登录\n */\nexport async function logoutApi() {\n  return baseRequestClient.post('/auth/logout', {\n    withCredentials: true,\n  });\n}\n\n/**\n * 获取用户权限码\n */\nexport async function getAccessCodesApi() {\n  return requestClient.get<string[]>('/auth/codes');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/api/core/index.ts",
    "content": "export * from './auth';\nexport * from './menu';\nexport * from './user';\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/api/core/menu.ts",
    "content": "import type { RouteRecordStringComponent } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户所有菜单\n */\nexport async function getAllMenusApi() {\n  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/api/core/user.ts",
    "content": "import type { UserInfo } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户信息\n */\nexport async function getUserInfoApi() {\n  return requestClient.get<UserInfo>('/user/info');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/api/index.ts",
    "content": "export * from './core';\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/api/request.ts",
    "content": "/**\n * 该文件可自行根据业务逻辑进行调整\n */\nimport type { RequestClientOptions } from '@vben/request';\n\nimport { useAppConfig } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\nimport {\n  authenticateResponseInterceptor,\n  defaultResponseInterceptor,\n  errorMessageResponseInterceptor,\n  RequestClient,\n} from '@vben/request';\nimport { useAccessStore } from '@vben/stores';\n\nimport { message } from 'ant-design-vue';\n\nimport { useAuthStore } from '#/store';\n\nimport { refreshTokenApi } from './core';\n\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n\nfunction createRequestClient(baseURL: string, options?: RequestClientOptions) {\n  const client = new RequestClient({\n    ...options,\n    baseURL,\n  });\n\n  /**\n   * 重新认证逻辑\n   */\n  async function doReAuthenticate() {\n    console.warn('Access token or refresh token is invalid or expired. ');\n    const accessStore = useAccessStore();\n    const authStore = useAuthStore();\n    accessStore.setAccessToken(null);\n    if (\n      preferences.app.loginExpiredMode === 'modal' &&\n      accessStore.isAccessChecked\n    ) {\n      accessStore.setLoginExpired(true);\n    } else {\n      await authStore.logout();\n    }\n  }\n\n  /**\n   * 刷新token逻辑\n   */\n  async function doRefreshToken() {\n    const accessStore = useAccessStore();\n    const resp = await refreshTokenApi();\n    const newToken = resp.data;\n    accessStore.setAccessToken(newToken);\n    return newToken;\n  }\n\n  function formatToken(token: null | string) {\n    return token ? `Bearer ${token}` : null;\n  }\n\n  // 请求头处理\n  client.addRequestInterceptor({\n    fulfilled: async (config) => {\n      const accessStore = useAccessStore();\n\n      config.headers.Authorization = formatToken(accessStore.accessToken);\n      config.headers['Accept-Language'] = preferences.app.locale;\n      return config;\n    },\n  });\n\n  // 处理返回的响应数据格式\n  client.addResponseInterceptor(\n    defaultResponseInterceptor({\n      codeField: 'code',\n      dataField: 'data',\n      successCode: 0,\n    }),\n  );\n\n  // token过期的处理\n  client.addResponseInterceptor(\n    authenticateResponseInterceptor({\n      client,\n      doReAuthenticate,\n      doRefreshToken,\n      enableRefreshToken: preferences.app.enableRefreshToken,\n      formatToken,\n    }),\n  );\n\n  // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里\n  client.addResponseInterceptor(\n    errorMessageResponseInterceptor((msg: string, error) => {\n      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg\n      // 当前mock接口返回的错误字段是 error 或者 message\n      const responseData = error?.response?.data ?? {};\n      const errorMessage = responseData?.error ?? responseData?.message ?? '';\n      // 如果没有错误信息，则会根据状态码进行提示\n      message.error(errorMessage || msg);\n    }),\n  );\n\n  return client;\n}\n\nexport const requestClient = createRequestClient(apiURL, {\n  responseReturn: 'data',\n});\n\nexport const baseRequestClient = new RequestClient({ baseURL: apiURL });\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/app.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { useAntdDesignTokens } from '@vben/hooks';\nimport { preferences, usePreferences } from '@vben/preferences';\n\nimport { App, ConfigProvider, theme } from 'ant-design-vue';\n\nimport { antdLocale } from '#/locales';\n\ndefineOptions({ name: 'App' });\n\nconst { isDark } = usePreferences();\nconst { tokens } = useAntdDesignTokens();\n\nconst tokenTheme = computed(() => {\n  const algorithm = isDark.value\n    ? [theme.darkAlgorithm]\n    : [theme.defaultAlgorithm];\n\n  // antd 紧凑模式算法\n  if (preferences.app.compact) {\n    algorithm.push(theme.compactAlgorithm);\n  }\n\n  return {\n    algorithm,\n    token: tokens,\n  };\n});\n</script>\n\n<template>\n  <ConfigProvider :locale=\"antdLocale\" :theme=\"tokenTheme\">\n    <App>\n      <RouterView />\n    </App>\n  </ConfigProvider>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/bootstrap.ts",
    "content": "import { createApp, watchEffect } from 'vue';\n\nimport { registerAccessDirective } from '@vben/access';\nimport { registerLoadingDirective } from '@vben/common-ui/es/loading';\nimport { preferences } from '@vben/preferences';\nimport { initStores } from '@vben/stores';\nimport '@vben/styles';\nimport '@vben/styles/antd';\n\nimport { useTitle } from '@vueuse/core';\n\nimport { $t, setupI18n } from '#/locales';\n\nimport { initComponentAdapter } from './adapter/component';\nimport { initSetupVbenForm } from './adapter/form';\nimport App from './app.vue';\nimport { router } from './router';\n\nasync function bootstrap(namespace: string) {\n  // 初始化组件适配器\n  await initComponentAdapter();\n\n  // 初始化表单组件\n  await initSetupVbenForm();\n\n  // // 设置弹窗的默认配置\n  // setDefaultModalProps({\n  //   fullscreenButton: false,\n  // });\n  // // 设置抽屉的默认配置\n  // setDefaultDrawerProps({\n  //   zIndex: 1020,\n  // });\n\n  const app = createApp(App);\n\n  // 注册v-loading指令\n  registerLoadingDirective(app, {\n    loading: 'loading', // 在这里可以自定义指令名称，也可以明确提供false表示不注册这个指令\n    spinning: 'spinning',\n  });\n\n  // 国际化 i18n 配置\n  await setupI18n(app);\n\n  // 配置 pinia-tore\n  await initStores(app, { namespace });\n\n  // 安装权限指令\n  registerAccessDirective(app);\n\n  // 初始化 tippy\n  const { initTippy } = await import('@vben/common-ui/es/tippy');\n  initTippy(app);\n\n  // 配置路由及路由守卫\n  app.use(router);\n\n  // 配置Motion插件\n  const { MotionPlugin } = await import('@vben/plugins/motion');\n  app.use(MotionPlugin);\n\n  // 动态更新标题\n  watchEffect(() => {\n    if (preferences.app.dynamicTitle) {\n      const routeTitle = router.currentRoute.value.meta?.title;\n      const pageTitle =\n        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;\n      useTitle(pageTitle);\n    }\n  });\n\n  app.mount('#app');\n}\n\nexport { bootstrap };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/layouts/auth.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { AuthPageLayout } from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst appName = computed(() => preferences.app.name);\nconst logo = computed(() => preferences.logo.source);\n</script>\n\n<template>\n  <AuthPageLayout\n    :app-name=\"appName\"\n    :logo=\"logo\"\n    :page-description=\"$t('authentication.pageDesc')\"\n    :page-title=\"$t('authentication.pageTitle')\"\n  >\n    <!-- 自定义工具栏 -->\n    <!-- <template #toolbar></template> -->\n  </AuthPageLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/layouts/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { NotificationItem } from '@vben/layouts';\n\nimport { computed, ref, watch } from 'vue';\n\nimport { AuthenticationLoginExpiredModal } from '@vben/common-ui';\nimport { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';\nimport { useWatermark } from '@vben/hooks';\nimport { BookOpenText, CircleHelp, SvgGithubIcon } from '@vben/icons';\nimport {\n  BasicLayout,\n  LockScreen,\n  Notification,\n  UserDropdown,\n} from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport { $t } from '#/locales';\nimport { useAuthStore } from '#/store';\nimport LoginForm from '#/views/_core/authentication/login.vue';\n\nconst notifications = ref<NotificationItem[]>([\n  {\n    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',\n    date: '3小时前',\n    isRead: true,\n    message: '描述信息描述信息描述信息',\n    title: '收到了 14 份新周报',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '刚刚',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '朱偏右 回复了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '2024-01-01',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '曲丽丽 评论了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/satori',\n    date: '1天前',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '代办提醒',\n  },\n]);\n\nconst userStore = useUserStore();\nconst authStore = useAuthStore();\nconst accessStore = useAccessStore();\nconst { destroyWatermark, updateWatermark } = useWatermark();\nconst showDot = computed(() =>\n  notifications.value.some((item) => !item.isRead),\n);\n\nconst menus = computed(() => [\n  {\n    handler: () => {\n      openWindow(VBEN_DOC_URL, {\n        target: '_blank',\n      });\n    },\n    icon: BookOpenText,\n    text: $t('ui.widgets.document'),\n  },\n  {\n    handler: () => {\n      openWindow(VBEN_GITHUB_URL, {\n        target: '_blank',\n      });\n    },\n    icon: SvgGithubIcon,\n    text: 'GitHub',\n  },\n  {\n    handler: () => {\n      openWindow(`${VBEN_GITHUB_URL}/issues`, {\n        target: '_blank',\n      });\n    },\n    icon: CircleHelp,\n    text: $t('ui.widgets.qa'),\n  },\n]);\n\nconst avatar = computed(() => {\n  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;\n});\n\nasync function handleLogout() {\n  await authStore.logout(false);\n}\n\nfunction handleNoticeClear() {\n  notifications.value = [];\n}\n\nfunction handleMakeAll() {\n  notifications.value.forEach((item) => (item.isRead = true));\n}\nwatch(\n  () => ({\n    enable: preferences.app.watermark,\n    content: preferences.app.watermarkContent,\n  }),\n  async ({ enable, content }) => {\n    if (enable) {\n      await updateWatermark({\n        content:\n          content ||\n          `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,\n      });\n    } else {\n      destroyWatermark();\n    }\n  },\n  {\n    immediate: true,\n  },\n);\n</script>\n\n<template>\n  <BasicLayout @clear-preferences-and-logout=\"handleLogout\">\n    <template #user-dropdown>\n      <UserDropdown\n        :avatar\n        :menus\n        :text=\"userStore.userInfo?.realName\"\n        description=\"ann.vben@gmail.com\"\n        tag-text=\"Pro\"\n        @logout=\"handleLogout\"\n      />\n    </template>\n    <template #notification>\n      <Notification\n        :dot=\"showDot\"\n        :notifications=\"notifications\"\n        @clear=\"handleNoticeClear\"\n        @make-all=\"handleMakeAll\"\n      />\n    </template>\n    <template #extra>\n      <AuthenticationLoginExpiredModal\n        v-model:open=\"accessStore.loginExpired\"\n        :avatar\n      >\n        <LoginForm />\n      </AuthenticationLoginExpiredModal>\n    </template>\n    <template #lock-screen>\n      <LockScreen :avatar @to-login=\"handleLogout\" />\n    </template>\n  </BasicLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/layouts/index.ts",
    "content": "const BasicLayout = () => import('./basic.vue');\nconst AuthPageLayout = () => import('./auth.vue');\n\nconst IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);\n\nexport { AuthPageLayout, BasicLayout, IFrameView };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/locales/README.md",
    "content": "# locale\n\n每个app使用的国际化可能不同，这里用于扩展国际化的功能，例如扩展 dayjs、antd组件库的多语言切换，以及app本身的国际化文件。\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/locales/index.ts",
    "content": "import type { Locale } from 'ant-design-vue/es/locale';\n\nimport type { App } from 'vue';\n\nimport type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';\n\nimport { ref } from 'vue';\n\nimport {\n  $t,\n  setupI18n as coreSetup,\n  loadLocalesMapFromDir,\n} from '@vben/locales';\nimport { preferences } from '@vben/preferences';\n\nimport antdEnLocale from 'ant-design-vue/es/locale/en_US';\nimport antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN';\nimport dayjs from 'dayjs';\n\nconst antdLocale = ref<Locale>(antdDefaultLocale);\n\nconst modules = import.meta.glob('./langs/**/*.json');\n\nconst localesMap = loadLocalesMapFromDir(\n  /\\.\\/langs\\/([^/]+)\\/(.*)\\.json$/,\n  modules,\n);\n/**\n * 加载应用特有的语言包\n * 这里也可以改造为从服务端获取翻译数据\n * @param lang\n */\nasync function loadMessages(lang: SupportedLanguagesType) {\n  const [appLocaleMessages] = await Promise.all([\n    localesMap[lang]?.(),\n    loadThirdPartyMessage(lang),\n  ]);\n  return appLocaleMessages?.default;\n}\n\n/**\n * 加载第三方组件库的语言包\n * @param lang\n */\nasync function loadThirdPartyMessage(lang: SupportedLanguagesType) {\n  await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);\n}\n\n/**\n * 加载dayjs的语言包\n * @param lang\n */\nasync function loadDayjsLocale(lang: SupportedLanguagesType) {\n  let locale;\n  switch (lang) {\n    case 'en-US': {\n      locale = await import('dayjs/locale/en');\n      break;\n    }\n    case 'zh-CN': {\n      locale = await import('dayjs/locale/zh-cn');\n      break;\n    }\n    // 默认使用英语\n    default: {\n      locale = await import('dayjs/locale/en');\n    }\n  }\n  if (locale) {\n    dayjs.locale(locale);\n  } else {\n    console.error(`Failed to load dayjs locale for ${lang}`);\n  }\n}\n\n/**\n * 加载antd的语言包\n * @param lang\n */\nasync function loadAntdLocale(lang: SupportedLanguagesType) {\n  switch (lang) {\n    case 'en-US': {\n      antdLocale.value = antdEnLocale;\n      break;\n    }\n    case 'zh-CN': {\n      antdLocale.value = antdDefaultLocale;\n      break;\n    }\n  }\n}\n\nasync function setupI18n(app: App, options: LocaleSetupOptions = {}) {\n  await coreSetup(app, {\n    defaultLocale: preferences.app.locale,\n    loadMessages,\n    missingWarn: !import.meta.env.PROD,\n    ...options,\n  });\n}\n\nexport { $t, antdLocale, setupI18n };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/locales/langs/en-US/demos.json",
    "content": "{\n  \"title\": \"Demos\",\n  \"antd\": \"Ant Design Vue\",\n  \"vben\": {\n    \"title\": \"Project\",\n    \"about\": \"About\",\n    \"document\": \"Document\",\n    \"antdv\": \"Ant Design Vue Version\",\n    \"naive-ui\": \"Naive UI Version\",\n    \"element-plus\": \"Element Plus Version\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/locales/langs/en-US/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"Login\",\n    \"register\": \"Register\",\n    \"codeLogin\": \"Code Login\",\n    \"qrcodeLogin\": \"Qr Code Login\",\n    \"forgetPassword\": \"Forget Password\"\n  },\n  \"dashboard\": {\n    \"title\": \"Dashboard\",\n    \"analytics\": \"Analytics\",\n    \"workspace\": \"Workspace\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/locales/langs/zh-CN/demos.json",
    "content": "{\n  \"title\": \"演示\",\n  \"antd\": \"Ant Design Vue\",\n  \"vben\": {\n    \"title\": \"项目\",\n    \"about\": \"关于\",\n    \"document\": \"文档\",\n    \"antdv\": \"Ant Design Vue 版本\",\n    \"naive-ui\": \"Naive UI 版本\",\n    \"element-plus\": \"Element Plus 版本\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/locales/langs/zh-CN/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"登录\",\n    \"register\": \"注册\",\n    \"codeLogin\": \"验证码登录\",\n    \"qrcodeLogin\": \"二维码登录\",\n    \"forgetPassword\": \"忘记密码\"\n  },\n  \"dashboard\": {\n    \"title\": \"概览\",\n    \"analytics\": \"分析页\",\n    \"workspace\": \"工作台\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/main.ts",
    "content": "import { initPreferences } from '@vben/preferences';\nimport { unmountGlobalLoading } from '@vben/utils';\n\nimport { overridesPreferences } from './preferences';\n\n/**\n * 应用初始化完成之后再进行页面加载渲染\n */\nasync function initApplication() {\n  // name用于指定项目唯一标识\n  // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据\n  const env = import.meta.env.PROD ? 'prod' : 'dev';\n  const appVersion = import.meta.env.VITE_APP_VERSION;\n  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;\n\n  // app偏好设置初始化\n  await initPreferences({\n    namespace,\n    overrides: overridesPreferences,\n  });\n\n  // 启动应用并挂载\n  // vue应用主要逻辑及视图\n  const { bootstrap } = await import('./bootstrap');\n  await bootstrap(namespace);\n\n  // 移除并销毁loading\n  unmountGlobalLoading();\n}\n\ninitApplication();\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/preferences.ts",
    "content": "import { defineOverridesPreferences } from '@vben/preferences';\n\n/**\n * @description 项目配置文件\n * 只需要覆盖项目中的一部分配置，不需要的配置不用覆盖，会自动使用默认配置\n * !!! 更改配置后请清空缓存，否则可能不生效\n */\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    name: import.meta.env.VITE_APP_TITLE,\n  },\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/router/access.ts",
    "content": "import type {\n  ComponentRecordType,\n  GenerateMenuAndRoutesOptions,\n} from '@vben/types';\n\nimport { generateAccessible } from '@vben/access';\nimport { preferences } from '@vben/preferences';\n\nimport { message } from 'ant-design-vue';\n\nimport { getAllMenusApi } from '#/api';\nimport { BasicLayout, IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');\n\nasync function generateAccess(options: GenerateMenuAndRoutesOptions) {\n  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');\n\n  const layoutMap: ComponentRecordType = {\n    BasicLayout,\n    IFrameView,\n  };\n\n  return await generateAccessible(preferences.app.accessMode, {\n    ...options,\n    fetchMenuListAsync: async () => {\n      message.loading({\n        content: `${$t('common.loadingMenu')}...`,\n        duration: 1.5,\n      });\n      return await getAllMenusApi();\n    },\n    // 可以指定没有权限跳转403页面\n    forbiddenComponent,\n    // 如果 route.meta.menuVisibleWithForbidden = true\n    layoutMap,\n    pageMap,\n  });\n}\n\nexport { generateAccess };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/router/guard.ts",
    "content": "import type { Router } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { startProgress, stopProgress } from '@vben/utils';\n\nimport { accessRoutes, coreRouteNames } from '#/router/routes';\nimport { useAuthStore } from '#/store';\n\nimport { generateAccess } from './access';\n\n/**\n * 通用守卫配置\n * @param router\n */\nfunction setupCommonGuard(router: Router) {\n  // 记录已经加载的页面\n  const loadedPaths = new Set<string>();\n\n  router.beforeEach((to) => {\n    to.meta.loaded = loadedPaths.has(to.path);\n\n    // 页面加载进度条\n    if (!to.meta.loaded && preferences.transition.progress) {\n      startProgress();\n    }\n    return true;\n  });\n\n  router.afterEach((to) => {\n    // 记录页面是否加载,如果已经加载，后续的页面切换动画等效果不在重复执行\n\n    loadedPaths.add(to.path);\n\n    // 关闭页面加载进度条\n    if (preferences.transition.progress) {\n      stopProgress();\n    }\n  });\n}\n\n/**\n * 权限访问守卫配置\n * @param router\n */\nfunction setupAccessGuard(router: Router) {\n  router.beforeEach(async (to, from) => {\n    const accessStore = useAccessStore();\n    const userStore = useUserStore();\n    const authStore = useAuthStore();\n\n    // 基本路由，这些路由不需要进入权限拦截\n    if (coreRouteNames.includes(to.name as string)) {\n      if (to.path === LOGIN_PATH && accessStore.accessToken) {\n        return decodeURIComponent(\n          (to.query?.redirect as string) ||\n            userStore.userInfo?.homePath ||\n            preferences.app.defaultHomePath,\n        );\n      }\n      return true;\n    }\n\n    // accessToken 检查\n    if (!accessStore.accessToken) {\n      // 明确声明忽略权限访问权限，则可以访问\n      if (to.meta.ignoreAccess) {\n        return true;\n      }\n\n      // 没有访问权限，跳转登录页面\n      if (to.fullPath !== LOGIN_PATH) {\n        return {\n          path: LOGIN_PATH,\n          // 如不需要，直接删除 query\n          query:\n            to.fullPath === preferences.app.defaultHomePath\n              ? {}\n              : { redirect: encodeURIComponent(to.fullPath) },\n          // 携带当前跳转的页面，登录后重新跳转该页面\n          replace: true,\n        };\n      }\n      return to;\n    }\n\n    // 是否已经生成过动态路由\n    if (accessStore.isAccessChecked) {\n      return true;\n    }\n\n    // 生成路由表\n    // 当前登录用户拥有的角色标识列表\n    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());\n    const userRoles = userInfo.roles ?? [];\n\n    // 生成菜单和路由\n    const { accessibleMenus, accessibleRoutes } = await generateAccess({\n      roles: userRoles,\n      router,\n      // 则会在菜单中显示，但是访问会被重定向到403\n      routes: accessRoutes,\n    });\n\n    // 保存菜单信息和路由信息\n    accessStore.setAccessMenus(accessibleMenus);\n    accessStore.setAccessRoutes(accessibleRoutes);\n    accessStore.setIsAccessChecked(true);\n    const redirectPath = (from.query.redirect ??\n      (to.path === preferences.app.defaultHomePath\n        ? userInfo.homePath || preferences.app.defaultHomePath\n        : to.fullPath)) as string;\n\n    return {\n      ...router.resolve(decodeURIComponent(redirectPath)),\n      replace: true,\n    };\n  });\n}\n\n/**\n * 项目守卫配置\n * @param router\n */\nfunction createRouterGuard(router: Router) {\n  /** 通用 */\n  setupCommonGuard(router);\n  /** 权限访问 */\n  setupAccessGuard(router);\n}\n\nexport { createRouterGuard };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/router/index.ts",
    "content": "import {\n  createRouter,\n  createWebHashHistory,\n  createWebHistory,\n} from 'vue-router';\n\nimport { resetStaticRoutes } from '@vben/utils';\n\nimport { createRouterGuard } from './guard';\nimport { routes } from './routes';\n\n/**\n *  @zh_CN 创建vue-router实例\n */\nconst router = createRouter({\n  history:\n    import.meta.env.VITE_ROUTER_HISTORY === 'hash'\n      ? createWebHashHistory(import.meta.env.VITE_BASE)\n      : createWebHistory(import.meta.env.VITE_BASE),\n  // 应该添加到路由的初始路由列表。\n  routes,\n  scrollBehavior: (to, _from, savedPosition) => {\n    if (savedPosition) {\n      return savedPosition;\n    }\n    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };\n  },\n  // 是否应该禁止尾部斜杠。\n  // strict: true,\n});\n\nconst resetRoutes = () => resetStaticRoutes(router, routes);\n\n// 创建路由守卫\ncreateRouterGuard(router);\n\nexport { resetRoutes, router };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/router/routes/core.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst BasicLayout = () => import('#/layouts/basic.vue');\nconst AuthPageLayout = () => import('#/layouts/auth.vue');\n/** 全局404页面 */\nconst fallbackNotFoundRoute: RouteRecordRaw = {\n  component: () => import('#/views/_core/fallback/not-found.vue'),\n  meta: {\n    hideInBreadcrumb: true,\n    hideInMenu: true,\n    hideInTab: true,\n    title: '404',\n  },\n  name: 'FallbackNotFound',\n  path: '/:path(.*)*',\n};\n\n/** 基本路由，这些路由是必须存在的 */\nconst coreRoutes: RouteRecordRaw[] = [\n  /**\n   * 根路由\n   * 使用基础布局，作为所有页面的父级容器，子级就不必配置BasicLayout。\n   * 此路由必须存在，且不应修改\n   */\n  {\n    component: BasicLayout,\n    meta: {\n      hideInBreadcrumb: true,\n      title: 'Root',\n    },\n    name: 'Root',\n    path: '/',\n    redirect: preferences.app.defaultHomePath,\n    children: [],\n  },\n  {\n    component: AuthPageLayout,\n    meta: {\n      hideInTab: true,\n      title: 'Authentication',\n    },\n    name: 'Authentication',\n    path: '/auth',\n    redirect: LOGIN_PATH,\n    children: [\n      {\n        name: 'Login',\n        path: 'login',\n        component: () => import('#/views/_core/authentication/login.vue'),\n        meta: {\n          title: $t('page.auth.login'),\n        },\n      },\n      {\n        name: 'CodeLogin',\n        path: 'code-login',\n        component: () => import('#/views/_core/authentication/code-login.vue'),\n        meta: {\n          title: $t('page.auth.codeLogin'),\n        },\n      },\n      {\n        name: 'QrCodeLogin',\n        path: 'qrcode-login',\n        component: () =>\n          import('#/views/_core/authentication/qrcode-login.vue'),\n        meta: {\n          title: $t('page.auth.qrcodeLogin'),\n        },\n      },\n      {\n        name: 'ForgetPassword',\n        path: 'forget-password',\n        component: () =>\n          import('#/views/_core/authentication/forget-password.vue'),\n        meta: {\n          title: $t('page.auth.forgetPassword'),\n        },\n      },\n      {\n        name: 'Register',\n        path: 'register',\n        component: () => import('#/views/_core/authentication/register.vue'),\n        meta: {\n          title: $t('page.auth.register'),\n        },\n      },\n    ],\n  },\n];\n\nexport { coreRoutes, fallbackNotFoundRoute };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/router/routes/index.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { mergeRouteModules, traverseTreeValues } from '@vben/utils';\n\nimport { coreRoutes, fallbackNotFoundRoute } from './core';\n\nconst dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {\n  eager: true,\n});\n\n// 有需要可以自行打开注释，并创建文件夹\n// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });\n// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });\n\n/** 动态路由 */\nconst dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);\n\n/** 外部路由列表，访问这些页面可以不需要Layout，可能用于内嵌在别的系统(不会显示在菜单中) */\n// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);\n// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);\nconst staticRoutes: RouteRecordRaw[] = [];\nconst externalRoutes: RouteRecordRaw[] = [];\n\n/** 路由列表，由基本路由、外部路由和404兜底路由组成\n *  无需走权限验证（会一直显示在菜单中） */\nconst routes: RouteRecordRaw[] = [\n  ...coreRoutes,\n  ...externalRoutes,\n  fallbackNotFoundRoute,\n];\n\n/** 基本路由列表，这些路由不需要进入权限拦截 */\nconst coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);\n\n/** 有权限校验的路由列表，包含动态路由和静态路由 */\nconst accessRoutes = [...dynamicRoutes, ...staticRoutes];\nexport { accessRoutes, coreRouteNames, routes };\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/router/routes/modules/dashboard.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'lucide:layout-dashboard',\n      order: -1,\n      title: $t('page.dashboard.title'),\n    },\n    name: 'Dashboard',\n    path: '/dashboard',\n    children: [\n      {\n        name: 'Analytics',\n        path: '/analytics',\n        component: () => import('#/views/dashboard/analytics/index.vue'),\n        meta: {\n          affixTab: true,\n          icon: 'lucide:area-chart',\n          title: $t('page.dashboard.analytics'),\n        },\n      },\n      {\n        name: 'Workspace',\n        path: '/workspace',\n        component: () => import('#/views/dashboard/workspace/index.vue'),\n        meta: {\n          icon: 'carbon:workspace',\n          title: $t('page.dashboard.workspace'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/router/routes/modules/demos.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'ic:baseline-view-in-ar',\n      keepAlive: true,\n      order: 1000,\n      title: $t('demos.title'),\n    },\n    name: 'Demos',\n    path: '/demos',\n    children: [\n      {\n        meta: {\n          title: $t('demos.antd'),\n        },\n        name: 'AntDesignDemos',\n        path: '/demos/ant-design',\n        component: () => import('#/views/demos/antd/index.vue'),\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/router/routes/modules/vben.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport {\n  VBEN_DOC_URL,\n  VBEN_ELE_PREVIEW_URL,\n  VBEN_GITHUB_URL,\n  VBEN_LOGO_URL,\n  VBEN_NAIVE_PREVIEW_URL,\n} from '@vben/constants';\n\nimport { IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      badgeType: 'dot',\n      icon: VBEN_LOGO_URL,\n      order: 9998,\n      title: $t('demos.vben.title'),\n    },\n    name: 'VbenProject',\n    path: '/vben-admin',\n    children: [\n      {\n        name: 'VbenDocument',\n        path: '/vben-admin/document',\n        component: IFrameView,\n        meta: {\n          icon: 'lucide:book-open-text',\n          link: VBEN_DOC_URL,\n          title: $t('demos.vben.document'),\n        },\n      },\n      {\n        name: 'VbenGithub',\n        path: '/vben-admin/github',\n        component: IFrameView,\n        meta: {\n          icon: 'mdi:github',\n          link: VBEN_GITHUB_URL,\n          title: 'Github',\n        },\n      },\n      {\n        name: 'VbenNaive',\n        path: '/vben-admin/naive',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: 'logos:naiveui',\n          link: VBEN_NAIVE_PREVIEW_URL,\n          title: $t('demos.vben.naive-ui'),\n        },\n      },\n      {\n        name: 'VbenElementPlus',\n        path: '/vben-admin/ele',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: 'logos:element',\n          link: VBEN_ELE_PREVIEW_URL,\n          title: $t('demos.vben.element-plus'),\n        },\n      },\n    ],\n  },\n  {\n    name: 'VbenAbout',\n    path: '/vben-admin/about',\n    component: () => import('#/views/_core/about/index.vue'),\n    meta: {\n      icon: 'lucide:copyright',\n      title: $t('demos.vben.about'),\n      order: 9999,\n    },\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/store/auth.ts",
    "content": "import type { Recordable, UserInfo } from '@vben/types';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';\n\nimport { notification } from 'ant-design-vue';\nimport { defineStore } from 'pinia';\n\nimport { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';\nimport { $t } from '#/locales';\n\nexport const useAuthStore = defineStore('auth', () => {\n  const accessStore = useAccessStore();\n  const userStore = useUserStore();\n  const router = useRouter();\n\n  const loginLoading = ref(false);\n\n  /**\n   * 异步处理登录操作\n   * Asynchronously handle the login process\n   * @param params 登录表单数据\n   */\n  async function authLogin(\n    params: Recordable<any>,\n    onSuccess?: () => Promise<void> | void,\n  ) {\n    // 异步处理用户登录操作并获取 accessToken\n    let userInfo: null | UserInfo = null;\n    try {\n      loginLoading.value = true;\n      const { accessToken } = await loginApi(params);\n\n      // 如果成功获取到 accessToken\n      if (accessToken) {\n        accessStore.setAccessToken(accessToken);\n\n        // 获取用户信息并存储到 accessStore 中\n        const [fetchUserInfoResult, accessCodes] = await Promise.all([\n          fetchUserInfo(),\n          getAccessCodesApi(),\n        ]);\n\n        userInfo = fetchUserInfoResult;\n\n        userStore.setUserInfo(userInfo);\n        accessStore.setAccessCodes(accessCodes);\n\n        if (accessStore.loginExpired) {\n          accessStore.setLoginExpired(false);\n        } else {\n          onSuccess\n            ? await onSuccess?.()\n            : await router.push(\n                userInfo.homePath || preferences.app.defaultHomePath,\n              );\n        }\n\n        if (userInfo?.realName) {\n          notification.success({\n            description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,\n            duration: 3,\n            message: $t('authentication.loginSuccess'),\n          });\n        }\n      }\n    } finally {\n      loginLoading.value = false;\n    }\n\n    return {\n      userInfo,\n    };\n  }\n\n  async function logout(redirect: boolean = true) {\n    try {\n      await logoutApi();\n    } catch {\n      // 不做任何处理\n    }\n    resetAllStores();\n    accessStore.setLoginExpired(false);\n\n    // 回登录页带上当前路由地址\n    await router.replace({\n      path: LOGIN_PATH,\n      query: redirect\n        ? {\n            redirect: encodeURIComponent(router.currentRoute.value.fullPath),\n          }\n        : {},\n    });\n  }\n\n  async function fetchUserInfo() {\n    let userInfo: null | UserInfo = null;\n    userInfo = await getUserInfoApi();\n    userStore.setUserInfo(userInfo);\n    return userInfo;\n  }\n\n  function $reset() {\n    loginLoading.value = false;\n  }\n\n  return {\n    $reset,\n    authLogin,\n    fetchUserInfo,\n    loginLoading,\n    logout,\n  };\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/store/index.ts",
    "content": "export * from './auth';\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/README.md",
    "content": "# \\_core\n\n此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/about/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { About } from '@vben/common-ui';\n\ndefineOptions({ name: 'About' });\n</script>\n\n<template>\n  <About />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/authentication/code-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, ref } from 'vue';\n\nimport { AuthenticationCodeLogin, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'CodeLogin' });\n\nconst loading = ref(false);\nconst CODE_LENGTH = 6;\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.mobile'),\n      },\n      fieldName: 'phoneNumber',\n      label: $t('authentication.mobile'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.mobileTip') })\n        .refine((v) => /^\\d{11}$/.test(v), {\n          message: $t('authentication.mobileErrortip'),\n        }),\n    },\n    {\n      component: 'VbenPinInput',\n      componentProps: {\n        codeLength: CODE_LENGTH,\n        createText: (countdown: number) => {\n          const text =\n            countdown > 0\n              ? $t('authentication.sendText', [countdown])\n              : $t('authentication.sendCode');\n          return text;\n        },\n        placeholder: $t('authentication.code'),\n      },\n      fieldName: 'code',\n      label: $t('authentication.code'),\n      rules: z.string().length(CODE_LENGTH, {\n        message: $t('authentication.codeTip', [CODE_LENGTH]),\n      }),\n    },\n  ];\n});\n/**\n * 异步处理登录操作\n * Asynchronously handle the login process\n * @param values 登录表单数据\n */\nasync function handleLogin(values: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log(values);\n}\n</script>\n\n<template>\n  <AuthenticationCodeLogin\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/authentication/forget-password.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, ref } from 'vue';\n\nimport { AuthenticationForgetPassword, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'ForgetPassword' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: 'example@example.com',\n      },\n      fieldName: 'email',\n      label: $t('authentication.email'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.emailTip') })\n        .email($t('authentication.emailValidErrorTip')),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log('reset email:', value);\n}\n</script>\n\n<template>\n  <AuthenticationForgetPassword\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/authentication/login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { BasicOption } from '@vben/types';\n\nimport { computed, markRaw } from 'vue';\n\nimport { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { useAuthStore } from '#/store';\n\ndefineOptions({ name: 'Login' });\n\nconst authStore = useAuthStore();\n\nconst MOCK_USER_OPTIONS: BasicOption[] = [\n  {\n    label: 'Super',\n    value: 'vben',\n  },\n  {\n    label: 'Admin',\n    value: 'admin',\n  },\n  {\n    label: 'User',\n    value: 'jack',\n  },\n];\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenSelect',\n      componentProps: {\n        options: MOCK_USER_OPTIONS,\n        placeholder: $t('authentication.selectAccount'),\n      },\n      fieldName: 'selectAccount',\n      label: $t('authentication.selectAccount'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.selectAccount') })\n        .optional()\n        .default('vben'),\n    },\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.usernameTip'),\n      },\n      dependencies: {\n        trigger(values, form) {\n          if (values.selectAccount) {\n            const findUser = MOCK_USER_OPTIONS.find(\n              (item) => item.value === values.selectAccount,\n            );\n            if (findUser) {\n              form.setValues({\n                password: '123456',\n                username: findUser.value,\n              });\n            }\n          }\n        },\n        triggerFields: ['selectAccount'],\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: markRaw(SliderCaptcha),\n      fieldName: 'captcha',\n      rules: z.boolean().refine((value) => value, {\n        message: $t('authentication.verifyRequiredTip'),\n      }),\n    },\n  ];\n});\n</script>\n\n<template>\n  <AuthenticationLogin\n    :form-schema=\"formSchema\"\n    :loading=\"authStore.loginLoading\"\n    @submit=\"authStore.authLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/authentication/qrcode-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport { AuthenticationQrCodeLogin } from '@vben/common-ui';\nimport { LOGIN_PATH } from '@vben/constants';\n\ndefineOptions({ name: 'QrCodeLogin' });\n</script>\n\n<template>\n  <AuthenticationQrCodeLogin :login-path=\"LOGIN_PATH\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/authentication/register.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, h, ref } from 'vue';\n\nimport { AuthenticationRegister, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'Register' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.usernameTip'),\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        passwordStrength: true,\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      renderComponentContent() {\n        return {\n          strengthText: () => $t('authentication.passwordStrength'),\n        };\n      },\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.confirmPassword'),\n      },\n      dependencies: {\n        rules(values) {\n          const { password } = values;\n          return z\n            .string({ required_error: $t('authentication.passwordTip') })\n            .min(1, { message: $t('authentication.passwordTip') })\n            .refine((value) => value === password, {\n              message: $t('authentication.confirmPasswordTip'),\n            });\n        },\n        triggerFields: ['password'],\n      },\n      fieldName: 'confirmPassword',\n      label: $t('authentication.confirmPassword'),\n    },\n    {\n      component: 'VbenCheckbox',\n      fieldName: 'agreePolicy',\n      renderComponentContent: () => ({\n        default: () =>\n          h('span', [\n            $t('authentication.agree'),\n            h(\n              'a',\n              {\n                class: 'vben-link ml-1 ',\n                href: '',\n              },\n              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,\n            ),\n          ]),\n      }),\n      rules: z.boolean().refine((value) => !!value, {\n        message: $t('authentication.agreeTip'),\n      }),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log('register submit:', value);\n}\n</script>\n\n<template>\n  <AuthenticationRegister\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/fallback/coming-soon.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/fallback/forbidden.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback403Demo' });\n</script>\n\n<template>\n  <Fallback status=\"403\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/fallback/internal-error.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback500Demo' });\n</script>\n\n<template>\n  <Fallback status=\"500\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/fallback/not-found.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback404Demo' });\n</script>\n\n<template>\n  <Fallback status=\"404\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/_core/fallback/offline.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'FallbackOfflineDemo' });\n</script>\n\n<template>\n  <Fallback status=\"offline\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/dashboard/analytics/analytics-trends.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        areaStyle: {},\n        data: [\n          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,\n          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,\n          111,\n        ],\n        itemStyle: {\n          color: '#5ab1ef',\n        },\n        smooth: true,\n        type: 'line',\n      },\n      {\n        areaStyle: {},\n        data: [\n          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,\n          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,\n        ],\n        itemStyle: {\n          color: '#019680',\n        },\n        smooth: true,\n        type: 'line',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          color: '#019680',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    // xAxis: {\n    //   axisTick: {\n    //     show: false,\n    //   },\n    //   boundaryGap: false,\n    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n    //   type: 'category',\n    // },\n    xAxis: {\n      axisTick: {\n        show: false,\n      },\n      boundaryGap: false,\n      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n      splitLine: {\n        lineStyle: {\n          type: 'solid',\n          width: 1,\n        },\n        show: true,\n      },\n      type: 'category',\n    },\n    yAxis: [\n      {\n        axisTick: {\n          show: false,\n        },\n        max: 80_000,\n        splitArea: {\n          show: true,\n        },\n        splitNumber: 4,\n        type: 'value',\n      },\n    ],\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/dashboard/analytics/analytics-visits-data.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: 0,\n      data: ['访问', '趋势'],\n    },\n    radar: {\n      indicator: [\n        {\n          name: '网页',\n        },\n        {\n          name: '移动端',\n        },\n        {\n          name: 'Ipad',\n        },\n        {\n          name: '客户端',\n        },\n        {\n          name: '第三方',\n        },\n        {\n          name: '其它',\n        },\n      ],\n      radius: '60%',\n      splitNumber: 8,\n    },\n    series: [\n      {\n        areaStyle: {\n          opacity: 1,\n          shadowBlur: 0,\n          shadowColor: 'rgba(0,0,0,.2)',\n          shadowOffsetX: 0,\n          shadowOffsetY: 10,\n        },\n        data: [\n          {\n            itemStyle: {\n              color: '#b6a2de',\n            },\n            name: '访问',\n            value: [90, 50, 86, 40, 50, 20],\n          },\n          {\n            itemStyle: {\n              color: '#5ab1ef',\n            },\n            name: '趋势',\n            value: [70, 75, 70, 76, 20, 85],\n          },\n        ],\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        symbolSize: 0,\n        type: 'radar',\n      },\n    ],\n    tooltip: {},\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/dashboard/analytics/analytics-visits-sales.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 400;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        center: ['50%', '50%'],\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '外包', value: 500 },\n          { name: '定制', value: 310 },\n          { name: '技术支持', value: 274 },\n          { name: '远程', value: 400 },\n        ].sort((a, b) => {\n          return a.value - b.value;\n        }),\n        name: '商业占比',\n        radius: '80%',\n        roseType: 'radius',\n        type: 'pie',\n      },\n    ],\n\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/dashboard/analytics/analytics-visits-source.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: '2%',\n      left: 'center',\n    },\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 100;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        avoidLabelOverlap: false,\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '搜索引擎', value: 1048 },\n          { name: '直接访问', value: 735 },\n          { name: '邮件营销', value: 580 },\n          { name: '联盟广告', value: 484 },\n        ],\n        emphasis: {\n          label: {\n            fontSize: '12',\n            fontWeight: 'bold',\n            show: true,\n          },\n        },\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        label: {\n          position: 'center',\n          show: false,\n        },\n        labelLine: {\n          show: false,\n        },\n        name: '访问来源',\n        radius: ['40%', '65%'],\n        type: 'pie',\n      },\n    ],\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/dashboard/analytics/analytics-visits.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        barMaxWidth: 80,\n        // color: '#4f69fd',\n        data: [\n          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,\n          3200, 4800,\n        ],\n        type: 'bar',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          // color: '#4f69fd',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    xAxis: {\n      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}月`),\n      type: 'category',\n    },\n    yAxis: {\n      max: 8000,\n      splitNumber: 4,\n      type: 'value',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/dashboard/analytics/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { AnalysisOverviewItem } from '@vben/common-ui';\nimport type { TabOption } from '@vben/types';\n\nimport {\n  AnalysisChartCard,\n  AnalysisChartsTabs,\n  AnalysisOverview,\n} from '@vben/common-ui';\nimport {\n  SvgBellIcon,\n  SvgCakeIcon,\n  SvgCardIcon,\n  SvgDownloadIcon,\n} from '@vben/icons';\n\nimport AnalyticsTrends from './analytics-trends.vue';\nimport AnalyticsVisitsData from './analytics-visits-data.vue';\nimport AnalyticsVisitsSales from './analytics-visits-sales.vue';\nimport AnalyticsVisitsSource from './analytics-visits-source.vue';\nimport AnalyticsVisits from './analytics-visits.vue';\n\nconst overviewItems: AnalysisOverviewItem[] = [\n  {\n    icon: SvgCardIcon,\n    title: '用户量',\n    totalTitle: '总用户量',\n    totalValue: 120_000,\n    value: 2000,\n  },\n  {\n    icon: SvgCakeIcon,\n    title: '访问量',\n    totalTitle: '总访问量',\n    totalValue: 500_000,\n    value: 20_000,\n  },\n  {\n    icon: SvgDownloadIcon,\n    title: '下载量',\n    totalTitle: '总下载量',\n    totalValue: 120_000,\n    value: 8000,\n  },\n  {\n    icon: SvgBellIcon,\n    title: '使用量',\n    totalTitle: '总使用量',\n    totalValue: 50_000,\n    value: 5000,\n  },\n];\n\nconst chartTabs: TabOption[] = [\n  {\n    label: '流量趋势',\n    value: 'trends',\n  },\n  {\n    label: '月访问量',\n    value: 'visits',\n  },\n];\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <AnalysisOverview :items=\"overviewItems\" />\n    <AnalysisChartsTabs :tabs=\"chartTabs\" class=\"mt-5\">\n      <template #trends>\n        <AnalyticsTrends />\n      </template>\n      <template #visits>\n        <AnalyticsVisits />\n      </template>\n    </AnalysisChartsTabs>\n\n    <div class=\"mt-5 w-full md:flex\">\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问数量\">\n        <AnalyticsVisitsData />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSource />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSales />\n      </AnalysisChartCard>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/dashboard/workspace/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  WorkbenchProjectItem,\n  WorkbenchQuickNavItem,\n  WorkbenchTodoItem,\n  WorkbenchTrendItem,\n} from '@vben/common-ui';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport {\n  AnalysisChartCard,\n  WorkbenchHeader,\n  WorkbenchProject,\n  WorkbenchQuickNav,\n  WorkbenchTodo,\n  WorkbenchTrends,\n} from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';\n\nconst userStore = useUserStore();\n\n// 这是一个示例数据，实际项目中需要根据实际情况进行调整\n// url 也可以是内部路由，在 navTo 方法中识别处理，进行内部跳转\n// 例如：url: /dashboard/workspace\nconst projectItems: WorkbenchProjectItem[] = [\n  {\n    color: '',\n    content: '不要等待机会，而要创造机会。',\n    date: '2021-04-01',\n    group: '开源组',\n    icon: 'carbon:logo-github',\n    title: 'Github',\n    url: 'https://github.com',\n  },\n  {\n    color: '#3fb27f',\n    content: '现在的你决定将来的你。',\n    date: '2021-04-01',\n    group: '算法组',\n    icon: 'ion:logo-vue',\n    title: 'Vue',\n    url: 'https://vuejs.org',\n  },\n  {\n    color: '#e18525',\n    content: '没有什么才能比努力更重要。',\n    date: '2021-04-01',\n    group: '上班摸鱼',\n    icon: 'ion:logo-html5',\n    title: 'Html5',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',\n  },\n  {\n    color: '#bf0c2c',\n    content: '热情和欲望可以突破一切难关。',\n    date: '2021-04-01',\n    group: 'UI',\n    icon: 'ion:logo-angular',\n    title: 'Angular',\n    url: 'https://angular.io',\n  },\n  {\n    color: '#00d8ff',\n    content: '健康的身体是实现目标的基石。',\n    date: '2021-04-01',\n    group: '技术牛',\n    icon: 'bx:bxl-react',\n    title: 'React',\n    url: 'https://reactjs.org',\n  },\n  {\n    color: '#EBD94E',\n    content: '路是走出来的，而不是空想出来的。',\n    date: '2021-04-01',\n    group: '架构组',\n    icon: 'ion:logo-javascript',\n    title: 'Js',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',\n  },\n];\n\n// 同样，这里的 url 也可以使用以 http 开头的外部链接\nconst quickNavItems: WorkbenchQuickNavItem[] = [\n  {\n    color: '#1fdaca',\n    icon: 'ion:home-outline',\n    title: '首页',\n    url: '/',\n  },\n  {\n    color: '#bf0c2c',\n    icon: 'ion:grid-outline',\n    title: '仪表盘',\n    url: '/dashboard',\n  },\n  {\n    color: '#e18525',\n    icon: 'ion:layers-outline',\n    title: '组件',\n    url: '/demos/features/icons',\n  },\n  {\n    color: '#3fb27f',\n    icon: 'ion:settings-outline',\n    title: '系统管理',\n    url: '/demos/features/login-expired', // 这里的 URL 是示例，实际项目中需要根据实际情况进行调整\n  },\n  {\n    color: '#4daf1bc9',\n    icon: 'ion:key-outline',\n    title: '权限管理',\n    url: '/demos/access/page-control',\n  },\n  {\n    color: '#00d8ff',\n    icon: 'ion:bar-chart-outline',\n    title: '图表',\n    url: '/analytics',\n  },\n];\n\nconst todoItems = ref<WorkbenchTodoItem[]>([\n  {\n    completed: false,\n    content: `审查最近提交到Git仓库的前端代码，确保代码质量和规范。`,\n    date: '2024-07-30 11:00:00',\n    title: '审查前端代码提交',\n  },\n  {\n    completed: true,\n    content: `检查并优化系统性能，降低CPU使用率。`,\n    date: '2024-07-30 11:00:00',\n    title: '系统性能优化',\n  },\n  {\n    completed: false,\n    content: `进行系统安全检查，确保没有安全漏洞或未授权的访问。 `,\n    date: '2024-07-30 11:00:00',\n    title: '安全检查',\n  },\n  {\n    completed: false,\n    content: `更新项目中的所有npm依赖包，确保使用最新版本。`,\n    date: '2024-07-30 11:00:00',\n    title: '更新项目依赖',\n  },\n  {\n    completed: false,\n    content: `修复用户报告的页面UI显示问题，确保在不同浏览器中显示一致。 `,\n    date: '2024-07-30 11:00:00',\n    title: '修复UI显示问题',\n  },\n]);\nconst trendItems: WorkbenchTrendItem[] = [\n  {\n    avatar: 'svg:avatar-1',\n    content: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,\n    date: '刚刚',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关注了 <a>威廉</a> `,\n    date: '1个小时前',\n    title: '艾文',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1天前',\n    title: '克里斯',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写一个Vite插件</a> `,\n    date: '2天前',\n    title: 'Vben',\n  },\n  {\n    avatar: 'svg:avatar-1',\n    content: `回复了 <a>杰克</a> 的问题 <a>如何进行项目优化？</a>`,\n    date: '3天前',\n    title: '皮特',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关闭了问题 <a>如何运行项目</a> `,\n    date: '1周前',\n    title: '杰克',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1周前',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `推送了代码到 <a>Github</a>`,\n    date: '2021-04-01 20:00',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写使用 Admin Vben</a> `,\n    date: '2021-03-01 20:00',\n    title: 'Vben',\n  },\n];\n\nconst router = useRouter();\n\n// 这是一个示例方法，实际项目中需要根据实际情况进行调整\n// This is a sample method, adjust according to the actual project requirements\nfunction navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {\n  if (nav.url?.startsWith('http')) {\n    openWindow(nav.url);\n    return;\n  }\n  if (nav.url?.startsWith('/')) {\n    router.push(nav.url).catch((error) => {\n      console.error('Navigation failed:', error);\n    });\n  } else {\n    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);\n  }\n}\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <WorkbenchHeader\n      :avatar=\"userStore.userInfo?.avatar || preferences.app.defaultAvatar\"\n    >\n      <template #title>\n        早安, {{ userStore.userInfo?.realName }}, 开始您一天的工作吧！\n      </template>\n      <template #description> 今日晴，20℃ - 32℃！ </template>\n    </WorkbenchHeader>\n\n    <div class=\"mt-5 flex flex-col lg:flex-row\">\n      <div class=\"mr-4 w-full lg:w-3/5\">\n        <WorkbenchProject :items=\"projectItems\" title=\"项目\" @click=\"navTo\" />\n        <WorkbenchTrends :items=\"trendItems\" class=\"mt-5\" title=\"最新动态\" />\n      </div>\n      <div class=\"w-full lg:w-2/5\">\n        <WorkbenchQuickNav\n          :items=\"quickNavItems\"\n          class=\"mt-5 lg:mt-0\"\n          title=\"快捷导航\"\n          @click=\"navTo\"\n        />\n        <WorkbenchTodo :items=\"todoItems\" class=\"mt-5\" title=\"待办事项\" />\n        <AnalysisChartCard class=\"mt-5\" title=\"访问来源\">\n          <AnalyticsVisitsSource />\n        </AnalysisChartCard>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/src/views/demos/antd/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Page } from '@vben/common-ui';\n\nimport { Button, Card, message, notification, Space } from 'ant-design-vue';\n\ntype NotificationType = 'error' | 'info' | 'success' | 'warning';\n\nfunction info() {\n  message.info('How many roads must a man walk down');\n}\n\nfunction error() {\n  message.error({\n    content: 'Once upon a time you dressed so fine',\n    duration: 2500,\n  });\n}\n\nfunction warning() {\n  message.warning('How many roads must a man walk down');\n}\nfunction success() {\n  message.success('Cause you walked hand in hand With another man in my place');\n}\n\nfunction notify(type: NotificationType) {\n  notification[type]({\n    duration: 2500,\n    message: '说点啥呢',\n    type,\n  });\n}\n</script>\n\n<template>\n  <Page\n    description=\"支持多语言，主题功能集成切换等\"\n    title=\"Ant Design Vue组件使用演示\"\n  >\n    <Card class=\"mb-5\" title=\"按钮\">\n      <Space>\n        <Button>Default</Button>\n        <Button type=\"primary\"> Primary </Button>\n        <Button> Info </Button>\n        <Button danger> Error </Button>\n      </Space>\n    </Card>\n    <Card class=\"mb-5\" title=\"Message\">\n      <Space>\n        <Button @click=\"info\"> 信息 </Button>\n        <Button danger @click=\"error\"> 错误 </Button>\n        <Button @click=\"warning\"> 警告 </Button>\n        <Button @click=\"success\"> 成功 </Button>\n      </Space>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"Notification\">\n      <Space>\n        <Button @click=\"notify('info')\"> 信息 </Button>\n        <Button danger @click=\"notify('error')\"> 错误 </Button>\n        <Button @click=\"notify('warning')\"> 警告 </Button>\n        <Button @click=\"notify('success')\"> 成功 </Button>\n      </Space>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web-app.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"#/*\": [\"./src/*\"]\n    }\n  },\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }],\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/tsconfig.node.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n    \"noEmit\": false\n  },\n  \"include\": [\"vite.config.mts\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-antd/vite.config.mts",
    "content": "import { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    application: {},\n    vite: {\n      server: {\n        proxy: {\n          '/api': {\n            changeOrigin: true,\n            rewrite: (path) => path.replace(/^\\/api/, ''),\n            // mock代理目标地址\n            target: 'http://localhost:5320/api',\n            ws: true,\n          },\n        },\n      },\n    },\n  };\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/index.html",
    "content": "<!doctype html>\n<html lang=\"zh\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n    <meta name=\"renderer\" content=\"webkit\" />\n    <meta name=\"description\" content=\"A Modern Back-end Management System\" />\n    <meta name=\"keywords\" content=\"Vben Admin Vue3 Vite\" />\n    <meta name=\"author\" content=\"Vben\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0\"\n    />\n    <!-- 由 vite 注入 VITE_APP_TITLE 变量，在 .env 文件内配置 -->\n    <title><%= VITE_APP_TITLE %></title>\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <script>\n      // 生产环境下注入百度统计\n      if (window._VBEN_ADMIN_PRO_APP_CONF_) {\n        var _hmt = _hmt || [];\n        (function () {\n          var hm = document.createElement('script');\n          hm.src =\n            'https://hm.baidu.com/hm.js?b38e689f40558f20a9a686d7f6f33edf';\n          var s = document.getElementsByTagName('script')[0];\n          s.parentNode.insertBefore(hm, s);\n        })();\n      }\n    </script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/package.json",
    "content": "{\n  \"name\": \"@vben/web-auth\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://vben.pro\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"apps/web-auth\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"vben\",\n    \"email\": \"ann.vben@gmail.com\",\n    \"url\": \"https://github.com/anncwb\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm vite build --mode production\",\n    \"build:analyze\": \"pnpm vite build --mode analyze\",\n    \"dev\": \"pnpm vite --mode development\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"vue-tsc --noEmit --skipLibCheck\"\n  },\n  \"imports\": {\n    \"#/*\": \"./src/*\"\n  },\n  \"dependencies\": {\n    \"@vben/access\": \"workspace:*\",\n    \"@vben/common-ui\": \"workspace:*\",\n    \"@vben/constants\": \"workspace:*\",\n    \"@vben/hooks\": \"workspace:*\",\n    \"@vben/icons\": \"workspace:*\",\n    \"@vben/layouts\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/plugins\": \"workspace:*\",\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/request\": \"workspace:*\",\n    \"@vben/stores\": \"workspace:*\",\n    \"@vben/styles\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"ant-design-vue\": \"catalog:\",\n    \"dayjs\": \"catalog:\",\n    \"jsencrypt\": \"^3.3.2\",\n    \"pinia\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/adapter/component/index.ts",
    "content": "/**\n * 通用组件共同的使用的基础组件，原先放在 adapter/form 内部，限制了使用范围，这里提取出来，方便其他地方使用\n * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,\n */\n\nimport type { Component } from 'vue';\n\nimport type { BaseFormComponentType } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { defineAsyncComponent, defineComponent, h, ref } from 'vue';\n\nimport { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { notification } from 'ant-design-vue';\n\nconst AutoComplete = defineAsyncComponent(\n  () => import('ant-design-vue/es/auto-complete'),\n);\nconst Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));\nconst Checkbox = defineAsyncComponent(\n  () => import('ant-design-vue/es/checkbox'),\n);\nconst CheckboxGroup = defineAsyncComponent(() =>\n  import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),\n);\nconst DatePicker = defineAsyncComponent(\n  () => import('ant-design-vue/es/date-picker'),\n);\nconst Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));\nconst Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));\nconst InputNumber = defineAsyncComponent(\n  () => import('ant-design-vue/es/input-number'),\n);\nconst InputPassword = defineAsyncComponent(() =>\n  import('ant-design-vue/es/input').then((res) => res.InputPassword),\n);\nconst Mentions = defineAsyncComponent(\n  () => import('ant-design-vue/es/mentions'),\n);\nconst Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));\nconst RadioGroup = defineAsyncComponent(() =>\n  import('ant-design-vue/es/radio').then((res) => res.RadioGroup),\n);\nconst RangePicker = defineAsyncComponent(() =>\n  import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),\n);\nconst Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));\nconst Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));\nconst Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));\nconst Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));\nconst Textarea = defineAsyncComponent(() =>\n  import('ant-design-vue/es/input').then((res) => res.Textarea),\n);\nconst TimePicker = defineAsyncComponent(\n  () => import('ant-design-vue/es/time-picker'),\n);\nconst TreeSelect = defineAsyncComponent(\n  () => import('ant-design-vue/es/tree-select'),\n);\nconst Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));\n\nconst withDefaultPlaceholder = <T extends Component>(\n  component: T,\n  type: 'input' | 'select',\n  componentProps: Recordable<any> = {},\n) => {\n  return defineComponent({\n    name: component.name,\n    inheritAttrs: false,\n    setup: (props: any, { attrs, expose, slots }) => {\n      const placeholder =\n        props?.placeholder ||\n        attrs?.placeholder ||\n        $t(`ui.placeholder.${type}`);\n      // 透传组件暴露的方法\n      const innerRef = ref();\n      expose(\n        new Proxy(\n          {},\n          {\n            get: (_target, key) => innerRef.value?.[key],\n            has: (_target, key) => key in (innerRef.value || {}),\n          },\n        ),\n      );\n      return () =>\n        h(\n          component,\n          { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },\n          slots,\n        );\n    },\n  });\n};\n\n// 这里需要自行根据业务组件库进行适配，需要用到的组件都需要在这里类型说明\nexport type ComponentType =\n  | 'ApiSelect'\n  | 'ApiTreeSelect'\n  | 'AutoComplete'\n  | 'Checkbox'\n  | 'CheckboxGroup'\n  | 'DatePicker'\n  | 'DefaultButton'\n  | 'Divider'\n  | 'IconPicker'\n  | 'Input'\n  | 'InputNumber'\n  | 'InputPassword'\n  | 'Mentions'\n  | 'PrimaryButton'\n  | 'Radio'\n  | 'RadioGroup'\n  | 'RangePicker'\n  | 'Rate'\n  | 'Select'\n  | 'Space'\n  | 'Switch'\n  | 'Textarea'\n  | 'TimePicker'\n  | 'TreeSelect'\n  | 'Upload'\n  | BaseFormComponentType;\n\nasync function initComponentAdapter() {\n  const components: Partial<Record<ComponentType, Component>> = {\n    // 如果你的组件体积比较大，可以使用异步加载\n    // Button: () =>\n    // import('xxx').then((res) => res.Button),\n    ApiSelect: withDefaultPlaceholder(\n      {\n        ...ApiComponent,\n        name: 'ApiSelect',\n      },\n      'select',\n      {\n        component: Select,\n        loadingSlot: 'suffixIcon',\n        visibleEvent: 'onDropdownVisibleChange',\n        modelPropName: 'value',\n      },\n    ),\n    ApiTreeSelect: withDefaultPlaceholder(\n      {\n        ...ApiComponent,\n        name: 'ApiTreeSelect',\n      },\n      'select',\n      {\n        component: TreeSelect,\n        fieldNames: { label: 'label', value: 'value', children: 'children' },\n        loadingSlot: 'suffixIcon',\n        modelPropName: 'value',\n        optionsPropName: 'treeData',\n        visibleEvent: 'onVisibleChange',\n      },\n    ),\n    AutoComplete,\n    Checkbox,\n    CheckboxGroup,\n    DatePicker,\n    // 自定义默认按钮\n    DefaultButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'default' }, slots);\n    },\n    Divider,\n    IconPicker: withDefaultPlaceholder(IconPicker, 'select', {\n      iconSlot: 'addonAfter',\n      inputComponent: Input,\n      modelValueProp: 'value',\n    }),\n    Input: withDefaultPlaceholder(Input, 'input'),\n    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),\n    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),\n    Mentions: withDefaultPlaceholder(Mentions, 'input'),\n    // 自定义主要按钮\n    PrimaryButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'primary' }, slots);\n    },\n    Radio,\n    RadioGroup,\n    RangePicker,\n    Rate,\n    Select: withDefaultPlaceholder(Select, 'select'),\n    Space,\n    Switch,\n    Textarea: withDefaultPlaceholder(Textarea, 'input'),\n    TimePicker,\n    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),\n    Upload,\n  };\n\n  // 将组件注册到全局共享状态中\n  globalShareState.setComponents(components);\n\n  // 定义全局共享状态中的消息提示\n  globalShareState.defineMessage({\n    // 复制成功消息提示\n    copyPreferencesSuccess: (title, content) => {\n      notification.success({\n        description: content,\n        message: title,\n        placement: 'bottomRight',\n      });\n    },\n  });\n}\n\nexport { initComponentAdapter };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/adapter/form.ts",
    "content": "import type {\n  VbenFormSchema as FormSchema,\n  VbenFormProps,\n} from '@vben/common-ui';\n\nimport type { ComponentType } from './component';\n\nimport { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nasync function initSetupVbenForm() {\n  setupVbenForm<ComponentType>({\n    config: {\n      // ant design vue组件库默认都是 v-model:value\n      baseModelPropName: 'value',\n\n      // 一些组件是 v-model:checked 或者 v-model:fileList\n      modelPropNameMap: {\n        Checkbox: 'checked',\n        Radio: 'checked',\n        Switch: 'checked',\n        Upload: 'fileList',\n      },\n    },\n    defineRules: {\n      // 输入项目必填国际化适配\n      required: (value, _params, ctx) => {\n        if (value === undefined || value === null || value.length === 0) {\n          return $t('ui.formRules.required', [ctx.label]);\n        }\n        return true;\n      },\n      // 选择项目必填国际化适配\n      selectRequired: (value, _params, ctx) => {\n        if (value === undefined || value === null) {\n          return $t('ui.formRules.selectRequired', [ctx.label]);\n        }\n        return true;\n      },\n    },\n  });\n}\n\nconst useVbenForm = useForm<ComponentType>;\n\nexport { initSetupVbenForm, useVbenForm, z };\n\nexport type VbenFormSchema = FormSchema<ComponentType>;\nexport type { VbenFormProps };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/adapter/vxe-table.ts",
    "content": "import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';\n\nimport { h } from 'vue';\n\nimport { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';\n\nimport { Button, Image } from 'ant-design-vue';\n\nimport { useVbenForm } from './form';\n\nsetupVbenVxeTable({\n  configVxeTable: (vxeUI) => {\n    vxeUI.setConfig({\n      grid: {\n        align: 'center',\n        border: false,\n        columnConfig: {\n          resizable: true,\n        },\n        minHeight: 180,\n        formConfig: {\n          // 全局禁用vxe-table的表单配置，使用formOptions\n          enabled: false,\n        },\n        proxyConfig: {\n          autoLoad: true,\n          response: {\n            result: 'items',\n            total: 'total',\n            list: 'items',\n          },\n          showActiveMsg: true,\n          showResponseMsg: false,\n        },\n        round: true,\n        showOverflow: true,\n        size: 'small',\n      } as VxeTableGridOptions,\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellImage' },\n    vxeUI.renderer.add('CellImage', {\n      renderTableDefault(_renderOpts, params) {\n        const { column, row } = params;\n        return h(Image, { src: row[column.field] });\n      },\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellLink' },\n    vxeUI.renderer.add('CellLink', {\n      renderTableDefault(renderOpts) {\n        const { props } = renderOpts;\n        return h(\n          Button,\n          { size: 'small', type: 'link' },\n          { default: () => props?.text },\n        );\n      },\n    });\n\n    // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化\n    // vxeUI.formats.add\n  },\n  useVbenForm,\n});\n\nexport { useVbenVxeGrid };\n\nexport type * from '@vben/plugins/vxe-table';\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/app.ts",
    "content": "import type { LimitDto, PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface AppPageDto extends PageDto {\n  name?: string;\n}\n\nexport interface AppLimitDto extends LimitDto {\n  name?: string;\n}\n\nexport interface AppCreateDto {\n  name?: string;\n  icon?: string;\n  remark?: string;\n}\n\nexport interface AppUpdateDto {\n  id: string;\n  name?: string;\n  icon?: string;\n  remark?: string;\n}\n\nexport interface AppVo {\n  id: string;\n  name: string;\n  icon: string;\n  createTime: string;\n  remark: string;\n}\n\nexport const pageAppApi = async (params: AppPageDto) => {\n  return requestClient.post<PageVo<AppVo>>('/api/common/appMgr/page', params);\n};\n\nexport const getAppByIdApi = async (id: string) => {\n  return requestClient.post<AppVo>(`/api/common/appMgr/findById?id=${id}`);\n};\n\n// 新增用户\nexport const createAppApi = async (params: AppCreateDto) => {\n  return requestClient.post<AppVo>('/api/common/appMgr/create', params);\n};\n\nexport const updateAppApi = async (params: AppUpdateDto) => {\n  return requestClient.post<AppVo>('/api/common/appMgr/update', params);\n};\n\nexport const deleteAppsApi = async (params: { ids: string[] }) => {\n  return requestClient.post('/api/common/appMgr/delete', params);\n};\n\nexport const limitAppApi = async (params: AppLimitDto) => {\n  return requestClient.post<AppVo[]>('/api/common/appMgr/limitList', params);\n};\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/appClient.ts",
    "content": "import type { AppVo } from '#/api/core/app';\nimport type { LimitDto, PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface AppClientPageDto extends PageDto {\n  cid?: string;\n  keyword?: string;\n}\n\nexport interface AppClientLimitDto extends LimitDto {\n  cid?: string;\n  name?: string;\n}\n\nexport interface AppClientCreateDto {\n  appIds: string[];\n  corpId?: string;\n}\n\nexport interface AppClientUpdateDto {\n  id: string;\n  clientId?: string;\n  clientSecret?: string;\n  clientName?: string;\n  redirectUris?: string;\n  scopes?: string;\n  accessTokenTimeToLive?: number;\n}\n\nexport interface AppClientDeleteDto {\n  appIds: string[];\n  corpId: string;\n}\n\nexport interface AppClientVo {\n  id: string;\n  cid: string;\n  appId: string;\n  name: string;\n  icon: string;\n  createTime: string;\n  remark: string;\n  clientId: string;\n  clientSecret: string;\n  clientName: string;\n  redirectUris: string[];\n  scopes: string;\n  accessTokenTimeToLive: number;\n}\n\nexport const pageAppClientApi = (params: AppClientPageDto) => {\n  return requestClient.post<PageVo<AppClientVo>>(\n    `/api/corpSpace/appClientMgr/page`,\n    params,\n  );\n};\n\nexport const getAppClientByIdApi = async (id: string) => {\n  return requestClient.post<AppClientVo>(\n    `/api/corpSpace/appClientMgr/findById?id=${id}`,\n  );\n};\n\n// 新增用户\nexport const addAppClientsApi = async (params: AppClientCreateDto) => {\n  return requestClient.post<AppClientVo>(\n    `/api/corpSpace/appClientMgr/add`,\n    params,\n  );\n};\n\nexport const createAppClientApi = async (params: AppClientCreateDto) => {\n  return requestClient.post<AppClientVo>(\n    `/api/corpSpace/appClientMgr/create`,\n    params,\n  );\n};\n\nexport const updateAppClientApi = async (params: AppClientUpdateDto) => {\n  return requestClient.post<AppClientVo>(\n    `/api/corpSpace/appClientMgr/update`,\n    params,\n  );\n};\n\nexport const deleteAppClientsApi = async (params: { ids: string[] }) => {\n  return requestClient.post(`/api/corpSpace/appClientMgr/delete`, params);\n};\n\nexport const limitHaveAppApi = async (params: AppClientLimitDto) => {\n  return requestClient.post<AppVo[]>(\n    `/api/corpSpace/appClientMgr/limitHaveApp`,\n    params,\n  );\n};\n\nexport const limitNotHaveAppApi = async (params: AppClientLimitDto) => {\n  return requestClient.post<AppVo[]>(\n    `/api/corpSpace/appClientMgr/limitNotHaveApp`,\n    params,\n  );\n};\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/appResource.ts",
    "content": "import type { PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface AppResourcePageDto extends PageDto {\n  appId: string;\n  pid?: string;\n  keyword?: string;\n  code?: string;\n  url?: string;\n  api?: string;\n  name?: string;\n  type?: number;\n}\n\nexport interface AppResourceCreateDto {\n  appId: string;\n  pid?: string;\n  code?: string;\n  url?: string;\n  api?: string;\n  name?: string;\n  type?: number;\n  remark?: string;\n  extend?: string;\n}\n\nexport interface AppResourceUpdateDto {\n  id: string;\n  pid?: string;\n  code?: string;\n  url?: string;\n  api?: string;\n  name?: string;\n  type?: number;\n  remark?: string;\n  extend?: string;\n}\n\nexport interface FindAppResourceIdsByRoleAndAppDto {\n  appId: string;\n  roleId: string;\n}\n\nexport interface AppResourceVo {\n  id: string;\n  appId: string;\n  pid: string;\n  code: string;\n  url: string;\n  api: string;\n  name: string;\n  type: number;\n  remark: string;\n  extend: string;\n}\n\nexport const AppResourceType = { 0: 'xx', 1: '菜单', 2: '页面', 3: '功能' };\nexport const AppResourceTypeOpt = [\n  { label: 'xx', value: 0 },\n  { label: '菜单', value: 1 },\n  { label: '页面', value: 2 },\n  { label: '功能', value: 3 },\n];\n\nexport const pageAppResourceApi = (params: AppResourcePageDto) => {\n  return requestClient.post<PageVo<AppResourceVo>>(\n    `/api/common/appResourceMgr/page`,\n    params,\n  );\n};\n\nexport const getAppResourceByIdApi = async (id: string) => {\n  return requestClient.post<AppResourceVo>(\n    `/api/common/appResourceMgr/findById?id=${id}`,\n  );\n};\n\nexport const createAppResourceApi = (params: AppResourceCreateDto) => {\n  return requestClient.post<AppResourceVo>(\n    `/api/common/appResourceMgr/create`,\n    params,\n  );\n};\n\nexport const updateAppResourceApi = (params: AppResourceUpdateDto) => {\n  return requestClient.post<AppResourceVo>(\n    `/api/common/appResourceMgr/update`,\n    params,\n  );\n};\n\nexport const deleteAppResourcesApi = (params: { ids: string[] }) => {\n  return requestClient.post(`/api/common/appResourceMgr/delete`, params);\n};\n\nexport const appResourceTreeApi = (appId: string) => {\n  return requestClient.post(\n    `/api/common/appResourceMgr/tree?appId=${appId}`,\n    {},\n  );\n};\n\nexport const findAppResourceIdsByRoleAndAppApi = (\n  params: FindAppResourceIdsByRoleAndAppDto,\n) => {\n  return requestClient.post<string[]>(\n    `/api/common/appResourceMgr/findAppResourceIdsByRoleAndApp`,\n    params,\n  );\n};\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/auth.ts",
    "content": "import { baseRequestClient, requestClient } from '#/api/request';\n\nexport namespace AuthApi {\n  /** 登录接口参数 */\n  export interface LoginParams {\n    password?: string;\n    username?: string;\n  }\n\n  export interface SmsCodeDto {\n    type: number;\n    requestId: string;\n    phoneNum: string;\n  }\n\n  export interface PhoneNumLoginDto {\n    requestId: string;\n    phoneNum: string;\n    smsCode: string;\n  }\n\n  /** 登录接口返回值 */\n  export interface LoginResult {\n    accessToken: string;\n  }\n\n  export interface RefreshTokenResult {\n    data: string;\n    status: number;\n  }\n}\n\nexport interface RegisterDto {\n  corpName: string;\n  username: string;\n  password: string;\n  phoneNum: string;\n  smsCode: string;\n}\n\n/**\n * 登录\n */\nexport async function loginApi(data: AuthApi.LoginParams) {\n  return requestClient.post<AuthApi.LoginResult>('/unpapi/login/account', data);\n}\n\nexport async function phoneNumLoginApi(data: AuthApi.PhoneNumLoginDto) {\n  return requestClient.post<AuthApi.LoginResult>(\n    '/unpapi/login/phoneNum',\n    data,\n  );\n}\n\nexport async function getSmsCodeApi(data: AuthApi.SmsCodeDto) {\n  return requestClient.post<boolean>('/unpapi/captcha/smsCode', data);\n}\n\n/**\n * 刷新accessToken\n */\nexport async function refreshTokenApi() {\n  return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {\n    withCredentials: true,\n  });\n}\n\n/**\n * 退出登录\n */\nexport async function logoutApi() {\n  return baseRequestClient.get('/api/logout', {\n    withCredentials: true,\n  });\n}\n\n/**\n * 获取用户权限码\n */\nexport async function getAccessCodesApi() {\n  return requestClient.post<string[]>('/api/common/codes');\n}\n\nexport async function registerApi(data: RegisterDto) {\n  return requestClient.post<boolean>('/unpapi/register', data);\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/common.ts",
    "content": "import { requestClient } from '#/api/request';\n\nexport interface R<T = any> {\n  code: string;\n  msg: string;\n  data: T;\n}\n\nexport interface PageVo<T> {\n  records: T[];\n  pageNum: number;\n  pageSize: number;\n  totalCount: number;\n}\n\nexport interface PageDto {\n  pageNum: number;\n  pageSize: number;\n}\n\nexport interface LimitDto {\n  offset: number;\n  limit: number;\n}\n\nexport interface FileUrlVo {\n  fileUrl: string;\n}\n\nexport interface MetadataVo {\n  usernamePlaceholder: string;\n  passwordPlaceholder: string;\n  encryptType: string;\n  publicKey: string;\n}\n\nexport const YesOrNoUseNum = { 0: '否', 1: '是' };\nexport const YesOrNoUseNumOpt = [\n  { label: '否', value: 0 },\n  { label: '是', value: 1 },\n];\n\nexport const YesOrNoUseBool = { false: '否', true: '是' };\nexport const YesOrNoUseBoolOpt = [\n  { label: '否', value: false },\n  { label: '是', value: true },\n];\n\nexport const EnableStatusUseNum = { 0: '禁用', 1: '启用' };\nexport const EnableStatusUseNumOpt = [\n  { label: '禁用', value: 0 },\n  { label: '启用', value: 1 },\n];\n\nexport const EnableStatusUseBool = { false: '禁用', true: '启用' };\nexport const EnableStatusUseBoolOpt = [\n  { label: '禁用', value: false },\n  { label: '启用', value: true },\n];\n\nexport async function getMetadataApi() {\n  return requestClient.post<MetadataVo>('/unpapi/metadata', {});\n}\n\nexport async function uploadImgApi(file: File) {\n  return await requestClient.upload('/api/common/file/uploadImg', { file });\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/corp.ts",
    "content": "import type { LimitDto, PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface CorpPageDto extends PageDto {\n  keyword?: string;\n}\n\nexport interface CorpLimitDto extends LimitDto {\n  keyword?: string;\n}\n\nexport interface CorpCreateDto {\n  name?: string;\n  status?: number;\n}\n\nexport interface CorpUpdateDto {\n  id: string;\n  name?: string;\n  status?: number;\n}\n\nexport interface CorpVo {\n  id: string;\n  name: string;\n  appCount: number;\n  depCount: number;\n  empCount: number;\n}\n\nexport const listCorpApi = () => {\n  return requestClient.post<CorpVo[]>('/api/adminSpace/corpMgr/listCorp');\n};\n\nexport const pageCorpApi = (params: CorpPageDto) => {\n  return requestClient.post<PageVo<CorpVo>>(\n    '/api/adminSpace/corpMgr/page',\n    params,\n  );\n};\n\nexport const limitCorpApi = (params: CorpLimitDto) => {\n  return requestClient.post<CorpVo[]>('/api/adminSpace/corpMgr/limit', params);\n};\n\nexport const getCorpByIdApi = async (id: string) => {\n  return requestClient.post<CorpVo>(\n    `/api/adminSpace/corpMgr/findById?id=${id}`,\n  );\n};\n\nexport const createCorpApi = (params: CorpCreateDto) => {\n  return requestClient.post<CorpVo>('/api/adminSpace/corpMgr/create', params);\n};\n\nexport const updateCorpApi = (params: CorpUpdateDto) => {\n  return requestClient.post<CorpVo>('/api/adminSpace/corpMgr/update', params);\n};\n\nexport const deleteCorpsApi = (params: { ids: string[] }) => {\n  return requestClient.post('/api/adminSpace/corpMgr/delete', params);\n};\n\nexport const intoCorpSpaceApi = (cid: string) => {\n  return requestClient.post<string>(\n    `/api/adminSpace/corpMgr/intoCorpSpace?cid=${cid}`,\n  );\n};\n\nexport const intoAdminSpaceApi = () => {\n  return requestClient.post<string>('/api/adminSpace/corpMgr/intoAdminSpace');\n};\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/dep.ts",
    "content": "import type { LimitDto, PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface DepPageDto extends PageDto {\n  cid?: string;\n  keyword?: string;\n  no?: string;\n  name?: string;\n  status?: number;\n}\n\nexport interface DepLimitDto extends LimitDto {\n  cid?: string;\n  keyword?: string;\n}\n\nexport interface DepCreateDto {\n  cid?: string;\n  sort?: number;\n  no?: string;\n  name?: string;\n  status?: number;\n  remark?: string;\n}\n\nexport interface DepUpdateDto {\n  id: string;\n  sort?: number;\n  no?: string;\n  name?: string;\n  status?: number;\n  remark?: string;\n}\n\nexport interface DepVo {\n  id: string;\n  cid: string;\n  sort: number;\n  no: string;\n  name: string;\n  createTime: string;\n  status: number;\n  remark: string;\n}\n\nexport const pageDepApi = (params: DepPageDto) => {\n  return requestClient.post<PageVo<DepVo>>(\n    '/api/corpSpace/depMgr/page',\n    params,\n  );\n};\n\nexport const limitDepApi = (params: DepLimitDto) => {\n  return requestClient.post<DepVo[]>('/api/corpSpace/depMgr/limit', params);\n};\n\nexport const getDepByIdApi = async (id: string) => {\n  return requestClient.post<DepVo>(`/api/corpSpace/depMgr/findById?id=${id}`);\n};\n\nexport const createDepApi = (params: DepCreateDto) => {\n  return requestClient.post<DepVo>('/api/corpSpace/depMgr/create', params);\n};\n\nexport const updateDepApi = (params: DepUpdateDto) => {\n  return requestClient.post<DepVo>('/api/corpSpace/depMgr/update', params);\n};\n\nexport const deleteDepsApi = (params: { ids: string[] }) => {\n  return requestClient.post('/api/corpSpace/depMgr/delete', params);\n};\n\nexport const depTreeApi = () => {\n  return requestClient.post('/api/corpSpace/depMgr/depTree', {});\n};\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/dict.ts",
    "content": "import type { LimitDto, PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface DictPageDto extends PageDto {\n  keyword: string | undefined;\n  code?: string;\n  name?: string;\n  isRoot: boolean;\n}\n\nexport interface DictLimitDto extends LimitDto {\n  keyword?: string;\n  pcode?: string;\n}\n\nexport interface DictCreateDto {\n  sort?: number;\n  code?: string;\n  pcode?: string;\n  name?: string;\n  value?: string;\n}\n\nexport interface DictUpdateDto {\n  id: string;\n  sort?: number;\n  code?: string;\n  pcode?: string;\n  name?: string;\n  value?: string;\n  isEnable?: boolean;\n}\n\nexport interface DictVo {\n  id: string;\n  sort: number;\n  code: string;\n  pCode: string;\n  name: string;\n  value: string;\n  isEnable: boolean;\n  createTime: string;\n  hasChild: boolean;\n}\n\nexport async function pageDictApi(params: DictPageDto) {\n  return requestClient.post<PageVo<DictVo>>(\n    '/api/corpSpace/dictMgr/page',\n    params,\n  );\n}\n\nexport async function getDictByIdApi(id: string) {\n  return requestClient.post<DictVo>(`/api/corpSpace/dictMgr/findById?id=${id}`);\n}\n\n// 新增用户\nexport async function createDictApi(params: DictCreateDto) {\n  return requestClient.post<DictVo>('/api/corpSpace/dictMgr/create', params);\n}\n\nexport async function updateDictApi(params: DictUpdateDto) {\n  return requestClient.post<DictVo>('/api/corpSpace/dictMgr/update', params);\n}\n\nexport async function deleteDictApi(params: { ids: string[] }) {\n  return requestClient.post('/api/corpSpace/dictMgr/delete', params);\n}\n\nexport async function findDictApi(params: DictLimitDto) {\n  return requestClient.post<DictVo[]>(\n    '/api/corpSpace/dictMgr/findDict',\n    params,\n  );\n}\n\nexport async function findSubDictApi(params: DictLimitDto) {\n  return requestClient.post<DictVo[]>(\n    '/api/corpSpace/dictMgr/findSubDict',\n    params,\n  );\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/emp.ts",
    "content": "import type { UserLimitDto, UserVo } from '#/api';\nimport type { PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface EmpPageDto extends PageDto {\n  cid?: string;\n  depIds?: string[];\n  keyword?: string;\n  name?: string;\n}\n\nexport interface EmpCreateDto {\n  cid?: string;\n  userId?: string;\n  no?: string;\n  name?: string;\n  email?: string;\n  isCorpAdmin?: boolean;\n  depIds?: string[];\n  roleIds?: string[];\n}\n\nexport interface EmpUpdateDto {\n  id: string;\n  userId?: string;\n  no?: string;\n  name?: string;\n  email?: string;\n  isCorpAdmin?: boolean;\n  depIds?: string[];\n  roleIds?: string[];\n}\n\nexport interface EmpVo {\n  id: string;\n  cid: string;\n  userId: string;\n  no: string;\n  name: string;\n  email: string;\n  createTime: string;\n  isCorpAdmin: boolean;\n  depIds: string[];\n}\n\nexport const pageEmpApi = (params: EmpPageDto) => {\n  return requestClient.post<PageVo<EmpVo>>(\n    '/api/corpSpace/empMgr/page',\n    params,\n  );\n};\n\nexport const getEmpByIdApi = async (id: string) => {\n  return requestClient.post<EmpVo>(`/api/corpSpace/empMgr/findById?id=${id}`);\n};\n\n// 新增用户\nexport const createEmpApi = (params: EmpCreateDto) => {\n  return requestClient.post<EmpVo>('/api/corpSpace/empMgr/create', params);\n};\n\nexport const updateEmpApi = (params: EmpUpdateDto) => {\n  return requestClient.post<EmpVo>('/api/corpSpace/empMgr/update', params);\n};\n\nexport const deleteEmpsApi = (params: { ids: string[] }) => {\n  return requestClient.post('/api/corpSpace/empMgr/delete', params);\n};\n\nexport const findUserApi = (params: UserLimitDto) => {\n  return requestClient.post<UserVo[]>('/api/corpSpace/empMgr/findUser', params);\n};\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/index.ts",
    "content": "export * from './auth';\nexport * from './dict';\nexport * from './menu';\nexport * from './user';\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/menu.ts",
    "content": "import type { RouteRecordStringComponent } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户所有菜单\n */\nexport async function getAllMenusApi() {\n  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/role.ts",
    "content": "import type { LimitDto, PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface RolePageDto extends PageDto {\n  cid?: string;\n  name?: string;\n}\n\nexport interface RoleLimitDto extends LimitDto {\n  keyword?: string;\n}\n\nexport interface RoleCreateDto {\n  cid?: string;\n  name?: string;\n  remark?: string;\n  isEnable?: boolean;\n}\n\nexport interface RoleUpdateDto {\n  id: string;\n  name?: string;\n  remark?: string;\n  isEnable?: boolean;\n}\n\nexport interface RoleAuthDto {\n  appId: string;\n  roleId: string | undefined;\n  appResourceIds: string[];\n}\n\nexport interface RoleVo {\n  id: string;\n  cid: string;\n  name: string;\n  createTime: string;\n  remark: string;\n  isEnable: boolean;\n}\n\nexport const pageRoleApi = (params: RolePageDto) => {\n  return requestClient.post<PageVo<RoleVo>>(\n    '/api/corpSpace/roleMgr/page',\n    params,\n  );\n};\n\nexport const limitRoleApi = (params: RoleLimitDto) => {\n  return requestClient.post<RoleVo[]>('/api/corpSpace/roleMgr/limit', params);\n};\n\nexport const getRoleByIdApi = async (id: string) => {\n  return requestClient.post<RoleVo>(`/api/corpSpace/roleMgr/findById?id=${id}`);\n};\n\n// 新增用户\nexport const createRoleApi = (params: RoleCreateDto) => {\n  return requestClient.post<RoleVo>('/api/corpSpace/roleMgr/create', params);\n};\n\nexport const updateRoleApi = (params: RoleUpdateDto) => {\n  return requestClient.post<RoleVo>('/api/corpSpace/roleMgr/update', params);\n};\n\nexport const deleteRolesApi = (params: { ids: string[] }) => {\n  return requestClient.post('/api/corpSpace/roleMgr/delete', params);\n};\n\nexport const authRoleApi = (params: RoleAuthDto) => {\n  return requestClient.post<boolean>('/api/corpSpace/roleMgr/auth', params);\n};\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/core/user.ts",
    "content": "import type { UserInfo } from '@vben/types';\n\nimport type { LimitDto, PageDto, PageVo } from '#/api/core/common';\n\nimport { requestClient } from '#/api/request';\n\nexport interface UserPageDto extends PageDto {\n  keyword: string;\n  name: string;\n  username: string;\n  phoneNum: string;\n  gender: number;\n  status: number;\n  regtime: string[];\n  isSysAdmin: boolean;\n}\n\nexport interface UserLimitDto extends LimitDto {\n  keyword?: string;\n}\n\nexport interface UserCreateDto {\n  name?: string;\n  avatar?: string;\n  username?: string;\n  phoneNum?: string;\n  gender?: number;\n  status?: number;\n  isSysAdmin?: boolean;\n}\n\nexport interface UserUpdateDto {\n  id: string;\n  name?: string;\n  avatar?: string;\n  username?: string;\n  phoneNum?: string;\n  gender?: number;\n  status?: number;\n  isSysAdmin?: boolean;\n}\n\nexport interface UserVo {\n  id: string;\n  name: string;\n  avatar: string;\n  username: string;\n  phoneNum: string;\n  gender: number;\n  status: number;\n  regtime: string;\n  lastLoginTime: string;\n  isSysAdmin: boolean;\n}\n\n/**\n * @description：用户性别\n */\nexport const GenderType = { 0: '未知', 1: '男', 2: '女' };\nexport const GenderTypeOpt = [\n  { label: '未知', value: 0 },\n  { label: '男', value: 1 },\n  { label: '女', value: 2 },\n];\n\n/**\n * 获取用户信息\n */\nexport async function getUserInfoApi() {\n  return requestClient.post<UserInfo>('/api/common/userInfo');\n}\n\nexport async function pageUserApi(params: UserPageDto) {\n  return requestClient.post<PageVo<UserVo>>(\n    '/api/adminSpace/userMgr/page',\n    params,\n  );\n}\n\nexport async function getUserByIdApi(id: string) {\n  return requestClient.post<UserVo>(\n    `/api/adminSpace/userMgr/findById?id=${id}`,\n  );\n}\n\n// 新增用户\nexport async function createUserApi(params: UserCreateDto) {\n  return requestClient.post<UserVo>('/api/adminSpace/userMgr/create', params);\n}\n\nexport async function updateUserApi(params: UserUpdateDto) {\n  return requestClient.post<UserVo>('/api/adminSpace/userMgr/update', params);\n}\n\nexport async function deleteUsersApi(params: { ids: string[] }) {\n  return requestClient.post('/api/adminSpace/userMgr/delete', params);\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/index.ts",
    "content": "export * from './core';\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/api/request.ts",
    "content": "/**\n * 该文件可自行根据业务逻辑进行调整\n */\nimport type { RequestClientOptions } from '@vben/request';\n\nimport { useAppConfig } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\nimport {\n  authenticateResponseInterceptor,\n  defaultResponseInterceptor,\n  errorMessageResponseInterceptor,\n  RequestClient,\n} from '@vben/request';\nimport { useAccessStore } from '@vben/stores';\n\nimport { message } from 'ant-design-vue';\n\nimport { useAuthStore } from '#/store';\n\nimport { refreshTokenApi } from './core';\n\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n\nfunction createRequestClient(baseURL: string, options?: RequestClientOptions) {\n  const client = new RequestClient({\n    ...options,\n    baseURL,\n  });\n\n  /**\n   * 重新认证逻辑\n   */\n  async function doReAuthenticate() {\n    console.warn('Access token or refresh token is invalid or expired. ');\n    const accessStore = useAccessStore();\n    const authStore = useAuthStore();\n    accessStore.setAccessToken(null);\n    if (\n      preferences.app.loginExpiredMode === 'modal' &&\n      accessStore.isAccessChecked\n    ) {\n      accessStore.setLoginExpired(true);\n    } else {\n      await authStore.logout();\n    }\n  }\n\n  /**\n   * 刷新token逻辑\n   */\n  async function doRefreshToken() {\n    const accessStore = useAccessStore();\n    const resp = await refreshTokenApi();\n    const newToken = resp.data;\n    accessStore.setAccessToken(newToken);\n    return newToken;\n  }\n\n  function formatToken(token: null | string) {\n    return token ? `Bearer ${token}` : null;\n  }\n\n  // 请求头处理\n  client.addRequestInterceptor({\n    fulfilled: async (config) => {\n      const accessStore = useAccessStore();\n\n      config.headers.Authorization = formatToken(accessStore.accessToken);\n      config.headers['Accept-Language'] = preferences.app.locale;\n      return config;\n    },\n  });\n\n  // 处理返回的响应数据格式\n  client.addResponseInterceptor(\n    defaultResponseInterceptor({\n      codeField: 'code',\n      dataField: 'data',\n      successCode: 10_000,\n    }),\n  );\n\n  // token过期的处理\n  client.addResponseInterceptor(\n    authenticateResponseInterceptor({\n      client,\n      doReAuthenticate,\n      doRefreshToken,\n      enableRefreshToken: preferences.app.enableRefreshToken,\n      formatToken,\n    }),\n  );\n\n  // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里\n  client.addResponseInterceptor(\n    errorMessageResponseInterceptor((msg: string, error) => {\n      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg\n      // 当前mock接口返回的错误字段是 error 或者 message\n      const responseData = error?.response?.data ?? {};\n      const errorMessage = responseData?.error ?? responseData?.message ?? '';\n      // 如果没有错误信息，则会根据状态码进行提示\n      message.error(errorMessage || msg);\n    }),\n  );\n\n  return client;\n}\n\nexport const requestClient = createRequestClient(apiURL, {\n  responseReturn: 'data',\n});\n\nexport const baseRequestClient = new RequestClient({ baseURL: apiURL });\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/app.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { useAntdDesignTokens } from '@vben/hooks';\nimport { preferences, usePreferences } from '@vben/preferences';\n\nimport { App, ConfigProvider, theme } from 'ant-design-vue';\n\nimport { antdLocale } from '#/locales';\n\ndefineOptions({ name: 'App' });\n\nconst { isDark } = usePreferences();\nconst { tokens } = useAntdDesignTokens();\n\nconst tokenTheme = computed(() => {\n  const algorithm = isDark.value\n    ? [theme.darkAlgorithm]\n    : [theme.defaultAlgorithm];\n\n  // antd 紧凑模式算法\n  if (preferences.app.compact) {\n    algorithm.push(theme.compactAlgorithm);\n  }\n\n  return {\n    algorithm,\n    token: tokens,\n  };\n});\n</script>\n\n<template>\n  <ConfigProvider :locale=\"antdLocale\" :theme=\"tokenTheme\">\n    <App>\n      <RouterView />\n    </App>\n  </ConfigProvider>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/bootstrap.ts",
    "content": "import { createApp, watchEffect } from 'vue';\n\nimport { registerAccessDirective } from '@vben/access';\nimport { registerLoadingDirective } from '@vben/common-ui/es/loading';\nimport { preferences } from '@vben/preferences';\nimport { initStores } from '@vben/stores';\nimport '@vben/styles';\nimport '@vben/styles/antd';\n\nimport { useTitle } from '@vueuse/core';\n\nimport { $t, setupI18n } from '#/locales';\n\nimport { initComponentAdapter } from './adapter/component';\nimport { initSetupVbenForm } from './adapter/form';\nimport App from './app.vue';\nimport { router } from './router';\n\nasync function bootstrap(namespace: string) {\n  // 初始化组件适配器\n  await initComponentAdapter();\n\n  // 初始化表单组件\n  await initSetupVbenForm();\n\n  // // 设置弹窗的默认配置\n  // setDefaultModalProps({\n  //   fullscreenButton: false,\n  // });\n  // // 设置抽屉的默认配置\n  // setDefaultDrawerProps({\n  //   zIndex: 1020,\n  // });\n\n  const app = createApp(App);\n\n  // 注册v-loading指令\n  registerLoadingDirective(app, {\n    loading: 'loading', // 在这里可以自定义指令名称，也可以明确提供false表示不注册这个指令\n    spinning: 'spinning',\n  });\n\n  // 国际化 i18n 配置\n  await setupI18n(app);\n\n  // 配置 pinia-tore\n  await initStores(app, { namespace });\n\n  // 安装权限指令\n  registerAccessDirective(app);\n\n  // 初始化 tippy\n  const { initTippy } = await import('@vben/common-ui/es/tippy');\n  initTippy(app);\n\n  // 配置路由及路由守卫\n  app.use(router);\n\n  // 配置Motion插件\n  const { MotionPlugin } = await import('@vben/plugins/motion');\n  app.use(MotionPlugin);\n\n  // 动态更新标题\n  watchEffect(() => {\n    if (preferences.app.dynamicTitle) {\n      const routeTitle = router.currentRoute.value.meta?.title;\n      const pageTitle =\n        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;\n      useTitle(pageTitle);\n    }\n  });\n\n  app.mount('#app');\n}\n\nexport { bootstrap };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/common/config.ts",
    "content": "import type { Context } from './types';\n\nconst defaultContext: Context = {\n  app: {\n    showGoAdminSpaceBut: false,\n  },\n};\n\nexport { defaultContext };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/common/constants.ts",
    "content": "const ROLE_SYS_ADMIN = 'sysAdmin';\nconst ROLE_CORP_ADMIN = 'corpAdmin';\n\nenum ACTION {\n  ADD = 'ADD',\n  EDIT = 'EDIT',\n  VIEW = 'VIEW',\n}\n\nexport { ACTION, ROLE_CORP_ADMIN, ROLE_SYS_ADMIN };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/common/context.ts",
    "content": "import type { DeepPartial } from '@vben/types';\n\nimport type { Context } from './types';\n\nimport { markRaw, reactive, readonly } from 'vue';\n\nimport { merge, StorageManager } from '@vben/utils';\n\nimport { useDebounceFn } from '@vueuse/core';\n\nimport { defaultContext } from './config';\n\nconst STORAGE_KEY = 'app-context';\n\nclass ContextManager {\n  private cache: null | StorageManager = new StorageManager({ prefix: 'auth' });\n  private initialContext: Context = defaultContext;\n  private saveContext: (preference: Context) => void;\n  private state: Context = reactive<Context>({\n    ...this.loadContext(),\n  });\n\n  constructor() {\n    // 避免频繁的操作缓存\n    this.saveContext = useDebounceFn(\n      (context: Context) => this._saveContext(context),\n      150,\n    );\n  }\n\n  public getContext() {\n    return readonly(this.state);\n  }\n\n  resetContext() {\n    // 将状态重置为初始偏好设置\n    Object.assign(this.state, this.initialContext);\n    // 保存重置后的偏好设置\n    this.saveContext(this.state);\n    // 从存储中移除偏好设置项\n    [STORAGE_KEY].forEach((key) => {\n      this.cache?.removeItem(key);\n    });\n    this.updateContext(this.state);\n  }\n\n  public updateContext(updates: DeepPartial<Context>) {\n    const mergedState = merge({}, updates, markRaw(this.state));\n    Object.assign(this.state, mergedState);\n    this.saveContext(this.state);\n  }\n\n  private _saveContext(preference: Context) {\n    this.cache?.setItem(STORAGE_KEY, preference);\n  }\n\n  private loadCachedContext() {\n    return this.cache?.getItem<Context>(STORAGE_KEY);\n  }\n\n  private loadContext(): Context {\n    return this.loadCachedContext() || { ...defaultContext };\n  }\n}\n\nconst contextManager = new ContextManager();\nexport { ContextManager, contextManager };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/common/index.ts",
    "content": "import type { Context } from './types';\n\nimport { contextManager } from './context';\n\n// 偏好设置（带有层级关系）\nconst context: Context = contextManager.getContext.apply(contextManager);\n\n// 更新偏好设置\nconst updateContext = contextManager.updateContext.bind(contextManager);\n\n// 重置偏好设置\nconst resetContext = contextManager.resetContext.bind(contextManager);\n\nexport { context, contextManager, resetContext, updateContext };\n\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/common/types.ts",
    "content": "interface AppContext {\n  /** 是否显示去管理员空间按钮 */\n  showGoAdminSpaceBut: boolean;\n}\n\ninterface Context {\n  /** 全局配置 */\n  app: AppContext;\n}\n\nexport type { AppContext, Context };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/layouts/auth.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { AuthPageLayout } from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst appName = computed(() => preferences.app.name);\nconst logo = computed(() => preferences.logo.source);\n</script>\n\n<template>\n  <AuthPageLayout\n    :app-name=\"appName\"\n    :logo=\"logo\"\n    :page-description=\"$t('authentication.pageDesc')\"\n    :page-title=\"$t('authentication.pageTitle')\"\n  >\n    <!-- 自定义工具栏 -->\n    <!-- <template #toolbar></template> -->\n  </AuthPageLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/layouts/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { NotificationItem } from '@vben/layouts';\n\nimport { computed, ref, watch } from 'vue';\n\nimport { AuthenticationLoginExpiredModal, useVbenModal } from '@vben/common-ui';\nimport { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';\nimport { useWatermark } from '@vben/hooks';\nimport { BookOpenText, CircleHelp, SvgGithubIcon } from '@vben/icons';\nimport {\n  BasicLayout,\n  LockScreen,\n  Notification,\n  UserDropdown,\n} from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport { context } from '#/common';\nimport { $t } from '#/locales';\nimport { useAuthStore } from '#/store';\nimport LoginForm from '#/views/_core/authentication/login.vue';\n\nimport ChangeCorp from './change-corp.vue';\nimport GoAdminSpaceButton from './go-admin-space-button.vue';\n\nconst [ChangeCorpModal, changeCorpModalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: ChangeCorp,\n});\n\nfunction openChangeCorpModal() {\n  changeCorpModalApi.open();\n}\n\nconst notifications = ref<NotificationItem[]>([\n  {\n    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',\n    date: '3小时前',\n    isRead: true,\n    message: '描述信息描述信息描述信息',\n    title: '收到了 14 份新周报',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '刚刚',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '朱偏右 回复了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '2024-01-01',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '曲丽丽 评论了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/satori',\n    date: '1天前',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '代办提醒',\n  },\n]);\n\nconst userStore = useUserStore();\nconst authStore = useAuthStore();\nconst accessStore = useAccessStore();\n\nconst { destroyWatermark, updateWatermark } = useWatermark();\nconst showDot = computed(() =>\n  notifications.value.some((item) => !item.isRead),\n);\n\nconst menus = computed(() => [\n  {\n    handler: () => {\n      openWindow(VBEN_DOC_URL, {\n        target: '_blank',\n      });\n    },\n    icon: BookOpenText,\n    text: $t('ui.widgets.document'),\n  },\n  {\n    handler: () => {\n      openWindow(VBEN_GITHUB_URL, {\n        target: '_blank',\n      });\n    },\n    icon: SvgGithubIcon,\n    text: 'GitHub',\n  },\n  {\n    handler: () => {\n      openWindow(`${VBEN_GITHUB_URL}/issues`, {\n        target: '_blank',\n      });\n    },\n    icon: CircleHelp,\n    text: $t('ui.widgets.qa'),\n  },\n  {\n    handler: () => {\n      openChangeCorpModal();\n    },\n    icon: CircleHelp,\n    text: '切换企业',\n  },\n]);\n\nconst avatar = computed(() => {\n  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;\n});\n\nasync function handleLogout() {\n  await authStore.logout(false);\n}\n\nfunction handleNoticeClear() {\n  notifications.value = [];\n}\n\nfunction handleMakeAll() {\n  notifications.value.forEach((item) => (item.isRead = true));\n}\nwatch(\n  () => ({\n    enable: preferences.app.watermark,\n    content: preferences.app.watermarkContent,\n  }),\n  async ({ enable, content }) => {\n    if (enable) {\n      await updateWatermark({\n        content:\n          content ||\n          `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,\n      });\n    } else {\n      destroyWatermark();\n    }\n  },\n  {\n    immediate: true,\n  },\n);\n</script>\n\n<template>\n  <BasicLayout @clear-preferences-and-logout=\"handleLogout\">\n    <template #user-dropdown>\n      <UserDropdown\n        :avatar\n        :description=\"userStore.userInfo?.username\"\n        :menus\n        :text=\"userStore.userInfo?.realName\"\n        tag-text=\"Pro\"\n        @logout=\"handleLogout\"\n      />\n    </template>\n    <template #notification>\n      <Notification\n        :dot=\"showDot\"\n        :notifications=\"notifications\"\n        @clear=\"handleNoticeClear\"\n        @make-all=\"handleMakeAll\"\n      />\n    </template>\n    <template #extra>\n      <AuthenticationLoginExpiredModal\n        v-model:open=\"accessStore.loginExpired\"\n        :avatar\n      >\n        <LoginForm />\n      </AuthenticationLoginExpiredModal>\n    </template>\n    <template #lock-screen>\n      <LockScreen :avatar @to-login=\"handleLogout\" />\n    </template>\n    <template #header-left-1-goback>\n      <GoAdminSpaceButton v-if=\"context.app.showGoAdminSpaceBut\" />\n    </template>\n  </BasicLayout>\n  <ChangeCorpModal />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/layouts/change-corp.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { message } from 'ant-design-vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onClosed() {\n    message.info('onClosed：关闭动画结束');\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // modalApi.close();\n  },\n  onOpened() {\n    message.info('onOpened：打开动画结束');\n  },\n});\n</script>\n<template>\n  <Modal class=\"w-[600px]\" title=\"切换租户\" title-tooltip=\"标题提示内容\">\n    租户列表\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/layouts/go-admin-space-button.vue",
    "content": "<script setup lang=\"ts\">\nimport { useRouter } from 'vue-router';\n\nimport { resetAllStores, useAccessStore } from '@vben/stores';\n\nimport { Button } from 'ant-design-vue';\n\nimport { intoAdminSpaceApi } from '#/api/core/corp';\nimport { useAuthStore } from '#/store';\n\nconst router = useRouter();\nconst accessStore = useAccessStore();\nconst authStore = useAuthStore();\n\nasync function onClick() {\n  await intoAdminSpaceApi();\n  const { accessToken } = accessStore;\n  resetAllStores();\n  await authStore.changeSpace(accessToken ?? '', async () => {\n    await router.replace(`/?r=${Date.now()}`);\n  });\n}\n</script>\n\n<template>\n  <Button\n    class=\"mr-1 inline-flex w-8 items-center justify-center px-1\"\n    type=\"text\"\n    @click=\"onClick()\"\n  >\n    <span class=\"icon-[ant-design--swap-outlined]\"></span>\n  </Button>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/layouts/index.ts",
    "content": "const BasicLayout = () => import('./basic.vue');\nconst AuthPageLayout = () => import('./auth.vue');\n\nconst IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);\n\nexport { AuthPageLayout, BasicLayout, IFrameView };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/locales/README.md",
    "content": "# locale\n\n每个app使用的国际化可能不同，这里用于扩展国际化的功能，例如扩展 dayjs、antd组件库的多语言切换，以及app本身的国际化文件。\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/locales/index.ts",
    "content": "import type { Locale } from 'ant-design-vue/es/locale';\n\nimport type { App } from 'vue';\n\nimport type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';\n\nimport { ref } from 'vue';\n\nimport {\n  $t,\n  setupI18n as coreSetup,\n  loadLocalesMapFromDir,\n} from '@vben/locales';\nimport { preferences } from '@vben/preferences';\n\nimport antdEnLocale from 'ant-design-vue/es/locale/en_US';\nimport antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN';\nimport dayjs from 'dayjs';\n\nconst antdLocale = ref<Locale>(antdDefaultLocale);\n\nconst modules = import.meta.glob('./langs/**/*.json');\n\nconst localesMap = loadLocalesMapFromDir(\n  /\\.\\/langs\\/([^/]+)\\/(.*)\\.json$/,\n  modules,\n);\n/**\n * 加载应用特有的语言包\n * 这里也可以改造为从服务端获取翻译数据\n * @param lang\n */\nasync function loadMessages(lang: SupportedLanguagesType) {\n  const [appLocaleMessages] = await Promise.all([\n    localesMap[lang]?.(),\n    loadThirdPartyMessage(lang),\n  ]);\n  return appLocaleMessages?.default;\n}\n\n/**\n * 加载第三方组件库的语言包\n * @param lang\n */\nasync function loadThirdPartyMessage(lang: SupportedLanguagesType) {\n  await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);\n}\n\n/**\n * 加载dayjs的语言包\n * @param lang\n */\nasync function loadDayjsLocale(lang: SupportedLanguagesType) {\n  let locale;\n  switch (lang) {\n    case 'en-US': {\n      locale = await import('dayjs/locale/en');\n      break;\n    }\n    case 'zh-CN': {\n      locale = await import('dayjs/locale/zh-cn');\n      break;\n    }\n    // 默认使用英语\n    default: {\n      locale = await import('dayjs/locale/en');\n    }\n  }\n  if (locale) {\n    dayjs.locale(locale);\n  } else {\n    console.error(`Failed to load dayjs locale for ${lang}`);\n  }\n}\n\n/**\n * 加载antd的语言包\n * @param lang\n */\nasync function loadAntdLocale(lang: SupportedLanguagesType) {\n  switch (lang) {\n    case 'en-US': {\n      antdLocale.value = antdEnLocale;\n      break;\n    }\n    case 'zh-CN': {\n      antdLocale.value = antdDefaultLocale;\n      break;\n    }\n  }\n}\n\nasync function setupI18n(app: App, options: LocaleSetupOptions = {}) {\n  await coreSetup(app, {\n    defaultLocale: preferences.app.locale,\n    loadMessages,\n    missingWarn: !import.meta.env.PROD,\n    ...options,\n  });\n}\n\nexport { $t, antdLocale, setupI18n };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/locales/langs/en-US/demos.json",
    "content": "{\n  \"title\": \"Demos\",\n  \"antd\": \"Ant Design Vue\",\n  \"vben\": {\n    \"title\": \"Project\",\n    \"about\": \"About\",\n    \"document\": \"Document\",\n    \"antdv\": \"Ant Design Vue Version\",\n    \"naive-ui\": \"Naive UI Version\",\n    \"element-plus\": \"Element Plus Version\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/locales/langs/en-US/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"Login\",\n    \"register\": \"Register\",\n    \"codeLogin\": \"Code Login\",\n    \"qrcodeLogin\": \"Qr Code Login\",\n    \"forgetPassword\": \"Forget Password\"\n  },\n  \"dashboard\": {\n    \"title\": \"Dashboard\",\n    \"analytics\": \"Analytics\",\n    \"workspace\": \"Workspace\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/locales/langs/zh-CN/demos.json",
    "content": "{\n  \"title\": \"演示\",\n  \"antd\": \"Ant Design Vue\",\n  \"vben\": {\n    \"title\": \"项目\",\n    \"about\": \"关于\",\n    \"document\": \"文档\",\n    \"antdv\": \"Ant Design Vue 版本\",\n    \"naive-ui\": \"Naive UI 版本\",\n    \"element-plus\": \"Element Plus 版本\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/locales/langs/zh-CN/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"登录\",\n    \"register\": \"注册\",\n    \"codeLogin\": \"验证码登录\",\n    \"qrcodeLogin\": \"二维码登录\",\n    \"forgetPassword\": \"忘记密码\"\n  },\n  \"dashboard\": {\n    \"title\": \"概览\",\n    \"analytics\": \"分析页\",\n    \"workspace\": \"工作台\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/main.ts",
    "content": "import { initPreferences } from '@vben/preferences';\nimport { unmountGlobalLoading } from '@vben/utils';\n\nimport { overridesPreferences } from './preferences';\n\n/**\n * 应用初始化完成之后再进行页面加载渲染\n */\nasync function initApplication() {\n  // name用于指定项目唯一标识\n  // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据\n  const env = import.meta.env.PROD ? 'prod' : 'dev';\n  const appVersion = import.meta.env.VITE_APP_VERSION;\n  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;\n\n  // app偏好设置初始化\n  await initPreferences({\n    namespace,\n    overrides: overridesPreferences,\n  });\n\n  // 启动应用并挂载\n  // vue应用主要逻辑及视图\n  const { bootstrap } = await import('./bootstrap');\n  await bootstrap(namespace);\n\n  // 移除并销毁loading\n  unmountGlobalLoading();\n}\n\ninitApplication();\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/preferences.ts",
    "content": "import { defineOverridesPreferences } from '@vben/preferences';\n\n/**\n * @description 项目配置文件\n * 只需要覆盖项目中的一部分配置，不需要的配置不用覆盖，会自动使用默认配置\n * !!! 更改配置后请清空缓存，否则可能不生效\n */\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    name: import.meta.env.VITE_APP_TITLE,\n  },\n  copyright: {\n    companyName: 'Earven',\n  },\n  theme: {\n    mode: 'light',\n  },\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/access.ts",
    "content": "import type {\n  ComponentRecordType,\n  GenerateMenuAndRoutesOptions,\n} from '@vben/types';\n\nimport { generateAccessible } from '@vben/access';\nimport { preferences } from '@vben/preferences';\n\nimport { message } from 'ant-design-vue';\n\nimport { getAllMenusApi } from '#/api';\nimport { BasicLayout, IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');\n\nasync function generateAccess(options: GenerateMenuAndRoutesOptions) {\n  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');\n\n  const layoutMap: ComponentRecordType = {\n    BasicLayout,\n    IFrameView,\n  };\n\n  return await generateAccessible(preferences.app.accessMode, {\n    ...options,\n    fetchMenuListAsync: async () => {\n      message.loading({\n        content: `${$t('common.loadingMenu')}...`,\n        duration: 1.5,\n      });\n      return await getAllMenusApi();\n    },\n    // 可以指定没有权限跳转403页面\n    forbiddenComponent,\n    // 如果 route.meta.menuVisibleWithForbidden = true\n    layoutMap,\n    pageMap,\n  });\n}\n\nexport { generateAccess };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/guard.ts",
    "content": "import type { Router } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { startProgress, stopProgress } from '@vben/utils';\n\nimport { accessRoutes, coreRouteNames } from '#/router/routes';\nimport { useAuthStore } from '#/store';\n\nimport { generateAccess } from './access';\n\n/**\n * 通用守卫配置\n * @param router\n */\nfunction setupCommonGuard(router: Router) {\n  // 记录已经加载的页面\n  const loadedPaths = new Set<string>();\n\n  router.beforeEach((to) => {\n    to.meta.loaded = loadedPaths.has(to.path);\n\n    // 页面加载进度条\n    if (!to.meta.loaded && preferences.transition.progress) {\n      startProgress();\n    }\n    return true;\n  });\n\n  router.afterEach((to) => {\n    // 记录页面是否加载,如果已经加载，后续的页面切换动画等效果不在重复执行\n\n    loadedPaths.add(to.path);\n\n    // 关闭页面加载进度条\n    if (preferences.transition.progress) {\n      stopProgress();\n    }\n  });\n}\n\n/**\n * 权限访问守卫配置\n * @param router\n */\nfunction setupAccessGuard(router: Router) {\n  router.beforeEach(async (to, from) => {\n    const accessStore = useAccessStore();\n    const userStore = useUserStore();\n    const authStore = useAuthStore();\n\n    // 基本路由，这些路由不需要进入权限拦截\n    if (coreRouteNames.includes(to.name as string)) {\n      if (to.path === LOGIN_PATH && accessStore.accessToken) {\n        return decodeURIComponent(\n          (to.query?.redirect as string) ||\n            userStore.userInfo?.homePath ||\n            preferences.app.defaultHomePath,\n        );\n      }\n      return true;\n    }\n\n    // accessToken 检查\n    if (!accessStore.accessToken) {\n      // 明确声明忽略权限访问权限，则可以访问\n      if (to.meta.ignoreAccess) {\n        return true;\n      }\n\n      // 没有访问权限，跳转登录页面\n      if (to.fullPath !== LOGIN_PATH) {\n        return {\n          path: LOGIN_PATH,\n          // 如不需要，直接删除 query\n          query:\n            to.fullPath === preferences.app.defaultHomePath\n              ? {}\n              : { redirect: encodeURIComponent(to.fullPath) },\n          // 携带当前跳转的页面，登录后重新跳转该页面\n          replace: true,\n        };\n      }\n      return to;\n    }\n\n    // 是否已经生成过动态路由\n    if (accessStore.isAccessChecked) {\n      return true;\n    }\n\n    // 生成路由表\n    // 当前登录用户拥有的角色标识列表\n    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());\n    const userRoles = userInfo.roles ?? [];\n\n    // 生成菜单和路由\n    const { accessibleMenus, accessibleRoutes } = await generateAccess({\n      roles: userRoles,\n      router,\n      // 则会在菜单中显示，但是访问会被重定向到403\n      routes: accessRoutes,\n    });\n\n    // 保存菜单信息和路由信息\n    accessStore.setAccessMenus(accessibleMenus);\n    accessStore.setAccessRoutes(accessibleRoutes);\n    accessStore.setIsAccessChecked(true);\n    const redirectPath = (from.query.redirect ??\n      (to.path === preferences.app.defaultHomePath\n        ? userInfo.homePath || preferences.app.defaultHomePath\n        : to.fullPath)) as string;\n\n    return {\n      ...router.resolve(decodeURIComponent(redirectPath)),\n      replace: true,\n    };\n  });\n}\n\n/**\n * 项目守卫配置\n * @param router\n */\nfunction createRouterGuard(router: Router) {\n  /** 通用 */\n  setupCommonGuard(router);\n  /** 权限访问 */\n  setupAccessGuard(router);\n}\n\nexport { createRouterGuard };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/index.ts",
    "content": "import {\n  createRouter,\n  createWebHashHistory,\n  createWebHistory,\n} from 'vue-router';\n\nimport { resetStaticRoutes } from '@vben/utils';\n\nimport { createRouterGuard } from './guard';\nimport { routes } from './routes';\n\n/**\n *  @zh_CN 创建vue-router实例\n */\nconst router = createRouter({\n  history:\n    import.meta.env.VITE_ROUTER_HISTORY === 'hash'\n      ? createWebHashHistory(import.meta.env.VITE_BASE)\n      : createWebHistory(import.meta.env.VITE_BASE),\n  // 应该添加到路由的初始路由列表。\n  routes,\n  scrollBehavior: (to, _from, savedPosition) => {\n    if (savedPosition) {\n      return savedPosition;\n    }\n    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };\n  },\n  // 是否应该禁止尾部斜杠。\n  // strict: true,\n});\n\nconst resetRoutes = () => resetStaticRoutes(router, routes);\n\n// 创建路由守卫\ncreateRouterGuard(router);\n\nexport { resetRoutes, router };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/routes/core.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst BasicLayout = () => import('#/layouts/basic.vue');\nconst AuthPageLayout = () => import('#/layouts/auth.vue');\n/** 全局404页面 */\nconst fallbackNotFoundRoute: RouteRecordRaw = {\n  component: () => import('#/views/_core/fallback/not-found.vue'),\n  meta: {\n    hideInBreadcrumb: true,\n    hideInMenu: true,\n    hideInTab: true,\n    title: '404',\n  },\n  name: 'FallbackNotFound',\n  path: '/:path(.*)*',\n};\n\n/** 基本路由，这些路由是必须存在的 */\nconst coreRoutes: RouteRecordRaw[] = [\n  /**\n   * 根路由\n   * 使用基础布局，作为所有页面的父级容器，子级就不必配置BasicLayout。\n   * 此路由必须存在，且不应修改\n   */\n  {\n    component: BasicLayout,\n    meta: {\n      hideInBreadcrumb: true,\n      title: 'Root',\n    },\n    name: 'Root',\n    path: '/',\n    redirect: preferences.app.defaultHomePath,\n    children: [],\n  },\n  {\n    component: AuthPageLayout,\n    props: {\n      pageTitle: '统一认证授权系统',\n      pageDescription: '应用管理、组织管理、账号管理、权限管理、统一授权',\n    },\n    meta: {\n      hideInTab: true,\n      title: 'Authentication',\n    },\n    name: 'Authentication',\n    path: '/auth',\n    redirect: LOGIN_PATH,\n    children: [\n      {\n        name: 'Login',\n        path: 'login',\n        component: () => import('#/views/_core/authentication/login.vue'),\n        meta: {\n          title: $t('page.auth.login'),\n        },\n      },\n      {\n        name: 'CodeLogin',\n        path: 'code-login',\n        component: () => import('#/views/_core/authentication/code-login.vue'),\n        meta: {\n          title: $t('page.auth.codeLogin'),\n        },\n      },\n      {\n        name: 'QrCodeLogin',\n        path: 'qrcode-login',\n        component: () =>\n          import('#/views/_core/authentication/qrcode-login.vue'),\n        meta: {\n          title: $t('page.auth.qrcodeLogin'),\n        },\n      },\n      {\n        name: 'ForgetPassword',\n        path: 'forget-password',\n        component: () =>\n          import('#/views/_core/authentication/forget-password.vue'),\n        meta: {\n          title: $t('page.auth.forgetPassword'),\n        },\n      },\n      {\n        name: 'Register',\n        path: 'register',\n        component: () => import('#/views/_core/authentication/register.vue'),\n        meta: {\n          title: $t('page.auth.register'),\n        },\n      },\n    ],\n  },\n];\n\nexport { coreRoutes, fallbackNotFoundRoute };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/routes/index.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { mergeRouteModules, traverseTreeValues } from '@vben/utils';\n\nimport { coreRoutes, fallbackNotFoundRoute } from './core';\n\nconst dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {\n  eager: true,\n});\n\n// 有需要可以自行打开注释，并创建文件夹\n// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });\n// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });\n\n/** 动态路由 */\nconst dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);\n\n/** 外部路由列表，访问这些页面可以不需要Layout，可能用于内嵌在别的系统(不会显示在菜单中) */\n// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);\n// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);\nconst staticRoutes: RouteRecordRaw[] = [];\nconst externalRoutes: RouteRecordRaw[] = [];\n\n/** 路由列表，由基本路由、外部路由和404兜底路由组成\n *  无需走权限验证（会一直显示在菜单中） */\nconst routes: RouteRecordRaw[] = [\n  ...coreRoutes,\n  ...externalRoutes,\n  fallbackNotFoundRoute,\n];\n\n/** 基本路由列表，这些路由不需要进入权限拦截 */\nconst coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);\n\n/** 有权限校验的路由列表，包含动态路由和静态路由 */\nconst accessRoutes = [...dynamicRoutes, ...staticRoutes];\nexport { accessRoutes, coreRouteNames, routes };\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/routes/modules/adminSpace.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { ROLE_SYS_ADMIN } from '#/common/constants';\nimport { BasicLayout } from '#/layouts';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    component: BasicLayout,\n    name: 'corpMgr',\n    path: '/adminSpace/corpMgr',\n    meta: {\n      title: '租户管理',\n      icon: 'ant-design:solution-outlined',\n      keepAlive: true,\n      order: 1000,\n      authority: [ROLE_SYS_ADMIN],\n    },\n    children: [\n      {\n        name: 'corpList',\n        path: '/adminSpace/corpMgr/list',\n        meta: {\n          title: '租户列表',\n          icon: 'ant-design:bars-outlined',\n        },\n        component: () => import('#/views/adminSpace/corpMgr/index.vue'),\n      },\n    ],\n  },\n  {\n    component: BasicLayout,\n    name: 'userMgr',\n    path: '/adminSpace/userMgr',\n    meta: {\n      title: '用户管理',\n      icon: 'ant-design:user-outlined',\n      keepAlive: true,\n      order: 1000,\n      authority: [ROLE_SYS_ADMIN],\n    },\n    children: [\n      {\n        name: 'userList',\n        path: '/adminSpace/userMgr/list',\n        meta: {\n          title: '用户列表',\n          icon: 'ant-design:bars-outlined',\n        },\n        component: () => import('#/views/adminSpace/userMgr/index.vue'),\n      },\n    ],\n  },\n  {\n    component: BasicLayout,\n    name: 'appMgr',\n    path: '/adminSpace/appMgr',\n    meta: {\n      title: '应用管理',\n      icon: 'ant-design:appstore-twotone',\n      keepAlive: true,\n      order: 1000,\n      authority: [ROLE_SYS_ADMIN],\n    },\n    children: [\n      {\n        name: 'appList',\n        path: '/adminSpace/appMgr/list',\n        meta: {\n          title: '应用列表',\n          icon: 'ant-design:bars-outlined',\n        },\n        component: () => import('#/views/common/appMgr/index.vue'),\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/routes/modules/common.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { BasicLayout } from '#/layouts';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    component: BasicLayout,\n    name: 'appResourceMgr',\n    path: '/common/appResourceMgr',\n    meta: {\n      title: '应用配置',\n      icon: 'ic:baseline-view-in-ar',\n      keepAlive: true,\n      order: 1000,\n      hideInMenu: true,\n    },\n    children: [\n      {\n        name: 'appResourceList',\n        path: '/common/appResourceMgr/list/:id',\n        meta: {\n          title: '配置列表',\n          isHide: true,\n        },\n        component: () => import('#/views/common/appResourceMgr/index.vue'),\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/routes/modules/corpSpace.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { ROLE_CORP_ADMIN } from '#/common/constants';\nimport { BasicLayout } from '#/layouts';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    component: BasicLayout,\n    name: 'depMgr',\n    path: '/corpSpace/depMgr',\n    meta: {\n      title: '部门管理',\n      icon: 'ant-design:bank-twotone',\n      keepAlive: true,\n      order: 1000,\n      authority: [ROLE_CORP_ADMIN],\n    },\n    children: [\n      {\n        name: 'depList',\n        path: '/corpSpace/depMgr/list',\n        meta: {\n          title: '部门列表',\n          icon: 'ant-design:bars-outlined',\n        },\n        component: () => import('#/views/corpSpace/depMgr/index.vue'),\n      },\n    ],\n  },\n  {\n    component: BasicLayout,\n    name: 'empMgr',\n    path: '/corpSpace/empMgr',\n    meta: {\n      title: '员工管理',\n      icon: 'mdi:account-hard-hat-outline',\n      keepAlive: true,\n      order: 1000,\n      authority: [ROLE_CORP_ADMIN],\n    },\n    children: [\n      {\n        name: 'empList',\n        path: '/corpSpace/empMgr/list',\n        meta: {\n          title: '员工列表',\n          icon: 'ant-design:bars-outlined',\n        },\n        component: () => import('#/views/corpSpace/empMgr/index.vue'),\n      },\n    ],\n  },\n  {\n    component: BasicLayout,\n    name: 'roleMgr',\n    path: '/corpSpace/roleMgr',\n    meta: {\n      title: '角色管理',\n      icon: 'ant-design:team-outlined',\n      keepAlive: true,\n      order: 1000,\n      authority: [ROLE_CORP_ADMIN],\n    },\n    children: [\n      {\n        name: 'roleList',\n        path: '/corpSpace/roleMgr/list',\n        meta: {\n          title: '角色列表',\n          icon: 'ant-design:bars-outlined',\n        },\n        component: () => import('#/views/corpSpace/roleMgr/index.vue'),\n      },\n    ],\n  },\n  {\n    component: BasicLayout,\n    name: 'corpAppMgr',\n    path: '/corpSpace/corpAppMgr',\n    meta: {\n      title: '应用管理',\n      icon: 'ant-design:appstore-twotone',\n      keepAlive: true,\n      order: 1000,\n      authority: [ROLE_CORP_ADMIN],\n    },\n    children: [\n      {\n        name: 'corpAppList',\n        path: '/corpSpace/corpAppMgr/list',\n        meta: {\n          title: '应用列表',\n          icon: 'ant-design:bars-outlined',\n        },\n        component: () => import('#/views/common/appMgr/index.vue'),\n      },\n      {\n        name: 'appClientList',\n        path: '/corpSpace/appClientMgr/list',\n        meta: {\n          title: '客户端列表',\n          icon: 'ant-design:bars-outlined',\n        },\n        component: () => import('#/views/corpSpace/appClientMgr/index.vue'),\n      },\n    ],\n  },\n  {\n    component: BasicLayout,\n    name: 'sysMgr',\n    path: '/corpSpace/sysMgr',\n    meta: {\n      title: '系统管理',\n      icon: 'ant-design:setting-outlined',\n      keepAlive: true,\n      order: 1000,\n      authority: [ROLE_CORP_ADMIN],\n    },\n    children: [\n      {\n        name: 'dictMgr',\n        path: '/corpSpace/sysMgr/dictMgr/list',\n        meta: {\n          title: '字典管理',\n          icon: 'material-symbols:book-3-outline',\n        },\n        component: () => import('#/views/corpSpace/sysMgr/dictMgr/index.vue'),\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/router/routes/modules/dashboard.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'lucide:layout-dashboard',\n      order: -1,\n      title: $t('page.dashboard.title'),\n    },\n    name: 'Dashboard',\n    path: '/dashboard',\n    children: [\n      {\n        name: 'Analytics',\n        path: '/analytics',\n        component: () => import('#/views/dashboard/analytics/index.vue'),\n        meta: {\n          affixTab: false,\n          icon: 'lucide:area-chart',\n          title: $t('page.dashboard.analytics'),\n        },\n      },\n      {\n        name: 'Workspace',\n        path: '/workspace',\n        component: () => import('#/views/dashboard/workspace/index.vue'),\n        meta: {\n          icon: 'carbon:workspace',\n          title: $t('page.dashboard.workspace'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/store/auth.ts",
    "content": "import type { Recordable, UserInfo } from '@vben/types';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';\n\nimport { notification } from 'ant-design-vue';\nimport { defineStore } from 'pinia';\n\nimport {\n  getAccessCodesApi,\n  getUserInfoApi,\n  loginApi,\n  logoutApi,\n  phoneNumLoginApi,\n} from '#/api';\nimport { updateContext } from '#/common';\nimport { ROLE_CORP_ADMIN } from '#/common/constants';\nimport { $t } from '#/locales';\nimport { useContentStore } from '#/store/content';\nimport { encrypt } from '#/utils/rsa';\n\nconst apiUrl = import.meta.env.VITE_GLOB_API_URL;\n\nexport const useAuthStore = defineStore('auth', () => {\n  const accessStore = useAccessStore();\n  const userStore = useUserStore();\n  const router = useRouter();\n  const contentStore = useContentStore();\n\n  const loginLoading = ref(false);\n\n  /**\n   * 异步处理登录操作\n   * Asynchronously handle the login process\n   * @param params 登录表单数据\n   * @param onSuccess\n   */\n  async function authLogin(\n    params: Recordable<any>,\n    onSuccess?: () => Promise<void> | void,\n  ) {\n    const ePwd =\n      contentStore.encryptType === 'RSA'\n        ? encrypt(contentStore.publicKey, params.password)\n        : params.password;\n    const { accessToken } = await loginApi({ ...params, password: ePwd });\n    return changeSpace(accessToken, onSuccess);\n  }\n\n  async function smsCodeLogin(\n    params: Recordable<any>,\n    onSuccess?: () => Promise<void> | void,\n  ) {\n    const { accessToken } = await phoneNumLoginApi({\n      requestId: params.phoneNumber,\n      phoneNum: params.phoneNumber,\n      smsCode: params.code,\n    });\n    return changeSpace(accessToken, onSuccess);\n  }\n\n  async function changeSpace(\n    accessToken: string,\n    onSuccess?: () => Promise<void> | void,\n  ) {\n    // 异步处理用户登录操作并获取 accessToken\n    let userInfo: null | UserInfo = null;\n    try {\n      loginLoading.value = true;\n\n      // 如果成功获取到 accessToken\n      if (accessToken) {\n        accessStore.setAccessToken(accessToken);\n\n        // 获取用户信息并存储到 accessStore 中\n        const [fetchUserInfoResult, accessCodes] = await Promise.all([\n          fetchUserInfo(),\n          getAccessCodesApi(),\n        ]);\n\n        userInfo = fetchUserInfoResult;\n        userStore.setUserInfo(userInfo);\n        accessStore.setAccessCodes(accessCodes);\n\n        const { roles } = userInfo;\n        const isCorpSpace: boolean =\n          roles !== undefined &&\n          roles.some((role) => {\n            return ROLE_CORP_ADMIN.includes(role);\n          });\n        updateContext({ app: { showGoAdminSpaceBut: isCorpSpace } });\n\n        if (accessStore.loginExpired) {\n          accessStore.setLoginExpired(false);\n        } else {\n          onSuccess\n            ? await onSuccess?.()\n            : await router.push(\n                userInfo.homePath || preferences.app.defaultHomePath,\n              );\n        }\n\n        if (userInfo?.realName) {\n          notification.success({\n            description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,\n            duration: 3,\n            message: $t('authentication.loginSuccess'),\n          });\n        }\n      }\n    } finally {\n      loginLoading.value = false;\n    }\n\n    return { userInfo };\n  }\n\n  async function logout(redirect: boolean = true) {\n    try {\n      await logoutApi();\n    } catch {\n      // 不做任何处理\n    }\n    resetAllStores();\n    accessStore.setLoginExpired(false);\n\n    // 回登录页带上当前路由地址\n    await router.replace({\n      path: LOGIN_PATH,\n      query: redirect\n        ? {\n            redirect: encodeURIComponent(router.currentRoute.value.fullPath),\n          }\n        : {},\n    });\n  }\n\n  async function fetchUserInfo() {\n    const userInfo: UserInfo = await getUserInfoApi();\n    userStore.setUserInfo(userInfo);\n    userInfo.avatar = apiUrl + userInfo.avatar;\n    return userInfo;\n  }\n\n  function $reset() {\n    loginLoading.value = false;\n  }\n\n  return {\n    $reset,\n    authLogin,\n    smsCodeLogin,\n    changeSpace,\n    fetchUserInfo,\n    loginLoading,\n    logout,\n  };\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/store/content.ts",
    "content": "import { acceptHMRUpdate, defineStore } from 'pinia';\n\ninterface ContentState {\n  /**\n   * 加密公钥，和后台传输敏感数据时使用\n   */\n  publicKey: string;\n  /**\n   * 加密公钥的加密算法，默认为 RSA\n   */\n  encryptType: string;\n}\n\n/**\n * @zh_CN 上下文信息相关\n */\nexport const useContentStore = defineStore('core-content', {\n  actions: {\n    setEncrypt(publicKey: string, encryptType: string) {\n      this.publicKey = publicKey;\n      this.encryptType = encryptType;\n    },\n  },\n  state: (): ContentState => ({\n    publicKey: '',\n    encryptType: 'RSA',\n  }),\n});\n\n// 解决热更新问题\nconst hot = import.meta.hot;\nif (hot) {\n  hot.accept(acceptHMRUpdate(useContentStore, hot));\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/store/index.ts",
    "content": "export * from './auth';\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/utils/rsa.ts",
    "content": "import JSEncrypt from 'jsencrypt';\n\nconst encryptor = new JSEncrypt();\n\nexport function encrypt(publicKey: string, content: string) {\n  encryptor.setPublicKey(publicKey);\n  return encryptor.encrypt(content);\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/README.md",
    "content": "# \\_core\n\n此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/about/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { About } from '@vben/common-ui';\n\ndefineOptions({ name: 'About' });\n</script>\n\n<template>\n  <About />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/authentication/code-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\n\nimport { computed, ref, useTemplateRef } from 'vue';\n\nimport { AuthenticationCodeLogin, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { message } from 'ant-design-vue';\n\nimport { getSmsCodeApi } from '#/api';\nimport { useAuthStore } from '#/store';\n\ndefineOptions({ name: 'CodeLogin' });\n\nconst authStore = useAuthStore();\nconst loading = ref(false);\nconst CODE_LENGTH = 6;\nconst loginRef =\n  useTemplateRef<InstanceType<typeof AuthenticationCodeLogin>>('loginRef');\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.mobile'),\n      },\n      fieldName: 'phoneNumber',\n      defaultValue: '13712345678',\n      label: $t('authentication.mobile'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.mobileTip') })\n        .refine((v) => /^\\d{11}$/.test(v), {\n          message: $t('authentication.mobileErrortip'),\n        }),\n    },\n    {\n      component: 'VbenPinInput',\n      componentProps: {\n        codeLength: CODE_LENGTH,\n        createText: (countdown: number) => {\n          const text =\n            countdown > 0\n              ? $t('authentication.sendText', [countdown])\n              : $t('authentication.sendCode');\n          return text;\n        },\n        placeholder: $t('authentication.code'),\n        handleSendCode: async () => {\n          // 模拟发送验证码\n          // Simulate sending verification code\n          loading.value = true;\n          const formApi = loginRef.value?.getFormApi();\n          if (!formApi) {\n            loading.value = false;\n            throw new Error('formApi is not ready');\n          }\n          await formApi.validateField('phoneNumber');\n          const isPhoneReady = await formApi.isFieldValid('phoneNumber');\n          if (!isPhoneReady) {\n            loading.value = false;\n            throw new Error('Phone number is not Ready');\n          }\n          const { phoneNumber } = await formApi.getValues();\n          await getSmsCodeApi({\n            type: 1,\n            requestId: phoneNumber,\n            phoneNum: phoneNumber,\n          });\n          loading.value = false;\n          message.success(`短信验证码已发送`);\n        },\n      },\n      fieldName: 'code',\n      label: $t('authentication.code'),\n      rules: z.string().length(CODE_LENGTH, {\n        message: $t('authentication.codeTip', [CODE_LENGTH]),\n      }),\n    },\n  ];\n});\n</script>\n<template>\n  <AuthenticationCodeLogin\n    ref=\"loginRef\"\n    :form-schema=\"formSchema\"\n    :loading=\"authStore.loginLoading\"\n    @submit=\"authStore.smsCodeLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/authentication/forget-password.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, ref } from 'vue';\n\nimport { AuthenticationForgetPassword, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'ForgetPassword' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: 'example@example.com',\n      },\n      fieldName: 'email',\n      label: $t('authentication.email'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.emailTip') })\n        .email($t('authentication.emailValidErrorTip')),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log('reset email:', value);\n}\n</script>\n\n<template>\n  <AuthenticationForgetPassword\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/authentication/login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\n\nimport { computed, markRaw, onBeforeMount, ref } from 'vue';\n\nimport { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { getMetadataApi } from '#/api/core/common';\nimport { useAuthStore } from '#/store';\nimport { useContentStore } from '#/store/content';\n\ndefineOptions({ name: 'Login' });\n\nconst authStore = useAuthStore();\nconst contentStore = useContentStore();\nconst up = ref<string>('请输入用户名');\nconst pp = ref<string>('请输入密码');\n\nonBeforeMount(async () => {\n  const { publicKey, encryptType, usernamePlaceholder, passwordPlaceholder } =\n    await getMetadataApi();\n  up.value = usernamePlaceholder;\n  pp.value = passwordPlaceholder;\n  contentStore.setEncrypt(publicKey, encryptType);\n});\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: up.value,\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      defaultValue: '',\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: pp.value,\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      defaultValue: '',\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: markRaw(SliderCaptcha),\n      fieldName: 'captcha',\n      rules: z.boolean().refine((value) => value, {\n        message: $t('authentication.verifyRequiredTip'),\n      }),\n    },\n  ];\n});\n</script>\n\n<template>\n  <AuthenticationLogin\n    title=\"欢迎使用👋🏻\"\n    sub-title=\"请输入您的帐户信息以开始管理您的项目\"\n    :form-schema=\"formSchema\"\n    :loading=\"authStore.loginLoading\"\n    @submit=\"authStore.authLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/authentication/qrcode-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport { AuthenticationQrCodeLogin } from '@vben/common-ui';\nimport { LOGIN_PATH } from '@vben/constants';\n\ndefineOptions({ name: 'QrCodeLogin' });\n</script>\n\n<template>\n  <AuthenticationQrCodeLogin :login-path=\"LOGIN_PATH\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/authentication/register.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, h, ref, useTemplateRef } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { AuthenticationRegister, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { message, notification } from 'ant-design-vue';\n\nimport { getSmsCodeApi, registerApi } from '#/api';\n\ndefineOptions({ name: 'Register' });\n\nconst loading = ref(false);\nconst CODE_LENGTH = 6;\nconst registerRef =\n  useTemplateRef<InstanceType<typeof AuthenticationRegister>>('registerRef');\n\nconst router = useRouter();\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.mobile'),\n      },\n      fieldName: 'phoneNum',\n      defaultValue: '',\n      label: $t('authentication.mobile'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.mobileTip') })\n        .refine((v) => /^\\d{11}$/.test(v), {\n          message: $t('authentication.mobileErrortip'),\n        }),\n    },\n    {\n      component: 'VbenPinInput',\n      componentProps: {\n        codeLength: CODE_LENGTH,\n        createText: (countdown: number) => {\n          return countdown > 0\n            ? $t('authentication.sendText', [countdown])\n            : $t('authentication.sendCode');\n        },\n        placeholder: $t('authentication.code'),\n        handleSendCode: async () => {\n          const formApi = registerRef.value?.getFormApi();\n          if (!formApi) {\n            throw new Error('formApi is not ready');\n          }\n          await formApi.validateField('phoneNum');\n          const isPhoneReady = await formApi.isFieldValid('phoneNum');\n          if (!isPhoneReady) {\n            throw new Error('Phone number is not Ready');\n          }\n          const { phoneNum } = await formApi.getValues();\n          const smsCode = await getSmsCodeApi({\n            type: 1,\n            requestId: phoneNum,\n            phoneNum,\n          });\n          message.success(`短信验证码:${smsCode}`);\n        },\n      },\n      fieldName: 'smsCode',\n      label: $t('authentication.code'),\n      rules: z.string().length(CODE_LENGTH, {\n        message: $t('authentication.codeTip', [CODE_LENGTH]),\n      }),\n    },\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: '租户名称',\n      },\n      fieldName: 'corpName',\n      defaultValue: '',\n      label: '租户名称',\n      rules: z\n        .string()\n        .min(5, { message: '长度应在5至30个字符内' })\n        .max(30, { message: '长度应在5至30个字符内' }),\n    },\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: '用户名',\n      },\n      fieldName: 'username',\n      defaultValue: '',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        passwordStrength: true,\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      defaultValue: '',\n      label: $t('authentication.password'),\n      renderComponentContent() {\n        return {\n          strengthText: () => $t('authentication.passwordStrength'),\n        };\n      },\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.confirmPassword'),\n      },\n      dependencies: {\n        rules(values) {\n          const { password } = values;\n          return z\n            .string({ required_error: $t('authentication.passwordTip') })\n            .min(1, { message: $t('authentication.passwordTip') })\n            .refine((value) => value === password, {\n              message: $t('authentication.confirmPasswordTip'),\n            });\n        },\n        triggerFields: ['password'],\n      },\n      fieldName: 'confirmPassword',\n      defaultValue: '',\n      label: $t('authentication.confirmPassword'),\n    },\n    {\n      component: 'VbenCheckbox',\n      fieldName: 'agreePolicy',\n      renderComponentContent: () => ({\n        default: () =>\n          h('span', [\n            $t('authentication.agree'),\n            h(\n              'a',\n              {\n                class: 'vben-link ml-1 ',\n                href: '',\n              },\n              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,\n            ),\n          ]),\n      }),\n      rules: z.boolean().refine((value) => !!value, {\n        message: $t('authentication.agreeTip'),\n      }),\n    },\n  ];\n});\n\nasync function handleSubmit(value: Recordable<any>) {\n  loading.value = true;\n  const { corpName, username, password, phoneNum, smsCode } = value;\n  await registerApi({ corpName, username, password, phoneNum, smsCode });\n  notification.success({\n    message: '注册成功',\n    description: '账号注册成功，请登录!',\n    duration: 5,\n    onClick: () => {\n      router.push('/auth/login');\n    },\n    onClose: () => {\n      router.push('/auth/login');\n    },\n  });\n}\n</script>\n\n<template>\n  <AuthenticationRegister\n    ref=\"registerRef\"\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  >\n    <template #title> 注册账号 </template>\n  </AuthenticationRegister>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/fallback/coming-soon.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/fallback/forbidden.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback403Demo' });\n</script>\n\n<template>\n  <Fallback status=\"403\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/fallback/internal-error.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback500Demo' });\n</script>\n\n<template>\n  <Fallback status=\"500\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/fallback/not-found.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback404Demo' });\n</script>\n\n<template>\n  <Fallback status=\"404\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/_core/fallback/offline.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'FallbackOfflineDemo' });\n</script>\n\n<template>\n  <Fallback status=\"offline\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/adminSpace/corpMgr/corp-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { EnableStatusUseNumOpt } from '#/api/core/common';\nimport { createCorpApi, updateCorpApi } from '#/api/core/corp';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'CorpDrawer' });\n\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'name',\n      label: '名称：',\n      rules: z\n        .string()\n        .min(5, { message: '长度应在5至30个字符内' })\n        .max(30, { message: '长度应在5至30个字符内' }),\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: EnableStatusUseNumOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'status',\n      label: '状态：',\n      rules: z.number({ required_error: '请选择状态' }),\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      const { action, corp, callback } =\n        drawerApi.getData<Record<string, any>>();\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (corp) {\n        formApi.setValues(corp);\n      }\n    }\n  },\n  title: '应用抽屉',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateCorpApi({ id: values.id, ...values });\n  } else if (drawerAction.value === ACTION.ADD) {\n    await createCorpApi({ ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\n</script>\n\n<template>\n  <Drawer>\n    <Form />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/adminSpace/corpMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { CorpVo } from '#/api/core/corp';\n\nimport { onMounted, ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { useVbenDrawer } from '@vben/common-ui';\nimport { resetAllStores, useAccessStore } from '@vben/stores';\n\nimport { Button, Card, List, Popconfirm } from 'ant-design-vue';\n\nimport {\n  deleteCorpsApi,\n  getCorpByIdApi,\n  intoCorpSpaceApi,\n  listCorpApi,\n} from '#/api/core/corp';\nimport { ACTION } from '#/common/constants';\nimport { useAuthStore } from '#/store';\n\nimport CorpDrawerCom from './corp-drawer.vue';\n\nconst router = useRouter();\nconst accessStore = useAccessStore();\nconst authStore = useAuthStore();\n\nconst corps = ref<CorpVo[]>();\n\nonMounted(async () => {\n  await reloadGrid();\n});\n\nconst [CorpDrawer, corpDrawerApi] = useVbenDrawer({\n  connectedComponent: CorpDrawerCom,\n});\n\nasync function mgrCorp(corp: CorpVo) {\n  await intoCorpSpaceApi(corp.id);\n  const { accessToken } = accessStore;\n  await resetAllStores();\n  await authStore.changeSpace(accessToken ?? '', async () => {\n    await router.replace(`/?r=${Date.now()}`);\n  });\n}\n\nasync function reloadGrid() {\n  corps.value = await listCorpApi();\n}\n\nasync function addDrawer() {\n  corpDrawerApi.setState({ title: '新增' });\n  corpDrawerApi.setData({ action: ACTION.ADD, callback: reloadGrid });\n  corpDrawerApi.open();\n}\n\nasync function editDrawer(vo: CorpVo) {\n  const corp: CorpVo = await getCorpByIdApi(vo.id);\n  corpDrawerApi.setState({ title: '编辑' });\n  corpDrawerApi.setData({ action: ACTION.EDIT, corp, callback: reloadGrid });\n  corpDrawerApi.open();\n}\n\nasync function del(row: CorpVo) {\n  await deleteCorpsApi({ ids: [row.id] });\n  await reloadGrid();\n}\n</script>\n\n<template>\n  <div style=\"padding: 20px\">\n    <List :data-source=\"corps\" :grid=\"{ gutter: 16 }\">\n      <template #renderItem=\"{ item }\">\n        <List.Item row-key=\"id\" style=\"padding: 0\">\n          <Card\n            :key=\"item.id\"\n            :title=\"item.name\"\n            hoverable\n            style=\"width: 260px\"\n          >\n            <template #cover>\n              <img\n                alt=\"example\"\n                src=\"https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png\"\n              />\n            </template>\n            <p>企业状态：{{ item.status ? '启用' : '禁用' }}</p>\n            <p>部门数量：{{ item.depCount }}个</p>\n            <p>用户数量：{{ item.depCount }}个</p>\n            <template #actions>\n              <Button type=\"text\" @click=\"mgrCorp(item)\">\n                <span class=\"icon-[ant-design--file-search-outlined]\"></span>\n              </Button>\n              <Button type=\"text\" @click=\"editDrawer(item)\">\n                <span class=\"icon-[ant-design--edit-twotone]\"></span>\n              </Button>\n              <Popconfirm\n                :description=\"`确定要删除【${item.name}】?`\"\n                cancel-text=\"否\"\n                ok-text=\"是\"\n                title=\"删除\"\n                @confirm=\"() => del(item)\"\n              >\n                <Button type=\"text\">\n                  <span class=\"icon-[ant-design--delete-outlined]\"></span>\n                </Button>\n              </Popconfirm>\n            </template>\n          </Card>\n        </List.Item>\n      </template>\n    </List>\n    <Button @click=\"addDrawer\">创建企业</Button>\n    <CorpDrawer />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/adminSpace/userMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormProps } from '#/adapter/form';\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\nimport type { UserVo } from '#/api';\n\nimport { onMounted, ref } from 'vue';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, Input, message, Popconfirm } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { deleteUsersApi, GenderType, getUserByIdApi, pageUserApi } from '#/api';\nimport {\n  EnableStatusUseNum,\n  YesOrNoUseBool,\n  YesOrNoUseNumOpt,\n} from '#/api/core/common';\nimport { ACTION } from '#/common/constants';\n\nimport UserDrawerCom from './user-drawer.vue';\n\nconst { Search } = Input;\n\nconst apiUrl = import.meta.env.VITE_GLOB_API_URL;\nconst simpleSearch = ref<boolean>(false);\nconst keyword = ref<string>();\n\nconst formOptions: VbenFormProps = {\n  // 默认展开\n  collapsed: true,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        allowClear: true,\n      },\n      fieldName: 'name',\n      label: '姓名：',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        allowClear: true,\n      },\n      fieldName: 'username',\n      label: '用户名：',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        allowClear: true,\n      },\n      fieldName: 'phoneNum',\n      label: '手机号：',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        options: YesOrNoUseNumOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'isSysAdmin',\n      label: '管理员：',\n    },\n    {\n      component: 'RangePicker',\n      fieldName: 'regtime',\n      label: '注册时间：',\n    },\n  ],\n  // 控制表单是否显示折叠按钮\n  showCollapseButton: true,\n  // 按下回车时是否提交表单\n  submitOnEnter: false,\n};\n\nconst gridOptions: VxeGridProps<UserVo> = {\n  size: 'medium',\n  border: true,\n  height: 'auto',\n  keepSource: true,\n  checkboxConfig: {\n    highlight: true,\n    labelField: 'name',\n  },\n  rowConfig: {\n    isCurrent: true,\n    isHover: true,\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'avatar', title: '头像', slots: { default: 'avatar' }, width: 50 },\n    { field: 'name', title: '姓名' },\n    { field: 'username', title: '账号' },\n    { field: 'phoneNum', title: '手机号码' },\n    { field: 'gender', title: '性别', slots: { default: 'gender' }, width: 80 },\n    {\n      field: 'isSysAdmin',\n      title: '管理员',\n      slots: { default: 'isSysAdmin' },\n      width: 80,\n    },\n    { field: 'status', title: '状态', slots: { default: 'status' }, width: 80 },\n    { field: 'regtime', title: '注册时间', formatter: 'formatDateTime' },\n    { field: 'lastLoginTime', title: '最近登录', formatter: 'formatDateTime' },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 260,\n    },\n  ],\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }, formValues) => {\n        return await pageUserApi({\n          pageNum: page.currentPage,\n          pageSize: page.pageSize,\n          keyword: keyword.value,\n          ...formValues,\n        });\n      },\n    },\n    response: {\n      result: 'records',\n      total: 'totalCount',\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<UserVo> = {\n  cellDblclick: (e) => {\n    if (e.column.field !== 'action') {\n      viewDrawer(e.row);\n      e.$event.stopPropagation();\n    }\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  formOptions,\n  gridOptions,\n  gridEvents,\n});\n\nconst [UserDrawer, userDrawerApi] = useVbenDrawer({\n  connectedComponent: UserDrawerCom,\n});\n\nasync function reloadGrid() {\n  await gridApi.query();\n}\n\nasync function onSearch(value: string) {\n  keyword.value = value;\n  await gridApi.query();\n}\n\nasync function viewDrawer(vo: UserVo) {\n  const user: UserVo = await getUserByIdApi(vo.id);\n  userDrawerApi.setState({ title: '查看' });\n  userDrawerApi.setData({ action: ACTION.VIEW, user });\n  userDrawerApi.open();\n}\n\nasync function addDrawer() {\n  userDrawerApi.setState({ title: '新增' });\n  userDrawerApi.setData({ action: ACTION.ADD, callback: reloadGrid });\n  userDrawerApi.open();\n}\n\nasync function search() {\n  simpleSearch.value = !simpleSearch.value;\n  gridApi.toggleSearchForm(!simpleSearch.value);\n}\n\nasync function editDrawer(vo: UserVo) {\n  const user: UserVo = await getUserByIdApi(vo.id);\n  userDrawerApi.setState({ title: '编辑' });\n  userDrawerApi.setData({ action: ACTION.EDIT, user, callback: reloadGrid });\n  userDrawerApi.open();\n}\n\nasync function resetPwd(row: UserVo) {\n  message.success({\n    content: `form values: ${JSON.stringify(row)}`,\n  });\n}\n\nasync function delUser(row: UserVo) {\n  await deleteUsersApi({ ids: [row.id] });\n  await reloadGrid();\n}\n\nonMounted(async () => {});\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #toolbar-actions>\n        <Search\n          :style=\"{ width: '240px' }\"\n          v-if=\"simpleSearch\"\n          allow-clear\n          placeholder=\"名称、编号\"\n          @search=\"onSearch\"\n        />\n      </template>\n      <template #toolbar-tools>\n        <Button\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"search\"\n        >\n          <span class=\"icon-[ant-design--search-outlined]\"></span>\n        </Button>\n        <Button\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"addDrawer\"\n        >\n          <span class=\"icon-[ant-design--plus-outlined]\"></span>\n        </Button>\n      </template>\n      <template #avatar=\"{ row }\">\n        <img\n          :src=\"apiUrl + row.avatar\"\n          alt=\"\"\n          style=\"width: 28px; height: 28px\"\n        />\n      </template>\n      <template #gender=\"{ row }\">\n        <div>{{ GenderType[row.gender as keyof typeof GenderType] }}</div>\n      </template>\n      <template #isSysAdmin=\"{ row }\">\n        <div>\n          {{\n            YesOrNoUseBool[\n              row.isSysAdmin?.toString() as keyof typeof YesOrNoUseBool\n            ]\n          }}\n        </div>\n      </template>\n      <template #status=\"{ row }\">\n        <div>\n          {{\n            EnableStatusUseNum[row.status as keyof typeof EnableStatusUseNum]\n          }}\n        </div>\n      </template>\n      <template #action=\"{ row }\">\n        <Button type=\"link\" @click=\"editDrawer(row)\">编辑</Button>\n        <Button type=\"link\" @click=\"resetPwd(row)\">重置密码</Button>\n        <Popconfirm\n          :description=\"`确定要删除【${row.name}】?`\"\n          cancel-text=\"否\"\n          ok-text=\"是\"\n          title=\"删除\"\n          @confirm=\"() => delUser(row)\"\n        >\n          <Button type=\"link\">删除</Button>\n        </Popconfirm>\n      </template>\n    </Grid>\n    <UserDrawer />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/adminSpace/userMgr/user-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { FileType } from 'ant-design-vue/es/upload/interface';\n\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { Image, message, Upload } from 'ant-design-vue';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { createUserApi, GenderTypeOpt, updateUserApi } from '#/api';\nimport {\n  EnableStatusUseNumOpt,\n  uploadImgApi,\n  YesOrNoUseNumOpt,\n} from '#/api/core/common';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'UserDrawer' });\n\nconst apiUrl = import.meta.env.VITE_GLOB_API_URL;\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'Upload',\n      componentProps: {},\n      fieldName: 'avatar',\n      label: '头像：',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'name',\n      label: '姓名：',\n      rules: z\n        .string()\n        .min(2, { message: '长度应在2至10个字符内' })\n        .max(10, { message: '长度应在2至10个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'username',\n      label: '用户名：',\n      rules: z\n        .string()\n        .min(5, { message: '长度应在5至20个字符内' })\n        .max(20, { message: '长度应在5至20个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'phoneNum',\n      label: '手机号：',\n      rules: z.string().regex(/^1[3-9]\\d{9}$/, '请填写正确的手机号'),\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: GenderTypeOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'gender',\n      label: '性别：',\n      rules: z.number({ required_error: '请选择性别' }),\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: YesOrNoUseNumOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'isSysAdmin',\n      label: '管理员：',\n      rules: z.number({ required_error: '请选择是否管理员' }),\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: EnableStatusUseNumOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'status',\n      label: '状态：',\n      rules: z.number({ required_error: '请选择状态' }),\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      const { action, user, callback } =\n        drawerApi.getData<Record<string, any>>();\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (user) {\n        formApi.setValues(user);\n      }\n    }\n  },\n  title: '用户抽屉',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateUserApi({ id: values.id, ...values });\n  } else if (drawerAction.value === ACTION.ADD) {\n    await createUserApi({ ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\nconst beforeUpload = async (file: FileType) => {\n  const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';\n  if (!isJpgOrPng) {\n    message.error('You can only upload JPG/PNG file!');\n  }\n  const isLt500K = file.size / 1024 < 500;\n  if (!isLt500K) {\n    message.error('Image must smaller than 500KB!');\n  }\n  return isJpgOrPng && isLt500K;\n};\n\nconst customRequest = async (options: any) => {\n  const { file } = options;\n  const fileUrl = await uploadImgApi(file);\n  await formApi.setValues({ avatar: fileUrl });\n};\n</script>\n<template>\n  <Drawer>\n    <Form>\n      <template #avatar=\"{ value, disabled }\">\n        <Upload\n          :before-upload=\"beforeUpload\"\n          :custom-request=\"customRequest\"\n          :disabled=\"disabled\"\n          :show-upload-list=\"false\"\n          accept=\".png, .jpg, .jpeg\"\n          list-type=\"picture-card\"\n        >\n          <Image\n            :preview=\"disabled ?? false\"\n            :src=\"apiUrl + value\"\n            style=\"width: 80px; height: 80px\"\n          />\n        </Upload>\n      </template>\n    </Form>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/common/appMgr/app-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { FileType } from 'ant-design-vue/es/upload/interface';\n\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { Image, message, Upload } from 'ant-design-vue';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { createAppApi, updateAppApi } from '#/api/core/app';\nimport { uploadImgApi } from '#/api/core/common';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'AppDrawer' });\n\nconst apiUrl = import.meta.env.VITE_GLOB_API_URL;\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'Upload',\n      componentProps: {},\n      fieldName: 'icon',\n      label: '图标：',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'name',\n      label: '名称：',\n      rules: z\n        .string()\n        .min(5, { message: '长度应在5至30个字符内' })\n        .max(30, { message: '长度应在5至30个字符内' }),\n    },\n    {\n      component: 'Textarea',\n      componentProps: {\n        placeholder: '请输入',\n        rows: 5,\n        showCount: true,\n        maxlength: 200,\n      },\n      fieldName: 'remark',\n      label: '备注：',\n      rules: z.string().max(200, { message: '长度应在200个字符内' }),\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      const { action, app, callback } =\n        drawerApi.getData<Record<string, any>>();\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (app) {\n        formApi.setValues(app);\n      }\n    }\n  },\n  title: '应用抽屉',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateAppApi({ id: values.id, ...values });\n  } else if (drawerAction.value === ACTION.ADD) {\n    await createAppApi({ ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\n\nconst beforeUpload = async (file: FileType) => {\n  const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';\n  if (!isJpgOrPng) {\n    message.error('You can only upload JPG/PNG file!');\n  }\n  const isLt500K = file.size / 1024 < 500;\n  if (!isLt500K) {\n    message.error('Image must smaller than 500KB!');\n  }\n  return isJpgOrPng && isLt500K;\n};\n\nconst customRequest = async (options: any) => {\n  const { file } = options;\n  const fileUrl = await uploadImgApi(file);\n  await formApi.setValues({ icon: fileUrl });\n};\n</script>\n\n<template>\n  <Drawer>\n    <Form>\n      <template #icon=\"{ value, disabled }\">\n        <Upload\n          :before-upload=\"beforeUpload\"\n          :custom-request=\"customRequest\"\n          :disabled=\"disabled\"\n          :show-upload-list=\"false\"\n          accept=\".png, .jpg, .jpeg\"\n          list-type=\"picture-card\"\n        >\n          <Image\n            :preview=\"disabled ?? false\"\n            :src=\"apiUrl + value\"\n            style=\"width: 80px; height: 80px\"\n          />\n        </Upload>\n      </template>\n    </Form>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/common/appMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\nimport type { AppVo } from '#/api/core/app';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, Input, Popconfirm } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { deleteAppsApi, getAppByIdApi, pageAppApi } from '#/api/core/app';\nimport { ACTION } from '#/common/constants';\n\nimport AppDrawerCom from './app-drawer.vue';\n\nconst { Search } = Input;\nconst router = useRouter();\n\nconst apiUrl = import.meta.env.VITE_GLOB_API_URL;\nconst keyword = ref<string>();\n\nconst gridOptions: VxeGridProps<AppVo> = {\n  height: 'auto',\n  size: 'medium',\n  border: true,\n  keepSource: true,\n  checkboxConfig: {\n    highlight: true,\n  },\n  rowConfig: {\n    isCurrent: true,\n    isHover: true,\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'icon', title: '图标', slots: { default: 'icon' }, width: 50 },\n    { field: 'name', title: '名称' },\n    { field: 'remark', title: '备注' },\n    { field: 'createTime', title: '创建时间', formatter: 'formatDateTime' },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 220,\n    },\n  ],\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await pageAppApi({\n          pageNum: page.currentPage,\n          pageSize: page.pageSize,\n          name: keyword.value,\n        });\n      },\n    },\n    response: {\n      result: 'records',\n      total: 'totalCount',\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<AppVo> = {\n  cellDblclick: (e) => {\n    if (e.column.field !== 'action') {\n      viewDrawer(e.row);\n      e.$event.stopPropagation();\n    }\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions,\n  gridEvents,\n});\n\nconst [AppDrawer, appDrawerApi] = useVbenDrawer({\n  connectedComponent: AppDrawerCom,\n});\n\nasync function reloadGrid() {\n  await gridApi.query();\n}\n\nasync function onSearch(value: string) {\n  keyword.value = value;\n  await gridApi.query();\n}\n\nasync function viewDrawer(vo: AppVo) {\n  const app: AppVo = await getAppByIdApi(vo.id);\n  appDrawerApi.setState({ title: '查看' });\n  appDrawerApi.setData({ action: ACTION.VIEW, app });\n  appDrawerApi.open();\n}\n\nasync function addDrawer() {\n  appDrawerApi.setState({ title: '新增' });\n  appDrawerApi.setData({ action: ACTION.ADD, callback: reloadGrid });\n  appDrawerApi.open();\n}\n\nasync function editDrawer(vo: AppVo) {\n  const app: AppVo = await getAppByIdApi(vo.id);\n  appDrawerApi.setState({ title: '编辑' });\n  appDrawerApi.setData({ action: ACTION.EDIT, app, callback: reloadGrid });\n  appDrawerApi.open();\n}\n\nasync function toConfig(vo: AppVo) {\n  await router.push(`/common/appResourceMgr/list/${vo.id}`);\n}\n\nasync function delApp(row: AppVo) {\n  await deleteAppsApi({ ids: [row.id] });\n  await reloadGrid();\n}\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #toolbar-actions>\n        <Search\n          :style=\"{ width: '240px' }\"\n          allow-clear\n          placeholder=\"名称\"\n          @search=\"onSearch\"\n        />\n      </template>\n      <template #toolbar-tools>\n        <Button\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"addDrawer\"\n        >\n          <span class=\"icon-[ant-design--plus-outlined]\"></span>\n        </Button>\n      </template>\n      <template #icon=\"{ row }\">\n        <img\n          :src=\"apiUrl + row.icon\"\n          alt=\"图标\"\n          style=\"width: 28px; height: 28px\"\n        />\n      </template>\n      <template #action=\"{ row }\">\n        <Button type=\"link\" @click=\"editDrawer(row)\">编辑</Button>\n        <Button type=\"link\" @click=\"toConfig(row)\">配置</Button>\n        <Popconfirm\n          :description=\"`确定要删除【${row.name}】?`\"\n          cancel-text=\"否\"\n          ok-text=\"是\"\n          title=\"删除\"\n          @confirm=\"() => delApp(row)\"\n        >\n          <Button type=\"link\">删除</Button>\n        </Popconfirm>\n      </template>\n    </Grid>\n    <AppDrawer />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/common/appResourceMgr/app-resource-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport {\n  appResourceTreeApi,\n  AppResourceTypeOpt,\n  createAppResourceApi,\n  updateAppResourceApi,\n} from '#/api/core/appResource';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'AppResourceDrawer' });\n\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nconst appIdRef = ref<string>('');\n\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'ApiTreeSelect',\n      componentProps: {\n        api: getArTree,\n        allowClear: true,\n        childrenField: 'children',\n        labelField: 'name',\n        valueField: 'id',\n      },\n      fieldName: 'pid',\n      label: '父权限：',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'name',\n      label: '名称：',\n      rules: z\n        .string()\n        .min(2, { message: '长度应在2至20个字符内' })\n        .max(20, { message: '长度应在2至20个字符内' }),\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: AppResourceTypeOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'type',\n      label: '类型：',\n      defaultValue: 1,\n      rules: z.number({ required_error: '请选择类型' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'code',\n      label: '编码：',\n      rules: z\n        .string()\n        .min(2, { message: '长度应在2至50个字符内' })\n        .max(50, { message: '长度应在2至50个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'url',\n      label: '页面地址：',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'api',\n      label: '接口地址：',\n    },\n    {\n      component: 'Textarea',\n      componentProps: {\n        placeholder: '请输入',\n        rows: 5,\n        showCount: true,\n        maxlength: 200,\n      },\n      fieldName: 'extend',\n      label: '扩展：',\n    },\n    {\n      component: 'Textarea',\n      componentProps: {\n        placeholder: '请输入',\n        rows: 3,\n        showCount: true,\n        maxlength: 200,\n      },\n      fieldName: 'remark',\n      label: '备注：',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      const { appId, action, appResource, callback } =\n        drawerApi.getData<Record<string, any>>();\n      appIdRef.value = appId;\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (appResource) {\n        formApi.setValues(appResource);\n      }\n    }\n  },\n  title: '应用抽屉',\n});\n\nasync function getArTree() {\n  return appResourceTreeApi(appIdRef.value);\n}\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateAppResourceApi({ id: values.id, ...values });\n  } else if (drawerAction.value === ACTION.ADD) {\n    await createAppResourceApi({ appId: appIdRef.value, ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\n</script>\n<template>\n  <Drawer>\n    <Form />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/common/appResourceMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\nimport type { AppResourceVo } from '#/api/core/appResource';\n\nimport { onMounted, ref } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\nimport { useUserStore } from '@vben/stores';\n\nimport { Button, Input, Popconfirm } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport {\n  AppResourceType,\n  deleteAppResourcesApi,\n  getAppResourceByIdApi,\n  pageAppResourceApi,\n} from '#/api/core/appResource';\nimport { ACTION, ROLE_SYS_ADMIN } from '#/common/constants';\n\nimport AppResourceDrawerCom from './app-resource-drawer.vue';\n\nconst { Search } = Input;\n\nconst route = useRoute();\nconst userStore = useUserStore();\n\nconst appIdRef = ref<string>('');\nconst keyword = ref<string>();\nconst roles = userStore.userInfo?.roles ?? [];\nconst isSysAdmin: boolean = roles.some((role) => ROLE_SYS_ADMIN.includes(role));\n\nonMounted(async () => {\n  appIdRef.value = route.params.id as string;\n});\n\nconst gridOptions: VxeGridProps<AppResourceVo> = {\n  height: 'auto',\n  size: 'medium',\n  align: 'left',\n  border: true,\n  keepSource: true,\n  checkboxConfig: {\n    highlight: true,\n  },\n  rowConfig: {\n    isCurrent: true,\n    isHover: true,\n  },\n  columns: [\n    { field: 'name', title: '名称', treeNode: true },\n    { field: 'code', title: '编号' },\n    { field: 'url', title: '页面地址' },\n    { field: 'api', title: '接口地址' },\n    {\n      field: 'type',\n      title: '类型',\n      slots: { default: 'type' },\n      width: 80,\n    },\n    { field: 'createTime', title: '创建时间', formatter: 'formatDateTime' },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 160,\n      visible: isSysAdmin,\n    },\n  ],\n  pagerConfig: {\n    pageSize: 200,\n    pageSizes: [200, 500],\n  },\n  treeConfig: {\n    parentField: 'pid',\n    rowField: 'id',\n    transform: true,\n  },\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await pageAppResourceApi({\n          pageNum: page.currentPage,\n          pageSize: page.pageSize,\n          appId: appIdRef.value,\n          keyword: keyword.value,\n        });\n      },\n    },\n    response: {\n      result: 'records',\n      total: 'totalCount',\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<AppResourceVo> = {\n  cellDblclick: (e) => {\n    if (e.column.field !== 'action') {\n      viewDrawer(e.row);\n      e.$event.stopPropagation();\n    }\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions,\n  gridEvents,\n});\n\nconst [AppResourceDrawer, appResourceDrawerApi] = useVbenDrawer({\n  connectedComponent: AppResourceDrawerCom,\n});\n\nasync function reloadGrid() {\n  await gridApi.query();\n}\n\nasync function onSearch(value: string) {\n  keyword.value = value;\n  await gridApi.query();\n}\n\nasync function viewDrawer(vo: AppResourceVo) {\n  const appResource: AppResourceVo = await getAppResourceByIdApi(vo.id);\n  appResourceDrawerApi.setState({ title: '查看' });\n  appResourceDrawerApi.setData({\n    appId: appIdRef.value,\n    action: ACTION.VIEW,\n    appResource,\n  });\n  appResourceDrawerApi.open();\n}\n\nasync function addDrawer() {\n  appResourceDrawerApi.setState({ title: '新增' });\n  appResourceDrawerApi.setData({\n    appId: appIdRef.value,\n    action: ACTION.ADD,\n    callback: reloadGrid,\n  });\n  appResourceDrawerApi.open();\n}\n\nasync function editDrawer(vo: AppResourceVo) {\n  const appResource: AppResourceVo = await getAppResourceByIdApi(vo.id);\n  appResourceDrawerApi.setState({ title: '编辑' });\n  appResourceDrawerApi.setData({\n    appId: appIdRef.value,\n    action: ACTION.EDIT,\n    appResource,\n    callback: reloadGrid,\n  });\n  appResourceDrawerApi.open();\n}\n\nasync function delAppResource(row: AppResourceVo) {\n  await deleteAppResourcesApi({ ids: [row.id] });\n  await reloadGrid();\n}\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #toolbar-actions>\n        <Search\n          :style=\"{ width: '240px' }\"\n          allow-clear\n          placeholder=\"名称、编号\"\n          @search=\"onSearch\"\n        />\n      </template>\n      <template #toolbar-tools>\n        <Button\n          v-show=\"isSysAdmin\"\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"addDrawer\"\n        >\n          <span class=\"icon-[ant-design--plus-outlined]\"></span>\n        </Button>\n      </template>\n      <template #type=\"{ row }\">\n        <div>\n          {{ AppResourceType[row.type as keyof typeof AppResourceType] }}\n        </div>\n      </template>\n      <template #action=\"{ row }\">\n        <Button type=\"link\" @click=\"editDrawer(row)\">编辑</Button>\n        <Popconfirm\n          :description=\"`确定要删除【${row.name}】?`\"\n          cancel-text=\"否\"\n          ok-text=\"是\"\n          title=\"删除\"\n          @confirm=\"() => delAppResource(row)\"\n        >\n          <Button type=\"link\">删除</Button>\n        </Popconfirm>\n      </template>\n    </Grid>\n    <AppResourceDrawer />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/appClientMgr/app-client-add-modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { AppVo } from '#/api/core/app';\n\nimport { ref } from 'vue';\n\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Radio } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\nimport { addAppClientsApi, limitNotHaveAppApi } from '#/api/core/appClient';\n\ndefineOptions({ name: 'FormModelDemo' });\n\nconst apiUrl = import.meta.env.VITE_GLOB_API_URL;\nconst apps = ref<AppVo[]>([]);\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  handleSubmit: onSubmit,\n  commonConfig: {\n    labelWidth: 0,\n  },\n  schema: [\n    {\n      component: 'RadioGroup',\n      componentProps: {},\n      fieldName: 'appId',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.validateAndSubmitForm();\n  },\n  onOpenChange: async (isOpen: boolean) => {\n    if (isOpen) {\n      await formApi.resetForm();\n      const param = { offset: 0, limit: 100 };\n      apps.value = await limitNotHaveAppApi(param);\n    }\n  },\n  title: '添加应用',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { callback } = modalApi.getData<Record<string, any>>();\n  gridCallback = callback;\n  await addAppClientsApi({ appIds: [values.appId] });\n  await modalApi.close();\n  await gridCallback();\n}\n</script>\n<template>\n  <Modal class=\"w-[1000px]\">\n    <Form>\n      <template #appId=\"slotProps\">\n        <Radio.Group v-bind=\"slotProps\">\n          <Radio\n            v-for=\"app in apps\"\n            :key=\"app.id\"\n            :label=\"app.name\"\n            :name=\"app.name\"\n            :value=\"app.id\"\n            border\n            class=\"app-checkbox\"\n          >\n            <div>\n              <img :alt=\"app.name\" :src=\"apiUrl + app.icon\" class=\"app-icon\" />\n              <div class=\"app-name\">{{ app.name }}</div>\n            </div>\n          </Radio>\n        </Radio.Group>\n      </template>\n    </Form>\n  </Modal>\n</template>\n<style scoped lang=\"scss\">\n.app-checkbox {\n  padding: 5px;\n  margin: 10px 5px;\n  border: solid 1px #dcdfe6;\n  border-radius: 5px;\n}\n\n.app-icon {\n  float: left;\n  height: 60px;\n}\n\n.app-name {\n  width: 120px;\n  height: 60px;\n  padding: 0 5px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  font-size: 16px;\n  line-height: 60px;\n  white-space: nowrap;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/appClientMgr/app-client-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { updateAppClientApi } from '#/api/core/appClient';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'AppClientDrawer' });\n\nconst isResetClientSecret = ref<boolean>(false);\nconst clientSecret = ref<string>();\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n        disabled: true,\n      },\n      fieldName: 'name',\n      label: '名称：',\n      rules: z\n        .string()\n        .min(5, { message: '长度应在5至30个字符内' })\n        .max(30, { message: '长度应在5至30个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'clientId',\n      label: 'ClientID：',\n      rules: z\n        .string()\n        .min(5, { message: '长度应在5至20个字符内' })\n        .max(50, { message: '长度应在5至50个字符内' }),\n    },\n    {\n      component: 'Button',\n      componentProps: {},\n      fieldName: 'clientSecret',\n      label: 'ClientSecret：',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'scopes',\n      label: 'Scopes：',\n      rules: z\n        .string()\n        .min(5, { message: '长度应在5至30个字符内' })\n        .max(30, { message: '长度应在5至30个字符内' }),\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n        min: 1,\n        max: 10_000,\n      },\n      fieldName: 'accessTokenTimeToLive',\n      label: 'Expire(H)：',\n      rules: z\n        .number()\n        .min(1, { message: '长度应在1至10000个字符内' })\n        .max(10_000, { message: '长度应在1至10000个字符内' }),\n    },\n    {\n      component: 'Textarea',\n      componentProps: {\n        placeholder: '请输入',\n        rows: 5,\n        maxlength: 500,\n        showCount: true,\n      },\n      fieldName: 'redirectUris',\n      label: '回调地址：',\n      rules: z\n        .string()\n        .min(5, { message: '长度应在5至500个字符内' })\n        .max(500, { message: '长度应在5至500个字符内' }),\n    },\n    {\n      component: 'Textarea',\n      componentProps: {\n        placeholder: '请输入',\n        rows: 5,\n        maxlength: 200,\n        showCount: true,\n        disabled: true,\n      },\n      fieldName: 'remark',\n      label: '备注：',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      isResetClientSecret.value = false;\n      const { action, appClient, callback } =\n        drawerApi.getData<Record<string, any>>();\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (appClient) {\n        formApi.setValues(appClient);\n      }\n    }\n  },\n  title: '应用抽屉',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateAppClientApi({\n      id: values.id,\n      ...values,\n      clientSecret: clientSecret.value,\n    });\n  } else if (drawerAction.value === ACTION.ADD) {\n    // await createAppClientApi({ ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\n\nfunction resetClientSecret() {\n  clientSecret.value = '';\n  isResetClientSecret.value = true;\n}\n</script>\n<template>\n  <Drawer>\n    <Form>\n      <template #clientSecret=\"slotProps\">\n        <input\n          name=\"clientSecret\"\n          type=\"text\"\n          v-if=\"isResetClientSecret\"\n          v-model=\"clientSecret\"\n          class=\"ant-input css-dev-only-do-not-override-14589v w-full\"\n          minlength=\"5\"\n          maxlength=\"20\"\n        />\n        <Button\n          @click=\"resetClientSecret\"\n          v-if=\"!isResetClientSecret\"\n          v-bind=\"slotProps\"\n          style=\"\n            height: 32px;\n            font-size: 0.8rem;\n            border: solid 1px #dcdfe6;\n            border-radius: 8px;\n          \"\n        >\n          重置\n        </Button>\n      </template>\n    </Form>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/appClientMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\nimport type { AppClientVo } from '#/api/core/appClient';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { Page, useVbenDrawer, useVbenModal } from '@vben/common-ui';\n\nimport { Button, Input, Popconfirm } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport {\n  deleteAppClientsApi,\n  getAppClientByIdApi,\n  pageAppClientApi,\n} from '#/api/core/appClient';\nimport { ACTION } from '#/common/constants';\n\nimport AppClientAddModalCom from './app-client-add-modal.vue';\nimport AppClientDrawerCom from './app-client-drawer.vue';\n\nconst { Search } = Input;\nconst router = useRouter();\n\nconst apiUrl = import.meta.env.VITE_GLOB_API_URL;\nconst keyword = ref<string>();\n\nconst gridOptions: VxeGridProps<AppClientVo> = {\n  height: 'auto',\n  size: 'medium',\n  border: true,\n  keepSource: true,\n  checkboxConfig: {\n    highlight: true,\n  },\n  rowConfig: {\n    isCurrent: true,\n    isHover: true,\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'icon', title: '图标', slots: { default: 'icon' }, width: 50 },\n    { field: 'name', title: '名称' },\n    { field: 'clientId', title: 'clientId' },\n    { field: 'scopes', title: 'scopes' },\n    { field: 'createTime', title: '创建时间', formatter: 'formatDateTime' },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 220,\n    },\n  ],\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await pageAppClientApi({\n          pageNum: page.currentPage,\n          pageSize: page.pageSize,\n          keyword: keyword.value,\n        });\n      },\n    },\n    response: {\n      result: 'records',\n      total: 'totalCount',\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<AppClientVo> = {\n  cellDblclick: (e) => {\n    if (e.column.field !== 'action') {\n      viewDrawer(e.row);\n      e.$event.stopPropagation();\n    }\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions,\n  gridEvents,\n});\n\nconst [AppClientDrawer, appClientDrawerApi] = useVbenDrawer({\n  connectedComponent: AppClientDrawerCom,\n});\n\nconst [AppClientAddModal, appClientAddModalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: AppClientAddModalCom,\n});\n\nasync function reloadGrid() {\n  await gridApi.query();\n}\n\nasync function onSearch(value: string) {\n  keyword.value = value;\n  await gridApi.query();\n}\n\nasync function viewDrawer(vo: AppClientVo) {\n  const appClient: AppClientVo = await getAppClientByIdApi(vo.id);\n  appClientDrawerApi.setState({ title: '查看' });\n  appClientDrawerApi.setData({ action: ACTION.VIEW, appClient });\n  appClientDrawerApi.open();\n}\n\nasync function addDrawer() {\n  appClientAddModalApi.setData({ callback: reloadGrid });\n  appClientAddModalApi.open();\n}\n\nasync function editDrawer(vo: AppClientVo) {\n  const appClient: AppClientVo = await getAppClientByIdApi(vo.id);\n  appClientDrawerApi.setState({ title: '编辑' });\n  appClientDrawerApi.setData({\n    action: ACTION.EDIT,\n    appClient,\n    callback: reloadGrid,\n  });\n  appClientDrawerApi.open();\n}\n\nasync function toConfig(vo: AppClientVo) {\n  await router.push(`/common/appResourceMgr/list/${vo.appId}`);\n}\n\nasync function delAppClient(row: AppClientVo) {\n  await deleteAppClientsApi({ ids: [row.id] });\n  await reloadGrid();\n}\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #toolbar-actions>\n        <Search\n          :style=\"{ width: '240px' }\"\n          allow-clear\n          placeholder=\"名称\"\n          @search=\"onSearch\"\n        />\n      </template>\n      <template #toolbar-tools>\n        <Button\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"addDrawer\"\n        >\n          <span class=\"icon-[ant-design--plus-outlined]\"></span>\n        </Button>\n      </template>\n      <template #icon=\"{ row }\">\n        <img\n          :src=\"apiUrl + row.icon\"\n          alt=\"图标\"\n          style=\"width: 28px; height: 28px\"\n        />\n      </template>\n      <template #action=\"{ row }\">\n        <Button type=\"link\" @click=\"editDrawer(row)\">编辑</Button>\n        <Button type=\"link\" @click=\"toConfig(row)\">配置</Button>\n        <Popconfirm\n          :description=\"`确定要删除【${row.name}】?`\"\n          cancel-text=\"否\"\n          ok-text=\"是\"\n          title=\"删除\"\n          @confirm=\"() => delAppClient(row)\"\n        >\n          <Button type=\"link\">删除</Button>\n        </Popconfirm>\n      </template>\n    </Grid>\n    <AppClientDrawer class=\"w-[600px]\" />\n    <AppClientAddModal />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/depMgr/dep-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { EnableStatusUseNumOpt } from '#/api/core/common';\nimport { createDepApi, depTreeApi, updateDepApi } from '#/api/core/dep';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'DepDrawer' });\n\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'ApiTreeSelect',\n      componentProps: {\n        api: depTreeApi,\n        allowClear: true,\n        childrenField: 'children',\n        labelField: 'name',\n        valueField: 'id',\n      },\n      fieldName: 'pid',\n      label: '父部门：',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'no',\n      label: '编码：',\n      rules: z\n        .string()\n        .min(2, { message: '长度应在2至10个字符内' })\n        .max(10, { message: '长度应在2至10个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'name',\n      label: '名称：',\n      rules: z\n        .string()\n        .min(2, { message: '长度应在2至20个字符内' })\n        .max(20, { message: '长度应在2至20个字符内' }),\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n        min: 1,\n        max: 9999,\n      },\n      defaultValue: 1,\n      fieldName: 'sort',\n      label: '排序：',\n      rules: z\n        .number()\n        .gte(1, { message: '大小应在1至9999之间' })\n        .lte(9999, { message: '大小应在1至9999之间' }),\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: EnableStatusUseNumOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'status',\n      label: '状态：',\n      rules: z.number({ required_error: '请选择状态' }),\n    },\n    {\n      component: 'Textarea',\n      componentProps: {\n        placeholder: '请输入',\n        rows: 5,\n        showCount: true,\n        maxlength: 200,\n      },\n      fieldName: 'remark',\n      label: '备注：',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      const { action, dep, callback } =\n        drawerApi.getData<Record<string, any>>();\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (dep) {\n        formApi.setValues(dep);\n      }\n    }\n  },\n  title: '应用抽屉',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateDepApi({ id: values.id, ...values });\n  } else if (drawerAction.value === ACTION.ADD) {\n    await createDepApi({ ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\n</script>\n<template>\n  <Drawer>\n    <Form />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/depMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\nimport type { DepVo } from '#/api/core/dep';\n\nimport { ref } from 'vue';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, Input, Popconfirm } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { EnableStatusUseNum } from '#/api/core/common';\nimport { deleteDepsApi, getDepByIdApi, pageDepApi } from '#/api/core/dep';\nimport { ACTION } from '#/common/constants';\n\nimport DepDrawerCom from './dep-drawer.vue';\n\nconst { Search } = Input;\n\nconst keyword = ref<string>();\n\nconst gridOptions: VxeGridProps<DepVo> = {\n  height: 'auto',\n  size: 'medium',\n  align: 'left',\n  border: true,\n  keepSource: true,\n  checkboxConfig: {\n    highlight: true,\n  },\n  rowConfig: {\n    isCurrent: true,\n    isHover: true,\n  },\n  columns: [\n    { field: 'name', title: '名称', treeNode: true },\n    { field: 'no', title: '编号' },\n    {\n      field: 'status',\n      title: '状态',\n      slots: { default: 'status' },\n      width: 80,\n    },\n    { field: 'remark', title: '备注' },\n    { field: 'createTime', title: '创建时间', formatter: 'formatDateTime' },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 160,\n    },\n  ],\n  pagerConfig: {\n    pageSize: 200,\n    pageSizes: [200, 500],\n  },\n  treeConfig: {\n    parentField: 'pid',\n    rowField: 'id',\n    transform: true,\n    expandAll: true,\n  },\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await pageDepApi({\n          pageNum: page.currentPage,\n          pageSize: page.pageSize,\n          keyword: keyword.value,\n        });\n      },\n    },\n    response: {\n      result: 'records',\n      total: 'totalCount',\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<DepVo> = {\n  cellDblclick: (e) => {\n    if (e.column.field !== 'action') {\n      viewDrawer(e.row);\n      e.$event.stopPropagation();\n    }\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions,\n  gridEvents,\n});\n\nconst [DepDrawer, depDrawerApi] = useVbenDrawer({\n  connectedComponent: DepDrawerCom,\n});\n\nasync function reloadGrid() {\n  await gridApi.query();\n  await gridApi.grid?.setAllTreeExpand(true);\n}\n\nasync function onSearch(value: string) {\n  keyword.value = value;\n  await gridApi.query();\n  await gridApi.grid?.setAllTreeExpand(true);\n}\n\nasync function viewDrawer(vo: DepVo) {\n  const dep: DepVo = await getDepByIdApi(vo.id);\n  depDrawerApi.setState({ title: '查看' });\n  depDrawerApi.setData({ action: ACTION.VIEW, dep });\n  depDrawerApi.open();\n}\n\nasync function addDrawer() {\n  depDrawerApi.setState({ title: '新增' });\n  depDrawerApi.setData({ action: ACTION.ADD, callback: reloadGrid });\n  depDrawerApi.open();\n}\n\nasync function editDrawer(vo: DepVo) {\n  const dep: DepVo = await getDepByIdApi(vo.id);\n  depDrawerApi.setState({ title: '编辑' });\n  depDrawerApi.setData({ action: ACTION.EDIT, dep, callback: reloadGrid });\n  depDrawerApi.open();\n}\n\nasync function delDep(row: DepVo) {\n  await deleteDepsApi({ ids: [row.id] });\n  await reloadGrid();\n}\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #toolbar-actions>\n        <Search\n          :style=\"{ width: '240px' }\"\n          allow-clear\n          placeholder=\"名称、编号\"\n          @search=\"onSearch\"\n        />\n      </template>\n      <template #toolbar-tools>\n        <Button\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"addDrawer\"\n        >\n          <span class=\"icon-[ant-design--plus-outlined]\"></span>\n        </Button>\n      </template>\n      <template #status=\"{ row }\">\n        <div>\n          {{\n            EnableStatusUseNum[row.status as keyof typeof EnableStatusUseNum]\n          }}\n        </div>\n      </template>\n      <template #action=\"{ row }\">\n        <Button type=\"link\" @click=\"editDrawer(row)\">编辑</Button>\n        <Popconfirm\n          :description=\"`确定要删除【${row.name}】?`\"\n          cancel-text=\"否\"\n          ok-text=\"是\"\n          title=\"删除\"\n          @confirm=\"() => delDep(row)\"\n        >\n          <Button type=\"link\">删除</Button>\n        </Popconfirm>\n      </template>\n    </Grid>\n    <DepDrawer />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/empMgr/emp-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EmpVo } from '#/api/core/emp';\n\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { useDebounceFn } from '@vueuse/core';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { YesOrNoUseBoolOpt } from '#/api/core/common';\nimport { depTreeApi } from '#/api/core/dep';\nimport { createEmpApi, findUserApi, updateEmpApi } from '#/api/core/emp';\nimport { limitRoleApi } from '#/api/core/role';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'EmpDrawer' });\n\nconst userKeyword = ref('');\nconst roleKeyword = ref('');\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nconst empRef = ref<EmpVo>();\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'ApiTreeSelect',\n      componentProps: {\n        api: depTreeApi,\n        showSearch: true,\n        multiple: true,\n        treeDefaultExpandAll: true,\n        allowClear: true,\n        childrenField: 'children',\n        labelField: 'name',\n        valueField: 'id',\n      },\n      fieldName: 'depIds',\n      label: '部门：',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'name',\n      label: '姓名：',\n      rules: z\n        .string()\n        .min(2, { message: '长度应在2至10个字符内' })\n        .max(10, { message: '长度应在2至10个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'no',\n      label: '工号：',\n      rules: z\n        .string()\n        .min(2, { message: '长度应在2至10个字符内' })\n        .max(10, { message: '长度应在2至10个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'email',\n      label: '邮箱：',\n      rules: z.string().email({ message: '请填写正确的邮箱' }),\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: YesOrNoUseBoolOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'isCorpAdmin',\n      label: '管理员：',\n      rules: z.boolean({ required_error: '请选择状态' }),\n    },\n    {\n      component: 'ApiSelect',\n      componentProps: {\n        api: limitRoleApi,\n        labelField: 'name',\n        valueField: 'id',\n        allowClear: true,\n        mode: 'multiple',\n        // 禁止本地过滤\n        filterOption: false,\n        // 搜索词变化时记录下来， 使用useDebounceFn防抖。\n        onSearch: useDebounceFn((value: string) => {\n          roleKeyword.value = value;\n        }, 1000),\n        // 远程搜索参数。当搜索词变化时，params也会更新\n        params: { keyword: roleKeyword.value },\n        showSearch: true,\n      },\n      fieldName: 'roleIds',\n      label: '角色：',\n    },\n    {\n      component: 'ApiSelect',\n      componentProps: () => {\n        return {\n          api: findUserApi,\n          labelField: 'name',\n          valueField: 'id',\n          allowClear: true,\n          // 禁止本地过滤\n          filterOption: false,\n          // 搜索词变化时记录下来， 使用useDebounceFn防抖。\n          onSearch: useDebounceFn((value: string) => {\n            userKeyword.value = value;\n          }, 1000),\n          // 远程搜索参数。当搜索词变化时，params也会更新\n          params: { keyword: userKeyword.value, userId: empRef?.value?.userId },\n          showSearch: true,\n        };\n      },\n      fieldName: 'userId',\n      label: '绑定账号：',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      const { action, emp, callback } =\n        drawerApi.getData<Record<string, any>>();\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (emp) {\n        empRef.value = emp;\n        formApi.setValues(emp);\n      }\n    }\n  },\n  title: '应用抽屉',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateEmpApi({ id: values.id, ...values });\n  } else if (drawerAction.value === ACTION.ADD) {\n    await createEmpApi({ ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\n</script>\n<template>\n  <Drawer>\n    <Form />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/empMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Key } from 'ant-design-vue/es/_util/type';\nimport type { TreeDataNode } from 'ant-design-vue/lib/vc-tree-select/interface';\n\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\nimport type { EmpVo } from '#/api/core/emp';\n\nimport { onMounted, ref } from 'vue';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, Flex, Input, Popconfirm, Tree } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { YesOrNoUseBool } from '#/api/core/common';\nimport { depTreeApi } from '#/api/core/dep';\nimport { deleteEmpsApi, getEmpByIdApi, pageEmpApi } from '#/api/core/emp';\nimport { ACTION } from '#/common/constants';\n\nimport EmpDrawerCom from './emp-drawer.vue';\n\nconst { Search } = Input;\n\nconst depIds = ref<string[]>([]);\nconst keyword = ref<string>();\n\nconst gridOptions: VxeGridProps<EmpVo> = {\n  height: 'auto',\n  size: 'medium',\n  border: true,\n  keepSource: true,\n  checkboxConfig: {\n    highlight: true,\n  },\n  rowConfig: {\n    isCurrent: true,\n    isHover: true,\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'no', title: '工号' },\n    { field: 'name', title: '姓名' },\n    { field: 'email', title: '邮箱' },\n    {\n      field: 'isCorpAdmin',\n      title: '企业管理员',\n      slots: { default: 'isCorpAdmin' },\n    },\n    { field: 'createTime', title: '创建时间', formatter: 'formatDateTime' },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 160,\n    },\n  ],\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await pageEmpApi({\n          pageNum: page.currentPage,\n          pageSize: page.pageSize,\n          depIds: depIds.value,\n          keyword: keyword.value,\n        });\n      },\n    },\n    response: {\n      result: 'records',\n      total: 'totalCount',\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<EmpVo> = {\n  cellDblclick: (e) => {\n    if (e.column.field !== 'action') {\n      viewDrawer(e.row);\n      e.$event.stopPropagation();\n    }\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions,\n  gridEvents,\n});\n\nconst [EmpDrawer, empDrawerApi] = useVbenDrawer({\n  connectedComponent: EmpDrawerCom,\n});\n\nasync function reloadGrid() {\n  await gridApi.query();\n}\n\nasync function onSearch(value: string) {\n  keyword.value = value;\n  await gridApi.query();\n}\n\nasync function viewDrawer(vo: EmpVo) {\n  const emp: EmpVo = await getEmpByIdApi(vo.id);\n  empDrawerApi.setState({ title: '查看' });\n  empDrawerApi.setData({ action: ACTION.VIEW, emp });\n  empDrawerApi.open();\n}\n\nasync function addDrawer() {\n  empDrawerApi.setState({ title: '新增' });\n  empDrawerApi.setData({ action: ACTION.ADD, callback: reloadGrid });\n  empDrawerApi.open();\n}\n\nasync function editDrawer(vo: EmpVo) {\n  const emp: EmpVo = await getEmpByIdApi(vo.id);\n  empDrawerApi.setState({ title: '编辑' });\n  empDrawerApi.setData({ action: ACTION.EDIT, emp, callback: reloadGrid });\n  empDrawerApi.open();\n}\n\nasync function delEmp(row: EmpVo) {\n  await deleteEmpsApi({ ids: [row.id] });\n  await reloadGrid();\n}\n\nconst treeData = ref<TreeDataNode[]>([]);\nconst expandedKeys = ref<string[]>([]);\n\nasync function expandAll() {\n  const allKeys: string[] = [];\n  const collectKeys = (nodes: TreeDataNode[]) => {\n    nodes.forEach((node) => {\n      allKeys.push(node.id);\n      if (node.children) {\n        collectKeys(node.children);\n      }\n    });\n  };\n  collectKeys(treeData.value);\n  expandedKeys.value = allKeys;\n}\n\nasync function onSelect(selectedKeys: Key[]) {\n  depIds.value = selectedKeys as string[];\n  await gridApi.query();\n}\n\nonMounted(async () => {\n  treeData.value = await depTreeApi();\n  await expandAll();\n});\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Flex :vertical=\"false\" class=\"h-full\">\n      <div\n        class=\"bg-card rounded-md\"\n        style=\"width: 15%; padding-top: 0.3em; margin-right: 0.6em\"\n      >\n        <div class=\"item w-full\">\n          <Input placeholder=\"输入关键字过滤\" />\n        </div>\n        <div v-if=\"false\" class=\"item w-full\">\n          <Button class=\"w-full\">全部</Button>\n        </div>\n        <div class=\"item w-full\">\n          <Tree\n            :expanded-keys=\"expandedKeys\"\n            :field-names=\"{ title: 'name', key: 'id', children: 'children' }\"\n            :tree-data=\"treeData\"\n            default-expand-all\n            @select=\"(keys) => onSelect(keys)\"\n          />\n        </div>\n      </div>\n      <div style=\"width: 85%\">\n        <Grid>\n          <template #toolbar-actions>\n            <Search\n              :style=\"{ width: '240px' }\"\n              allow-clear\n              placeholder=\"姓名、工号、邮箱\"\n              @search=\"onSearch\"\n            />\n          </template>\n          <template #toolbar-tools>\n            <Button\n              class=\"vxe-button type--button size--medium is--circle\"\n              @click=\"addDrawer\"\n            >\n              <span class=\"icon-[ant-design--plus-outlined]\"></span>\n            </Button>\n          </template>\n          <template #isCorpAdmin=\"{ row }\">\n            <div>\n              {{\n                YesOrNoUseBool[\n                  row.isCorpAdmin?.toString() as keyof typeof YesOrNoUseBool\n                ]\n              }}\n            </div>\n          </template>\n          <template #action=\"{ row }\">\n            <Button type=\"link\" @click=\"editDrawer(row)\">编辑</Button>\n            <Popconfirm\n              :description=\"`确定要删除【${row.name}】?`\"\n              cancel-text=\"否\"\n              ok-text=\"是\"\n              title=\"删除\"\n              @confirm=\"() => delEmp(row)\"\n            >\n              <Button type=\"link\">删除</Button>\n            </Popconfirm>\n          </template>\n        </Grid>\n      </div>\n    </Flex>\n    <EmpDrawer />\n  </Page>\n</template>\n<style>\n.item {\n  padding: 0.3em 0.6em 0;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/roleMgr/auth-modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Key } from 'ant-design-vue/es/_util/type';\nimport type { CheckInfo } from 'ant-design-vue/es/vc-tree/props';\nimport type { TreeDataNode } from 'ant-design-vue/lib/vc-tree-select/interface';\n\nimport type { AppVo } from '#/api/core/app';\n\nimport { ref } from 'vue';\n\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Tree, TreeSelect } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\nimport { limitHaveAppApi } from '#/api/core/appClient';\nimport {\n  appResourceTreeApi,\n  findAppResourceIdsByRoleAndAppApi,\n} from '#/api/core/appResource';\nimport { authRoleApi } from '#/api/core/role';\n\ndefineOptions({ name: 'AuthFormModel' });\n\nconst apps = ref<AppVo[]>([]);\nconst roleIdRef = ref<string>('');\nconst appIdRef = ref<string>('');\nconst checkedKeysRef = ref<string[]>([]);\nconst arTreeData = ref<TreeDataNode[]>([]);\nlet gridCallback = () => {};\n\nconst handleAppSelectOnChange = async (appId: string) => {\n  appIdRef.value = appId;\n  arTreeData.value = await appResourceTreeApi(appId);\n  checkedKeysRef.value = await findAppResourceIdsByRoleAndAppApi({\n    appId,\n    roleId: roleIdRef.value,\n  });\n};\n\nconst handleTreeOnCheck = async (\n  checkedKeys: Key[] | { checked: Key[]; halfChecked: Key[] },\n  info: CheckInfo,\n) => {\n  const { checked, node } = info;\n  const keys = checkedKeys as { checked: string[]; halfChecked: string[] };\n  checkedKeysRef.value = [...keys.checked, ...keys.halfChecked];\n  if (checked) {\n    node.children?.forEach((child) => {\n      checkedKeysRef.value.push(child.id);\n    });\n  }\n};\n\nconst resetForm = async () => {\n  apps.value = [];\n  roleIdRef.value = '';\n  appIdRef.value = '';\n  checkedKeysRef.value = [];\n  arTreeData.value = [];\n};\n\nconst [Form, formApi] = useVbenForm({\n  handleSubmit: onFormSubmit,\n  showDefaultActions: false,\n});\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.validateAndSubmitForm();\n  },\n  onOpenChange: async (isOpen: boolean) => {\n    if (isOpen) {\n      await formApi.resetForm();\n      const { roleId, callback } = modalApi.getData<Record<string, any>>();\n      await resetForm();\n      roleIdRef.value = roleId;\n      gridCallback = callback;\n      const param = { offset: 0, limit: 100 };\n      apps.value = await limitHaveAppApi(param);\n    }\n  },\n  fullscreenButton: false,\n  title: '应用授权',\n});\nasync function onFormSubmit() {\n  await authRoleApi({\n    roleId: roleIdRef.value,\n    appId: appIdRef.value,\n    appResourceIds: checkedKeysRef.value,\n  });\n  await modalApi.close();\n  await gridCallback();\n}\n</script>\n<template>\n  <Modal class=\"h-[700px] w-[450px]\">\n    <Form>\n      <input v-model=\"roleIdRef\" name=\"roleId\" type=\"hidden\" />\n      <TreeSelect\n        :field-names=\"{ label: 'name', value: 'id' }\"\n        :tree-data=\"apps\"\n        class=\"w-full\"\n        name=\"appId\"\n        @change=\"handleAppSelectOnChange\"\n      />\n      <Tree\n        :checked-keys=\"checkedKeysRef\"\n        :field-names=\"{ title: 'name', key: 'id', children: 'children' }\"\n        :tree-data=\"arTreeData\"\n        check-strictly\n        checkable\n        class=\"app-resource-tree\"\n        name=\"appResourceIds\"\n        @check=\"handleTreeOnCheck\"\n      />\n    </Form>\n  </Modal>\n</template>\n<style>\n.app-resource-tree {\n  height: 530px;\n  margin-top: 10px;\n  overflow: auto;\n  border: solid 1px #e5e7eb;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/roleMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\nimport type { RoleVo } from '#/api/core/role';\n\nimport { ref } from 'vue';\n\nimport { Page, useVbenDrawer, useVbenModal } from '@vben/common-ui';\n\nimport { Button, Input, Popconfirm } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { EnableStatusUseBool } from '#/api/core/common';\nimport { deleteRolesApi, getRoleByIdApi, pageRoleApi } from '#/api/core/role';\nimport { ACTION } from '#/common/constants';\n\nimport AuthModalCom from './auth-modal.vue';\nimport RoleDrawerCom from './role-drawer.vue';\n// import CorpAppAddModalCom from \"#/views/corpSpace/corpAppMgr/corp-app-add-modal.vue\";\n\nconst { Search } = Input;\n\nconst keyword = ref<string>();\n\nconst gridOptions: VxeGridProps<RoleVo> = {\n  height: 'auto',\n  size: 'medium',\n  border: true,\n  keepSource: true,\n  checkboxConfig: {\n    highlight: true,\n  },\n  rowConfig: {\n    isCurrent: true,\n    isHover: true,\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'name', title: '名称' },\n    {\n      field: 'isEnable',\n      title: '状态',\n      slots: { default: 'isEnable' },\n      width: 80,\n    },\n    { field: 'remark', title: '备注' },\n    { field: 'createTime', title: '创建时间', formatter: 'formatDateTime' },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 220,\n    },\n  ],\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await pageRoleApi({\n          pageNum: page.currentPage,\n          pageSize: page.pageSize,\n          name: keyword.value,\n        });\n      },\n    },\n    response: {\n      result: 'records',\n      total: 'totalCount',\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<RoleVo> = {\n  cellDblclick: (e) => {\n    if (e.column.field !== 'action') {\n      viewDrawer(e.row);\n      e.$event.stopPropagation();\n    }\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions,\n  gridEvents,\n});\n\nconst [RoleDrawer, roleDrawerApi] = useVbenDrawer({\n  connectedComponent: RoleDrawerCom,\n});\n\nconst [AuthModal, authModalApi] = useVbenModal({\n  connectedComponent: AuthModalCom,\n});\n\nasync function reloadGrid() {\n  await gridApi.query();\n}\n\nasync function onSearch(value: string) {\n  keyword.value = value;\n  await gridApi.query();\n}\n\nasync function viewDrawer(vo: RoleVo) {\n  const role: RoleVo = await getRoleByIdApi(vo.id);\n  roleDrawerApi.setState({ title: '查看' });\n  roleDrawerApi.setData({ action: ACTION.VIEW, role });\n  roleDrawerApi.open();\n}\n\nasync function addDrawer() {\n  roleDrawerApi.setState({ title: '新增' });\n  roleDrawerApi.setData({ action: ACTION.ADD, role: {}, callback: reloadGrid });\n  roleDrawerApi.open();\n}\n\nasync function editDrawer(vo: RoleVo) {\n  const role: RoleVo = await getRoleByIdApi(vo.id);\n  roleDrawerApi.setState({ title: '编辑' });\n  roleDrawerApi.setData({ action: ACTION.EDIT, role, callback: reloadGrid });\n  roleDrawerApi.open();\n}\n\nasync function auth(vo: RoleVo) {\n  authModalApi.setData({ roleId: vo.id, callback: reloadGrid });\n  authModalApi.open();\n}\n\nasync function delRole(row: RoleVo) {\n  await deleteRolesApi({ ids: [row.id] });\n  await reloadGrid();\n}\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #toolbar-actions>\n        <Search\n          :style=\"{ width: '240px' }\"\n          allow-clear\n          placeholder=\"名称\"\n          @search=\"onSearch\"\n        />\n      </template>\n      <template #toolbar-tools>\n        <Button\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"addDrawer\"\n        >\n          <span class=\"icon-[ant-design--plus-outlined]\"></span>\n        </Button>\n      </template>\n      <template #isEnable=\"{ row }\">\n        <div>\n          {{\n            EnableStatusUseBool[\n              row.isEnable?.toString() as keyof typeof EnableStatusUseBool\n            ]\n          }}\n        </div>\n      </template>\n      <template #action=\"{ row }\">\n        <Button type=\"link\" @click=\"editDrawer(row)\">编辑</Button>\n        <Button type=\"link\" @click=\"auth(row)\">授权</Button>\n        <Popconfirm\n          :description=\"`确定要删除【${row.name}】?`\"\n          cancel-text=\"否\"\n          ok-text=\"是\"\n          title=\"删除\"\n          @confirm=\"() => delRole(row)\"\n        >\n          <Button type=\"link\">删除</Button>\n        </Popconfirm>\n      </template>\n    </Grid>\n    <RoleDrawer />\n    <AuthModal />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/roleMgr/role-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { EnableStatusUseBoolOpt } from '#/api/core/common';\nimport { createRoleApi, updateRoleApi } from '#/api/core/role';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'RoleDrawer' });\n\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nlet gridCallback = () => {};\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'name',\n      label: '名称：',\n      rules: z\n        .string()\n        .min(2, { message: '长度应在2至20个字符内' })\n        .max(20, { message: '长度应在2至20个字符内' }),\n    },\n    {\n      component: 'Textarea',\n      componentProps: {\n        placeholder: '请输入',\n        rows: 5,\n        showCount: true,\n        maxlength: 200,\n      },\n      fieldName: 'remark',\n      label: '备注：',\n      rules: z.string().max(200, { message: '长度应在200个字符内' }),\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: EnableStatusUseBoolOpt,\n        placeholder: '请选择',\n      },\n      fieldName: 'isEnable',\n      label: '状态：',\n      rules: z.boolean({ required_error: '请选择状态' }),\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      const { action, role, callback } =\n        drawerApi.getData<Record<string, any>>();\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (role) {\n        formApi.setValues(role);\n      }\n    }\n  },\n  title: '应用抽屉',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateRoleApi({ id: values.id, ...values });\n  } else if (drawerAction.value === ACTION.ADD) {\n    await createRoleApi({ ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\n</script>\n<template>\n  <Drawer>\n    <Form />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/sysMgr/dictMgr/dict-drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h, ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { useDebounceFn } from '@vueuse/core';\nimport { Spin } from 'ant-design-vue';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { createDictApi, findDictApi, updateDictApi } from '#/api/core/dict';\nimport { ACTION } from '#/common/constants';\n\ndefineOptions({ name: 'DictDrawer' });\n\nconst dictKeyword = ref('');\nconst drawerAction = ref<ACTION>(ACTION.VIEW);\nlet gridCallback = () => {};\nconst fetching = ref(false);\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        type: 'hidden',\n      },\n      fieldName: 'id',\n    },\n    {\n      component: 'ApiSelect',\n      // 对应组件的参数\n      componentProps: () => {\n        return {\n          api: findDictApi,\n          labelField: 'name',\n          valueField: 'code',\n          allowClear: true,\n          // 禁止本地过滤\n          filterOption: false,\n          // 如果正在获取数据，使用插槽显示一个loading\n          notFoundContent: fetching.value ? undefined : null,\n          // 搜索词变化时记录下来， 使用useDebounceFn防抖。\n          onSearch: useDebounceFn((value: string) => {\n            dictKeyword.value = value;\n          }, 300),\n          // 远程搜索参数。当搜索词变化时，params也会更新\n          params: { keyword: dictKeyword.value },\n          showSearch: true,\n        };\n      },\n      // defaultValue: { value: 'product_sell_unit'},\n      fieldName: 'pcode',\n      label: '父节点：',\n      renderComponentContent: () => {\n        return {\n          notFoundContent: fetching.value ? h(Spin) : undefined,\n        };\n      },\n    },\n\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'name',\n      label: '名称：',\n      rules: z\n        .string()\n        .min(1, { message: '长度应在1至20个字符内' })\n        .max(20, { message: '长度应在1至20个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'code',\n      label: '编码：',\n      rules: z\n        .string()\n        .min(1, { message: '长度应在1至20个字符内' })\n        .max(50, { message: '长度应在1至20个字符内' }),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'value',\n      label: '值：',\n      rules: z\n        .string()\n        .min(1, { message: '长度应在1至100个字符内' })\n        .max(100, { message: '长度应在1至100个字符内' }),\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      formApi.resetForm();\n      const { action, dict, callback } =\n        drawerApi.getData<Record<string, any>>();\n      const disabled = action === ACTION.VIEW;\n      formApi.setState({ commonConfig: { disabled } });\n      drawerApi.setState({ showConfirmButton: !disabled });\n      drawerAction.value = action;\n      gridCallback = callback;\n      if (dict) {\n        formApi.setValues(dict);\n      }\n    }\n  },\n  title: '字典抽屉',\n});\n\nasync function onSubmit(values: Record<string, any>) {\n  const { valid } = await formApi.validate();\n  if (!valid) return;\n  if (drawerAction.value === ACTION.EDIT) {\n    await updateDictApi({ id: values.id, ...values });\n  } else if (drawerAction.value === ACTION.ADD) {\n    await createDictApi({ ...values });\n  }\n  await drawerApi.close();\n  await gridCallback();\n}\n</script>\n<template>\n  <Drawer>\n    <Form />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/corpSpace/sysMgr/dictMgr/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormProps } from '#/adapter/form';\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\nimport type { DictVo } from '#/api';\n\nimport { onMounted, ref } from 'vue';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, Input, Popconfirm } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport {\n  deleteDictApi,\n  findSubDictApi,\n  getDictByIdApi,\n  pageDictApi,\n} from '#/api';\nimport { EnableStatusUseBool } from '#/api/core/common';\nimport { ACTION } from '#/common/constants';\n\nimport DictDrawerCom from './dict-drawer.vue';\n\nconst { Search } = Input;\n\nconst simpleSearch = ref<boolean>(true);\nconst keyword = ref<string>();\n\nconst formOptions: VbenFormProps = {\n  // 默认展开\n  collapsed: true,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        allowClear: true,\n      },\n      fieldName: 'name',\n      label: '名称：',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        allowClear: true,\n      },\n      fieldName: 'code',\n      label: '编码：',\n    },\n  ],\n  // 控制表单是否显示折叠按钮\n  showCollapseButton: false,\n  // 按下回车时是否提交表单\n  submitOnEnter: false,\n};\n\nconst gridOptions: VxeGridProps<DictVo> = {\n  size: 'medium',\n  border: true,\n  height: 'auto',\n  keepSource: true,\n  checkboxConfig: {\n    highlight: true,\n    labelField: 'name',\n  },\n  rowConfig: {\n    isCurrent: true,\n    isHover: true,\n  },\n  treeConfig: {\n    parentField: 'pCode',\n    rowField: 'code',\n    transform: true,\n    lazy: true,\n    hasChildField: 'hasChild',\n    loadMethod: async ({ row }) => {\n      return findSubDictApi({ offset: 0, limit: 200, pcode: row.code });\n    },\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'name', title: '名称', align: 'left', treeNode: true },\n    { field: 'code', title: '编码', align: 'left' },\n    { field: 'value', title: '值', align: 'left' },\n    { field: 'createTime', title: '创建时间', formatter: 'formatDateTime' },\n    {\n      field: 'isEnable',\n      title: '状态',\n      slots: { default: 'isEnable' },\n      width: 80,\n    },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 260,\n    },\n  ],\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }, formValues) => {\n        const { code, name } = formValues;\n        return await pageDictApi({\n          pageNum: page.currentPage,\n          pageSize: page.pageSize,\n          isRoot: !code && !name && !keyword.value,\n          keyword: keyword.value,\n          code,\n          name,\n        });\n      },\n    },\n    response: {\n      result: 'records',\n      total: 'totalCount',\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<DictVo> = {\n  cellDblclick: (e) => {\n    if (e.column.field !== 'action') {\n      viewDrawer(e.row);\n      e.$event.stopPropagation();\n    }\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  formOptions,\n  gridOptions,\n  gridEvents,\n});\n\nconst [DictDrawer, dictDrawerApi] = useVbenDrawer({\n  connectedComponent: DictDrawerCom,\n});\n\nasync function reloadGrid() {\n  await gridApi.query();\n}\n\nasync function onSearch(value: string) {\n  keyword.value = value;\n  await gridApi.query();\n}\n\nasync function viewDrawer(vo: DictVo) {\n  const dict: DictVo = await getDictByIdApi(vo.id);\n  dictDrawerApi.setState({ title: '查看' });\n  dictDrawerApi.setData({ action: ACTION.VIEW, dict });\n  dictDrawerApi.open();\n}\n\nasync function createDrawer() {\n  await addDrawer(null);\n}\n\nasync function addDrawer(row: DictVo | null) {\n  dictDrawerApi.setState({ title: '新增' });\n  dictDrawerApi.setData({\n    action: ACTION.ADD,\n    dict: { pcode: row?.code },\n    callback: reloadGrid,\n  });\n  dictDrawerApi.open();\n}\n\nasync function search() {\n  simpleSearch.value = !simpleSearch.value;\n  gridApi.toggleSearchForm(!simpleSearch.value);\n}\n\nasync function editDrawer(vo: DictVo) {\n  const dict: DictVo = await getDictByIdApi(vo.id);\n  dictDrawerApi.setState({ title: '编辑' });\n  dictDrawerApi.setData({ action: ACTION.EDIT, dict, callback: reloadGrid });\n  dictDrawerApi.open();\n}\n\nasync function delDict(row: DictVo) {\n  await deleteDictApi({ ids: [row.id] });\n  await reloadGrid();\n}\n\nonMounted(async () => {\n  gridApi.toggleSearchForm(!simpleSearch.value);\n});\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #toolbar-actions>\n        <Search\n          :style=\"{ width: '240px' }\"\n          v-if=\"simpleSearch\"\n          allow-clear\n          placeholder=\"名称、编码\"\n          @search=\"onSearch\"\n        />\n      </template>\n      <template #toolbar-tools>\n        <Button\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"search\"\n        >\n          <span class=\"icon-[ant-design--search-outlined]\"></span>\n        </Button>\n        <Button\n          class=\"vxe-button type--button size--medium is--circle\"\n          @click=\"createDrawer\"\n        >\n          <span class=\"icon-[ant-design--plus-outlined]\"></span>\n        </Button>\n      </template>\n      <template #isEnable=\"{ row }\">\n        <div>\n          {{\n            EnableStatusUseBool[\n              row.isEnable?.toString() as keyof typeof EnableStatusUseBool\n            ]\n          }}\n        </div>\n      </template>\n      <template #action=\"{ row }\">\n        <Button type=\"link\" @click=\"addDrawer(row)\">添加</Button>\n        <Button type=\"link\" @click=\"editDrawer(row)\">编辑</Button>\n        <Popconfirm\n          :description=\"`确定要删除【${row.name}】?`\"\n          cancel-text=\"否\"\n          ok-text=\"是\"\n          title=\"删除\"\n          @confirm=\"() => delDict(row)\"\n        >\n          <Button type=\"link\">删除</Button>\n        </Popconfirm>\n      </template>\n    </Grid>\n    <DictDrawer />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/dashboard/analytics/analytics-trends.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        areaStyle: {},\n        data: [\n          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,\n          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,\n          111,\n        ],\n        itemStyle: {\n          color: '#5ab1ef',\n        },\n        smooth: true,\n        type: 'line',\n      },\n      {\n        areaStyle: {},\n        data: [\n          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,\n          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,\n        ],\n        itemStyle: {\n          color: '#019680',\n        },\n        smooth: true,\n        type: 'line',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          color: '#019680',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    // xAxis: {\n    //   axisTick: {\n    //     show: false,\n    //   },\n    //   boundaryGap: false,\n    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n    //   type: 'category',\n    // },\n    xAxis: {\n      axisTick: {\n        show: false,\n      },\n      boundaryGap: false,\n      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n      splitLine: {\n        lineStyle: {\n          type: 'solid',\n          width: 1,\n        },\n        show: true,\n      },\n      type: 'category',\n    },\n    yAxis: [\n      {\n        axisTick: {\n          show: false,\n        },\n        max: 80_000,\n        splitArea: {\n          show: true,\n        },\n        splitNumber: 4,\n        type: 'value',\n      },\n    ],\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/dashboard/analytics/analytics-visits-data.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: 0,\n      data: ['访问', '趋势'],\n    },\n    radar: {\n      indicator: [\n        {\n          name: '网页',\n        },\n        {\n          name: '移动端',\n        },\n        {\n          name: 'Ipad',\n        },\n        {\n          name: '客户端',\n        },\n        {\n          name: '第三方',\n        },\n        {\n          name: '其它',\n        },\n      ],\n      radius: '60%',\n      splitNumber: 8,\n    },\n    series: [\n      {\n        areaStyle: {\n          opacity: 1,\n          shadowBlur: 0,\n          shadowColor: 'rgba(0,0,0,.2)',\n          shadowOffsetX: 0,\n          shadowOffsetY: 10,\n        },\n        data: [\n          {\n            itemStyle: {\n              color: '#b6a2de',\n            },\n            name: '访问',\n            value: [90, 50, 86, 40, 50, 20],\n          },\n          {\n            itemStyle: {\n              color: '#5ab1ef',\n            },\n            name: '趋势',\n            value: [70, 75, 70, 76, 20, 85],\n          },\n        ],\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        symbolSize: 0,\n        type: 'radar',\n      },\n    ],\n    tooltip: {},\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/dashboard/analytics/analytics-visits-sales.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 400;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        center: ['50%', '50%'],\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '外包', value: 500 },\n          { name: '定制', value: 310 },\n          { name: '技术支持', value: 274 },\n          { name: '远程', value: 400 },\n        ].sort((a, b) => {\n          return a.value - b.value;\n        }),\n        name: '商业占比',\n        radius: '80%',\n        roseType: 'radius',\n        type: 'pie',\n      },\n    ],\n\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/dashboard/analytics/analytics-visits-source.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: '2%',\n      left: 'center',\n    },\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 100;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        avoidLabelOverlap: false,\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '搜索引擎', value: 1048 },\n          { name: '直接访问', value: 735 },\n          { name: '邮件营销', value: 580 },\n          { name: '联盟广告', value: 484 },\n        ],\n        emphasis: {\n          label: {\n            fontSize: '12',\n            fontWeight: 'bold',\n            show: true,\n          },\n        },\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        label: {\n          position: 'center',\n          show: false,\n        },\n        labelLine: {\n          show: false,\n        },\n        name: '访问来源',\n        radius: ['40%', '65%'],\n        type: 'pie',\n      },\n    ],\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/dashboard/analytics/analytics-visits.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        barMaxWidth: 80,\n        // color: '#4f69fd',\n        data: [\n          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,\n          3200, 4800,\n        ],\n        type: 'bar',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          // color: '#4f69fd',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    xAxis: {\n      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}月`),\n      type: 'category',\n    },\n    yAxis: {\n      max: 8000,\n      splitNumber: 4,\n      type: 'value',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/dashboard/analytics/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { AnalysisOverviewItem } from '@vben/common-ui';\nimport type { TabOption } from '@vben/types';\n\nimport {\n  AnalysisChartCard,\n  AnalysisChartsTabs,\n  AnalysisOverview,\n} from '@vben/common-ui';\nimport {\n  SvgBellIcon,\n  SvgCakeIcon,\n  SvgCardIcon,\n  SvgDownloadIcon,\n} from '@vben/icons';\n\nimport AnalyticsTrends from './analytics-trends.vue';\nimport AnalyticsVisitsData from './analytics-visits-data.vue';\nimport AnalyticsVisitsSales from './analytics-visits-sales.vue';\nimport AnalyticsVisitsSource from './analytics-visits-source.vue';\nimport AnalyticsVisits from './analytics-visits.vue';\n\nconst overviewItems: AnalysisOverviewItem[] = [\n  {\n    icon: SvgCardIcon,\n    title: '用户量',\n    totalTitle: '总用户量',\n    totalValue: 120_000,\n    value: 2000,\n  },\n  {\n    icon: SvgCakeIcon,\n    title: '访问量',\n    totalTitle: '总访问量',\n    totalValue: 500_000,\n    value: 20_000,\n  },\n  {\n    icon: SvgDownloadIcon,\n    title: '下载量',\n    totalTitle: '总下载量',\n    totalValue: 120_000,\n    value: 8000,\n  },\n  {\n    icon: SvgBellIcon,\n    title: '使用量',\n    totalTitle: '总使用量',\n    totalValue: 50_000,\n    value: 5000,\n  },\n];\n\nconst chartTabs: TabOption[] = [\n  {\n    label: '流量趋势',\n    value: 'trends',\n  },\n  {\n    label: '月访问量',\n    value: 'visits',\n  },\n];\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <AnalysisOverview :items=\"overviewItems\" />\n    <AnalysisChartsTabs :tabs=\"chartTabs\" class=\"mt-5\">\n      <template #trends>\n        <AnalyticsTrends />\n      </template>\n      <template #visits>\n        <AnalyticsVisits />\n      </template>\n    </AnalysisChartsTabs>\n\n    <div class=\"mt-5 w-full md:flex\">\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问数量\">\n        <AnalyticsVisitsData />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSource />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSales />\n      </AnalysisChartCard>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/dashboard/workspace/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  WorkbenchProjectItem,\n  WorkbenchQuickNavItem,\n  WorkbenchTodoItem,\n  WorkbenchTrendItem,\n} from '@vben/common-ui';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport {\n  AnalysisChartCard,\n  WorkbenchHeader,\n  WorkbenchProject,\n  WorkbenchQuickNav,\n  WorkbenchTodo,\n  WorkbenchTrends,\n} from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';\n\nconst userStore = useUserStore();\n\n// 这是一个示例数据，实际项目中需要根据实际情况进行调整\n// url 也可以是内部路由，在 navTo 方法中识别处理，进行内部跳转\n// 例如：url: /dashboard/workspace\nconst projectItems: WorkbenchProjectItem[] = [\n  {\n    color: '',\n    content: '不要等待机会，而要创造机会。',\n    date: '2021-04-01',\n    group: '开源组',\n    icon: 'carbon:logo-github',\n    title: 'Github',\n    url: 'https://github.com',\n  },\n  {\n    color: '#3fb27f',\n    content: '现在的你决定将来的你。',\n    date: '2021-04-01',\n    group: '算法组',\n    icon: 'ion:logo-vue',\n    title: 'Vue',\n    url: 'https://vuejs.org',\n  },\n  {\n    color: '#e18525',\n    content: '没有什么才能比努力更重要。',\n    date: '2021-04-01',\n    group: '上班摸鱼',\n    icon: 'ion:logo-html5',\n    title: 'Html5',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',\n  },\n  {\n    color: '#bf0c2c',\n    content: '热情和欲望可以突破一切难关。',\n    date: '2021-04-01',\n    group: 'UI',\n    icon: 'ion:logo-angular',\n    title: 'Angular',\n    url: 'https://angular.io',\n  },\n  {\n    color: '#00d8ff',\n    content: '健康的身体是实现目标的基石。',\n    date: '2021-04-01',\n    group: '技术牛',\n    icon: 'bx:bxl-react',\n    title: 'React',\n    url: 'https://reactjs.org',\n  },\n  {\n    color: '#EBD94E',\n    content: '路是走出来的，而不是空想出来的。',\n    date: '2021-04-01',\n    group: '架构组',\n    icon: 'ion:logo-javascript',\n    title: 'Js',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',\n  },\n];\n\n// 同样，这里的 url 也可以使用以 http 开头的外部链接\nconst quickNavItems: WorkbenchQuickNavItem[] = [\n  {\n    color: '#1fdaca',\n    icon: 'ion:home-outline',\n    title: '首页',\n    url: '/',\n  },\n  {\n    color: '#bf0c2c',\n    icon: 'ion:grid-outline',\n    title: '仪表盘',\n    url: '/dashboard',\n  },\n  {\n    color: '#e18525',\n    icon: 'ion:layers-outline',\n    title: '组件',\n    url: '/demos/features/icons',\n  },\n  {\n    color: '#3fb27f',\n    icon: 'ion:settings-outline',\n    title: '系统管理',\n    url: '/demos/features/login-expired', // 这里的 URL 是示例，实际项目中需要根据实际情况进行调整\n  },\n  {\n    color: '#4daf1bc9',\n    icon: 'ion:key-outline',\n    title: '权限管理',\n    url: '/demos/access/page-control',\n  },\n  {\n    color: '#00d8ff',\n    icon: 'ion:bar-chart-outline',\n    title: '图表',\n    url: '/analytics',\n  },\n];\n\nconst todoItems = ref<WorkbenchTodoItem[]>([\n  {\n    completed: false,\n    content: `审查最近提交到Git仓库的前端代码，确保代码质量和规范。`,\n    date: '2024-07-30 11:00:00',\n    title: '审查前端代码提交',\n  },\n  {\n    completed: true,\n    content: `检查并优化系统性能，降低CPU使用率。`,\n    date: '2024-07-30 11:00:00',\n    title: '系统性能优化',\n  },\n  {\n    completed: false,\n    content: `进行系统安全检查，确保没有安全漏洞或未授权的访问。 `,\n    date: '2024-07-30 11:00:00',\n    title: '安全检查',\n  },\n  {\n    completed: false,\n    content: `更新项目中的所有npm依赖包，确保使用最新版本。`,\n    date: '2024-07-30 11:00:00',\n    title: '更新项目依赖',\n  },\n  {\n    completed: false,\n    content: `修复用户报告的页面UI显示问题，确保在不同浏览器中显示一致。 `,\n    date: '2024-07-30 11:00:00',\n    title: '修复UI显示问题',\n  },\n]);\nconst trendItems: WorkbenchTrendItem[] = [\n  {\n    avatar: 'svg:avatar-1',\n    content: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,\n    date: '刚刚',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关注了 <a>威廉</a> `,\n    date: '1个小时前',\n    title: '艾文',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1天前',\n    title: '克里斯',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写一个Vite插件</a> `,\n    date: '2天前',\n    title: 'Vben',\n  },\n  {\n    avatar: 'svg:avatar-1',\n    content: `回复了 <a>杰克</a> 的问题 <a>如何进行项目优化？</a>`,\n    date: '3天前',\n    title: '皮特',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关闭了问题 <a>如何运行项目</a> `,\n    date: '1周前',\n    title: '杰克',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1周前',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `推送了代码到 <a>Github</a>`,\n    date: '2021-04-01 20:00',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写使用 Admin Vben</a> `,\n    date: '2021-03-01 20:00',\n    title: 'Vben',\n  },\n];\n\nconst router = useRouter();\n\n// 这是一个示例方法，实际项目中需要根据实际情况进行调整\n// This is a sample method, adjust according to the actual project requirements\nfunction navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {\n  if (nav.url?.startsWith('http')) {\n    openWindow(nav.url);\n    return;\n  }\n  if (nav.url?.startsWith('/')) {\n    router.push(nav.url).catch((error) => {\n      console.error('Navigation failed:', error);\n    });\n  } else {\n    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);\n  }\n}\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <WorkbenchHeader\n      :avatar=\"userStore.userInfo?.avatar || preferences.app.defaultAvatar\"\n    >\n      <template #title>\n        早安, {{ userStore.userInfo?.realName }}, 开始您一天的工作吧！\n      </template>\n      <template #description> 今日晴，20℃ - 32℃！ </template>\n    </WorkbenchHeader>\n\n    <div class=\"mt-5 flex flex-col lg:flex-row\">\n      <div class=\"mr-4 w-full lg:w-3/5\">\n        <WorkbenchProject :items=\"projectItems\" title=\"项目\" @click=\"navTo\" />\n        <WorkbenchTrends :items=\"trendItems\" class=\"mt-5\" title=\"最新动态\" />\n      </div>\n      <div class=\"w-full lg:w-2/5\">\n        <WorkbenchQuickNav\n          :items=\"quickNavItems\"\n          class=\"mt-5 lg:mt-0\"\n          title=\"快捷导航\"\n          @click=\"navTo\"\n        />\n        <WorkbenchTodo :items=\"todoItems\" class=\"mt-5\" title=\"待办事项\" />\n        <AnalysisChartCard class=\"mt-5\" title=\"访问来源\">\n          <AnalyticsVisitsSource />\n        </AnalysisChartCard>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/src/views/demos/antd/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Page } from '@vben/common-ui';\n\nimport { Button, Card, message, notification, Space } from 'ant-design-vue';\n\ntype NotificationType = 'error' | 'info' | 'success' | 'warning';\n\nfunction info() {\n  message.info('How many roads must a man walk down');\n}\n\nfunction error() {\n  message.error({\n    content: 'Once upon a time you dressed so fine',\n    duration: 2500,\n  });\n}\n\nfunction warning() {\n  message.warning('How many roads must a man walk down');\n}\nfunction success() {\n  message.success('Cause you walked hand in hand With another man in my place');\n}\n\nfunction notify(type: NotificationType) {\n  notification[type]({\n    duration: 2500,\n    message: '说点啥呢',\n    type,\n  });\n}\n</script>\n\n<template>\n  <Page\n    description=\"支持多语言，主题功能集成切换等\"\n    title=\"Ant Design Vue组件使用演示\"\n  >\n    <Card class=\"mb-5\" title=\"按钮\">\n      <Space>\n        <Button>Default</Button>\n        <Button type=\"primary\"> Primary </Button>\n        <Button> Info </Button>\n        <Button danger> Error </Button>\n      </Space>\n    </Card>\n    <Card class=\"mb-5\" title=\"Message\">\n      <Space>\n        <Button @click=\"info\"> 信息 </Button>\n        <Button danger @click=\"error\"> 错误 </Button>\n        <Button @click=\"warning\"> 警告 </Button>\n        <Button @click=\"success\"> 成功 </Button>\n      </Space>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"Notification\">\n      <Space>\n        <Button @click=\"notify('info')\"> 信息 </Button>\n        <Button danger @click=\"notify('error')\"> 错误 </Button>\n        <Button @click=\"notify('warning')\"> 警告 </Button>\n        <Button @click=\"notify('success')\"> 成功 </Button>\n      </Space>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web-app.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"#/*\": [\"./src/*\"]\n    }\n  },\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }],\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/tsconfig.node.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n    \"noEmit\": false\n  },\n  \"include\": [\"vite.config.mts\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-auth/vite.config.mts",
    "content": "import { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    application: {},\n    vite: {\n      server: {\n        proxy: {\n          '/gateway': {\n            changeOrigin: true,\n            rewrite: (path) => path.replace(/^\\/gateway/, ''),\n            target: 'http://127.0.0.1:8080',\n            ws: true,\n          },\n        },\n      },\n    },\n  };\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/index.html",
    "content": "<!doctype html>\n<html lang=\"zh\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n    <meta name=\"renderer\" content=\"webkit\" />\n    <meta name=\"description\" content=\"A Modern Back-end Management System\" />\n    <meta name=\"keywords\" content=\"Vben Admin Vue3 Vite\" />\n    <meta name=\"author\" content=\"Vben\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0\"\n    />\n    <!-- 由 vite 注入 VITE_APP_TITLE 变量，在 .env 文件内配置 -->\n    <title><%= VITE_APP_TITLE %></title>\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <script>\n      // 生产环境下注入百度统计\n      if (window._VBEN_ADMIN_PRO_APP_CONF_) {\n        var _hmt = _hmt || [];\n        (function () {\n          var hm = document.createElement('script');\n          hm.src =\n            'https://hm.baidu.com/hm.js?97352b16ed2df8c3860cf5a1a65fb4dd';\n          var s = document.getElementsByTagName('script')[0];\n          s.parentNode.insertBefore(hm, s);\n        })();\n      }\n    </script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/package.json",
    "content": "{\n  \"name\": \"@vben/web-ele\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://vben.pro\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"apps/web-ele\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"vben\",\n    \"email\": \"ann.vben@gmail.com\",\n    \"url\": \"https://github.com/anncwb\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm vite build --mode production\",\n    \"build:analyze\": \"pnpm vite build --mode analyze\",\n    \"dev\": \"pnpm vite --mode development\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"vue-tsc --noEmit --skipLibCheck\"\n  },\n  \"imports\": {\n    \"#/*\": \"./src/*\"\n  },\n  \"dependencies\": {\n    \"@vben/access\": \"workspace:*\",\n    \"@vben/common-ui\": \"workspace:*\",\n    \"@vben/constants\": \"workspace:*\",\n    \"@vben/hooks\": \"workspace:*\",\n    \"@vben/icons\": \"workspace:*\",\n    \"@vben/layouts\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/plugins\": \"workspace:*\",\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/request\": \"workspace:*\",\n    \"@vben/stores\": \"workspace:*\",\n    \"@vben/styles\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"dayjs\": \"catalog:\",\n    \"element-plus\": \"catalog:\",\n    \"pinia\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"unplugin-element-plus\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/adapter/component/index.ts",
    "content": "/**\n * 通用组件共同的使用的基础组件，原先放在 adapter/form 内部，限制了使用范围，这里提取出来，方便其他地方使用\n * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,\n */\n\nimport type { Component } from 'vue';\n\nimport type { BaseFormComponentType } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { defineAsyncComponent, defineComponent, h, ref } from 'vue';\n\nimport { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { ElNotification } from 'element-plus';\n\nconst ElButton = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/button/index'),\n    import('element-plus/es/components/button/style/css'),\n  ]).then(([res]) => res.ElButton),\n);\nconst ElCheckbox = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/checkbox/index'),\n    import('element-plus/es/components/checkbox/style/css'),\n  ]).then(([res]) => res.ElCheckbox),\n);\nconst ElCheckboxButton = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/checkbox/index'),\n    import('element-plus/es/components/checkbox-button/style/css'),\n  ]).then(([res]) => res.ElCheckboxButton),\n);\nconst ElCheckboxGroup = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/checkbox/index'),\n    import('element-plus/es/components/checkbox-group/style/css'),\n  ]).then(([res]) => res.ElCheckboxGroup),\n);\nconst ElDatePicker = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/date-picker/index'),\n    import('element-plus/es/components/date-picker/style/css'),\n  ]).then(([res]) => res.ElDatePicker),\n);\nconst ElDivider = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/divider/index'),\n    import('element-plus/es/components/divider/style/css'),\n  ]).then(([res]) => res.ElDivider),\n);\nconst ElInput = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/input/index'),\n    import('element-plus/es/components/input/style/css'),\n  ]).then(([res]) => res.ElInput),\n);\nconst ElInputNumber = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/input-number/index'),\n    import('element-plus/es/components/input-number/style/css'),\n  ]).then(([res]) => res.ElInputNumber),\n);\nconst ElRadio = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/radio/index'),\n    import('element-plus/es/components/radio/style/css'),\n  ]).then(([res]) => res.ElRadio),\n);\nconst ElRadioButton = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/radio/index'),\n    import('element-plus/es/components/radio-button/style/css'),\n  ]).then(([res]) => res.ElRadioButton),\n);\nconst ElRadioGroup = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/radio/index'),\n    import('element-plus/es/components/radio-group/style/css'),\n  ]).then(([res]) => res.ElRadioGroup),\n);\nconst ElSelectV2 = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/select-v2/index'),\n    import('element-plus/es/components/select-v2/style/css'),\n  ]).then(([res]) => res.ElSelectV2),\n);\nconst ElSpace = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/space/index'),\n    import('element-plus/es/components/space/style/css'),\n  ]).then(([res]) => res.ElSpace),\n);\nconst ElSwitch = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/switch/index'),\n    import('element-plus/es/components/switch/style/css'),\n  ]).then(([res]) => res.ElSwitch),\n);\nconst ElTimePicker = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/time-picker/index'),\n    import('element-plus/es/components/time-picker/style/css'),\n  ]).then(([res]) => res.ElTimePicker),\n);\nconst ElTreeSelect = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/tree-select/index'),\n    import('element-plus/es/components/tree-select/style/css'),\n  ]).then(([res]) => res.ElTreeSelect),\n);\nconst ElUpload = defineAsyncComponent(() =>\n  Promise.all([\n    import('element-plus/es/components/upload/index'),\n    import('element-plus/es/components/upload/style/css'),\n  ]).then(([res]) => res.ElUpload),\n);\n\nconst withDefaultPlaceholder = <T extends Component>(\n  component: T,\n  type: 'input' | 'select',\n  componentProps: Recordable<any> = {},\n) => {\n  return defineComponent({\n    name: component.name,\n    inheritAttrs: false,\n    setup: (props: any, { attrs, expose, slots }) => {\n      const placeholder =\n        props?.placeholder ||\n        attrs?.placeholder ||\n        $t(`ui.placeholder.${type}`);\n      // 透传组件暴露的方法\n      const innerRef = ref();\n      expose(\n        new Proxy(\n          {},\n          {\n            get: (_target, key) => innerRef.value?.[key],\n            has: (_target, key) => key in (innerRef.value || {}),\n          },\n        ),\n      );\n      return () =>\n        h(\n          component,\n          { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },\n          slots,\n        );\n    },\n  });\n};\n\n// 这里需要自行根据业务组件库进行适配，需要用到的组件都需要在这里类型说明\nexport type ComponentType =\n  | 'ApiSelect'\n  | 'ApiTreeSelect'\n  | 'Checkbox'\n  | 'CheckboxGroup'\n  | 'DatePicker'\n  | 'Divider'\n  | 'IconPicker'\n  | 'Input'\n  | 'InputNumber'\n  | 'RadioGroup'\n  | 'Select'\n  | 'Space'\n  | 'Switch'\n  | 'TimePicker'\n  | 'TreeSelect'\n  | 'Upload'\n  | BaseFormComponentType;\n\nasync function initComponentAdapter() {\n  const components: Partial<Record<ComponentType, Component>> = {\n    // 如果你的组件体积比较大，可以使用异步加载\n    // Button: () =>\n    // import('xxx').then((res) => res.Button),\n    ApiSelect: withDefaultPlaceholder(\n      {\n        ...ApiComponent,\n        name: 'ApiSelect',\n      },\n      'select',\n      {\n        component: ElSelectV2,\n        loadingSlot: 'loading',\n        visibleEvent: 'onVisibleChange',\n      },\n    ),\n    ApiTreeSelect: withDefaultPlaceholder(\n      {\n        ...ApiComponent,\n        name: 'ApiTreeSelect',\n      },\n      'select',\n      {\n        component: ElTreeSelect,\n        props: { label: 'label', children: 'children' },\n        nodeKey: 'value',\n        loadingSlot: 'loading',\n        optionsPropName: 'data',\n        visibleEvent: 'onVisibleChange',\n      },\n    ),\n    Checkbox: ElCheckbox,\n    CheckboxGroup: (props, { attrs, slots }) => {\n      let defaultSlot;\n      if (Reflect.has(slots, 'default')) {\n        defaultSlot = slots.default;\n      } else {\n        const { options, isButton } = attrs;\n        if (Array.isArray(options)) {\n          defaultSlot = () =>\n            options.map((option) =>\n              h(isButton ? ElCheckboxButton : ElCheckbox, option),\n            );\n        }\n      }\n      return h(\n        ElCheckboxGroup,\n        { ...props, ...attrs },\n        { ...slots, default: defaultSlot },\n      );\n    },\n    // 自定义默认按钮\n    DefaultButton: (props, { attrs, slots }) => {\n      return h(ElButton, { ...props, attrs, type: 'info' }, slots);\n    },\n    // 自定义主要按钮\n    PrimaryButton: (props, { attrs, slots }) => {\n      return h(ElButton, { ...props, attrs, type: 'primary' }, slots);\n    },\n    Divider: ElDivider,\n    IconPicker: withDefaultPlaceholder(IconPicker, 'select', {\n      iconSlot: 'append',\n      modelValueProp: 'model-value',\n      inputComponent: ElInput,\n    }),\n    Input: withDefaultPlaceholder(ElInput, 'input'),\n    InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'),\n    RadioGroup: (props, { attrs, slots }) => {\n      let defaultSlot;\n      if (Reflect.has(slots, 'default')) {\n        defaultSlot = slots.default;\n      } else {\n        const { options } = attrs;\n        if (Array.isArray(options)) {\n          defaultSlot = () =>\n            options.map((option) =>\n              h(attrs.isButton ? ElRadioButton : ElRadio, option),\n            );\n        }\n      }\n      return h(\n        ElRadioGroup,\n        { ...props, ...attrs },\n        { ...slots, default: defaultSlot },\n      );\n    },\n    Select: (props, { attrs, slots }) => {\n      return h(ElSelectV2, { ...props, attrs }, slots);\n    },\n    Space: ElSpace,\n    Switch: ElSwitch,\n    TimePicker: (props, { attrs, slots }) => {\n      const { name, id, isRange } = props;\n      const extraProps: Recordable<any> = {};\n      if (isRange) {\n        if (name && !Array.isArray(name)) {\n          extraProps.name = [name, `${name}_end`];\n        }\n        if (id && !Array.isArray(id)) {\n          extraProps.id = [id, `${id}_end`];\n        }\n      }\n      return h(\n        ElTimePicker,\n        {\n          ...props,\n          ...attrs,\n          ...extraProps,\n        },\n        slots,\n      );\n    },\n    DatePicker: (props, { attrs, slots }) => {\n      const { name, id, type } = props;\n      const extraProps: Recordable<any> = {};\n      if (type && type.includes('range')) {\n        if (name && !Array.isArray(name)) {\n          extraProps.name = [name, `${name}_end`];\n        }\n        if (id && !Array.isArray(id)) {\n          extraProps.id = [id, `${id}_end`];\n        }\n      }\n      return h(\n        ElDatePicker,\n        {\n          ...props,\n          ...attrs,\n          ...extraProps,\n        },\n        slots,\n      );\n    },\n    TreeSelect: withDefaultPlaceholder(ElTreeSelect, 'select'),\n    Upload: ElUpload,\n  };\n\n  // 将组件注册到全局共享状态中\n  globalShareState.setComponents(components);\n\n  // 定义全局共享状态中的消息提示\n  globalShareState.defineMessage({\n    // 复制成功消息提示\n    copyPreferencesSuccess: (title, content) => {\n      ElNotification({\n        title,\n        message: content,\n        position: 'bottom-right',\n        duration: 0,\n        type: 'success',\n      });\n    },\n  });\n}\n\nexport { initComponentAdapter };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/adapter/form.ts",
    "content": "import type {\n  VbenFormSchema as FormSchema,\n  VbenFormProps,\n} from '@vben/common-ui';\n\nimport type { ComponentType } from './component';\n\nimport { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nasync function initSetupVbenForm() {\n  setupVbenForm<ComponentType>({\n    config: {\n      modelPropNameMap: {\n        Upload: 'fileList',\n        CheckboxGroup: 'model-value',\n      },\n    },\n    defineRules: {\n      required: (value, _params, ctx) => {\n        if (value === undefined || value === null || value.length === 0) {\n          return $t('ui.formRules.required', [ctx.label]);\n        }\n        return true;\n      },\n      selectRequired: (value, _params, ctx) => {\n        if (value === undefined || value === null) {\n          return $t('ui.formRules.selectRequired', [ctx.label]);\n        }\n        return true;\n      },\n    },\n  });\n}\n\nconst useVbenForm = useForm<ComponentType>;\n\nexport { initSetupVbenForm, useVbenForm, z };\n\nexport type VbenFormSchema = FormSchema<ComponentType>;\nexport type { VbenFormProps };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/adapter/vxe-table.ts",
    "content": "import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';\n\nimport { h } from 'vue';\n\nimport { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';\n\nimport { ElButton, ElImage } from 'element-plus';\n\nimport { useVbenForm } from './form';\n\nsetupVbenVxeTable({\n  configVxeTable: (vxeUI) => {\n    vxeUI.setConfig({\n      grid: {\n        align: 'center',\n        border: false,\n        columnConfig: {\n          resizable: true,\n        },\n        minHeight: 180,\n        formConfig: {\n          // 全局禁用vxe-table的表单配置，使用formOptions\n          enabled: false,\n        },\n        proxyConfig: {\n          autoLoad: true,\n          response: {\n            result: 'items',\n            total: 'total',\n            list: 'items',\n          },\n          showActiveMsg: true,\n          showResponseMsg: false,\n        },\n        round: true,\n        showOverflow: true,\n        size: 'small',\n      } as VxeTableGridOptions,\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellImage' },\n    vxeUI.renderer.add('CellImage', {\n      renderTableDefault(_renderOpts, params) {\n        const { column, row } = params;\n        const src = row[column.field];\n        return h(ElImage, { src, previewSrcList: [src] });\n      },\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellLink' },\n    vxeUI.renderer.add('CellLink', {\n      renderTableDefault(renderOpts) {\n        const { props } = renderOpts;\n        return h(\n          ElButton,\n          { size: 'small', link: true },\n          { default: () => props?.text },\n        );\n      },\n    });\n\n    // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化\n    // vxeUI.formats.add\n  },\n  useVbenForm,\n});\n\nexport { useVbenVxeGrid };\n\nexport type * from '@vben/plugins/vxe-table';\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/api/core/auth.ts",
    "content": "import { baseRequestClient, requestClient } from '#/api/request';\n\nexport namespace AuthApi {\n  /** 登录接口参数 */\n  export interface LoginParams {\n    password?: string;\n    username?: string;\n  }\n\n  /** 登录接口返回值 */\n  export interface LoginResult {\n    accessToken: string;\n  }\n\n  export interface RefreshTokenResult {\n    data: string;\n    status: number;\n  }\n}\n\n/**\n * 登录\n */\nexport async function loginApi(data: AuthApi.LoginParams) {\n  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);\n}\n\n/**\n * 刷新accessToken\n */\nexport async function refreshTokenApi() {\n  return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {\n    withCredentials: true,\n  });\n}\n\n/**\n * 退出登录\n */\nexport async function logoutApi() {\n  return baseRequestClient.post('/auth/logout', {\n    withCredentials: true,\n  });\n}\n\n/**\n * 获取用户权限码\n */\nexport async function getAccessCodesApi() {\n  return requestClient.get<string[]>('/auth/codes');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/api/core/index.ts",
    "content": "export * from './auth';\nexport * from './menu';\nexport * from './user';\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/api/core/menu.ts",
    "content": "import type { RouteRecordStringComponent } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户所有菜单\n */\nexport async function getAllMenusApi() {\n  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/api/core/user.ts",
    "content": "import type { UserInfo } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户信息\n */\nexport async function getUserInfoApi() {\n  return requestClient.get<UserInfo>('/user/info');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/api/index.ts",
    "content": "export * from './core';\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/api/request.ts",
    "content": "/**\n * 该文件可自行根据业务逻辑进行调整\n */\nimport type { RequestClientOptions } from '@vben/request';\n\nimport { useAppConfig } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\nimport {\n  authenticateResponseInterceptor,\n  defaultResponseInterceptor,\n  errorMessageResponseInterceptor,\n  RequestClient,\n} from '@vben/request';\nimport { useAccessStore } from '@vben/stores';\n\nimport { ElMessage } from 'element-plus';\n\nimport { useAuthStore } from '#/store';\n\nimport { refreshTokenApi } from './core';\n\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n\nfunction createRequestClient(baseURL: string, options?: RequestClientOptions) {\n  const client = new RequestClient({\n    ...options,\n    baseURL,\n  });\n\n  /**\n   * 重新认证逻辑\n   */\n  async function doReAuthenticate() {\n    console.warn('Access token or refresh token is invalid or expired. ');\n    const accessStore = useAccessStore();\n    const authStore = useAuthStore();\n    accessStore.setAccessToken(null);\n    if (\n      preferences.app.loginExpiredMode === 'modal' &&\n      accessStore.isAccessChecked\n    ) {\n      accessStore.setLoginExpired(true);\n    } else {\n      await authStore.logout();\n    }\n  }\n\n  /**\n   * 刷新token逻辑\n   */\n  async function doRefreshToken() {\n    const accessStore = useAccessStore();\n    const resp = await refreshTokenApi();\n    const newToken = resp.data;\n    accessStore.setAccessToken(newToken);\n    return newToken;\n  }\n\n  function formatToken(token: null | string) {\n    return token ? `Bearer ${token}` : null;\n  }\n\n  // 请求头处理\n  client.addRequestInterceptor({\n    fulfilled: async (config) => {\n      const accessStore = useAccessStore();\n\n      config.headers.Authorization = formatToken(accessStore.accessToken);\n      config.headers['Accept-Language'] = preferences.app.locale;\n      return config;\n    },\n  });\n\n  // 处理返回的响应数据格式\n  client.addResponseInterceptor(\n    defaultResponseInterceptor({\n      codeField: 'code',\n      dataField: 'data',\n      successCode: 0,\n    }),\n  );\n\n  // token过期的处理\n  client.addResponseInterceptor(\n    authenticateResponseInterceptor({\n      client,\n      doReAuthenticate,\n      doRefreshToken,\n      enableRefreshToken: preferences.app.enableRefreshToken,\n      formatToken,\n    }),\n  );\n\n  // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里\n  client.addResponseInterceptor(\n    errorMessageResponseInterceptor((msg: string, error) => {\n      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg\n      // 当前mock接口返回的错误字段是 error 或者 message\n      const responseData = error?.response?.data ?? {};\n      const errorMessage = responseData?.error ?? responseData?.message ?? '';\n      // 如果没有错误信息，则会根据状态码进行提示\n      ElMessage.error(errorMessage || msg);\n    }),\n  );\n\n  return client;\n}\n\nexport const requestClient = createRequestClient(apiURL, {\n  responseReturn: 'data',\n});\n\nexport const baseRequestClient = new RequestClient({ baseURL: apiURL });\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/app.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useElementPlusDesignTokens } from '@vben/hooks';\n\nimport { ElConfigProvider } from 'element-plus';\n\nimport { elementLocale } from '#/locales';\n\ndefineOptions({ name: 'App' });\n\nuseElementPlusDesignTokens();\n</script>\n\n<template>\n  <ElConfigProvider :locale=\"elementLocale\">\n    <RouterView />\n  </ElConfigProvider>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/bootstrap.ts",
    "content": "import { createApp, watchEffect } from 'vue';\n\nimport { registerAccessDirective } from '@vben/access';\nimport { registerLoadingDirective } from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { initStores } from '@vben/stores';\nimport '@vben/styles';\nimport '@vben/styles/ele';\n\nimport { useTitle } from '@vueuse/core';\nimport { ElLoading } from 'element-plus';\n\nimport { $t, setupI18n } from '#/locales';\n\nimport { initComponentAdapter } from './adapter/component';\nimport { initSetupVbenForm } from './adapter/form';\nimport App from './app.vue';\nimport { router } from './router';\n\nasync function bootstrap(namespace: string) {\n  // 初始化组件适配器\n  await initComponentAdapter();\n\n  // 初始化表单组件\n  await initSetupVbenForm();\n\n  // // 设置弹窗的默认配置\n  // setDefaultModalProps({\n  //   fullscreenButton: false,\n  // });\n  // // 设置抽屉的默认配置\n  // setDefaultDrawerProps({\n  //   zIndex: 2000,\n  // });\n  const app = createApp(App);\n\n  // 注册Element Plus提供的v-loading指令\n  app.directive('loading', ElLoading.directive);\n\n  // 注册Vben提供的v-loading和v-spinning指令\n  registerLoadingDirective(app, {\n    loading: false, // Vben提供的v-loading指令和Element Plus提供的v-loading指令二选一即可，此处false表示不注册Vben提供的v-loading指令\n    spinning: 'spinning',\n  });\n\n  // 国际化 i18n 配置\n  await setupI18n(app);\n\n  // 配置 pinia-tore\n  await initStores(app, { namespace });\n\n  // 安装权限指令\n  registerAccessDirective(app);\n\n  // 初始化 tippy\n  const { initTippy } = await import('@vben/common-ui/es/tippy');\n  initTippy(app);\n\n  // 配置路由及路由守卫\n  app.use(router);\n\n  // 配置Motion插件\n  const { MotionPlugin } = await import('@vben/plugins/motion');\n  app.use(MotionPlugin);\n\n  // 动态更新标题\n  watchEffect(() => {\n    if (preferences.app.dynamicTitle) {\n      const routeTitle = router.currentRoute.value.meta?.title;\n      const pageTitle =\n        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;\n      useTitle(pageTitle);\n    }\n  });\n\n  app.mount('#app');\n}\n\nexport { bootstrap };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/layouts/auth.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { AuthPageLayout } from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst appName = computed(() => preferences.app.name);\nconst logo = computed(() => preferences.logo.source);\n</script>\n\n<template>\n  <AuthPageLayout\n    :app-name=\"appName\"\n    :logo=\"logo\"\n    :page-description=\"$t('authentication.pageDesc')\"\n    :page-title=\"$t('authentication.pageTitle')\"\n  >\n    <!-- 自定义工具栏 -->\n    <!-- <template #toolbar></template> -->\n  </AuthPageLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/layouts/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { NotificationItem } from '@vben/layouts';\n\nimport { computed, ref, watch } from 'vue';\n\nimport { AuthenticationLoginExpiredModal } from '@vben/common-ui';\nimport { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';\nimport { useWatermark } from '@vben/hooks';\nimport { BookOpenText, CircleHelp, SvgGithubIcon } from '@vben/icons';\nimport {\n  BasicLayout,\n  LockScreen,\n  Notification,\n  UserDropdown,\n} from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport { $t } from '#/locales';\nimport { useAuthStore } from '#/store';\nimport LoginForm from '#/views/_core/authentication/login.vue';\n\nconst notifications = ref<NotificationItem[]>([\n  {\n    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',\n    date: '3小时前',\n    isRead: true,\n    message: '描述信息描述信息描述信息',\n    title: '收到了 14 份新周报',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '刚刚',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '朱偏右 回复了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '2024-01-01',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '曲丽丽 评论了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/satori',\n    date: '1天前',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '代办提醒',\n  },\n]);\n\nconst userStore = useUserStore();\nconst authStore = useAuthStore();\nconst accessStore = useAccessStore();\nconst { destroyWatermark, updateWatermark } = useWatermark();\nconst showDot = computed(() =>\n  notifications.value.some((item) => !item.isRead),\n);\n\nconst menus = computed(() => [\n  {\n    handler: () => {\n      openWindow(VBEN_DOC_URL, {\n        target: '_blank',\n      });\n    },\n    icon: BookOpenText,\n    text: $t('ui.widgets.document'),\n  },\n  {\n    handler: () => {\n      openWindow(VBEN_GITHUB_URL, {\n        target: '_blank',\n      });\n    },\n    icon: SvgGithubIcon,\n    text: 'GitHub',\n  },\n  {\n    handler: () => {\n      openWindow(`${VBEN_GITHUB_URL}/issues`, {\n        target: '_blank',\n      });\n    },\n    icon: CircleHelp,\n    text: $t('ui.widgets.qa'),\n  },\n]);\n\nconst avatar = computed(() => {\n  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;\n});\n\nasync function handleLogout() {\n  await authStore.logout(false);\n}\n\nfunction handleNoticeClear() {\n  notifications.value = [];\n}\n\nfunction handleMakeAll() {\n  notifications.value.forEach((item) => (item.isRead = true));\n}\nwatch(\n  () => ({\n    enable: preferences.app.watermark,\n    content: preferences.app.watermarkContent,\n  }),\n  async ({ enable, content }) => {\n    if (enable) {\n      await updateWatermark({\n        content:\n          content ||\n          `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,\n      });\n    } else {\n      destroyWatermark();\n    }\n  },\n  {\n    immediate: true,\n  },\n);\n</script>\n\n<template>\n  <BasicLayout @clear-preferences-and-logout=\"handleLogout\">\n    <template #user-dropdown>\n      <UserDropdown\n        :avatar\n        :menus\n        :text=\"userStore.userInfo?.realName\"\n        description=\"ann.vben@gmail.com\"\n        tag-text=\"Pro\"\n        @logout=\"handleLogout\"\n      />\n    </template>\n    <template #notification>\n      <Notification\n        :dot=\"showDot\"\n        :notifications=\"notifications\"\n        @clear=\"handleNoticeClear\"\n        @make-all=\"handleMakeAll\"\n      />\n    </template>\n    <template #extra>\n      <AuthenticationLoginExpiredModal\n        v-model:open=\"accessStore.loginExpired\"\n        :avatar\n      >\n        <LoginForm />\n      </AuthenticationLoginExpiredModal>\n    </template>\n    <template #lock-screen>\n      <LockScreen :avatar @to-login=\"handleLogout\" />\n    </template>\n  </BasicLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/layouts/index.ts",
    "content": "const BasicLayout = () => import('./basic.vue');\nconst AuthPageLayout = () => import('./auth.vue');\n\nconst IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);\n\nexport { AuthPageLayout, BasicLayout, IFrameView };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/locales/README.md",
    "content": "# locale\n\n每个app使用的国际化可能不同，这里用于扩展国际化的功能，例如扩展 dayjs、antd组件库的多语言切换，以及app本身的国际化文件。\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/locales/index.ts",
    "content": "import type { Language } from 'element-plus/es/locale';\n\nimport type { App } from 'vue';\n\nimport type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';\n\nimport { ref } from 'vue';\n\nimport {\n  $t,\n  setupI18n as coreSetup,\n  loadLocalesMapFromDir,\n} from '@vben/locales';\nimport { preferences } from '@vben/preferences';\n\nimport dayjs from 'dayjs';\nimport enLocale from 'element-plus/es/locale/lang/en';\nimport defaultLocale from 'element-plus/es/locale/lang/zh-cn';\n\nconst elementLocale = ref<Language>(defaultLocale);\n\nconst modules = import.meta.glob('./langs/**/*.json');\n\nconst localesMap = loadLocalesMapFromDir(\n  /\\.\\/langs\\/([^/]+)\\/(.*)\\.json$/,\n  modules,\n);\n/**\n * 加载应用特有的语言包\n * 这里也可以改造为从服务端获取翻译数据\n * @param lang\n */\nasync function loadMessages(lang: SupportedLanguagesType) {\n  const [appLocaleMessages] = await Promise.all([\n    localesMap[lang]?.(),\n    loadThirdPartyMessage(lang),\n  ]);\n  return appLocaleMessages?.default;\n}\n\n/**\n * 加载第三方组件库的语言包\n * @param lang\n */\nasync function loadThirdPartyMessage(lang: SupportedLanguagesType) {\n  await Promise.all([loadElementLocale(lang), loadDayjsLocale(lang)]);\n}\n\n/**\n * 加载dayjs的语言包\n * @param lang\n */\nasync function loadDayjsLocale(lang: SupportedLanguagesType) {\n  let locale;\n  switch (lang) {\n    case 'en-US': {\n      locale = await import('dayjs/locale/en');\n      break;\n    }\n    case 'zh-CN': {\n      locale = await import('dayjs/locale/zh-cn');\n      break;\n    }\n    // 默认使用英语\n    default: {\n      locale = await import('dayjs/locale/en');\n    }\n  }\n  if (locale) {\n    dayjs.locale(locale);\n  } else {\n    console.error(`Failed to load dayjs locale for ${lang}`);\n  }\n}\n\n/**\n * 加载element-plus的语言包\n * @param lang\n */\nasync function loadElementLocale(lang: SupportedLanguagesType) {\n  switch (lang) {\n    case 'en-US': {\n      elementLocale.value = enLocale;\n      break;\n    }\n    case 'zh-CN': {\n      elementLocale.value = defaultLocale;\n      break;\n    }\n  }\n}\n\nasync function setupI18n(app: App, options: LocaleSetupOptions = {}) {\n  await coreSetup(app, {\n    defaultLocale: preferences.app.locale,\n    loadMessages,\n    missingWarn: !import.meta.env.PROD,\n    ...options,\n  });\n}\n\nexport { $t, elementLocale, setupI18n };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/locales/langs/en-US/demos.json",
    "content": "{\n  \"title\": \"Demos\",\n  \"elementPlus\": \"Element Plus\",\n  \"form\": \"Form\",\n  \"vben\": {\n    \"title\": \"Project\",\n    \"about\": \"About\",\n    \"document\": \"Document\",\n    \"antdv\": \"Ant Design Vue Version\",\n    \"naive-ui\": \"Naive UI Version\",\n    \"element-plus\": \"Element Plus Version\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/locales/langs/en-US/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"Login\",\n    \"register\": \"Register\",\n    \"codeLogin\": \"Code Login\",\n    \"qrcodeLogin\": \"Qr Code Login\",\n    \"forgetPassword\": \"Forget Password\"\n  },\n  \"dashboard\": {\n    \"title\": \"Dashboard\",\n    \"analytics\": \"Analytics\",\n    \"workspace\": \"Workspace\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/locales/langs/zh-CN/demos.json",
    "content": "{\n  \"title\": \"演示\",\n  \"elementPlus\": \"Element Plus\",\n  \"form\": \"表单演示\",\n  \"vben\": {\n    \"title\": \"项目\",\n    \"about\": \"关于\",\n    \"document\": \"文档\",\n    \"antdv\": \"Ant Design Vue 版本\",\n    \"naive-ui\": \"Naive UI 版本\",\n    \"element-plus\": \"Element Plus 版本\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/locales/langs/zh-CN/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"登录\",\n    \"register\": \"注册\",\n    \"codeLogin\": \"验证码登录\",\n    \"qrcodeLogin\": \"二维码登录\",\n    \"forgetPassword\": \"忘记密码\"\n  },\n  \"dashboard\": {\n    \"title\": \"概览\",\n    \"analytics\": \"分析页\",\n    \"workspace\": \"工作台\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/main.ts",
    "content": "import { initPreferences } from '@vben/preferences';\nimport { unmountGlobalLoading } from '@vben/utils';\n\nimport { overridesPreferences } from './preferences';\n\n/**\n * 应用初始化完成之后再进行页面加载渲染\n */\nasync function initApplication() {\n  // name用于指定项目唯一标识\n  // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据\n  const env = import.meta.env.PROD ? 'prod' : 'dev';\n  const appVersion = import.meta.env.VITE_APP_VERSION;\n  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;\n\n  // app偏好设置初始化\n  await initPreferences({\n    namespace,\n    overrides: overridesPreferences,\n  });\n\n  // 启动应用并挂载\n  // vue应用主要逻辑及视图\n  const { bootstrap } = await import('./bootstrap');\n  await bootstrap(namespace);\n\n  // 移除并销毁loading\n  unmountGlobalLoading();\n}\n\ninitApplication();\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/preferences.ts",
    "content": "import { defineOverridesPreferences } from '@vben/preferences';\n\n/**\n * @description 项目配置文件\n * 只需要覆盖项目中的一部分配置，不需要的配置不用覆盖，会自动使用默认配置\n * !!! 更改配置后请清空缓存，否则可能不生效\n */\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    name: import.meta.env.VITE_APP_TITLE,\n  },\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/router/access.ts",
    "content": "import type {\n  ComponentRecordType,\n  GenerateMenuAndRoutesOptions,\n} from '@vben/types';\n\nimport { generateAccessible } from '@vben/access';\nimport { preferences } from '@vben/preferences';\n\nimport { ElMessage } from 'element-plus';\n\nimport { getAllMenusApi } from '#/api';\nimport { BasicLayout, IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');\n\nasync function generateAccess(options: GenerateMenuAndRoutesOptions) {\n  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');\n\n  const layoutMap: ComponentRecordType = {\n    BasicLayout,\n    IFrameView,\n  };\n\n  return await generateAccessible(preferences.app.accessMode, {\n    ...options,\n    fetchMenuListAsync: async () => {\n      ElMessage({\n        duration: 1500,\n        message: `${$t('common.loadingMenu')}...`,\n      });\n      return await getAllMenusApi();\n    },\n    // 可以指定没有权限跳转403页面\n    forbiddenComponent,\n    // 如果 route.meta.menuVisibleWithForbidden = true\n    layoutMap,\n    pageMap,\n  });\n}\n\nexport { generateAccess };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/router/guard.ts",
    "content": "import type { Router } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { startProgress, stopProgress } from '@vben/utils';\n\nimport { accessRoutes, coreRouteNames } from '#/router/routes';\nimport { useAuthStore } from '#/store';\n\nimport { generateAccess } from './access';\n\n/**\n * 通用守卫配置\n * @param router\n */\nfunction setupCommonGuard(router: Router) {\n  // 记录已经加载的页面\n  const loadedPaths = new Set<string>();\n\n  router.beforeEach((to) => {\n    to.meta.loaded = loadedPaths.has(to.path);\n\n    // 页面加载进度条\n    if (!to.meta.loaded && preferences.transition.progress) {\n      startProgress();\n    }\n    return true;\n  });\n\n  router.afterEach((to) => {\n    // 记录页面是否加载,如果已经加载，后续的页面切换动画等效果不在重复执行\n\n    loadedPaths.add(to.path);\n\n    // 关闭页面加载进度条\n    if (preferences.transition.progress) {\n      stopProgress();\n    }\n  });\n}\n\n/**\n * 权限访问守卫配置\n * @param router\n */\nfunction setupAccessGuard(router: Router) {\n  router.beforeEach(async (to, from) => {\n    const accessStore = useAccessStore();\n    const userStore = useUserStore();\n    const authStore = useAuthStore();\n\n    // 基本路由，这些路由不需要进入权限拦截\n    if (coreRouteNames.includes(to.name as string)) {\n      if (to.path === LOGIN_PATH && accessStore.accessToken) {\n        return decodeURIComponent(\n          (to.query?.redirect as string) ||\n            userStore.userInfo?.homePath ||\n            preferences.app.defaultHomePath,\n        );\n      }\n      return true;\n    }\n\n    // accessToken 检查\n    if (!accessStore.accessToken) {\n      // 明确声明忽略权限访问权限，则可以访问\n      if (to.meta.ignoreAccess) {\n        return true;\n      }\n\n      // 没有访问权限，跳转登录页面\n      if (to.fullPath !== LOGIN_PATH) {\n        return {\n          path: LOGIN_PATH,\n          // 如不需要，直接删除 query\n          query:\n            to.fullPath === preferences.app.defaultHomePath\n              ? {}\n              : { redirect: encodeURIComponent(to.fullPath) },\n          // 携带当前跳转的页面，登录后重新跳转该页面\n          replace: true,\n        };\n      }\n      return to;\n    }\n\n    // 是否已经生成过动态路由\n    if (accessStore.isAccessChecked) {\n      return true;\n    }\n\n    // 生成路由表\n    // 当前登录用户拥有的角色标识列表\n    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());\n    const userRoles = userInfo.roles ?? [];\n\n    // 生成菜单和路由\n    const { accessibleMenus, accessibleRoutes } = await generateAccess({\n      roles: userRoles,\n      router,\n      // 则会在菜单中显示，但是访问会被重定向到403\n      routes: accessRoutes,\n    });\n\n    // 保存菜单信息和路由信息\n    accessStore.setAccessMenus(accessibleMenus);\n    accessStore.setAccessRoutes(accessibleRoutes);\n    accessStore.setIsAccessChecked(true);\n    const redirectPath = (from.query.redirect ??\n      (to.path === preferences.app.defaultHomePath\n        ? userInfo.homePath || preferences.app.defaultHomePath\n        : to.fullPath)) as string;\n\n    return {\n      ...router.resolve(decodeURIComponent(redirectPath)),\n      replace: true,\n    };\n  });\n}\n\n/**\n * 项目守卫配置\n * @param router\n */\nfunction createRouterGuard(router: Router) {\n  /** 通用 */\n  setupCommonGuard(router);\n  /** 权限访问 */\n  setupAccessGuard(router);\n}\n\nexport { createRouterGuard };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/router/index.ts",
    "content": "import {\n  createRouter,\n  createWebHashHistory,\n  createWebHistory,\n} from 'vue-router';\n\nimport { resetStaticRoutes } from '@vben/utils';\n\nimport { createRouterGuard } from './guard';\nimport { routes } from './routes';\n\n/**\n *  @zh_CN 创建vue-router实例\n */\nconst router = createRouter({\n  history:\n    import.meta.env.VITE_ROUTER_HISTORY === 'hash'\n      ? createWebHashHistory(import.meta.env.VITE_BASE)\n      : createWebHistory(import.meta.env.VITE_BASE),\n  // 应该添加到路由的初始路由列表。\n  routes,\n  scrollBehavior: (to, _from, savedPosition) => {\n    if (savedPosition) {\n      return savedPosition;\n    }\n    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };\n  },\n  // 是否应该禁止尾部斜杠。\n  // strict: true,\n});\n\nconst resetRoutes = () => resetStaticRoutes(router, routes);\n\n// 创建路由守卫\ncreateRouterGuard(router);\n\nexport { resetRoutes, router };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/router/routes/core.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst BasicLayout = () => import('#/layouts/basic.vue');\nconst AuthPageLayout = () => import('#/layouts/auth.vue');\n/** 全局404页面 */\nconst fallbackNotFoundRoute: RouteRecordRaw = {\n  component: () => import('#/views/_core/fallback/not-found.vue'),\n  meta: {\n    hideInBreadcrumb: true,\n    hideInMenu: true,\n    hideInTab: true,\n    title: '404',\n  },\n  name: 'FallbackNotFound',\n  path: '/:path(.*)*',\n};\n\n/** 基本路由，这些路由是必须存在的 */\nconst coreRoutes: RouteRecordRaw[] = [\n  /**\n   * 根路由\n   * 使用基础布局，作为所有页面的父级容器，子级就不必配置BasicLayout。\n   * 此路由必须存在，且不应修改\n   */\n  {\n    component: BasicLayout,\n    meta: {\n      hideInBreadcrumb: true,\n      title: 'Root',\n    },\n    name: 'Root',\n    path: '/',\n    redirect: preferences.app.defaultHomePath,\n    children: [],\n  },\n  {\n    component: AuthPageLayout,\n    meta: {\n      hideInTab: true,\n      title: 'Authentication',\n    },\n    name: 'Authentication',\n    path: '/auth',\n    redirect: LOGIN_PATH,\n    children: [\n      {\n        name: 'Login',\n        path: 'login',\n        component: () => import('#/views/_core/authentication/login.vue'),\n        meta: {\n          title: $t('page.auth.login'),\n        },\n      },\n      {\n        name: 'CodeLogin',\n        path: 'code-login',\n        component: () => import('#/views/_core/authentication/code-login.vue'),\n        meta: {\n          title: $t('page.auth.codeLogin'),\n        },\n      },\n      {\n        name: 'QrCodeLogin',\n        path: 'qrcode-login',\n        component: () =>\n          import('#/views/_core/authentication/qrcode-login.vue'),\n        meta: {\n          title: $t('page.auth.qrcodeLogin'),\n        },\n      },\n      {\n        name: 'ForgetPassword',\n        path: 'forget-password',\n        component: () =>\n          import('#/views/_core/authentication/forget-password.vue'),\n        meta: {\n          title: $t('page.auth.forgetPassword'),\n        },\n      },\n      {\n        name: 'Register',\n        path: 'register',\n        component: () => import('#/views/_core/authentication/register.vue'),\n        meta: {\n          title: $t('page.auth.register'),\n        },\n      },\n    ],\n  },\n];\n\nexport { coreRoutes, fallbackNotFoundRoute };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/router/routes/index.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { mergeRouteModules, traverseTreeValues } from '@vben/utils';\n\nimport { coreRoutes, fallbackNotFoundRoute } from './core';\n\nconst dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {\n  eager: true,\n});\n\n// 有需要可以自行打开注释，并创建文件夹\n// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });\n// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });\n\n/** 动态路由 */\nconst dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);\n\n/** 外部路由列表，访问这些页面可以不需要Layout，可能用于内嵌在别的系统(不会显示在菜单中) */\n// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);\n// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);\nconst staticRoutes: RouteRecordRaw[] = [];\nconst externalRoutes: RouteRecordRaw[] = [];\n\n/** 路由列表，由基本路由、外部路由和404兜底路由组成\n *  无需走权限验证（会一直显示在菜单中） */\nconst routes: RouteRecordRaw[] = [\n  ...coreRoutes,\n  ...externalRoutes,\n  fallbackNotFoundRoute,\n];\n\n/** 基本路由列表，这些路由不需要进入权限拦截 */\nconst coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);\n\n/** 有权限校验的路由列表，包含动态路由和静态路由 */\nconst accessRoutes = [...dynamicRoutes, ...staticRoutes];\nexport { accessRoutes, coreRouteNames, routes };\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/router/routes/modules/dashboard.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'lucide:layout-dashboard',\n      order: -1,\n      title: $t('page.dashboard.title'),\n    },\n    name: 'Dashboard',\n    path: '/dashboard',\n    children: [\n      {\n        name: 'Analytics',\n        path: '/analytics',\n        component: () => import('#/views/dashboard/analytics/index.vue'),\n        meta: {\n          affixTab: true,\n          icon: 'lucide:area-chart',\n          title: $t('page.dashboard.analytics'),\n        },\n      },\n      {\n        name: 'Workspace',\n        path: '/workspace',\n        component: () => import('#/views/dashboard/workspace/index.vue'),\n        meta: {\n          icon: 'carbon:workspace',\n          title: $t('page.dashboard.workspace'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/router/routes/modules/demos.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'ic:baseline-view-in-ar',\n      keepAlive: true,\n      order: 1000,\n      title: $t('demos.title'),\n    },\n    name: 'Demos',\n    path: '/demos',\n    children: [\n      {\n        meta: {\n          title: $t('demos.elementPlus'),\n        },\n        name: 'NaiveDemos',\n        path: '/demos/element',\n        component: () => import('#/views/demos/element/index.vue'),\n      },\n      {\n        meta: {\n          title: $t('demos.form'),\n        },\n        name: 'BasicForm',\n        path: '/demos/form',\n        component: () => import('#/views/demos/form/basic.vue'),\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/router/routes/modules/vben.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport {\n  VBEN_ANT_PREVIEW_URL,\n  VBEN_DOC_URL,\n  VBEN_GITHUB_URL,\n  VBEN_LOGO_URL,\n  VBEN_NAIVE_PREVIEW_URL,\n} from '@vben/constants';\nimport { SvgAntdvLogoIcon } from '@vben/icons';\n\nimport { IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      badgeType: 'dot',\n      icon: VBEN_LOGO_URL,\n      order: 9998,\n      title: $t('demos.vben.title'),\n    },\n    name: 'VbenProject',\n    path: '/vben-admin',\n    children: [\n      {\n        name: 'VbenDocument',\n        path: '/vben-admin/document',\n        component: IFrameView,\n        meta: {\n          icon: 'lucide:book-open-text',\n          link: VBEN_DOC_URL,\n          title: $t('demos.vben.document'),\n        },\n      },\n      {\n        name: 'VbenGithub',\n        path: '/vben-admin/github',\n        component: IFrameView,\n        meta: {\n          icon: 'mdi:github',\n          link: VBEN_GITHUB_URL,\n          title: 'Github',\n        },\n      },\n      {\n        name: 'VbenNaive',\n        path: '/vben-admin/naive',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: 'logos:naiveui',\n          link: VBEN_NAIVE_PREVIEW_URL,\n          title: $t('demos.vben.naive-ui'),\n        },\n      },\n      {\n        name: 'VbenAntd',\n        path: '/vben-admin/antd',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: SvgAntdvLogoIcon,\n          link: VBEN_ANT_PREVIEW_URL,\n          title: $t('demos.vben.antdv'),\n        },\n      },\n    ],\n  },\n  {\n    name: 'VbenAbout',\n    path: '/vben-admin/about',\n    component: () => import('#/views/_core/about/index.vue'),\n    meta: {\n      icon: 'lucide:copyright',\n      title: $t('demos.vben.about'),\n      order: 9999,\n    },\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/store/auth.ts",
    "content": "import type { Recordable, UserInfo } from '@vben/types';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';\n\nimport { ElNotification } from 'element-plus';\nimport { defineStore } from 'pinia';\n\nimport { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';\nimport { $t } from '#/locales';\n\nexport const useAuthStore = defineStore('auth', () => {\n  const accessStore = useAccessStore();\n  const userStore = useUserStore();\n  const router = useRouter();\n\n  const loginLoading = ref(false);\n\n  /**\n   * 异步处理登录操作\n   * Asynchronously handle the login process\n   * @param params 登录表单数据\n   */\n  async function authLogin(\n    params: Recordable<any>,\n    onSuccess?: () => Promise<void> | void,\n  ) {\n    // 异步处理用户登录操作并获取 accessToken\n    let userInfo: null | UserInfo = null;\n    try {\n      loginLoading.value = true;\n      const { accessToken } = await loginApi(params);\n\n      // 如果成功获取到 accessToken\n      if (accessToken) {\n        // 将 accessToken 存储到 accessStore 中\n        accessStore.setAccessToken(accessToken);\n\n        // 获取用户信息并存储到 accessStore 中\n        const [fetchUserInfoResult, accessCodes] = await Promise.all([\n          fetchUserInfo(),\n          getAccessCodesApi(),\n        ]);\n\n        userInfo = fetchUserInfoResult;\n\n        userStore.setUserInfo(userInfo);\n        accessStore.setAccessCodes(accessCodes);\n\n        if (accessStore.loginExpired) {\n          accessStore.setLoginExpired(false);\n        } else {\n          onSuccess\n            ? await onSuccess?.()\n            : await router.push(\n                userInfo.homePath || preferences.app.defaultHomePath,\n              );\n        }\n\n        if (userInfo?.realName) {\n          ElNotification({\n            message: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,\n            title: $t('authentication.loginSuccess'),\n            type: 'success',\n          });\n        }\n      }\n    } finally {\n      loginLoading.value = false;\n    }\n\n    return {\n      userInfo,\n    };\n  }\n\n  async function logout(redirect: boolean = true) {\n    try {\n      await logoutApi();\n    } catch {\n      // 不做任何处理\n    }\n    resetAllStores();\n    accessStore.setLoginExpired(false);\n\n    // 回登录页带上当前路由地址\n    await router.replace({\n      path: LOGIN_PATH,\n      query: redirect\n        ? {\n            redirect: encodeURIComponent(router.currentRoute.value.fullPath),\n          }\n        : {},\n    });\n  }\n\n  async function fetchUserInfo() {\n    let userInfo: null | UserInfo = null;\n    userInfo = await getUserInfoApi();\n    userStore.setUserInfo(userInfo);\n    return userInfo;\n  }\n\n  function $reset() {\n    loginLoading.value = false;\n  }\n\n  return {\n    $reset,\n    authLogin,\n    fetchUserInfo,\n    loginLoading,\n    logout,\n  };\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/store/index.ts",
    "content": "export * from './auth';\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/README.md",
    "content": "# \\_core\n\n此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/about/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { About } from '@vben/common-ui';\n\ndefineOptions({ name: 'About' });\n</script>\n\n<template>\n  <About />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/authentication/code-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, ref } from 'vue';\n\nimport { AuthenticationCodeLogin, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'CodeLogin' });\n\nconst loading = ref(false);\nconst CODE_LENGTH = 6;\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.mobile'),\n      },\n      fieldName: 'phoneNumber',\n      label: $t('authentication.mobile'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.mobileTip') })\n        .refine((v) => /^\\d{11}$/.test(v), {\n          message: $t('authentication.mobileErrortip'),\n        }),\n    },\n    {\n      component: 'VbenPinInput',\n      componentProps: {\n        codeLength: CODE_LENGTH,\n        createText: (countdown: number) => {\n          const text =\n            countdown > 0\n              ? $t('authentication.sendText', [countdown])\n              : $t('authentication.sendCode');\n          return text;\n        },\n        placeholder: $t('authentication.code'),\n      },\n      fieldName: 'code',\n      label: $t('authentication.code'),\n      rules: z.string().length(CODE_LENGTH, {\n        message: $t('authentication.codeTip', [CODE_LENGTH]),\n      }),\n    },\n  ];\n});\n/**\n * 异步处理登录操作\n * Asynchronously handle the login process\n * @param values 登录表单数据\n */\nasync function handleLogin(values: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log(values);\n}\n</script>\n\n<template>\n  <AuthenticationCodeLogin\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/authentication/forget-password.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, ref } from 'vue';\n\nimport { AuthenticationForgetPassword, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'ForgetPassword' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: 'example@example.com',\n      },\n      fieldName: 'email',\n      label: $t('authentication.email'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.emailTip') })\n        .email($t('authentication.emailValidErrorTip')),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log('reset email:', value);\n}\n</script>\n\n<template>\n  <AuthenticationForgetPassword\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/authentication/login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { BasicOption } from '@vben/types';\n\nimport { computed, markRaw } from 'vue';\n\nimport { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { useAuthStore } from '#/store';\n\ndefineOptions({ name: 'Login' });\n\nconst authStore = useAuthStore();\n\nconst MOCK_USER_OPTIONS: BasicOption[] = [\n  {\n    label: 'Super',\n    value: 'vben',\n  },\n  {\n    label: 'Admin',\n    value: 'admin',\n  },\n  {\n    label: 'User',\n    value: 'jack',\n  },\n];\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenSelect',\n      componentProps: {\n        options: MOCK_USER_OPTIONS,\n        placeholder: $t('authentication.selectAccount'),\n      },\n      fieldName: 'selectAccount',\n      label: $t('authentication.selectAccount'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.selectAccount') })\n        .optional()\n        .default('vben'),\n    },\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.usernameTip'),\n      },\n      dependencies: {\n        trigger(values, form) {\n          if (values.selectAccount) {\n            const findUser = MOCK_USER_OPTIONS.find(\n              (item) => item.value === values.selectAccount,\n            );\n            if (findUser) {\n              form.setValues({\n                password: '123456',\n                username: findUser.value,\n              });\n            }\n          }\n        },\n        triggerFields: ['selectAccount'],\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: markRaw(SliderCaptcha),\n      fieldName: 'captcha',\n      rules: z.boolean().refine((value) => value, {\n        message: $t('authentication.verifyRequiredTip'),\n      }),\n    },\n  ];\n});\n</script>\n\n<template>\n  <AuthenticationLogin\n    :form-schema=\"formSchema\"\n    :loading=\"authStore.loginLoading\"\n    @submit=\"authStore.authLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/authentication/qrcode-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport { AuthenticationQrCodeLogin } from '@vben/common-ui';\nimport { LOGIN_PATH } from '@vben/constants';\n\ndefineOptions({ name: 'QrCodeLogin' });\n</script>\n\n<template>\n  <AuthenticationQrCodeLogin :login-path=\"LOGIN_PATH\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/authentication/register.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, h, ref } from 'vue';\n\nimport { AuthenticationRegister, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'Register' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.usernameTip'),\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        passwordStrength: true,\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      renderComponentContent() {\n        return {\n          strengthText: () => $t('authentication.passwordStrength'),\n        };\n      },\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.confirmPassword'),\n      },\n      dependencies: {\n        rules(values) {\n          const { password } = values;\n          return z\n            .string({ required_error: $t('authentication.passwordTip') })\n            .min(1, { message: $t('authentication.passwordTip') })\n            .refine((value) => value === password, {\n              message: $t('authentication.confirmPasswordTip'),\n            });\n        },\n        triggerFields: ['password'],\n      },\n      fieldName: 'confirmPassword',\n      label: $t('authentication.confirmPassword'),\n    },\n    {\n      component: 'VbenCheckbox',\n      fieldName: 'agreePolicy',\n      renderComponentContent: () => ({\n        default: () =>\n          h('span', [\n            $t('authentication.agree'),\n            h(\n              'a',\n              {\n                class: 'vben-link ml-1 ',\n                href: '',\n              },\n              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,\n            ),\n          ]),\n      }),\n      rules: z.boolean().refine((value) => !!value, {\n        message: $t('authentication.agreeTip'),\n      }),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log('register submit:', value);\n}\n</script>\n\n<template>\n  <AuthenticationRegister\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/fallback/coming-soon.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/fallback/forbidden.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback403Demo' });\n</script>\n\n<template>\n  <Fallback status=\"403\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/fallback/internal-error.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback500Demo' });\n</script>\n\n<template>\n  <Fallback status=\"500\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/fallback/not-found.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback404Demo' });\n</script>\n\n<template>\n  <Fallback status=\"404\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/_core/fallback/offline.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'FallbackOfflineDemo' });\n</script>\n\n<template>\n  <Fallback status=\"offline\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        areaStyle: {},\n        data: [\n          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,\n          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,\n          111,\n        ],\n        itemStyle: {\n          color: '#5ab1ef',\n        },\n        smooth: true,\n        type: 'line',\n      },\n      {\n        areaStyle: {},\n        data: [\n          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,\n          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,\n        ],\n        itemStyle: {\n          color: '#019680',\n        },\n        smooth: true,\n        type: 'line',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          color: '#019680',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    // xAxis: {\n    //   axisTick: {\n    //     show: false,\n    //   },\n    //   boundaryGap: false,\n    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n    //   type: 'category',\n    // },\n    xAxis: {\n      axisTick: {\n        show: false,\n      },\n      boundaryGap: false,\n      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n      splitLine: {\n        lineStyle: {\n          type: 'solid',\n          width: 1,\n        },\n        show: true,\n      },\n      type: 'category',\n    },\n    yAxis: [\n      {\n        axisTick: {\n          show: false,\n        },\n        max: 80_000,\n        splitArea: {\n          show: true,\n        },\n        splitNumber: 4,\n        type: 'value',\n      },\n    ],\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: 0,\n      data: ['访问', '趋势'],\n    },\n    radar: {\n      indicator: [\n        {\n          name: '网页',\n        },\n        {\n          name: '移动端',\n        },\n        {\n          name: 'Ipad',\n        },\n        {\n          name: '客户端',\n        },\n        {\n          name: '第三方',\n        },\n        {\n          name: '其它',\n        },\n      ],\n      radius: '60%',\n      splitNumber: 8,\n    },\n    series: [\n      {\n        areaStyle: {\n          opacity: 1,\n          shadowBlur: 0,\n          shadowColor: 'rgba(0,0,0,.2)',\n          shadowOffsetX: 0,\n          shadowOffsetY: 10,\n        },\n        data: [\n          {\n            itemStyle: {\n              color: '#b6a2de',\n            },\n            name: '访问',\n            value: [90, 50, 86, 40, 50, 20],\n          },\n          {\n            itemStyle: {\n              color: '#5ab1ef',\n            },\n            name: '趋势',\n            value: [70, 75, 70, 76, 20, 85],\n          },\n        ],\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        symbolSize: 0,\n        type: 'radar',\n      },\n    ],\n    tooltip: {},\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 400;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        center: ['50%', '50%'],\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '外包', value: 500 },\n          { name: '定制', value: 310 },\n          { name: '技术支持', value: 274 },\n          { name: '远程', value: 400 },\n        ].sort((a, b) => {\n          return a.value - b.value;\n        }),\n        name: '商业占比',\n        radius: '80%',\n        roseType: 'radius',\n        type: 'pie',\n      },\n    ],\n\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: '2%',\n      left: 'center',\n    },\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 100;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        avoidLabelOverlap: false,\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '搜索引擎', value: 1048 },\n          { name: '直接访问', value: 735 },\n          { name: '邮件营销', value: 580 },\n          { name: '联盟广告', value: 484 },\n        ],\n        emphasis: {\n          label: {\n            fontSize: '12',\n            fontWeight: 'bold',\n            show: true,\n          },\n        },\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        label: {\n          position: 'center',\n          show: false,\n        },\n        labelLine: {\n          show: false,\n        },\n        name: '访问来源',\n        radius: ['40%', '65%'],\n        type: 'pie',\n      },\n    ],\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        barMaxWidth: 80,\n        // color: '#4f69fd',\n        data: [\n          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,\n          3200, 4800,\n        ],\n        type: 'bar',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          // color: '#4f69fd',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    xAxis: {\n      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}月`),\n      type: 'category',\n    },\n    yAxis: {\n      max: 8000,\n      splitNumber: 4,\n      type: 'value',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/dashboard/analytics/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { AnalysisOverviewItem } from '@vben/common-ui';\nimport type { TabOption } from '@vben/types';\n\nimport {\n  AnalysisChartCard,\n  AnalysisChartsTabs,\n  AnalysisOverview,\n} from '@vben/common-ui';\nimport {\n  SvgBellIcon,\n  SvgCakeIcon,\n  SvgCardIcon,\n  SvgDownloadIcon,\n} from '@vben/icons';\n\nimport AnalyticsTrends from './analytics-trends.vue';\nimport AnalyticsVisitsData from './analytics-visits-data.vue';\nimport AnalyticsVisitsSales from './analytics-visits-sales.vue';\nimport AnalyticsVisitsSource from './analytics-visits-source.vue';\nimport AnalyticsVisits from './analytics-visits.vue';\n\nconst overviewItems: AnalysisOverviewItem[] = [\n  {\n    icon: SvgCardIcon,\n    title: '用户量',\n    totalTitle: '总用户量',\n    totalValue: 120_000,\n    value: 2000,\n  },\n  {\n    icon: SvgCakeIcon,\n    title: '访问量',\n    totalTitle: '总访问量',\n    totalValue: 500_000,\n    value: 20_000,\n  },\n  {\n    icon: SvgDownloadIcon,\n    title: '下载量',\n    totalTitle: '总下载量',\n    totalValue: 120_000,\n    value: 8000,\n  },\n  {\n    icon: SvgBellIcon,\n    title: '使用量',\n    totalTitle: '总使用量',\n    totalValue: 50_000,\n    value: 5000,\n  },\n];\n\nconst chartTabs: TabOption[] = [\n  {\n    label: '流量趋势',\n    value: 'trends',\n  },\n  {\n    label: '月访问量',\n    value: 'visits',\n  },\n];\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <AnalysisOverview :items=\"overviewItems\" />\n    <AnalysisChartsTabs :tabs=\"chartTabs\" class=\"mt-5\">\n      <template #trends>\n        <AnalyticsTrends />\n      </template>\n      <template #visits>\n        <AnalyticsVisits />\n      </template>\n    </AnalysisChartsTabs>\n\n    <div class=\"mt-5 w-full md:flex\">\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问数量\">\n        <AnalyticsVisitsData />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSource />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSales />\n      </AnalysisChartCard>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/dashboard/workspace/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  WorkbenchProjectItem,\n  WorkbenchQuickNavItem,\n  WorkbenchTodoItem,\n  WorkbenchTrendItem,\n} from '@vben/common-ui';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport {\n  AnalysisChartCard,\n  WorkbenchHeader,\n  WorkbenchProject,\n  WorkbenchQuickNav,\n  WorkbenchTodo,\n  WorkbenchTrends,\n} from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';\n\nconst userStore = useUserStore();\n\n// 这是一个示例数据，实际项目中需要根据实际情况进行调整\n// url 也可以是内部路由，在 navTo 方法中识别处理，进行内部跳转\n// 例如：url: /dashboard/workspace\nconst projectItems: WorkbenchProjectItem[] = [\n  {\n    color: '',\n    content: '不要等待机会，而要创造机会。',\n    date: '2021-04-01',\n    group: '开源组',\n    icon: 'carbon:logo-github',\n    title: 'Github',\n    url: 'https://github.com',\n  },\n  {\n    color: '#3fb27f',\n    content: '现在的你决定将来的你。',\n    date: '2021-04-01',\n    group: '算法组',\n    icon: 'ion:logo-vue',\n    title: 'Vue',\n    url: 'https://vuejs.org',\n  },\n  {\n    color: '#e18525',\n    content: '没有什么才能比努力更重要。',\n    date: '2021-04-01',\n    group: '上班摸鱼',\n    icon: 'ion:logo-html5',\n    title: 'Html5',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',\n  },\n  {\n    color: '#bf0c2c',\n    content: '热情和欲望可以突破一切难关。',\n    date: '2021-04-01',\n    group: 'UI',\n    icon: 'ion:logo-angular',\n    title: 'Angular',\n    url: 'https://angular.io',\n  },\n  {\n    color: '#00d8ff',\n    content: '健康的身体是实现目标的基石。',\n    date: '2021-04-01',\n    group: '技术牛',\n    icon: 'bx:bxl-react',\n    title: 'React',\n    url: 'https://reactjs.org',\n  },\n  {\n    color: '#EBD94E',\n    content: '路是走出来的，而不是空想出来的。',\n    date: '2021-04-01',\n    group: '架构组',\n    icon: 'ion:logo-javascript',\n    title: 'Js',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',\n  },\n];\n\n// 同样，这里的 url 也可以使用以 http 开头的外部链接\nconst quickNavItems: WorkbenchQuickNavItem[] = [\n  {\n    color: '#1fdaca',\n    icon: 'ion:home-outline',\n    title: '首页',\n    url: '/',\n  },\n  {\n    color: '#bf0c2c',\n    icon: 'ion:grid-outline',\n    title: '仪表盘',\n    url: '/dashboard',\n  },\n  {\n    color: '#e18525',\n    icon: 'ion:layers-outline',\n    title: '组件',\n    url: '/demos/features/icons',\n  },\n  {\n    color: '#3fb27f',\n    icon: 'ion:settings-outline',\n    title: '系统管理',\n    url: '/demos/features/login-expired', // 这里的 URL 是示例，实际项目中需要根据实际情况进行调整\n  },\n  {\n    color: '#4daf1bc9',\n    icon: 'ion:key-outline',\n    title: '权限管理',\n    url: '/demos/access/page-control',\n  },\n  {\n    color: '#00d8ff',\n    icon: 'ion:bar-chart-outline',\n    title: '图表',\n    url: '/analytics',\n  },\n];\n\nconst todoItems = ref<WorkbenchTodoItem[]>([\n  {\n    completed: false,\n    content: `审查最近提交到Git仓库的前端代码，确保代码质量和规范。`,\n    date: '2024-07-30 11:00:00',\n    title: '审查前端代码提交',\n  },\n  {\n    completed: true,\n    content: `检查并优化系统性能，降低CPU使用率。`,\n    date: '2024-07-30 11:00:00',\n    title: '系统性能优化',\n  },\n  {\n    completed: false,\n    content: `进行系统安全检查，确保没有安全漏洞或未授权的访问。 `,\n    date: '2024-07-30 11:00:00',\n    title: '安全检查',\n  },\n  {\n    completed: false,\n    content: `更新项目中的所有npm依赖包，确保使用最新版本。`,\n    date: '2024-07-30 11:00:00',\n    title: '更新项目依赖',\n  },\n  {\n    completed: false,\n    content: `修复用户报告的页面UI显示问题，确保在不同浏览器中显示一致。 `,\n    date: '2024-07-30 11:00:00',\n    title: '修复UI显示问题',\n  },\n]);\nconst trendItems: WorkbenchTrendItem[] = [\n  {\n    avatar: 'svg:avatar-1',\n    content: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,\n    date: '刚刚',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关注了 <a>威廉</a> `,\n    date: '1个小时前',\n    title: '艾文',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1天前',\n    title: '克里斯',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写一个Vite插件</a> `,\n    date: '2天前',\n    title: 'Vben',\n  },\n  {\n    avatar: 'svg:avatar-1',\n    content: `回复了 <a>杰克</a> 的问题 <a>如何进行项目优化？</a>`,\n    date: '3天前',\n    title: '皮特',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关闭了问题 <a>如何运行项目</a> `,\n    date: '1周前',\n    title: '杰克',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1周前',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `推送了代码到 <a>Github</a>`,\n    date: '2021-04-01 20:00',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写使用 Admin Vben</a> `,\n    date: '2021-03-01 20:00',\n    title: 'Vben',\n  },\n];\n\nconst router = useRouter();\n\n// 这是一个示例方法，实际项目中需要根据实际情况进行调整\n// This is a sample method, adjust according to the actual project requirements\nfunction navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {\n  if (nav.url?.startsWith('http')) {\n    openWindow(nav.url);\n    return;\n  }\n  if (nav.url?.startsWith('/')) {\n    router.push(nav.url).catch((error) => {\n      console.error('Navigation failed:', error);\n    });\n  } else {\n    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);\n  }\n}\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <WorkbenchHeader\n      :avatar=\"userStore.userInfo?.avatar || preferences.app.defaultAvatar\"\n    >\n      <template #title>\n        早安, {{ userStore.userInfo?.realName }}, 开始您一天的工作吧！\n      </template>\n      <template #description> 今日晴，20℃ - 32℃！ </template>\n    </WorkbenchHeader>\n\n    <div class=\"mt-5 flex flex-col lg:flex-row\">\n      <div class=\"mr-4 w-full lg:w-3/5\">\n        <WorkbenchProject :items=\"projectItems\" title=\"项目\" @click=\"navTo\" />\n        <WorkbenchTrends :items=\"trendItems\" class=\"mt-5\" title=\"最新动态\" />\n      </div>\n      <div class=\"w-full lg:w-2/5\">\n        <WorkbenchQuickNav\n          :items=\"quickNavItems\"\n          class=\"mt-5 lg:mt-0\"\n          title=\"快捷导航\"\n          @click=\"navTo\"\n        />\n        <WorkbenchTodo :items=\"todoItems\" class=\"mt-5\" title=\"待办事项\" />\n        <AnalysisChartCard class=\"mt-5\" title=\"访问来源\">\n          <AnalyticsVisitsSource />\n        </AnalysisChartCard>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/demos/element/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport {\n  ElButton,\n  ElCard,\n  ElMessage,\n  ElNotification,\n  ElSegmented,\n  ElSpace,\n  ElTable,\n} from 'element-plus';\n\ntype NotificationType = 'error' | 'info' | 'success' | 'warning';\n\nfunction info() {\n  ElMessage.info('How many roads must a man walk down');\n}\n\nfunction error() {\n  ElMessage.error({\n    duration: 2500,\n    message: 'Once upon a time you dressed so fine',\n  });\n}\n\nfunction warning() {\n  ElMessage.warning('How many roads must a man walk down');\n}\nfunction success() {\n  ElMessage.success(\n    'Cause you walked hand in hand With another man in my place',\n  );\n}\n\nfunction notify(type: NotificationType) {\n  ElNotification({\n    duration: 2500,\n    message: '说点啥呢',\n    type,\n  });\n}\nconst tableData = [\n  { prop1: '1', prop2: 'A' },\n  { prop1: '2', prop2: 'B' },\n  { prop1: '3', prop2: 'C' },\n  { prop1: '4', prop2: 'D' },\n  { prop1: '5', prop2: 'E' },\n  { prop1: '6', prop2: 'F' },\n];\n\nconst segmentedValue = ref('Mon');\n\nconst segmentedOptions = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];\n</script>\n\n<template>\n  <Page\n    description=\"支持多语言，主题功能集成切换等\"\n    title=\"Element Plus组件使用演示\"\n  >\n    <div class=\"flex flex-wrap gap-5\">\n      <ElCard class=\"mb-5 w-auto\">\n        <template #header> 按钮 </template>\n        <ElSpace>\n          <ElButton text>Text</ElButton>\n          <ElButton>Default</ElButton>\n          <ElButton type=\"primary\"> Primary </ElButton>\n          <ElButton type=\"info\"> Info </ElButton>\n          <ElButton type=\"success\"> Success </ElButton>\n          <ElButton type=\"warning\"> Warning </ElButton>\n          <ElButton type=\"danger\"> Error </ElButton>\n        </ElSpace>\n      </ElCard>\n      <ElCard class=\"mb-5 w-80\">\n        <template #header> Message </template>\n        <ElSpace>\n          <ElButton type=\"info\" @click=\"info\"> 信息 </ElButton>\n          <ElButton type=\"danger\" @click=\"error\"> 错误 </ElButton>\n          <ElButton type=\"warning\" @click=\"warning\"> 警告 </ElButton>\n          <ElButton type=\"success\" @click=\"success\"> 成功 </ElButton>\n        </ElSpace>\n      </ElCard>\n      <ElCard class=\"mb-5 w-80\">\n        <template #header> Notification </template>\n        <ElSpace>\n          <ElButton type=\"info\" @click=\"notify('info')\"> 信息 </ElButton>\n          <ElButton type=\"danger\" @click=\"notify('error')\"> 错误 </ElButton>\n          <ElButton type=\"warning\" @click=\"notify('warning')\"> 警告 </ElButton>\n          <ElButton type=\"success\" @click=\"notify('success')\"> 成功 </ElButton>\n        </ElSpace>\n      </ElCard>\n      <ElCard class=\"mb-5 w-auto\">\n        <template #header> Segmented </template>\n        <ElSegmented\n          v-model=\"segmentedValue\"\n          :options=\"segmentedOptions\"\n          size=\"large\"\n        />\n      </ElCard>\n      <ElCard class=\"mb-5 w-80\">\n        <template #header> V-Loading </template>\n        <div class=\"flex size-72 items-center justify-center\" v-loading=\"true\">\n          一些演示的内容\n        </div>\n      </ElCard>\n      <ElCard class=\"mb-5 w-80\">\n        <ElTable :data=\"tableData\" stripe>\n          <ElTable.TableColumn label=\"测试列1\" prop=\"prop1\" />\n          <ElTable.TableColumn label=\"测试列2\" prop=\"prop2\" />\n        </ElTable>\n      </ElCard>\n    </div>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/src/views/demos/form/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h } from 'vue';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\n\nimport { ElButton, ElCard, ElCheckbox, ElMessage } from 'element-plus';\n\nimport { useVbenForm } from '#/adapter/form';\nimport { getAllMenusApi } from '#/api';\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  layout: 'horizontal',\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  // wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n  handleSubmit: (values) => {\n    ElMessage.success(`表单数据：${JSON.stringify(values)}`);\n  },\n  schema: [\n    {\n      component: 'IconPicker',\n      fieldName: 'icon',\n      label: 'IconPicker',\n    },\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'ApiSelect',\n      // 对应组件的参数\n      componentProps: {\n        // 菜单接口转options格式\n        afterFetch: (data: { name: string; path: string }[]) => {\n          return data.map((item: any) => ({\n            label: item.name,\n            value: item.path,\n          }));\n        },\n        // 菜单接口\n        api: getAllMenusApi,\n      },\n      // 字段名\n      fieldName: 'api',\n      // 界面显示的label\n      label: 'ApiSelect',\n    },\n    {\n      component: 'ApiTreeSelect',\n      // 对应组件的参数\n      componentProps: {\n        // 菜单接口\n        api: getAllMenusApi,\n        childrenField: 'children',\n        // 菜单接口转options格式\n        labelField: 'name',\n        valueField: 'path',\n      },\n      // 字段名\n      fieldName: 'apiTree',\n      // 界面显示的label\n      label: 'ApiTreeSelect',\n    },\n    {\n      component: 'Input',\n      fieldName: 'string',\n      label: 'String',\n    },\n    {\n      component: 'InputNumber',\n      fieldName: 'number',\n      label: 'Number',\n    },\n    {\n      component: 'RadioGroup',\n      fieldName: 'radio',\n      label: 'Radio',\n      componentProps: {\n        options: [\n          { value: 'A', label: 'A' },\n          { value: 'B', label: 'B' },\n          { value: 'C', label: 'C' },\n          { value: 'D', label: 'D' },\n          { value: 'E', label: 'E' },\n        ],\n      },\n    },\n    {\n      component: 'RadioGroup',\n      fieldName: 'radioButton',\n      label: 'RadioButton',\n      componentProps: {\n        isButton: true,\n        options: ['A', 'B', 'C', 'D', 'E', 'F'].map((v) => ({\n          value: v,\n          label: `选项${v}`,\n        })),\n      },\n    },\n    {\n      component: 'CheckboxGroup',\n      fieldName: 'checkbox',\n      label: 'Checkbox',\n      componentProps: {\n        options: ['A', 'B', 'C'].map((v) => ({ value: v, label: `选项${v}` })),\n      },\n    },\n    {\n      component: 'CheckboxGroup',\n      fieldName: 'checkbox1',\n      label: 'Checkbox1',\n      renderComponentContent: () => {\n        return {\n          default: () => {\n            return ['A', 'B', 'C', 'D'].map((v) =>\n              h(ElCheckbox, { label: v, value: v }),\n            );\n          },\n        };\n      },\n    },\n    {\n      component: 'CheckboxGroup',\n      fieldName: 'checkbotton',\n      label: 'CheckBotton',\n      componentProps: {\n        isButton: true,\n        options: [\n          { value: 'A', label: '选项A' },\n          { value: 'B', label: '选项B' },\n          { value: 'C', label: '选项C' },\n        ],\n      },\n    },\n    {\n      component: 'DatePicker',\n      fieldName: 'date',\n      label: 'Date',\n    },\n    {\n      component: 'Select',\n      fieldName: 'select',\n      label: 'Select',\n      componentProps: {\n        filterable: true,\n        options: [\n          { value: 'A', label: '选项A' },\n          { value: 'B', label: '选项B' },\n          { value: 'C', label: '选项C' },\n        ],\n      },\n    },\n  ],\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer();\nfunction setFormValues() {\n  formApi.setValues({\n    string: 'string',\n    number: 123,\n    radio: 'B',\n    radioButton: 'C',\n    checkbox: ['A', 'C'],\n    checkbotton: ['B', 'C'],\n    checkbox1: ['A', 'B'],\n    date: new Date(),\n    select: 'B',\n  });\n}\n</script>\n<template>\n  <Page\n    description=\"我们重新包装了CheckboxGroup、RadioGroup、Select，可以通过options属性传入选项属性数组以自动生成选项\"\n    title=\"表单演示\"\n  >\n    <Drawer class=\"w-[600px]\" title=\"基础表单示例\">\n      <Form />\n    </Drawer>\n    <ElCard>\n      <template #header>\n        <div class=\"flex items-center\">\n          <span class=\"flex-auto\">基础表单演示</span>\n          <ElButton type=\"primary\" @click=\"setFormValues\">设置表单值</ElButton>\n        </div>\n      </template>\n      <ElButton type=\"primary\" @click=\"drawerApi.open\"> 打开抽屉 </ElButton>\n    </ElCard>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web-app.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"#/*\": [\"./src/*\"]\n    }\n  },\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }],\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/tsconfig.node.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n    \"noEmit\": false\n  },\n  \"include\": [\"vite.config.mts\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-ele/vite.config.mts",
    "content": "import { defineConfig } from '@vben/vite-config';\n\nimport ElementPlus from 'unplugin-element-plus/vite';\n\nexport default defineConfig(async () => {\n  return {\n    application: {},\n    vite: {\n      plugins: [\n        ElementPlus({\n          format: 'esm',\n        }),\n      ],\n      server: {\n        proxy: {\n          '/api': {\n            changeOrigin: true,\n            rewrite: (path) => path.replace(/^\\/api/, ''),\n            // mock代理目标地址\n            target: 'http://localhost:5320/api',\n            ws: true,\n          },\n        },\n      },\n    },\n  };\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/index.html",
    "content": "<!doctype html>\n<html lang=\"zh\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n    <meta name=\"renderer\" content=\"webkit\" />\n    <meta name=\"description\" content=\"A Modern Back-end Management System\" />\n    <meta name=\"keywords\" content=\"Vben Admin Vue3 Vite\" />\n    <meta name=\"author\" content=\"Vben\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0\"\n    />\n    <!-- 由 vite 注入 VITE_APP_TITLE 变量，在 .env 文件内配置 -->\n    <title><%= VITE_APP_TITLE %></title>\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <script>\n      // 生产环境下注入百度统计\n      if (window._VBEN_ADMIN_PRO_APP_CONF_) {\n        var _hmt = _hmt || [];\n        (function () {\n          var hm = document.createElement('script');\n          hm.src =\n            'https://hm.baidu.com/hm.js?24bb3eb91dfe4ebfcbcee6952a107cb6';\n          var s = document.getElementsByTagName('script')[0];\n          s.parentNode.insertBefore(hm, s);\n        })();\n      }\n    </script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/package.json",
    "content": "{\n  \"name\": \"@vben/web-naive\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://vben.pro\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"apps/web-naive\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"vben\",\n    \"email\": \"ann.vben@gmail.com\",\n    \"url\": \"https://github.com/anncwb\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm vite build --mode production\",\n    \"build:analyze\": \"pnpm vite build --mode analyze\",\n    \"dev\": \"pnpm vite --mode development\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"vue-tsc --noEmit --skipLibCheck\"\n  },\n  \"imports\": {\n    \"#/*\": \"./src/*\"\n  },\n  \"dependencies\": {\n    \"@vben/access\": \"workspace:*\",\n    \"@vben/common-ui\": \"workspace:*\",\n    \"@vben/constants\": \"workspace:*\",\n    \"@vben/hooks\": \"workspace:*\",\n    \"@vben/icons\": \"workspace:*\",\n    \"@vben/layouts\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/plugins\": \"workspace:*\",\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/request\": \"workspace:*\",\n    \"@vben/stores\": \"workspace:*\",\n    \"@vben/styles\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"naive-ui\": \"catalog:\",\n    \"pinia\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/adapter/component/index.ts",
    "content": "/**\n * 通用组件共同的使用的基础组件，原先放在 adapter/form 内部，限制了使用范围，这里提取出来，方便其他地方使用\n * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,\n */\n\nimport type { Component } from 'vue';\n\nimport type { BaseFormComponentType } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { defineAsyncComponent, defineComponent, h, ref } from 'vue';\n\nimport { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { message } from '#/adapter/naive';\n\nconst NButton = defineAsyncComponent(() =>\n  import('naive-ui/es/button').then((res) => res.NButton),\n);\nconst NCheckbox = defineAsyncComponent(() =>\n  import('naive-ui/es/checkbox').then((res) => res.NCheckbox),\n);\nconst NCheckboxGroup = defineAsyncComponent(() =>\n  import('naive-ui/es/checkbox').then((res) => res.NCheckboxGroup),\n);\nconst NDatePicker = defineAsyncComponent(() =>\n  import('naive-ui/es/date-picker').then((res) => res.NDatePicker),\n);\nconst NDivider = defineAsyncComponent(() =>\n  import('naive-ui/es/divider').then((res) => res.NDivider),\n);\nconst NInput = defineAsyncComponent(() =>\n  import('naive-ui/es/input').then((res) => res.NInput),\n);\nconst NInputNumber = defineAsyncComponent(() =>\n  import('naive-ui/es/input-number').then((res) => res.NInputNumber),\n);\nconst NRadio = defineAsyncComponent(() =>\n  import('naive-ui/es/radio').then((res) => res.NRadio),\n);\nconst NRadioButton = defineAsyncComponent(() =>\n  import('naive-ui/es/radio').then((res) => res.NRadioButton),\n);\nconst NRadioGroup = defineAsyncComponent(() =>\n  import('naive-ui/es/radio').then((res) => res.NRadioGroup),\n);\nconst NSelect = defineAsyncComponent(() =>\n  import('naive-ui/es/select').then((res) => res.NSelect),\n);\nconst NSpace = defineAsyncComponent(() =>\n  import('naive-ui/es/space').then((res) => res.NSpace),\n);\nconst NSwitch = defineAsyncComponent(() =>\n  import('naive-ui/es/switch').then((res) => res.NSwitch),\n);\nconst NTimePicker = defineAsyncComponent(() =>\n  import('naive-ui/es/time-picker').then((res) => res.NTimePicker),\n);\nconst NTreeSelect = defineAsyncComponent(() =>\n  import('naive-ui/es/tree-select').then((res) => res.NTreeSelect),\n);\nconst NUpload = defineAsyncComponent(() =>\n  import('naive-ui/es/upload').then((res) => res.NUpload),\n);\n\nconst withDefaultPlaceholder = <T extends Component>(\n  component: T,\n  type: 'input' | 'select',\n  componentProps: Recordable<any> = {},\n) => {\n  return defineComponent({\n    name: component.name,\n    inheritAttrs: false,\n    setup: (props: any, { attrs, expose, slots }) => {\n      const placeholder =\n        props?.placeholder ||\n        attrs?.placeholder ||\n        $t(`ui.placeholder.${type}`);\n      // 透传组件暴露的方法\n      const innerRef = ref();\n      expose(\n        new Proxy(\n          {},\n          {\n            get: (_target, key) => innerRef.value?.[key],\n            has: (_target, key) => key in (innerRef.value || {}),\n          },\n        ),\n      );\n      return () =>\n        h(\n          component,\n          { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },\n          slots,\n        );\n    },\n  });\n};\n\n// 这里需要自行根据业务组件库进行适配，需要用到的组件都需要在这里类型说明\nexport type ComponentType =\n  | 'ApiSelect'\n  | 'ApiTreeSelect'\n  | 'Checkbox'\n  | 'CheckboxGroup'\n  | 'DatePicker'\n  | 'Divider'\n  | 'IconPicker'\n  | 'Input'\n  | 'InputNumber'\n  | 'RadioGroup'\n  | 'Select'\n  | 'Space'\n  | 'Switch'\n  | 'TimePicker'\n  | 'TreeSelect'\n  | 'Upload'\n  | BaseFormComponentType;\n\nasync function initComponentAdapter() {\n  const components: Partial<Record<ComponentType, Component>> = {\n    // 如果你的组件体积比较大，可以使用异步加载\n    // Button: () =>\n    // import('xxx').then((res) => res.Button),\n\n    ApiSelect: withDefaultPlaceholder(\n      {\n        ...ApiComponent,\n        name: 'ApiSelect',\n      },\n      'select',\n      {\n        component: NSelect,\n        modelPropName: 'value',\n      },\n    ),\n    ApiTreeSelect: withDefaultPlaceholder(\n      {\n        ...ApiComponent,\n        name: 'ApiTreeSelect',\n      },\n      'select',\n      {\n        component: NTreeSelect,\n        nodeKey: 'value',\n        loadingSlot: 'arrow',\n        keyField: 'value',\n        modelPropName: 'value',\n        optionsPropName: 'options',\n        visibleEvent: 'onVisibleChange',\n      },\n    ),\n    Checkbox: NCheckbox,\n    CheckboxGroup: (props, { attrs, slots }) => {\n      let defaultSlot;\n      if (Reflect.has(slots, 'default')) {\n        defaultSlot = slots.default;\n      } else {\n        const { options } = attrs;\n        if (Array.isArray(options)) {\n          defaultSlot = () => options.map((option) => h(NCheckbox, option));\n        }\n      }\n      return h(\n        NCheckboxGroup,\n        { ...props, ...attrs },\n        { default: defaultSlot },\n      );\n    },\n    DatePicker: NDatePicker,\n    // 自定义默认按钮\n    DefaultButton: (props, { attrs, slots }) => {\n      return h(NButton, { ...props, attrs, type: 'default' }, slots);\n    },\n    // 自定义主要按钮\n    PrimaryButton: (props, { attrs, slots }) => {\n      return h(NButton, { ...props, attrs, type: 'primary' }, slots);\n    },\n    Divider: NDivider,\n    IconPicker: withDefaultPlaceholder(IconPicker, 'select', {\n      iconSlot: 'suffix',\n      inputComponent: NInput,\n    }),\n    Input: withDefaultPlaceholder(NInput, 'input'),\n    InputNumber: withDefaultPlaceholder(NInputNumber, 'input'),\n    RadioGroup: (props, { attrs, slots }) => {\n      let defaultSlot;\n      if (Reflect.has(slots, 'default')) {\n        defaultSlot = slots.default;\n      } else {\n        const { options } = attrs;\n        if (Array.isArray(options)) {\n          defaultSlot = () =>\n            options.map((option) =>\n              h(attrs.isButton ? NRadioButton : NRadio, option),\n            );\n        }\n      }\n      const groupRender = h(\n        NRadioGroup,\n        { ...props, ...attrs },\n        { default: defaultSlot },\n      );\n      return attrs.isButton\n        ? h(NSpace, { vertical: true }, () => groupRender)\n        : groupRender;\n    },\n    Select: withDefaultPlaceholder(NSelect, 'select'),\n    Space: NSpace,\n    Switch: NSwitch,\n    TimePicker: NTimePicker,\n    TreeSelect: withDefaultPlaceholder(NTreeSelect, 'select'),\n    Upload: NUpload,\n  };\n\n  // 将组件注册到全局共享状态中\n  globalShareState.setComponents(components);\n\n  // 定义全局共享状态中的消息提示\n  globalShareState.defineMessage({\n    // 复制成功消息提示\n    copyPreferencesSuccess: (title, content) => {\n      message.success(content || title, {\n        duration: 0,\n      });\n    },\n  });\n}\n\nexport { initComponentAdapter };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/adapter/form.ts",
    "content": "import type {\n  VbenFormSchema as FormSchema,\n  VbenFormProps,\n} from '@vben/common-ui';\n\nimport type { ComponentType } from './component';\n\nimport { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nasync function initSetupVbenForm() {\n  setupVbenForm<ComponentType>({\n    config: {\n      // naive-ui组件的空值为null,不能是undefined，否则重置表单时不生效\n      emptyStateValue: null,\n      baseModelPropName: 'value',\n      modelPropNameMap: {\n        Checkbox: 'checked',\n        Radio: 'checked',\n        Upload: 'fileList',\n      },\n    },\n    defineRules: {\n      required: (value, _params, ctx) => {\n        if (value === undefined || value === null || value.length === 0) {\n          return $t('ui.formRules.required', [ctx.label]);\n        }\n        return true;\n      },\n      selectRequired: (value, _params, ctx) => {\n        if (value === undefined || value === null) {\n          return $t('ui.formRules.selectRequired', [ctx.label]);\n        }\n        return true;\n      },\n    },\n  });\n}\n\nconst useVbenForm = useForm<ComponentType>;\n\nexport { initSetupVbenForm, useVbenForm, z };\n\nexport type VbenFormSchema = FormSchema<ComponentType>;\nexport type { VbenFormProps };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/adapter/naive.ts",
    "content": "import { computed } from 'vue';\n\nimport { preferences } from '@vben/preferences';\nimport '@vben/styles';\n\nimport { createDiscreteApi, darkTheme, lightTheme } from 'naive-ui';\n\nconst themeOverridesProviderProps = computed(() => ({\n  themeOverrides: preferences.theme.mode === 'light' ? lightTheme : darkTheme,\n}));\n\nconst themeProviderProps = computed(() => ({\n  theme: preferences.theme.mode === 'light' ? lightTheme : darkTheme,\n}));\n\nexport const { dialog, loadingBar, message, modal, notification } =\n  createDiscreteApi(\n    ['message', 'dialog', 'notification', 'loadingBar', 'modal'],\n    {\n      configProviderProps: themeProviderProps,\n      loadingBarProviderProps: themeOverridesProviderProps,\n      messageProviderProps: themeOverridesProviderProps,\n      notificationProviderProps: themeOverridesProviderProps,\n    },\n  );\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/adapter/vxe-table.ts",
    "content": "import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';\n\nimport { h } from 'vue';\n\nimport { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';\n\nimport { NButton, NImage } from 'naive-ui';\n\nimport { useVbenForm } from './form';\n\nsetupVbenVxeTable({\n  configVxeTable: (vxeUI) => {\n    vxeUI.setConfig({\n      grid: {\n        align: 'center',\n        border: false,\n        columnConfig: {\n          resizable: true,\n        },\n        minHeight: 180,\n        formConfig: {\n          // 全局禁用vxe-table的表单配置，使用formOptions\n          enabled: false,\n        },\n        proxyConfig: {\n          autoLoad: true,\n          response: {\n            result: 'items',\n            total: 'total',\n            list: 'items',\n          },\n          showActiveMsg: true,\n          showResponseMsg: false,\n        },\n        round: true,\n        showOverflow: true,\n        size: 'small',\n      } as VxeTableGridOptions,\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellImage' },\n    vxeUI.renderer.add('CellImage', {\n      renderTableDefault(_renderOpts, params) {\n        const { column, row } = params;\n        return h(NImage, { src: row[column.field] });\n      },\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellLink' },\n    vxeUI.renderer.add('CellLink', {\n      renderTableDefault(renderOpts) {\n        const { props } = renderOpts;\n        return h(\n          NButton,\n          { size: 'small', type: 'primary', quaternary: true },\n          { default: () => props?.text },\n        );\n      },\n    });\n\n    // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化\n    // vxeUI.formats.add\n  },\n  useVbenForm,\n});\n\nexport { useVbenVxeGrid };\n\nexport type * from '@vben/plugins/vxe-table';\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/api/core/auth.ts",
    "content": "import { baseRequestClient, requestClient } from '#/api/request';\n\nexport namespace AuthApi {\n  /** 登录接口参数 */\n  export interface LoginParams {\n    password?: string;\n    username?: string;\n  }\n\n  /** 登录接口返回值 */\n  export interface LoginResult {\n    accessToken: string;\n  }\n\n  export interface RefreshTokenResult {\n    data: string;\n    status: number;\n  }\n}\n\n/**\n * 登录\n */\nexport async function loginApi(data: AuthApi.LoginParams) {\n  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);\n}\n\n/**\n * 刷新accessToken\n */\nexport async function refreshTokenApi() {\n  return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {\n    withCredentials: true,\n  });\n}\n\n/**\n * 退出登录\n */\nexport async function logoutApi() {\n  return baseRequestClient.post('/auth/logout', {\n    withCredentials: true,\n  });\n}\n\n/**\n * 获取用户权限码\n */\nexport async function getAccessCodesApi() {\n  return requestClient.get<string[]>('/auth/codes');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/api/core/index.ts",
    "content": "export * from './auth';\nexport * from './menu';\nexport * from './user';\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/api/core/menu.ts",
    "content": "import type { RouteRecordStringComponent } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户所有菜单\n */\nexport async function getAllMenusApi() {\n  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/api/core/user.ts",
    "content": "import type { UserInfo } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户信息\n */\nexport async function getUserInfoApi() {\n  return requestClient.get<UserInfo>('/user/info');\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/api/index.ts",
    "content": "export * from './core';\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/api/request.ts",
    "content": "/**\n * 该文件可自行根据业务逻辑进行调整\n */\nimport type { RequestClientOptions } from '@vben/request';\n\nimport { useAppConfig } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\nimport {\n  authenticateResponseInterceptor,\n  defaultResponseInterceptor,\n  errorMessageResponseInterceptor,\n  RequestClient,\n} from '@vben/request';\nimport { useAccessStore } from '@vben/stores';\n\nimport { message } from '#/adapter/naive';\nimport { useAuthStore } from '#/store';\n\nimport { refreshTokenApi } from './core';\n\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n\nfunction createRequestClient(baseURL: string, options?: RequestClientOptions) {\n  const client = new RequestClient({\n    ...options,\n    baseURL,\n  });\n\n  /**\n   * 重新认证逻辑\n   */\n  async function doReAuthenticate() {\n    console.warn('Access token or refresh token is invalid or expired. ');\n    const accessStore = useAccessStore();\n    const authStore = useAuthStore();\n    accessStore.setAccessToken(null);\n    if (\n      preferences.app.loginExpiredMode === 'modal' &&\n      accessStore.isAccessChecked\n    ) {\n      accessStore.setLoginExpired(true);\n    } else {\n      await authStore.logout();\n    }\n  }\n\n  /**\n   * 刷新token逻辑\n   */\n  async function doRefreshToken() {\n    const accessStore = useAccessStore();\n    const resp = await refreshTokenApi();\n    const newToken = resp.data;\n    accessStore.setAccessToken(newToken);\n    return newToken;\n  }\n\n  function formatToken(token: null | string) {\n    return token ? `Bearer ${token}` : null;\n  }\n\n  // 请求头处理\n  client.addRequestInterceptor({\n    fulfilled: async (config) => {\n      const accessStore = useAccessStore();\n\n      config.headers.Authorization = formatToken(accessStore.accessToken);\n      config.headers['Accept-Language'] = preferences.app.locale;\n      return config;\n    },\n  });\n\n  // 处理返回的响应数据格式\n  client.addResponseInterceptor(\n    defaultResponseInterceptor({\n      codeField: 'code',\n      dataField: 'data',\n      successCode: 0,\n    }),\n  );\n\n  // token过期的处理\n  client.addResponseInterceptor(\n    authenticateResponseInterceptor({\n      client,\n      doReAuthenticate,\n      doRefreshToken,\n      enableRefreshToken: preferences.app.enableRefreshToken,\n      formatToken,\n    }),\n  );\n\n  // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里\n  client.addResponseInterceptor(\n    errorMessageResponseInterceptor((msg: string, error) => {\n      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg\n      // 当前mock接口返回的错误字段是 error 或者 message\n      const responseData = error?.response?.data ?? {};\n      const errorMessage = responseData?.error ?? responseData?.message ?? '';\n      // 如果没有错误信息，则会根据状态码进行提示\n      message.error(errorMessage || msg);\n    }),\n  );\n\n  return client;\n}\n\nexport const requestClient = createRequestClient(apiURL, {\n  responseReturn: 'data',\n});\n\nexport const baseRequestClient = new RequestClient({ baseURL: apiURL });\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/app.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { GlobalThemeOverrides } from 'naive-ui';\n\nimport { computed } from 'vue';\n\nimport { useNaiveDesignTokens } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\n\nimport {\n  darkTheme,\n  dateEnUS,\n  dateZhCN,\n  enUS,\n  lightTheme,\n  NConfigProvider,\n  NMessageProvider,\n  NNotificationProvider,\n  zhCN,\n} from 'naive-ui';\n\ndefineOptions({ name: 'App' });\n\nconst { commonTokens } = useNaiveDesignTokens();\n\nconst tokenLocale = computed(() =>\n  preferences.app.locale === 'zh-CN' ? zhCN : enUS,\n);\nconst tokenDateLocale = computed(() =>\n  preferences.app.locale === 'zh-CN' ? dateZhCN : dateEnUS,\n);\nconst tokenTheme = computed(() =>\n  preferences.theme.mode === 'dark' ? darkTheme : lightTheme,\n);\n\nconst themeOverrides = computed((): GlobalThemeOverrides => {\n  return {\n    common: commonTokens,\n  };\n});\n</script>\n\n<template>\n  <NConfigProvider\n    :date-locale=\"tokenDateLocale\"\n    :locale=\"tokenLocale\"\n    :theme=\"tokenTheme\"\n    :theme-overrides=\"themeOverrides\"\n    class=\"h-full\"\n  >\n    <NNotificationProvider>\n      <NMessageProvider>\n        <RouterView />\n      </NMessageProvider>\n    </NNotificationProvider>\n  </NConfigProvider>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/bootstrap.ts",
    "content": "import { createApp, watchEffect } from 'vue';\n\nimport { registerAccessDirective } from '@vben/access';\nimport { registerLoadingDirective } from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { initStores } from '@vben/stores';\nimport '@vben/styles';\nimport '@vben/styles/naive';\n\nimport { useTitle } from '@vueuse/core';\n\nimport { $t, setupI18n } from '#/locales';\n\nimport { initComponentAdapter } from './adapter/component';\nimport { initSetupVbenForm } from './adapter/form';\nimport App from './app.vue';\nimport { router } from './router';\n\nasync function bootstrap(namespace: string) {\n  // 初始化组件适配器\n  await initComponentAdapter();\n\n  // 初始化表单组件\n  await initSetupVbenForm();\n\n  // // 设置弹窗的默认配置\n  // setDefaultModalProps({\n  //   fullscreenButton: false,\n  // });\n  // // 设置抽屉的默认配置\n  // setDefaultDrawerProps({\n  //   // zIndex: 2000,\n  // });\n\n  const app = createApp(App);\n\n  // 注册v-loading指令\n  registerLoadingDirective(app, {\n    loading: 'loading', // 在这里可以自定义指令名称,也可以明确提供false表示不注册这个指令\n    spinning: 'spinning',\n  });\n\n  // 国际化 i18n 配置\n  await setupI18n(app);\n\n  // 配置 pinia-tore\n  await initStores(app, { namespace });\n\n  // 安装权限指令\n  registerAccessDirective(app);\n\n  // 初始化 tippy\n  const { initTippy } = await import('@vben/common-ui/es/tippy');\n  initTippy(app);\n\n  // 配置路由及路由守卫\n  app.use(router);\n\n  // 配置Motion插件\n  const { MotionPlugin } = await import('@vben/plugins/motion');\n  app.use(MotionPlugin);\n\n  // 动态更新标题\n  watchEffect(() => {\n    if (preferences.app.dynamicTitle) {\n      const routeTitle = router.currentRoute.value.meta?.title;\n      const pageTitle =\n        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;\n      useTitle(pageTitle);\n    }\n  });\n\n  app.mount('#app');\n}\n\nexport { bootstrap };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/layouts/auth.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { AuthPageLayout } from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst appName = computed(() => preferences.app.name);\nconst logo = computed(() => preferences.logo.source);\n</script>\n\n<template>\n  <AuthPageLayout\n    :app-name=\"appName\"\n    :logo=\"logo\"\n    :page-description=\"$t('authentication.pageDesc')\"\n    :page-title=\"$t('authentication.pageTitle')\"\n  >\n    <!-- 自定义工具栏 -->\n    <!-- <template #toolbar></template> -->\n  </AuthPageLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/layouts/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { NotificationItem } from '@vben/layouts';\n\nimport { computed, ref, watch } from 'vue';\n\nimport { AuthenticationLoginExpiredModal } from '@vben/common-ui';\nimport { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';\nimport { useWatermark } from '@vben/hooks';\nimport { BookOpenText, CircleHelp, SvgGithubIcon } from '@vben/icons';\nimport {\n  BasicLayout,\n  LockScreen,\n  Notification,\n  UserDropdown,\n} from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport { $t } from '#/locales';\nimport { useAuthStore } from '#/store';\nimport LoginForm from '#/views/_core/authentication/login.vue';\n\nconst notifications = ref<NotificationItem[]>([\n  {\n    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',\n    date: '3小时前',\n    isRead: true,\n    message: '描述信息描述信息描述信息',\n    title: '收到了 14 份新周报',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '刚刚',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '朱偏右 回复了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '2024-01-01',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '曲丽丽 评论了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/satori',\n    date: '1天前',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '代办提醒',\n  },\n]);\n\nconst userStore = useUserStore();\nconst authStore = useAuthStore();\nconst accessStore = useAccessStore();\nconst { destroyWatermark, updateWatermark } = useWatermark();\nconst showDot = computed(() =>\n  notifications.value.some((item) => !item.isRead),\n);\n\nconst menus = computed(() => [\n  {\n    handler: () => {\n      openWindow(VBEN_DOC_URL, {\n        target: '_blank',\n      });\n    },\n    icon: BookOpenText,\n    text: $t('ui.widgets.document'),\n  },\n  {\n    handler: () => {\n      openWindow(VBEN_GITHUB_URL, {\n        target: '_blank',\n      });\n    },\n    icon: SvgGithubIcon,\n    text: 'GitHub',\n  },\n  {\n    handler: () => {\n      openWindow(`${VBEN_GITHUB_URL}/issues`, {\n        target: '_blank',\n      });\n    },\n    icon: CircleHelp,\n    text: $t('ui.widgets.qa'),\n  },\n]);\n\nconst avatar = computed(() => {\n  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;\n});\n\nasync function handleLogout() {\n  await authStore.logout(false);\n}\n\nfunction handleNoticeClear() {\n  notifications.value = [];\n}\n\nfunction handleMakeAll() {\n  notifications.value.forEach((item) => (item.isRead = true));\n}\n\nwatch(\n  () => ({\n    enable: preferences.app.watermark,\n    content: preferences.app.watermarkContent,\n  }),\n  async ({ enable, content }) => {\n    if (enable) {\n      await updateWatermark({\n        content:\n          content ||\n          `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,\n      });\n    } else {\n      destroyWatermark();\n    }\n  },\n  {\n    immediate: true,\n  },\n);\n</script>\n\n<template>\n  <BasicLayout @clear-preferences-and-logout=\"handleLogout\">\n    <template #user-dropdown>\n      <UserDropdown\n        :avatar\n        :menus\n        :text=\"userStore.userInfo?.realName\"\n        description=\"ann.vben@gmail.com\"\n        tag-text=\"Pro\"\n        @logout=\"handleLogout\"\n      />\n    </template>\n    <template #notification>\n      <Notification\n        :dot=\"showDot\"\n        :notifications=\"notifications\"\n        @clear=\"handleNoticeClear\"\n        @make-all=\"handleMakeAll\"\n      />\n    </template>\n    <template #extra>\n      <AuthenticationLoginExpiredModal\n        v-model:open=\"accessStore.loginExpired\"\n        :avatar\n      >\n        <LoginForm />\n      </AuthenticationLoginExpiredModal>\n    </template>\n    <template #lock-screen>\n      <LockScreen :avatar @to-login=\"handleLogout\" />\n    </template>\n  </BasicLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/layouts/index.ts",
    "content": "const BasicLayout = () => import('./basic.vue');\nconst AuthPageLayout = () => import('./auth.vue');\n\nconst IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);\n\nexport { AuthPageLayout, BasicLayout, IFrameView };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/locales/README.md",
    "content": "# locale\n\n每个app使用的国际化可能不同，这里用于扩展国际化的功能，例如扩展 dayjs、antd组件库的多语言切换，以及app本身的国际化文件。\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/locales/index.ts",
    "content": "import type { App } from 'vue';\n\nimport type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';\n\nimport {\n  $t,\n  setupI18n as coreSetup,\n  loadLocalesMapFromDir,\n} from '@vben/locales';\nimport { preferences } from '@vben/preferences';\n\nconst modules = import.meta.glob('./langs/**/*.json');\n\nconst localesMap = loadLocalesMapFromDir(\n  /\\.\\/langs\\/([^/]+)\\/(.*)\\.json$/,\n  modules,\n);\n\n/**\n * 加载应用特有的语言包\n * 这里也可以改造为从服务端获取翻译数据\n * @param lang\n */\nasync function loadMessages(lang: SupportedLanguagesType) {\n  const appLocaleMessages = await localesMap[lang]?.();\n  return appLocaleMessages?.default;\n}\n\nasync function setupI18n(app: App, options: LocaleSetupOptions = {}) {\n  await coreSetup(app, {\n    defaultLocale: preferences.app.locale,\n    loadMessages,\n    missingWarn: !import.meta.env.PROD,\n    ...options,\n  });\n}\n\nexport { $t, setupI18n };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/locales/langs/en-US/demos.json",
    "content": "{\n  \"title\": \"Demos\",\n  \"naive\": \"Naive UI\",\n  \"table\": \"Table\",\n  \"form\": \"Form\",\n  \"vben\": {\n    \"title\": \"Project\",\n    \"about\": \"About\",\n    \"document\": \"Document\",\n    \"antdv\": \"Ant Design Vue Version\",\n    \"naive-ui\": \"Naive UI Version\",\n    \"element-plus\": \"Element Plus Version\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/locales/langs/en-US/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"Login\",\n    \"register\": \"Register\",\n    \"codeLogin\": \"Code Login\",\n    \"qrcodeLogin\": \"Qr Code Login\",\n    \"forgetPassword\": \"Forget Password\"\n  },\n  \"dashboard\": {\n    \"title\": \"Dashboard\",\n    \"analytics\": \"Analytics\",\n    \"workspace\": \"Workspace\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/locales/langs/zh-CN/demos.json",
    "content": "{\n  \"title\": \"演示\",\n  \"naive\": \"Naive UI\",\n  \"table\": \"Table\",\n  \"form\": \"表单\",\n  \"vben\": {\n    \"title\": \"项目\",\n    \"about\": \"关于\",\n    \"document\": \"文档\",\n    \"antdv\": \"Ant Design Vue 版本\",\n    \"naive-ui\": \"Naive UI 版本\",\n    \"element-plus\": \"Element Plus 版本\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/locales/langs/zh-CN/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"登录\",\n    \"register\": \"注册\",\n    \"codeLogin\": \"验证码登录\",\n    \"qrcodeLogin\": \"二维码登录\",\n    \"forgetPassword\": \"忘记密码\"\n  },\n  \"dashboard\": {\n    \"title\": \"概览\",\n    \"analytics\": \"分析页\",\n    \"workspace\": \"工作台\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/main.ts",
    "content": "import { initPreferences } from '@vben/preferences';\nimport { unmountGlobalLoading } from '@vben/utils';\n\nimport { overridesPreferences } from './preferences';\n\n/**\n * 应用初始化完成之后再进行页面加载渲染\n */\nasync function initApplication() {\n  // name用于指定项目唯一标识\n  // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据\n  const env = import.meta.env.PROD ? 'prod' : 'dev';\n  const appVersion = import.meta.env.VITE_APP_VERSION;\n  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;\n\n  // app偏好设置初始化\n  await initPreferences({\n    namespace,\n    overrides: overridesPreferences,\n  });\n\n  // 启动应用并挂载\n  // vue应用主要逻辑及视图\n  const { bootstrap } = await import('./bootstrap');\n  await bootstrap(namespace);\n\n  // 移除并销毁loading\n  unmountGlobalLoading();\n}\n\ninitApplication();\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/preferences.ts",
    "content": "import { defineOverridesPreferences } from '@vben/preferences';\n\n/**\n * @description 项目配置文件\n * 只需要覆盖项目中的一部分配置，不需要的配置不用覆盖，会自动使用默认配置\n * !!! 更改配置后请清空缓存，否则可能不生效\n */\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    name: import.meta.env.VITE_APP_TITLE,\n  },\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/router/access.ts",
    "content": "import type {\n  ComponentRecordType,\n  GenerateMenuAndRoutesOptions,\n} from '@vben/types';\n\nimport { generateAccessible } from '@vben/access';\nimport { preferences } from '@vben/preferences';\n\nimport { message } from '#/adapter/naive';\nimport { getAllMenusApi } from '#/api';\nimport { BasicLayout, IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');\n\nasync function generateAccess(options: GenerateMenuAndRoutesOptions) {\n  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');\n\n  const layoutMap: ComponentRecordType = {\n    BasicLayout,\n    IFrameView,\n  };\n\n  return await generateAccessible(preferences.app.accessMode, {\n    ...options,\n    fetchMenuListAsync: async () => {\n      message.loading(`${$t('common.loadingMenu')}...`, {\n        duration: 1.5,\n      });\n      return await getAllMenusApi();\n    },\n    // 可以指定没有权限跳转403页面\n    forbiddenComponent,\n    // 如果 route.meta.menuVisibleWithForbidden = true\n    layoutMap,\n    pageMap,\n  });\n}\n\nexport { generateAccess };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/router/guard.ts",
    "content": "import type { Router } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { startProgress, stopProgress } from '@vben/utils';\n\nimport { accessRoutes, coreRouteNames } from '#/router/routes';\nimport { useAuthStore } from '#/store';\n\nimport { generateAccess } from './access';\n\n/**\n * 通用守卫配置\n * @param router\n */\nfunction setupCommonGuard(router: Router) {\n  // 记录已经加载的页面\n  const loadedPaths = new Set<string>();\n\n  router.beforeEach((to) => {\n    to.meta.loaded = loadedPaths.has(to.path);\n\n    // 页面加载进度条\n    if (!to.meta.loaded && preferences.transition.progress) {\n      startProgress();\n    }\n    return true;\n  });\n\n  router.afterEach((to) => {\n    // 记录页面是否加载,如果已经加载，后续的页面切换动画等效果不在重复执行\n\n    loadedPaths.add(to.path);\n\n    // 关闭页面加载进度条\n    if (preferences.transition.progress) {\n      stopProgress();\n    }\n  });\n}\n\n/**\n * 权限访问守卫配置\n * @param router\n */\nfunction setupAccessGuard(router: Router) {\n  router.beforeEach(async (to, from) => {\n    const accessStore = useAccessStore();\n    const userStore = useUserStore();\n    const authStore = useAuthStore();\n\n    // 基本路由，这些路由不需要进入权限拦截\n    if (coreRouteNames.includes(to.name as string)) {\n      if (to.path === LOGIN_PATH && accessStore.accessToken) {\n        return decodeURIComponent(\n          (to.query?.redirect as string) ||\n            userStore.userInfo?.homePath ||\n            preferences.app.defaultHomePath,\n        );\n      }\n      return true;\n    }\n\n    // accessToken 检查\n    if (!accessStore.accessToken) {\n      // 明确声明忽略权限访问权限，则可以访问\n      if (to.meta.ignoreAccess) {\n        return true;\n      }\n\n      // 没有访问权限，跳转登录页面\n      if (to.fullPath !== LOGIN_PATH) {\n        return {\n          path: LOGIN_PATH,\n          // 如不需要，直接删除 query\n          query:\n            to.fullPath === preferences.app.defaultHomePath\n              ? {}\n              : { redirect: encodeURIComponent(to.fullPath) },\n          // 携带当前跳转的页面，登录后重新跳转该页面\n          replace: true,\n        };\n      }\n      return to;\n    }\n\n    // 是否已经生成过动态路由\n    if (accessStore.isAccessChecked) {\n      return true;\n    }\n    // 生成路由表\n    // 当前登录用户拥有的角色标识列表\n    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());\n    const userRoles = userInfo.roles ?? [];\n\n    // 生成菜单和路由\n    const { accessibleMenus, accessibleRoutes } = await generateAccess({\n      roles: userRoles,\n      router,\n      // 则会在菜单中显示，但是访问会被重定向到403\n      routes: accessRoutes,\n    });\n\n    // 保存菜单信息和路由信息\n    accessStore.setAccessMenus(accessibleMenus);\n    accessStore.setAccessRoutes(accessibleRoutes);\n    accessStore.setIsAccessChecked(true);\n    const redirectPath = (from.query.redirect ??\n      (to.path === preferences.app.defaultHomePath\n        ? userInfo.homePath || preferences.app.defaultHomePath\n        : to.fullPath)) as string;\n\n    return {\n      ...router.resolve(decodeURIComponent(redirectPath)),\n      replace: true,\n    };\n  });\n}\n\n/**\n * 项目守卫配置\n * @param router\n */\nfunction createRouterGuard(router: Router) {\n  /** 通用 */\n  setupCommonGuard(router);\n  /** 权限访问 */\n  setupAccessGuard(router);\n}\n\nexport { createRouterGuard };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/router/index.ts",
    "content": "import {\n  createRouter,\n  createWebHashHistory,\n  createWebHistory,\n} from 'vue-router';\n\nimport { resetStaticRoutes } from '@vben/utils';\n\nimport { createRouterGuard } from './guard';\nimport { routes } from './routes';\n\n/**\n *  @zh_CN 创建vue-router实例\n */\nconst router = createRouter({\n  history:\n    import.meta.env.VITE_ROUTER_HISTORY === 'hash'\n      ? createWebHashHistory(import.meta.env.VITE_BASE)\n      : createWebHistory(import.meta.env.VITE_BASE),\n  // 应该添加到路由的初始路由列表。\n  routes,\n  scrollBehavior: (to, _from, savedPosition) => {\n    if (savedPosition) {\n      return savedPosition;\n    }\n    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };\n  },\n  // 是否应该禁止尾部斜杠。\n  // strict: true,\n});\n\nconst resetRoutes = () => resetStaticRoutes(router, routes);\n\n// 创建路由守卫\ncreateRouterGuard(router);\n\nexport { resetRoutes, router };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/router/routes/core.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst BasicLayout = () => import('#/layouts/basic.vue');\nconst AuthPageLayout = () => import('#/layouts/auth.vue');\n/** 全局404页面 */\nconst fallbackNotFoundRoute: RouteRecordRaw = {\n  component: () => import('#/views/_core/fallback/not-found.vue'),\n  meta: {\n    hideInBreadcrumb: true,\n    hideInMenu: true,\n    hideInTab: true,\n    title: '404',\n  },\n  name: 'FallbackNotFound',\n  path: '/:path(.*)*',\n};\n\n/** 基本路由，这些路由是必须存在的 */\nconst coreRoutes: RouteRecordRaw[] = [\n  /**\n   * 根路由\n   * 使用基础布局，作为所有页面的父级容器，子级就不必配置BasicLayout。\n   * 此路由必须存在，且不应修改\n   */\n  {\n    component: BasicLayout,\n    meta: {\n      hideInBreadcrumb: true,\n      title: 'Root',\n    },\n    name: 'Root',\n    path: '/',\n    redirect: preferences.app.defaultHomePath,\n    children: [],\n  },\n  {\n    component: AuthPageLayout,\n    meta: {\n      hideInTab: true,\n      title: 'Authentication',\n    },\n    name: 'Authentication',\n    path: '/auth',\n    redirect: LOGIN_PATH,\n    children: [\n      {\n        name: 'Login',\n        path: 'login',\n        component: () => import('#/views/_core/authentication/login.vue'),\n        meta: {\n          title: $t('page.auth.login'),\n        },\n      },\n      {\n        name: 'CodeLogin',\n        path: 'code-login',\n        component: () => import('#/views/_core/authentication/code-login.vue'),\n        meta: {\n          title: $t('page.auth.codeLogin'),\n        },\n      },\n      {\n        name: 'QrCodeLogin',\n        path: 'qrcode-login',\n        component: () =>\n          import('#/views/_core/authentication/qrcode-login.vue'),\n        meta: {\n          title: $t('page.auth.qrcodeLogin'),\n        },\n      },\n      {\n        name: 'ForgetPassword',\n        path: 'forget-password',\n        component: () =>\n          import('#/views/_core/authentication/forget-password.vue'),\n        meta: {\n          title: $t('page.auth.forgetPassword'),\n        },\n      },\n      {\n        name: 'Register',\n        path: 'register',\n        component: () => import('#/views/_core/authentication/register.vue'),\n        meta: {\n          title: $t('page.auth.register'),\n        },\n      },\n    ],\n  },\n];\n\nexport { coreRoutes, fallbackNotFoundRoute };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/router/routes/index.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { mergeRouteModules, traverseTreeValues } from '@vben/utils';\n\nimport { coreRoutes, fallbackNotFoundRoute } from './core';\n\nconst dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {\n  eager: true,\n});\n\n// 有需要可以自行打开注释，并创建文件夹\n// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });\n// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });\n\n/** 动态路由 */\nconst dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);\n\n/** 外部路由列表，访问这些页面可以不需要Layout，可能用于内嵌在别的系统(不会显示在菜单中) */\n// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);\n// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);\nconst staticRoutes: RouteRecordRaw[] = [];\nconst externalRoutes: RouteRecordRaw[] = [];\n\n/** 路由列表，由基本路由、外部路由和404兜底路由组成\n *  无需走权限验证（会一直显示在菜单中） */\nconst routes: RouteRecordRaw[] = [\n  ...coreRoutes,\n  ...externalRoutes,\n  fallbackNotFoundRoute,\n];\n\n/** 基本路由列表，这些路由不需要进入权限拦截 */\nconst coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);\n\n/** 有权限校验的路由列表，包含动态路由和静态路由 */\nconst accessRoutes = [...dynamicRoutes, ...staticRoutes];\nexport { accessRoutes, coreRouteNames, routes };\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/router/routes/modules/dashboard.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'lucide:layout-dashboard',\n      order: -1,\n      title: $t('page.dashboard.title'),\n    },\n    name: 'Dashboard',\n    path: '/dashboard',\n    children: [\n      {\n        name: 'Analytics',\n        path: '/analytics',\n        component: () => import('#/views/dashboard/analytics/index.vue'),\n        meta: {\n          affixTab: true,\n          icon: 'lucide:area-chart',\n          title: $t('page.dashboard.analytics'),\n        },\n      },\n      {\n        name: 'Workspace',\n        path: '/workspace',\n        component: () => import('#/views/dashboard/workspace/index.vue'),\n        meta: {\n          icon: 'carbon:workspace',\n          title: $t('page.dashboard.workspace'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/router/routes/modules/demos.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'ic:baseline-view-in-ar',\n      keepAlive: true,\n      order: 1000,\n      title: $t('demos.title'),\n    },\n    name: 'Demos',\n    path: '/demos',\n    children: [\n      {\n        meta: {\n          title: $t('demos.naive'),\n        },\n        name: 'NaiveDemos',\n        path: '/demos/naive',\n        component: () => import('#/views/demos/naive/index.vue'),\n      },\n      {\n        meta: {\n          title: $t('demos.table'),\n        },\n        name: 'Table',\n        path: '/demos/table',\n        component: () => import('#/views/demos/table/index.vue'),\n      },\n      {\n        meta: {\n          title: $t('demos.form'),\n        },\n        name: 'Form',\n        path: '/demos/form',\n        component: () => import('#/views/demos/form/basic.vue'),\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/router/routes/modules/vben.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport {\n  VBEN_ANT_PREVIEW_URL,\n  VBEN_DOC_URL,\n  VBEN_ELE_PREVIEW_URL,\n  VBEN_GITHUB_URL,\n  VBEN_LOGO_URL,\n} from '@vben/constants';\nimport { SvgAntdvLogoIcon } from '@vben/icons';\n\nimport { IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      badgeType: 'dot',\n      icon: VBEN_LOGO_URL,\n      order: 9998,\n      title: $t('demos.vben.title'),\n    },\n    name: 'VbenProject',\n    path: '/vben-admin',\n    children: [\n      {\n        name: 'VbenDocument',\n        path: '/vben-admin/document',\n        component: IFrameView,\n        meta: {\n          icon: 'lucide:book-open-text',\n          link: VBEN_DOC_URL,\n          title: $t('demos.vben.document'),\n        },\n      },\n      {\n        name: 'VbenGithub',\n        path: '/vben-admin/github',\n        component: IFrameView,\n        meta: {\n          icon: 'mdi:github',\n          link: VBEN_GITHUB_URL,\n          title: 'Github',\n        },\n      },\n      {\n        name: 'VbenAntd',\n        path: '/vben-admin/antd',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: SvgAntdvLogoIcon,\n          link: VBEN_ANT_PREVIEW_URL,\n          title: $t('demos.vben.antdv'),\n        },\n      },\n      {\n        name: 'VbenElementPlus',\n        path: '/vben-admin/ele',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: 'logos:element',\n          link: VBEN_ELE_PREVIEW_URL,\n          title: $t('demos.vben.element-plus'),\n        },\n      },\n    ],\n  },\n  {\n    name: 'VbenAbout',\n    path: '/vben-admin/about',\n    component: () => import('#/views/_core/about/index.vue'),\n    meta: {\n      icon: 'lucide:copyright',\n      title: $t('demos.vben.about'),\n      order: 9999,\n    },\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/store/auth.ts",
    "content": "import type { Recordable, UserInfo } from '@vben/types';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';\n\nimport { defineStore } from 'pinia';\n\nimport { notification } from '#/adapter/naive';\nimport { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';\nimport { $t } from '#/locales';\n\nexport const useAuthStore = defineStore('auth', () => {\n  const accessStore = useAccessStore();\n  const userStore = useUserStore();\n  const router = useRouter();\n\n  const loginLoading = ref(false);\n\n  /**\n   * 异步处理登录操作\n   * Asynchronously handle the login process\n   * @param params 登录表单数据\n   */\n  async function authLogin(\n    params: Recordable<any>,\n    onSuccess?: () => Promise<void> | void,\n  ) {\n    // 异步处理用户登录操作并获取 accessToken\n    let userInfo: null | UserInfo = null;\n    try {\n      loginLoading.value = true;\n      const { accessToken } = await loginApi(params);\n\n      // 如果成功获取到 accessToken\n      if (accessToken) {\n        // 将 accessToken 存储到 accessStore 中\n        accessStore.setAccessToken(accessToken);\n\n        // 获取用户信息并存储到 accessStore 中\n        const [fetchUserInfoResult, accessCodes] = await Promise.all([\n          fetchUserInfo(),\n          getAccessCodesApi(),\n        ]);\n\n        userInfo = fetchUserInfoResult;\n\n        userStore.setUserInfo(userInfo);\n        accessStore.setAccessCodes(accessCodes);\n\n        if (accessStore.loginExpired) {\n          accessStore.setLoginExpired(false);\n        } else {\n          onSuccess\n            ? await onSuccess?.()\n            : await router.push(\n                userInfo.homePath || preferences.app.defaultHomePath,\n              );\n        }\n\n        if (userInfo?.realName) {\n          notification.success({\n            content: $t('authentication.loginSuccess'),\n            description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,\n            duration: 3000,\n          });\n        }\n      }\n    } finally {\n      loginLoading.value = false;\n    }\n\n    return {\n      userInfo,\n    };\n  }\n\n  async function logout(redirect: boolean = true) {\n    try {\n      await logoutApi();\n    } catch {\n      // 不做任何处理\n    }\n    resetAllStores();\n    accessStore.setLoginExpired(false);\n\n    // 回登录页带上当前路由地址\n    await router.replace({\n      path: LOGIN_PATH,\n      query: redirect\n        ? {\n            redirect: encodeURIComponent(router.currentRoute.value.fullPath),\n          }\n        : {},\n    });\n  }\n\n  async function fetchUserInfo() {\n    let userInfo: null | UserInfo = null;\n    userInfo = await getUserInfoApi();\n    userStore.setUserInfo(userInfo);\n    return userInfo;\n  }\n\n  function $reset() {\n    loginLoading.value = false;\n  }\n\n  return {\n    $reset,\n    authLogin,\n    fetchUserInfo,\n    loginLoading,\n    logout,\n  };\n});\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/store/index.ts",
    "content": "export * from './auth';\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/README.md",
    "content": "# \\_core\n\n此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/about/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { About } from '@vben/common-ui';\n\ndefineOptions({ name: 'About' });\n</script>\n\n<template>\n  <About />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/authentication/code-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, ref } from 'vue';\n\nimport { AuthenticationCodeLogin, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'CodeLogin' });\n\nconst loading = ref(false);\nconst CODE_LENGTH = 6;\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.mobile'),\n      },\n      fieldName: 'phoneNumber',\n      label: $t('authentication.mobile'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.mobileTip') })\n        .refine((v) => /^\\d{11}$/.test(v), {\n          message: $t('authentication.mobileErrortip'),\n        }),\n    },\n    {\n      component: 'VbenPinInput',\n      componentProps: {\n        codeLength: CODE_LENGTH,\n        createText: (countdown: number) => {\n          const text =\n            countdown > 0\n              ? $t('authentication.sendText', [countdown])\n              : $t('authentication.sendCode');\n          return text;\n        },\n        placeholder: $t('authentication.code'),\n      },\n      fieldName: 'code',\n      label: $t('authentication.code'),\n      rules: z.string().length(CODE_LENGTH, {\n        message: $t('authentication.codeTip', [CODE_LENGTH]),\n      }),\n    },\n  ];\n});\n/**\n * 异步处理登录操作\n * Asynchronously handle the login process\n * @param values 登录表单数据\n */\nasync function handleLogin(values: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log(values);\n}\n</script>\n\n<template>\n  <AuthenticationCodeLogin\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/authentication/forget-password.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, ref } from 'vue';\n\nimport { AuthenticationForgetPassword, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'ForgetPassword' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: 'example@example.com',\n      },\n      fieldName: 'email',\n      label: $t('authentication.email'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.emailTip') })\n        .email($t('authentication.emailValidErrorTip')),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log('reset email:', value);\n}\n</script>\n\n<template>\n  <AuthenticationForgetPassword\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/authentication/login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { BasicOption } from '@vben/types';\n\nimport { computed, markRaw } from 'vue';\n\nimport { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { useAuthStore } from '#/store';\n\ndefineOptions({ name: 'Login' });\n\nconst authStore = useAuthStore();\n\nconst MOCK_USER_OPTIONS: BasicOption[] = [\n  {\n    label: 'Super',\n    value: 'vben',\n  },\n  {\n    label: 'Admin',\n    value: 'admin',\n  },\n  {\n    label: 'User',\n    value: 'jack',\n  },\n];\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenSelect',\n      componentProps: {\n        options: MOCK_USER_OPTIONS,\n        placeholder: $t('authentication.selectAccount'),\n      },\n      fieldName: 'selectAccount',\n      label: $t('authentication.selectAccount'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.selectAccount') })\n        .optional()\n        .default('vben'),\n    },\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.usernameTip'),\n      },\n      dependencies: {\n        trigger(values, form) {\n          if (values.selectAccount) {\n            const findUser = MOCK_USER_OPTIONS.find(\n              (item) => item.value === values.selectAccount,\n            );\n            if (findUser) {\n              form.setValues({\n                password: '123456',\n                username: findUser.value,\n              });\n            }\n          }\n        },\n        triggerFields: ['selectAccount'],\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: markRaw(SliderCaptcha),\n      fieldName: 'captcha',\n      rules: z.boolean().refine((value) => value, {\n        message: $t('authentication.verifyRequiredTip'),\n      }),\n    },\n  ];\n});\n</script>\n\n<template>\n  <AuthenticationLogin\n    :form-schema=\"formSchema\"\n    :loading=\"authStore.loginLoading\"\n    @submit=\"authStore.authLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/authentication/qrcode-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport { AuthenticationQrCodeLogin } from '@vben/common-ui';\nimport { LOGIN_PATH } from '@vben/constants';\n\ndefineOptions({ name: 'QrCodeLogin' });\n</script>\n\n<template>\n  <AuthenticationQrCodeLogin :login-path=\"LOGIN_PATH\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/authentication/register.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, h, ref } from 'vue';\n\nimport { AuthenticationRegister, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'Register' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.usernameTip'),\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        passwordStrength: true,\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      renderComponentContent() {\n        return {\n          strengthText: () => $t('authentication.passwordStrength'),\n        };\n      },\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.confirmPassword'),\n      },\n      dependencies: {\n        rules(values) {\n          const { password } = values;\n          return z\n            .string({ required_error: $t('authentication.passwordTip') })\n            .min(1, { message: $t('authentication.passwordTip') })\n            .refine((value) => value === password, {\n              message: $t('authentication.confirmPasswordTip'),\n            });\n        },\n        triggerFields: ['password'],\n      },\n      fieldName: 'confirmPassword',\n      label: $t('authentication.confirmPassword'),\n    },\n    {\n      component: 'VbenCheckbox',\n      fieldName: 'agreePolicy',\n      renderComponentContent: () => ({\n        default: () =>\n          h('span', [\n            $t('authentication.agree'),\n            h(\n              'a',\n              {\n                class: 'vben-link ml-1',\n                href: '',\n              },\n              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,\n            ),\n          ]),\n      }),\n      rules: z.boolean().refine((value) => !!value, {\n        message: $t('authentication.agreeTip'),\n      }),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log('register submit:', value);\n}\n</script>\n\n<template>\n  <AuthenticationRegister\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/fallback/coming-soon.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/fallback/forbidden.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback403Demo' });\n</script>\n\n<template>\n  <Fallback status=\"403\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/fallback/internal-error.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback500Demo' });\n</script>\n\n<template>\n  <Fallback status=\"500\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/fallback/not-found.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback404Demo' });\n</script>\n\n<template>\n  <Fallback status=\"404\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/_core/fallback/offline.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'FallbackOfflineDemo' });\n</script>\n\n<template>\n  <Fallback status=\"offline\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        areaStyle: {},\n        data: [\n          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,\n          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,\n          111,\n        ],\n        itemStyle: {\n          color: '#5ab1ef',\n        },\n        smooth: true,\n        type: 'line',\n      },\n      {\n        areaStyle: {},\n        data: [\n          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,\n          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,\n        ],\n        itemStyle: {\n          color: '#019680',\n        },\n        smooth: true,\n        type: 'line',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          color: '#019680',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    // xAxis: {\n    //   axisTick: {\n    //     show: false,\n    //   },\n    //   boundaryGap: false,\n    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n    //   type: 'category',\n    // },\n    xAxis: {\n      axisTick: {\n        show: false,\n      },\n      boundaryGap: false,\n      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n      splitLine: {\n        lineStyle: {\n          type: 'solid',\n          width: 1,\n        },\n        show: true,\n      },\n      type: 'category',\n    },\n    yAxis: [\n      {\n        axisTick: {\n          show: false,\n        },\n        max: 80_000,\n        splitArea: {\n          show: true,\n        },\n        splitNumber: 4,\n        type: 'value',\n      },\n    ],\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: 0,\n      data: ['访问', '趋势'],\n    },\n    radar: {\n      indicator: [\n        {\n          name: '网页',\n        },\n        {\n          name: '移动端',\n        },\n        {\n          name: 'Ipad',\n        },\n        {\n          name: '客户端',\n        },\n        {\n          name: '第三方',\n        },\n        {\n          name: '其它',\n        },\n      ],\n      radius: '60%',\n      splitNumber: 8,\n    },\n    series: [\n      {\n        areaStyle: {\n          opacity: 1,\n          shadowBlur: 0,\n          shadowColor: 'rgba(0,0,0,.2)',\n          shadowOffsetX: 0,\n          shadowOffsetY: 10,\n        },\n        data: [\n          {\n            itemStyle: {\n              color: '#b6a2de',\n            },\n            name: '访问',\n            value: [90, 50, 86, 40, 50, 20],\n          },\n          {\n            itemStyle: {\n              color: '#5ab1ef',\n            },\n            name: '趋势',\n            value: [70, 75, 70, 76, 20, 85],\n          },\n        ],\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        symbolSize: 0,\n        type: 'radar',\n      },\n    ],\n    tooltip: {},\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 400;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        center: ['50%', '50%'],\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '外包', value: 500 },\n          { name: '定制', value: 310 },\n          { name: '技术支持', value: 274 },\n          { name: '远程', value: 400 },\n        ].sort((a, b) => {\n          return a.value - b.value;\n        }),\n        name: '商业占比',\n        radius: '80%',\n        roseType: 'radius',\n        type: 'pie',\n      },\n    ],\n\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: '2%',\n      left: 'center',\n    },\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 100;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        avoidLabelOverlap: false,\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '搜索引擎', value: 1048 },\n          { name: '直接访问', value: 735 },\n          { name: '邮件营销', value: 580 },\n          { name: '联盟广告', value: 484 },\n        ],\n        emphasis: {\n          label: {\n            fontSize: '12',\n            fontWeight: 'bold',\n            show: true,\n          },\n        },\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        label: {\n          position: 'center',\n          show: false,\n        },\n        labelLine: {\n          show: false,\n        },\n        name: '访问来源',\n        radius: ['40%', '65%'],\n        type: 'pie',\n      },\n    ],\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        barMaxWidth: 80,\n        // color: '#4f69fd',\n        data: [\n          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,\n          3200, 4800,\n        ],\n        type: 'bar',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          // color: '#4f69fd',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    xAxis: {\n      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}月`),\n      type: 'category',\n    },\n    yAxis: {\n      max: 8000,\n      splitNumber: 4,\n      type: 'value',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/dashboard/analytics/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { AnalysisOverviewItem } from '@vben/common-ui';\nimport type { TabOption } from '@vben/types';\n\nimport {\n  AnalysisChartCard,\n  AnalysisChartsTabs,\n  AnalysisOverview,\n} from '@vben/common-ui';\nimport {\n  SvgBellIcon,\n  SvgCakeIcon,\n  SvgCardIcon,\n  SvgDownloadIcon,\n} from '@vben/icons';\n\nimport AnalyticsTrends from './analytics-trends.vue';\nimport AnalyticsVisitsData from './analytics-visits-data.vue';\nimport AnalyticsVisitsSales from './analytics-visits-sales.vue';\nimport AnalyticsVisitsSource from './analytics-visits-source.vue';\nimport AnalyticsVisits from './analytics-visits.vue';\n\nconst overviewItems: AnalysisOverviewItem[] = [\n  {\n    icon: SvgCardIcon,\n    title: '用户量',\n    totalTitle: '总用户量',\n    totalValue: 120_000,\n    value: 2000,\n  },\n  {\n    icon: SvgCakeIcon,\n    title: '访问量',\n    totalTitle: '总访问量',\n    totalValue: 500_000,\n    value: 20_000,\n  },\n  {\n    icon: SvgDownloadIcon,\n    title: '下载量',\n    totalTitle: '总下载量',\n    totalValue: 120_000,\n    value: 8000,\n  },\n  {\n    icon: SvgBellIcon,\n    title: '使用量',\n    totalTitle: '总使用量',\n    totalValue: 50_000,\n    value: 5000,\n  },\n];\n\nconst chartTabs: TabOption[] = [\n  {\n    label: '流量趋势',\n    value: 'trends',\n  },\n  {\n    label: '月访问量',\n    value: 'visits',\n  },\n];\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <AnalysisOverview :items=\"overviewItems\" />\n    <AnalysisChartsTabs :tabs=\"chartTabs\" class=\"mt-5\">\n      <template #trends>\n        <AnalyticsTrends />\n      </template>\n      <template #visits>\n        <AnalyticsVisits />\n      </template>\n    </AnalysisChartsTabs>\n\n    <div class=\"mt-5 w-full md:flex\">\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问数量\">\n        <AnalyticsVisitsData />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSource />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSales />\n      </AnalysisChartCard>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/dashboard/workspace/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  WorkbenchProjectItem,\n  WorkbenchQuickNavItem,\n  WorkbenchTodoItem,\n  WorkbenchTrendItem,\n} from '@vben/common-ui';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport {\n  AnalysisChartCard,\n  WorkbenchHeader,\n  WorkbenchProject,\n  WorkbenchQuickNav,\n  WorkbenchTodo,\n  WorkbenchTrends,\n} from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';\n\nconst userStore = useUserStore();\n\n// 这是一个示例数据，实际项目中需要根据实际情况进行调整\n// url 也可以是内部路由，在 navTo 方法中识别处理，进行内部跳转\n// 例如：url: /dashboard/workspace\nconst projectItems: WorkbenchProjectItem[] = [\n  {\n    color: '',\n    content: '不要等待机会，而要创造机会。',\n    date: '2021-04-01',\n    group: '开源组',\n    icon: 'carbon:logo-github',\n    title: 'Github',\n    url: 'https://github.com',\n  },\n  {\n    color: '#3fb27f',\n    content: '现在的你决定将来的你。',\n    date: '2021-04-01',\n    group: '算法组',\n    icon: 'ion:logo-vue',\n    title: 'Vue',\n    url: 'https://vuejs.org',\n  },\n  {\n    color: '#e18525',\n    content: '没有什么才能比努力更重要。',\n    date: '2021-04-01',\n    group: '上班摸鱼',\n    icon: 'ion:logo-html5',\n    title: 'Html5',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',\n  },\n  {\n    color: '#bf0c2c',\n    content: '热情和欲望可以突破一切难关。',\n    date: '2021-04-01',\n    group: 'UI',\n    icon: 'ion:logo-angular',\n    title: 'Angular',\n    url: 'https://angular.io',\n  },\n  {\n    color: '#00d8ff',\n    content: '健康的身体是实现目标的基石。',\n    date: '2021-04-01',\n    group: '技术牛',\n    icon: 'bx:bxl-react',\n    title: 'React',\n    url: 'https://reactjs.org',\n  },\n  {\n    color: '#EBD94E',\n    content: '路是走出来的，而不是空想出来的。',\n    date: '2021-04-01',\n    group: '架构组',\n    icon: 'ion:logo-javascript',\n    title: 'Js',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',\n  },\n];\n\n// 同样，这里的 url 也可以使用以 http 开头的外部链接\nconst quickNavItems: WorkbenchQuickNavItem[] = [\n  {\n    color: '#1fdaca',\n    icon: 'ion:home-outline',\n    title: '首页',\n    url: '/',\n  },\n  {\n    color: '#bf0c2c',\n    icon: 'ion:grid-outline',\n    title: '仪表盘',\n    url: '/dashboard',\n  },\n  {\n    color: '#e18525',\n    icon: 'ion:layers-outline',\n    title: '组件',\n    url: '/demos/features/icons',\n  },\n  {\n    color: '#3fb27f',\n    icon: 'ion:settings-outline',\n    title: '系统管理',\n    url: '/demos/features/login-expired', // 这里的 URL 是示例，实际项目中需要根据实际情况进行调整\n  },\n  {\n    color: '#4daf1bc9',\n    icon: 'ion:key-outline',\n    title: '权限管理',\n    url: '/demos/access/page-control',\n  },\n  {\n    color: '#00d8ff',\n    icon: 'ion:bar-chart-outline',\n    title: '图表',\n    url: '/analytics',\n  },\n];\n\nconst todoItems = ref<WorkbenchTodoItem[]>([\n  {\n    completed: false,\n    content: `审查最近提交到Git仓库的前端代码，确保代码质量和规范。`,\n    date: '2024-07-30 11:00:00',\n    title: '审查前端代码提交',\n  },\n  {\n    completed: true,\n    content: `检查并优化系统性能，降低CPU使用率。`,\n    date: '2024-07-30 11:00:00',\n    title: '系统性能优化',\n  },\n  {\n    completed: false,\n    content: `进行系统安全检查，确保没有安全漏洞或未授权的访问。 `,\n    date: '2024-07-30 11:00:00',\n    title: '安全检查',\n  },\n  {\n    completed: false,\n    content: `更新项目中的所有npm依赖包，确保使用最新版本。`,\n    date: '2024-07-30 11:00:00',\n    title: '更新项目依赖',\n  },\n  {\n    completed: false,\n    content: `修复用户报告的页面UI显示问题，确保在不同浏览器中显示一致。 `,\n    date: '2024-07-30 11:00:00',\n    title: '修复UI显示问题',\n  },\n]);\nconst trendItems: WorkbenchTrendItem[] = [\n  {\n    avatar: 'svg:avatar-1',\n    content: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,\n    date: '刚刚',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关注了 <a>威廉</a> `,\n    date: '1个小时前',\n    title: '艾文',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1天前',\n    title: '克里斯',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写一个Vite插件</a> `,\n    date: '2天前',\n    title: 'Vben',\n  },\n  {\n    avatar: 'svg:avatar-1',\n    content: `回复了 <a>杰克</a> 的问题 <a>如何进行项目优化？</a>`,\n    date: '3天前',\n    title: '皮特',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关闭了问题 <a>如何运行项目</a> `,\n    date: '1周前',\n    title: '杰克',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1周前',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `推送了代码到 <a>Github</a>`,\n    date: '2021-04-01 20:00',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写使用 Admin Vben</a> `,\n    date: '2021-03-01 20:00',\n    title: 'Vben',\n  },\n];\n\nconst router = useRouter();\n\n// 这是一个示例方法，实际项目中需要根据实际情况进行调整\n// This is a sample method, adjust according to the actual project requirements\nfunction navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {\n  if (nav.url?.startsWith('http')) {\n    openWindow(nav.url);\n    return;\n  }\n  if (nav.url?.startsWith('/')) {\n    router.push(nav.url).catch((error) => {\n      console.error('Navigation failed:', error);\n    });\n  } else {\n    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);\n  }\n}\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <WorkbenchHeader\n      :avatar=\"userStore.userInfo?.avatar || preferences.app.defaultAvatar\"\n    >\n      <template #title>\n        早安, {{ userStore.userInfo?.realName }}, 开始您一天的工作吧！\n      </template>\n      <template #description> 今日晴，20℃ - 32℃！ </template>\n    </WorkbenchHeader>\n\n    <div class=\"mt-5 flex flex-col lg:flex-row\">\n      <div class=\"mr-4 w-full lg:w-3/5\">\n        <WorkbenchProject :items=\"projectItems\" title=\"项目\" @click=\"navTo\" />\n        <WorkbenchTrends :items=\"trendItems\" class=\"mt-5\" title=\"最新动态\" />\n      </div>\n      <div class=\"w-full lg:w-2/5\">\n        <WorkbenchQuickNav\n          :items=\"quickNavItems\"\n          class=\"mt-5 lg:mt-0\"\n          title=\"快捷导航\"\n          @click=\"navTo\"\n        />\n        <WorkbenchTodo :items=\"todoItems\" class=\"mt-5\" title=\"待办事项\" />\n        <AnalysisChartCard class=\"mt-5\" title=\"访问来源\">\n          <AnalyticsVisitsSource />\n        </AnalysisChartCard>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/demos/form/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Page, useVbenModal } from '@vben/common-ui';\n\nimport { NButton, NCard, useMessage } from 'naive-ui';\n\nimport { useVbenForm } from '#/adapter/form';\nimport { getAllMenusApi } from '#/api';\n\nimport modalDemo from './modal.vue';\n\nconst message = useMessage();\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  layout: 'horizontal',\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n  handleSubmit: (values) => {\n    message.success(`表单数据：${JSON.stringify(values)}`);\n  },\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'ApiSelect',\n      // 对应组件的参数\n      componentProps: {\n        // 菜单接口转options格式\n        afterFetch: (data: { name: string; path: string }[]) => {\n          return data.map((item: any) => ({\n            label: item.name,\n            value: item.path,\n          }));\n        },\n        // 菜单接口\n        api: getAllMenusApi,\n      },\n      // 字段名\n      fieldName: 'api',\n      // 界面显示的label\n      label: 'ApiSelect',\n      rules: 'required',\n    },\n    {\n      component: 'ApiTreeSelect',\n      // 对应组件的参数\n      componentProps: {\n        // 菜单接口\n        api: getAllMenusApi,\n        childrenField: 'children',\n        // 菜单接口转options格式\n        labelField: 'name',\n        valueField: 'path',\n      },\n      // 字段名\n      fieldName: 'apiTree',\n      // 界面显示的label\n      label: 'ApiTreeSelect',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      fieldName: 'string',\n      label: 'String',\n      rules: 'required',\n    },\n    {\n      component: 'InputNumber',\n      fieldName: 'number',\n      label: 'Number',\n      rules: 'required',\n    },\n    {\n      component: 'RadioGroup',\n      fieldName: 'radio',\n      label: 'Radio',\n      componentProps: {\n        options: [\n          { value: 'A', label: 'A' },\n          { value: 'B', label: 'B' },\n          { value: 'C', label: 'C' },\n          { value: 'D', label: 'D' },\n          { value: 'E', label: 'E' },\n        ],\n      },\n      rules: 'selectRequired',\n    },\n    {\n      component: 'RadioGroup',\n      fieldName: 'radioButton',\n      label: 'RadioButton',\n      componentProps: {\n        isButton: true,\n        class: 'flex flex-wrap', // 如果选项过多，可以添加class来自动折叠\n        options: [\n          { value: 'A', label: '选项A' },\n          { value: 'B', label: '选项B' },\n          { value: 'C', label: '选项C' },\n          { value: 'D', label: '选项D' },\n          { value: 'E', label: '选项E' },\n        ],\n      },\n      rules: 'selectRequired',\n    },\n    {\n      component: 'CheckboxGroup',\n      fieldName: 'checkbox',\n      label: 'Checkbox',\n      componentProps: {\n        options: [\n          { value: 'A', label: '选项A' },\n          { value: 'B', label: '选项B' },\n          { value: 'C', label: '选项C' },\n        ],\n      },\n      rules: 'selectRequired',\n    },\n    {\n      component: 'DatePicker',\n      fieldName: 'date',\n      label: 'Date',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      fieldName: 'textArea',\n      label: 'TextArea',\n      componentProps: {\n        type: 'textarea',\n      },\n      rules: 'required',\n    },\n  ],\n});\nfunction setFormValues() {\n  formApi.setValues({\n    string: 'string',\n    number: 123,\n    radio: 'B',\n    radioButton: 'C',\n    checkbox: ['A', 'C'],\n    date: Date.now(),\n  });\n}\n\nconst [Modal, modalApi] = useVbenModal({\n  connectedComponent: modalDemo,\n});\n</script>\n<template>\n  <Page\n    description=\"表单适配器重新包装了CheckboxGroup和RadioGroup，可以通过options属性传递选项数据（选项数据将作为子组件的属性）\"\n    title=\"表单演示\"\n  >\n    <NCard title=\"基础表单\">\n      <template #header-extra>\n        <NButton type=\"primary\" @click=\"setFormValues\">设置表单值</NButton>\n        <NButton type=\"primary\" @click=\"modalApi.open()\" class=\"ml-2\">\n          打开弹窗\n        </NButton>\n      </template>\n      <Form />\n    </NCard>\n    <Modal />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/demos/form/modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { useVbenForm } from '#/adapter/form';\n\ndefineOptions({\n  name: 'FormModelDemo',\n});\n\nconst [Form, formApi] = useVbenForm({\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field1',\n      label: '字段1',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field2',\n      label: '字段2',\n      rules: 'required',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: [\n          { label: '选项1', value: '1' },\n          { label: '选项2', value: '2' },\n        ],\n        placeholder: '请输入',\n      },\n      fieldName: 'field3',\n      label: '字段3',\n      rules: 'required',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Modal, modalApi] = useVbenModal({\n  fullscreenButton: false,\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.validateAndSubmitForm();\n    // modalApi.close();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      const { values } = modalApi.getData<Record<string, any>>();\n      if (values) {\n        formApi.setValues(values);\n      }\n    }\n  },\n  title: '内嵌表单示例',\n});\n</script>\n<template>\n  <Modal>\n    <Form />\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/demos/naive/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { NotificationType } from 'naive-ui';\n\nimport { Page } from '@vben/common-ui';\n\nimport { NButton, NCard, NSpace, useMessage, useNotification } from 'naive-ui';\n\nconst notification = useNotification();\n\nconst message = useMessage();\nfunction error() {\n  message.error('Once upon a time you dressed so fine');\n}\n\nfunction warning() {\n  message.warning('How many roads must a man walk down');\n}\nfunction success() {\n  message.success('Cause you walked hand in hand With another man in my place');\n}\nfunction loading() {\n  message.loading(\n    'If I were you, I will realize that I love you more than any other guy',\n  );\n}\n\nfunction notify(type: NotificationType) {\n  notification[type]({\n    content: '说点啥呢',\n    duration: 2500,\n    keepAliveOnHover: true,\n    meta: '想不出来',\n  });\n}\n</script>\n\n<template>\n  <Page description=\"支持多语言，主题功能集成切换等\" title=\"naive组件使用演示\">\n    <NCard class=\"mb-5\" title=\"按钮\">\n      <NSpace>\n        <NButton>Default</NButton>\n        <NButton type=\"tertiary\"> Tertiary </NButton>\n        <NButton type=\"primary\"> Primary </NButton>\n        <NButton type=\"info\"> Info </NButton>\n        <NButton type=\"success\"> Success </NButton>\n        <NButton type=\"warning\"> Warning </NButton>\n        <NButton type=\"error\"> Error </NButton>\n      </NSpace>\n    </NCard>\n\n    <NCard class=\"mb-5\" title=\"Message\">\n      <NSpace>\n        <NButton type=\"error\" @click=\"error\"> 错误 </NButton>\n        <NButton type=\"warning\" @click=\"warning\"> 警告 </NButton>\n        <NButton type=\"success\" @click=\"success\"> 成功 </NButton>\n        <NButton type=\"primary\" @click=\"loading\"> 加载中 </NButton>\n      </NSpace>\n    </NCard>\n\n    <NCard class=\"mb-5\" title=\"Notification\">\n      <NSpace>\n        <NButton type=\"error\" @click=\"notify('error')\"> 错误 </NButton>\n        <NButton type=\"warning\" @click=\"notify('warning')\"> 警告 </NButton>\n        <NButton type=\"success\" @click=\"notify('success')\"> 成功 </NButton>\n        <NButton type=\"primary\" @click=\"notify('info')\"> 加载中 </NButton>\n      </NSpace>\n    </NCard>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/src/views/demos/table/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { NDataTable } from 'naive-ui';\n\nconst columns = ref([\n  {\n    key: 'no',\n    title: 'No',\n  },\n  {\n    key: 'title',\n    title: 'Title',\n  },\n  {\n    key: 'length',\n    title: 'Length',\n  },\n]);\nconst data = [\n  { length: '4:18', no: 3, title: 'Wonderwall' },\n  { length: '4:48', no: 4, title: \"Don't Look Back in Anger\" },\n  { length: '7:27', no: 12, title: 'Champagne Supernova' },\n];\n</script>\n\n<template>\n  <Page\n    description=\"表单页用于向用户收集或验证信息，基础表单常见于数据项较少的表单场景。\"\n    title=\"NDataTable\"\n  >\n    <NDataTable :columns=\"columns\" :data=\"data\" />\n  </Page>\n</template>\n\n<style scoped></style>\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web-app.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"#/*\": [\"./src/*\"]\n    }\n  },\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }],\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/tsconfig.node.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n    \"noEmit\": false\n  },\n  \"include\": [\"vite.config.mts\"]\n}\n"
  },
  {
    "path": "hiauth-front/apps/web-naive/vite.config.mts",
    "content": "import { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    application: {},\n    vite: {\n      server: {\n        proxy: {\n          '/api': {\n            changeOrigin: true,\n            rewrite: (path) => path.replace(/^\\/api/, ''),\n            // mock代理目标地址\n            target: 'http://localhost:5320/api',\n            ws: true,\n          },\n        },\n      },\n    },\n  };\n});\n"
  },
  {
    "path": "hiauth-front/changlist.txt",
    "content": "本目录，除了如下内容，其他全部删除：\n1、changlist.txt；\n2、deploy.yaml；\n3、Dockerfile；\n4、apps；（单独处理）\n\n官方源码，剔除的内容：\n1、.git目录；\n2、.github目录；\n3、.idea目录；\n4、apps目录；（单独处理）\n\n需要手动合并的\n1、./package.json\n  - \"build:auth\": \"pnpm run build --filter=@vben/web-auth\"\n  - \"dev:auth\": \"pnpm -F @vben/web-auth run dev\",\n2、./vben-admin.code-workspace\n  - 添加 web-auth\n3、./apps/web-auth/package.json\n  - \"jsencrypt\": \"^3.3.2\"\n"
  },
  {
    "path": "hiauth-front/cspell.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json\",\n  \"version\": \"0.2\",\n  \"language\": \"en,en-US\",\n  \"allowCompoundWords\": true,\n  \"words\": [\n    \"acmr\",\n    \"antd\",\n    \"antdv\",\n    \"astro\",\n    \"brotli\",\n    \"clsx\",\n    \"defu\",\n    \"demi\",\n    \"echarts\",\n    \"ependencies\",\n    \"esno\",\n    \"etag\",\n    \"execa\",\n    \"iconify\",\n    \"iconoir\",\n    \"intlify\",\n    \"lockb\",\n    \"lucide\",\n    \"minh\",\n    \"minw\",\n    \"mkdist\",\n    \"mockjs\",\n    \"naiveui\",\n    \"nocheck\",\n    \"noopener\",\n    \"noreferrer\",\n    \"nprogress\",\n    \"nuxt\",\n    \"pinia\",\n    \"prefixs\",\n    \"publint\",\n    \"qrcode\",\n    \"shadcn\",\n    \"sonner\",\n    \"sortablejs\",\n    \"styl\",\n    \"taze\",\n    \"ui-kit\",\n    \"uicons\",\n    \"unplugin\",\n    \"unref\",\n    \"vben\",\n    \"vbenjs\",\n    \"vite\",\n    \"vitejs\",\n    \"vitepress\",\n    \"vnode\",\n    \"vueuse\",\n    \"yxxx\"\n  ],\n  \"ignorePaths\": [\n    \"**/node_modules/**\",\n    \"**/dist/**\",\n    \"**/*-dist/**\",\n    \"**/icons/**\",\n    \"pnpm-lock.yaml\",\n    \"**/*.log\",\n    \"**/*.test.ts\",\n    \"**/*.spec.ts\",\n    \"**/__tests__/**\"\n  ]\n}\n"
  },
  {
    "path": "hiauth-front/deploy.yaml",
    "content": "kind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ingress\n  namespace: $NAMESPACE\nspec:\n  selector:\n    matchLabels:\n      app: ingress\n  replicas: $APP_REPLICAS\n  template:\n    metadata:\n      labels:\n        app: ingress\n    spec:\n      imagePullSecrets:\n        - name: harborsecret\n      containers:\n        - name: ingress\n          image: $IMAGE_NAME\n          imagePullPolicy: 'Always'\n          ports:\n            - containerPort: 80\n            - containerPort: 443\n          resources:\n            requests:\n              memory: 1Gi\n              cpu: 1\n            limits:\n              memory: 2Gi\n              cpu: 2\n          volumeMounts:\n            - name: nginx-config\n              mountPath: /etc/nginx/\n          lifecycle:\n            postStart:\n              exec:\n                command:\n                  [\n                    '/bin/sh',\n                    '-c',\n                    'cp -rf /etc/nginx/..data/nginx.conf /usr/local/nginx/conf/ && /usr/local/nginx/sbin/nginx -s reload',\n                  ]\n            preStop:\n              exec:\n                command:\n                  - sh\n                  - '-c'\n                  - sleep 5 && kill -SIGQUIT 1\n      volumes:\n        - name: nginx-config\n          configMap:\n            name: ingress.conf\n\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: ingress-svc\n  namespace: platform\nspec:\n  ports:\n    - name: http\n      nodePort: 30280\n      port: 80\n      protocol: TCP\n      targetPort: 80\n  selector:\n    app: ingress\n  type: LoadBalancer\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/components/demo-preview.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\nimport PreviewGroup from './preview-group.vue';\n\ninterface Props {\n  files?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), { files: '() => []' });\n\nconst parsedFiles = computed(() => {\n  try {\n    return JSON.parse(decodeURIComponent(props.files ?? ''));\n  } catch {\n    return [];\n  }\n});\n</script>\n\n<template>\n  <div class=\"border-border shadow-float relative rounded-xl border\">\n    <div\n      class=\"not-prose relative w-full overflow-x-auto rounded-t-lg px-4 py-6\"\n    >\n      <div class=\"flex w-full max-w-[700px] px-2\">\n        <ClientOnly>\n          <slot v-if=\"parsedFiles.length > 0\"></slot>\n          <div v-else class=\"text-destructive text-sm\">\n            <span class=\"bg-destructive text-foreground rounded-sm px-1 py-1\">\n              ERROR:\n            </span>\n            The preview directory does not exist. Please check the 'dir'\n            parameter.\n          </div>\n        </ClientOnly>\n      </div>\n    </div>\n    <PreviewGroup v-if=\"parsedFiles.length > 0\" :files=\"parsedFiles\">\n      <template v-for=\"file in parsedFiles\" #[file]>\n        <slot :name=\"file\"></slot>\n      </template>\n    </PreviewGroup>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/components/index.ts",
    "content": "export { default as DemoPreview } from './demo-preview.vue';\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/components/preview-group.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SetupContext } from 'vue';\n\nimport { computed, ref, useSlots } from 'vue';\n\nimport { VbenTooltip } from '@vben-core/shadcn-ui';\n\nimport { Code } from 'lucide-vue-next';\nimport {\n  TabsContent,\n  TabsIndicator,\n  TabsList,\n  TabsRoot,\n  TabsTrigger,\n} from 'radix-vue';\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\nconst props = withDefaults(\n  defineProps<{\n    files?: string[];\n  }>(),\n  { files: () => [] },\n);\n\nconst open = ref(false);\n\nconst slots: SetupContext['slots'] = useSlots();\n\nconst tabs = computed(() => {\n  return props.files.map((file) => {\n    return {\n      component: slots[file],\n      label: file,\n    };\n  });\n});\n\nconst currentTab = ref('index.vue');\n\nconst toggleOpen = () => {\n  open.value = !open.value;\n};\n</script>\n\n<template>\n  <TabsRoot\n    v-model=\"currentTab\"\n    class=\"bg-background-deep border-border overflow-hidden rounded-b-xl border-t\"\n    @update:model-value=\"open = true\"\n  >\n    <div class=\"border-border bg-background flex border-b-2 pr-2\">\n      <div class=\"flex w-full items-center justify-between text-[13px]\">\n        <TabsList class=\"relative flex\">\n          <template v-if=\"open\">\n            <TabsIndicator\n              class=\"absolute bottom-0 left-0 h-[2px] w-[--radix-tabs-indicator-size] translate-x-[--radix-tabs-indicator-position] rounded-full transition-[width,transform] duration-300\"\n            >\n              <div class=\"size-full bg-[var(--vp-c-indigo-1)]\"></div>\n            </TabsIndicator>\n            <TabsTrigger\n              v-for=\"(tab, index) in tabs\"\n              :key=\"index\"\n              :value=\"tab.label\"\n              class=\"border-box text-foreground px-4 py-3 data-[state=active]:text-[var(--vp-c-indigo-1)]\"\n              tabindex=\"-1\"\n            >\n              {{ tab.label }}\n            </TabsTrigger>\n          </template>\n        </TabsList>\n\n        <div\n          :class=\"{\n            'py-2': !open,\n          }\"\n          class=\"flex items-center\"\n        >\n          <VbenTooltip side=\"top\">\n            <template #trigger>\n              <Code\n                class=\"hover:bg-accent size-7 cursor-pointer rounded-full p-1.5\"\n                @click=\"toggleOpen\"\n              />\n            </template>\n            {{ open ? 'Collapse code' : 'Expand code' }}\n          </VbenTooltip>\n        </div>\n      </div>\n    </div>\n    <div\n      :class=\"`${open ? 'h-[unset] max-h-[80vh]' : 'h-0'}`\"\n      class=\"block overflow-y-scroll bg-[var(--vp-code-block-bg)] transition-all duration-300\"\n    >\n      <TabsContent\n        v-for=\"tab in tabs\"\n        :key=\"tab.label\"\n        :value=\"tab.label\"\n        as-child\n        class=\"rounded-xl\"\n      >\n        <div class=\"text-foreground relative rounded-xl\">\n          <component :is=\"tab.component\" class=\"border-0\" />\n        </div>\n      </TabsContent>\n    </div>\n  </TabsRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/config/en.mts",
    "content": "import type { DefaultTheme } from 'vitepress';\n\nimport { defineConfig } from 'vitepress';\n\nimport { version } from '../../../package.json';\n\nexport const en = defineConfig({\n  description: 'Vben Admin & Enterprise level management system framework',\n  lang: 'en-US',\n  themeConfig: {\n    darkModeSwitchLabel: 'Theme',\n    darkModeSwitchTitle: 'Switch to Dark Mode',\n    docFooter: {\n      next: 'Next Page',\n      prev: 'Previous Page',\n    },\n    editLink: {\n      pattern:\n        'https://github.com/vbenjs/vue-vben-admin/edit/main/docs/src/:path',\n      text: 'Edit this page on GitHub',\n    },\n    footer: {\n      copyright: `Copyright © 2020-${new Date().getFullYear()} Vben`,\n      message: 'Released under the MIT License.',\n    },\n    langMenuLabel: 'Language',\n    lastUpdated: {\n      formatOptions: {\n        dateStyle: 'short',\n        timeStyle: 'medium',\n      },\n      text: 'Last updated on',\n    },\n    lightModeSwitchTitle: 'Switch to Light Mode',\n    nav: nav(),\n    outline: {\n      label: 'Navigate',\n    },\n    returnToTopLabel: 'Back to top',\n    sidebar: {\n      '/en/commercial/': {\n        base: '/en/commercial/',\n        items: sidebarCommercial(),\n      },\n      '/en/guide/': { base: '/en/guide/', items: sidebarGuide() },\n    },\n  },\n});\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      collapsed: false,\n      text: 'Introduction',\n      items: [\n        {\n          link: 'introduction/vben',\n          text: 'About Vben Admin',\n        },\n        {\n          link: 'introduction/why',\n          text: 'Why Choose Us?',\n        },\n        { link: 'introduction/quick-start', text: 'Quick Start' },\n        { link: 'introduction/thin', text: 'Lite Version' },\n      ],\n    },\n    {\n      text: 'Basics',\n      items: [\n        { link: 'essentials/concept', text: 'Basic Concepts' },\n        { link: 'essentials/development', text: 'Local Development' },\n        { link: 'essentials/route', text: 'Routing and Menu' },\n        { link: 'essentials/settings', text: 'Configuration' },\n        { link: 'essentials/icons', text: 'Icons' },\n        { link: 'essentials/styles', text: 'Styles' },\n        { link: 'essentials/external-module', text: 'External Modules' },\n        { link: 'essentials/build', text: 'Build and Deployment' },\n        { link: 'essentials/server', text: 'Server Interaction and Data Mock' },\n      ],\n    },\n    {\n      text: 'Advanced',\n      items: [\n        { link: 'in-depth/login', text: 'Login' },\n        { link: 'in-depth/theme', text: 'Theme' },\n        { link: 'in-depth/access', text: 'Access Control' },\n        { link: 'in-depth/locale', text: 'Internationalization' },\n        { link: 'in-depth/features', text: 'Common Features' },\n        { link: 'in-depth/check-updates', text: 'Check Updates' },\n        { link: 'in-depth/loading', text: 'Global Loading' },\n        { link: 'in-depth/ui-framework', text: 'UI Framework Switching' },\n      ],\n    },\n    {\n      text: 'Engineering',\n      items: [\n        { link: 'project/standard', text: 'Standards' },\n        { link: 'project/cli', text: 'CLI' },\n        { link: 'project/dir', text: 'Directory Explanation' },\n        { link: 'project/test', text: 'Unit Testing' },\n        { link: 'project/tailwindcss', text: 'Tailwind CSS' },\n        { link: 'project/changeset', text: 'Changeset' },\n        { link: 'project/vite', text: 'Vite Config' },\n      ],\n    },\n    {\n      text: 'Others',\n      items: [\n        { link: 'other/project-update', text: 'Project Update' },\n        { link: 'other/remove-code', text: 'Remove Code' },\n        { link: 'other/faq', text: 'FAQ' },\n      ],\n    },\n  ];\n}\n\nfunction sidebarCommercial(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      link: 'community',\n      text: 'Community',\n    },\n    {\n      link: 'technical-support',\n      text: 'Technical-support',\n    },\n    {\n      link: 'customized',\n      text: 'Customized',\n    },\n  ];\n}\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      activeMatch: '^/en/(guide|components)/',\n      text: 'Doc',\n      items: [\n        {\n          activeMatch: '^/en/guide/',\n          link: '/en/guide/introduction/vben',\n          text: 'Guide',\n        },\n        // {\n        //   activeMatch: '^/en/components/',\n        //   link: '/en/components/introduction',\n        //   text: 'Components',\n        // },\n        {\n          text: 'Historical Versions',\n          items: [\n            {\n              link: 'https://doc.vvbin.cn',\n              text: '2.x Version Documentation',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      text: 'Demo',\n      items: [\n        {\n          text: 'Vben Admin',\n          items: [\n            {\n              link: 'https://www.vben.pro',\n              text: 'Demo Version',\n            },\n            {\n              link: 'https://ant.vben.pro',\n              text: 'Ant Design Vue Version',\n            },\n            {\n              link: 'https://naive.vben.pro',\n              text: 'Naive Version',\n            },\n            {\n              link: 'https://ele.vben.pro',\n              text: 'Element Plus Version',\n            },\n          ],\n        },\n        {\n          text: 'Others',\n          items: [\n            {\n              link: 'https://vben.vvbin.cn',\n              text: 'Vben Admin 2.x',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      text: version,\n      items: [\n        {\n          link: 'https://github.com/vbenjs/vue-vben-admin/releases',\n          text: 'Changelog',\n        },\n        {\n          link: 'https://github.com/orgs/vbenjs/projects/5',\n          text: 'Roadmap',\n        },\n        {\n          link: 'https://github.com/vbenjs/vue-vben-admin/blob/main/.github/contributing.md',\n          text: 'Contribution',\n        },\n      ],\n    },\n    {\n      link: '/commercial/technical-support',\n      text: '🦄 Tech Support',\n    },\n    {\n      link: '/sponsor/personal',\n      text: '✨ Sponsor',\n    },\n    {\n      link: '/commercial/community',\n      text: '👨‍👦‍👦 Community',\n    },\n    // {\n    //   link: '/friend-links/',\n    //   text: '🤝 Friend Links',\n    // },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/config/index.mts",
    "content": "import { withPwa } from '@vite-pwa/vitepress';\nimport { defineConfigWithTheme } from 'vitepress';\n\nimport { en } from './en.mts';\nimport { shared } from './shared.mts';\nimport { zh } from './zh.mts';\n\nexport default withPwa(\n  defineConfigWithTheme({\n    ...shared,\n    locales: {\n      en: {\n        label: 'English',\n        lang: 'en',\n        link: '/en/',\n        ...en,\n      },\n      root: {\n        label: '简体中文',\n        lang: 'zh-CN',\n        ...zh,\n      },\n    },\n  }),\n);\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/config/plugins/demo-preview.ts",
    "content": "import type { MarkdownEnv, MarkdownRenderer } from 'vitepress';\n\nimport crypto from 'node:crypto';\nimport { readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport const rawPathRegexp =\n  // eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/strict\n  /^(.+?(?:\\.([\\da-z]+))?)(#[\\w-]+)?(?: ?{(\\d+(?:[,-]\\d+)*)? ?(\\S+)?})? ?(?:\\[(.+)])?$/;\n\nfunction rawPathToToken(rawPath: string) {\n  const [\n    filepath = '',\n    extension = '',\n    region = '',\n    lines = '',\n    lang = '',\n    rawTitle = '',\n  ] = (rawPathRegexp.exec(rawPath) || []).slice(1);\n\n  const title = rawTitle || filepath.split('/').pop() || '';\n\n  return { extension, filepath, lang, lines, region, title };\n}\n\nexport const demoPreviewPlugin = (md: MarkdownRenderer) => {\n  md.core.ruler.after('inline', 'demo-preview', (state) => {\n    const insertComponentImport = (importString: string) => {\n      const index = state.tokens.findIndex(\n        (i) => i.type === 'html_block' && i.content.match(/<script setup>/g),\n      );\n      if (index === -1) {\n        const importComponent = new state.Token('html_block', '', 0);\n        importComponent.content = `<script setup>\\n${importString}\\n</script>\\n`;\n        state.tokens.splice(0, 0, importComponent);\n      } else {\n        if (state.tokens[index]) {\n          const content = state.tokens[index].content;\n          state.tokens[index].content = content.replace(\n            '</script>',\n            `${importString}\\n</script>`,\n          );\n        }\n      }\n    };\n    // Define the regular expression to match the desired pattern\n    const regex = /<DemoPreview[^>]*\\sdir=\"([^\"]*)\"/g;\n    // Iterate through the Markdown content and replace the pattern\n    state.src = state.src.replaceAll(regex, (_match, dir) => {\n      const componentDir = join(process.cwd(), 'src', dir).replaceAll(\n        '\\\\',\n        '/',\n      );\n\n      let childFiles: string[] = [];\n      let dirExists = true;\n\n      try {\n        childFiles =\n          readdirSync(componentDir, {\n            encoding: 'utf8',\n            recursive: false,\n            withFileTypes: false,\n          }) || [];\n      } catch {\n        dirExists = false;\n      }\n\n      if (!dirExists) {\n        return '';\n      }\n\n      const uniqueWord = generateContentHash(componentDir);\n\n      const ComponentName = `DemoComponent_${uniqueWord}`;\n      insertComponentImport(\n        `import ${ComponentName} from '${componentDir}/index.vue'`,\n      );\n      const { path: _path } = state.env as MarkdownEnv;\n\n      const index = state.tokens.findIndex((i) => i.content.match(regex));\n\n      if (!state.tokens[index]) {\n        return '';\n      }\n      const firstString = 'index.vue';\n      childFiles = childFiles.sort((a, b) => {\n        if (a === firstString) return -1;\n        if (b === firstString) return 1;\n        return a.localeCompare(b, 'en', { sensitivity: 'base' });\n      });\n      state.tokens[index].content =\n        `<DemoPreview files=\"${encodeURIComponent(JSON.stringify(childFiles))}\" ><${ComponentName}/>\n        `;\n\n      const _dummyToken = new state.Token('', '', 0);\n      const tokenArray: Array<typeof _dummyToken> = [];\n      childFiles.forEach((filename) => {\n        // const slotName = filename.replace(extname(filename), '');\n\n        const templateStart = new state.Token('html_inline', '', 0);\n        templateStart.content = `<template #${filename}>`;\n        tokenArray.push(templateStart);\n\n        const resolvedPath = join(componentDir, filename);\n\n        const { extension, filepath, lang, lines, title } =\n          rawPathToToken(resolvedPath);\n        // Add code tokens for each line\n        const token = new state.Token('fence', 'code', 0);\n        token.info = `${lang || extension}${lines ? `{${lines}}` : ''}${\n          title ? `[${title}]` : ''\n        }`;\n\n        token.content = `<<< ${filepath}`;\n        (token as any).src = [resolvedPath];\n        tokenArray.push(token);\n\n        const templateEnd = new state.Token('html_inline', '', 0);\n        templateEnd.content = '</template>';\n        tokenArray.push(templateEnd);\n      });\n      const endTag = new state.Token('html_inline', '', 0);\n      endTag.content = '</DemoPreview>';\n      tokenArray.push(endTag);\n\n      state.tokens.splice(index + 1, 0, ...tokenArray);\n\n      // console.log(\n      //   state.md.renderer.render(state.tokens, state?.options ?? [], state.env),\n      // );\n      return '';\n    });\n  });\n};\n\nfunction generateContentHash(input: string, length: number = 10): string {\n  // 使用 SHA-256 生成哈希值\n  const hash = crypto.createHash('sha256').update(input).digest('hex');\n\n  // 将哈希值转换为 Base36 编码，并取指定长度的字符作为结果\n  return Number.parseInt(hash, 16).toString(36).slice(0, length);\n}\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/config/shared.mts",
    "content": "import type { PwaOptions } from '@vite-pwa/vitepress';\nimport type { HeadConfig } from 'vitepress';\n\nimport { resolve } from 'node:path';\n\nimport {\n  viteArchiverPlugin,\n  viteVxeTableImportsPlugin,\n} from '@vben/vite-config';\n\nimport {\n  GitChangelog,\n  GitChangelogMarkdownSection,\n} from '@nolebase/vitepress-plugin-git-changelog/vite';\nimport tailwind from 'tailwindcss';\nimport { defineConfig, postcssIsolateStyles } from 'vitepress';\nimport {\n  groupIconMdPlugin,\n  groupIconVitePlugin,\n} from 'vitepress-plugin-group-icons';\n\nimport { demoPreviewPlugin } from './plugins/demo-preview';\nimport { search as zhSearch } from './zh.mts';\n\nexport const shared = defineConfig({\n  appearance: 'dark',\n  head: head(),\n  markdown: {\n    preConfig(md) {\n      md.use(demoPreviewPlugin);\n      md.use(groupIconMdPlugin);\n    },\n  },\n  pwa: pwa(),\n  srcDir: 'src',\n  themeConfig: {\n    i18nRouting: true,\n    logo: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n    search: {\n      options: {\n        locales: {\n          ...zhSearch,\n        },\n      },\n      provider: 'local',\n    },\n    siteTitle: 'Vben Admin',\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/vbenjs/vue-vben-admin' },\n    ],\n  },\n  title: 'Vben Admin',\n  vite: {\n    build: {\n      chunkSizeWarningLimit: Infinity,\n      minify: 'terser',\n    },\n    css: {\n      postcss: {\n        plugins: [\n          tailwind(),\n          postcssIsolateStyles({ includeFiles: [/vp-doc\\.css/] }),\n        ],\n      },\n      preprocessorOptions: {\n        scss: {\n          api: 'modern',\n        },\n      },\n    },\n    json: {\n      stringify: true,\n    },\n    plugins: [\n      GitChangelog({\n        mapAuthors: [\n          {\n            mapByNameAliases: ['Vben'],\n            name: 'vben',\n            username: 'anncwb',\n          },\n          {\n            name: 'vince',\n            username: 'vince292007',\n          },\n          {\n            name: 'Li Kui',\n            username: 'likui628',\n          },\n        ],\n        repoURL: () => 'https://github.com/vbenjs/vue-vben-admin',\n      }),\n      GitChangelogMarkdownSection(),\n      viteArchiverPlugin({ outputDir: '.vitepress' }),\n      groupIconVitePlugin(),\n      await viteVxeTableImportsPlugin(),\n    ],\n    server: {\n      fs: {\n        allow: ['../..'],\n      },\n      host: true,\n      port: 6173,\n    },\n\n    ssr: {\n      external: ['@vue/repl'],\n    },\n  },\n});\n\nfunction head(): HeadConfig[] {\n  return [\n    ['meta', { content: 'Vbenjs Team', name: 'author' }],\n    [\n      'meta',\n      {\n        content: 'vben, vitejs, vite, shacdn-ui, vue',\n        name: 'keywords',\n      },\n    ],\n    ['link', { href: '/favicon.ico', rel: 'icon', type: 'image/svg+xml' }],\n    [\n      'meta',\n      {\n        content:\n          'width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no',\n        name: 'viewport',\n      },\n    ],\n    ['meta', { content: 'vben admin docs', name: 'keywords' }],\n    ['link', { href: '/favicon.ico', rel: 'icon' }],\n    // [\n    //   'script',\n    //   {\n    //     src: 'https://cdn.tailwindcss.com',\n    //   },\n    // ],\n  ];\n}\n\nfunction pwa(): PwaOptions {\n  return {\n    includeManifestIcons: false,\n    manifest: {\n      description:\n        'Vben Admin is a modern admin dashboard template based on Vue 3. ',\n      icons: [\n        {\n          sizes: '192x192',\n          src: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/pwa-icon-192.png',\n          type: 'image/png',\n        },\n        {\n          sizes: '512x512',\n          src: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/pwa-icon-512.png',\n          type: 'image/png',\n        },\n      ],\n      id: '/',\n      name: 'Vben Admin Doc',\n      short_name: 'vben_admin_doc',\n      theme_color: '#ffffff',\n    },\n    outDir: resolve(process.cwd(), '.vitepress/dist'),\n    registerType: 'autoUpdate',\n    workbox: {\n      globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'],\n      maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,\n    },\n  };\n}\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/config/zh.mts",
    "content": "import type { DefaultTheme } from 'vitepress';\n\nimport { defineConfig } from 'vitepress';\n\nimport { version } from '../../../package.json';\n\nexport const zh = defineConfig({\n  description: 'Vben Admin & 企业级管理系统框架',\n  lang: 'zh-Hans',\n  themeConfig: {\n    darkModeSwitchLabel: '主题',\n    darkModeSwitchTitle: '切换到深色模式',\n    docFooter: {\n      next: '下一页',\n      prev: '上一页',\n    },\n    editLink: {\n      pattern:\n        'https://github.com/vbenjs/vue-vben-admin/edit/main/docs/src/:path',\n      text: '在 GitHub 上编辑此页面',\n    },\n    footer: {\n      copyright: `Copyright © 2020-${new Date().getFullYear()} Vben`,\n      message: '基于 MIT 许可发布.',\n    },\n    langMenuLabel: '多语言',\n    lastUpdated: {\n      formatOptions: {\n        dateStyle: 'short',\n        timeStyle: 'medium',\n      },\n      text: '最后更新于',\n    },\n    lightModeSwitchTitle: '切换到浅色模式',\n    nav: nav(),\n\n    outline: {\n      label: '页面导航',\n    },\n    returnToTopLabel: '回到顶部',\n\n    sidebar: {\n      '/commercial/': { base: '/commercial/', items: sidebarCommercial() },\n      '/components/': { base: '/components/', items: sidebarComponents() },\n      '/guide/': { base: '/guide/', items: sidebarGuide() },\n    },\n    sidebarMenuLabel: '菜单',\n  },\n});\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      collapsed: false,\n      text: '简介',\n      items: [\n        {\n          link: 'introduction/vben',\n          text: '关于 Vben Admin',\n        },\n        {\n          link: 'introduction/why',\n          text: '为什么选择我们?',\n        },\n        { link: 'introduction/quick-start', text: '快速开始' },\n        { link: 'introduction/thin', text: '精简版本' },\n        {\n          base: '/',\n          link: 'components/introduction',\n          text: '组件文档',\n        },\n      ],\n    },\n    {\n      text: '基础',\n      items: [\n        { link: 'essentials/concept', text: '基础概念' },\n        { link: 'essentials/development', text: '本地开发' },\n        { link: 'essentials/route', text: '路由和菜单' },\n        { link: 'essentials/settings', text: '配置' },\n        { link: 'essentials/icons', text: '图标' },\n        { link: 'essentials/styles', text: '样式' },\n        { link: 'essentials/external-module', text: '外部模块' },\n        { link: 'essentials/build', text: '构建与部署' },\n        { link: 'essentials/server', text: '服务端交互与数据Mock' },\n      ],\n    },\n    {\n      text: '深入',\n      items: [\n        { link: 'in-depth/login', text: '登录' },\n        // { link: 'in-depth/layout', text: '布局' },\n        { link: 'in-depth/theme', text: '主题' },\n        { link: 'in-depth/access', text: '权限' },\n        { link: 'in-depth/locale', text: '国际化' },\n        { link: 'in-depth/features', text: '常用功能' },\n        { link: 'in-depth/check-updates', text: '检查更新' },\n        { link: 'in-depth/loading', text: '全局loading' },\n        { link: 'in-depth/ui-framework', text: '组件库切换' },\n      ],\n    },\n    {\n      text: '工程',\n      items: [\n        { link: 'project/standard', text: '规范' },\n        { link: 'project/cli', text: 'CLI' },\n        { link: 'project/dir', text: '目录说明' },\n        { link: 'project/test', text: '单元测试' },\n        { link: 'project/tailwindcss', text: 'Tailwind CSS' },\n        { link: 'project/changeset', text: 'Changeset' },\n        { link: 'project/vite', text: 'Vite Config' },\n      ],\n    },\n    {\n      text: '其他',\n      items: [\n        { link: 'other/project-update', text: '项目更新' },\n        { link: 'other/remove-code', text: '移除代码' },\n        { link: 'other/faq', text: '常见问题' },\n      ],\n    },\n  ];\n}\n\nfunction sidebarCommercial(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      link: 'community',\n      text: '交流群',\n    },\n    {\n      link: 'technical-support',\n      text: '技术支持',\n    },\n    {\n      link: 'customized',\n      text: '定制开发',\n    },\n  ];\n}\n\nfunction sidebarComponents(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: '组件',\n      items: [\n        {\n          link: 'introduction',\n          text: '介绍',\n        },\n      ],\n    },\n    {\n      collapsed: false,\n      text: '布局组件',\n      items: [\n        {\n          link: 'layout-ui/page',\n          text: 'Page 页面',\n        },\n      ],\n    },\n    {\n      collapsed: false,\n      text: '通用组件',\n      items: [\n        {\n          link: 'common-ui/vben-api-component',\n          text: 'ApiComponent Api组件包装器',\n        },\n        {\n          link: 'common-ui/vben-alert',\n          text: 'Alert 轻量提示框',\n        },\n        {\n          link: 'common-ui/vben-modal',\n          text: 'Modal 模态框',\n        },\n        {\n          link: 'common-ui/vben-drawer',\n          text: 'Drawer 抽屉',\n        },\n        {\n          link: 'common-ui/vben-form',\n          text: 'Form 表单',\n        },\n        {\n          link: 'common-ui/vben-vxe-table',\n          text: 'Vxe Table 表格',\n        },\n        {\n          link: 'common-ui/vben-count-to-animator',\n          text: 'CountToAnimator 数字动画',\n        },\n        {\n          link: 'common-ui/vben-ellipsis-text',\n          text: 'EllipsisText 省略文本',\n        },\n      ],\n    },\n  ];\n}\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      activeMatch: '^/(guide|components)/',\n      text: '文档',\n      items: [\n        {\n          activeMatch: '^/guide/',\n          link: '/guide/introduction/vben',\n          text: '指南',\n        },\n        {\n          activeMatch: '^/components/',\n          link: '/components/introduction',\n          text: '组件',\n        },\n        {\n          text: '历史版本',\n          items: [\n            {\n              link: 'https://doc.vvbin.cn',\n              text: '2.x版本文档',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      text: '演示',\n      items: [\n        {\n          text: 'Vben Admin',\n          items: [\n            {\n              link: 'https://www.vben.pro',\n              text: '演示版本',\n            },\n            {\n              link: 'https://ant.vben.pro',\n              text: 'Ant Design Vue 版本',\n            },\n            {\n              link: 'https://naive.vben.pro',\n              text: 'Naive 版本',\n            },\n            {\n              link: 'https://ele.vben.pro',\n              text: 'Element Plus版本',\n            },\n          ],\n        },\n        {\n          text: '其他',\n          items: [\n            {\n              link: 'https://vben.vvbin.cn',\n              text: 'Vben Admin 2.x',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      text: version,\n      items: [\n        {\n          link: 'https://github.com/vbenjs/vue-vben-admin/releases',\n          text: '更新日志',\n        },\n        {\n          link: 'https://github.com/orgs/vbenjs/projects/5',\n          text: '路线图',\n        },\n        {\n          link: 'https://github.com/vbenjs/vue-vben-admin/blob/main/.github/contributing.md',\n          text: '贡献',\n        },\n      ],\n    },\n    {\n      link: '/commercial/technical-support',\n      text: '🦄 技术支持',\n    },\n    {\n      link: '/sponsor/personal',\n      text: '✨ 赞助',\n    },\n    {\n      link: '/commercial/community',\n      text: '👨‍👦‍👦 交流群',\n      // items: [\n      //   {\n      //     link: 'https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=22ySzj7pKiw&businessType=9&from=246610&biz=ka&mainSourceId=share&subSourceId=others&jumpsource=shorturl#/pc',\n      //     text: 'QQ频道',\n      //   },\n      //   {\n      //     link: 'https://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=mjZmlhgVzzUxvdxllB6C1vHpX8O8QRL0&authKey=DBdFbBwERmfaKY95JvRWqLCJIRGJAmKyZbrpzZ41EKDMZ5SR6MfbjOBaaNRN73fr&noverify=0&group_code=4286109',\n      //     text: 'QQ群',\n      //   },\n      //   {\n      //     link: 'https://discord.gg/VU62jTecad',\n      //     text: 'Discord',\n      //   },\n      // ],\n    },\n    // {\n    //   link: '/friend-links/',\n    //   text: '🤝 友情链接',\n    // },\n  ];\n}\n\nexport const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {\n  root: {\n    placeholder: '搜索文档',\n    translations: {\n      button: {\n        buttonAriaLabel: '搜索文档',\n        buttonText: '搜索文档',\n      },\n      modal: {\n        errorScreen: {\n          helpText: '你可能需要检查你的网络连接',\n          titleText: '无法获取结果',\n        },\n        footer: {\n          closeText: '关闭',\n          navigateText: '切换',\n          searchByText: '搜索提供者',\n          selectText: '选择',\n        },\n        noResultsScreen: {\n          noResultsText: '无法找到相关结果',\n          reportMissingResultsLinkText: '点击反馈',\n          reportMissingResultsText: '你认为该查询应该有结果？',\n          suggestedQueryText: '你可以尝试查询',\n        },\n        searchBox: {\n          cancelButtonAriaLabel: '取消',\n          cancelButtonText: '取消',\n          resetButtonAriaLabel: '清除查询条件',\n          resetButtonTitle: '清除查询条件',\n        },\n        startScreen: {\n          favoriteSearchesTitle: '收藏',\n          noRecentSearchesText: '没有搜索历史',\n          recentSearchesTitle: '搜索历史',\n          removeFavoriteSearchButtonTitle: '从收藏中移除',\n          removeRecentSearchButtonTitle: '从搜索历史中移除',\n          saveRecentSearchButtonTitle: '保存至搜索历史',\n        },\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/theme/components/site-layout.vue",
    "content": "<script lang=\"ts\" setup>\nimport {\n  computed,\n  nextTick,\n  onBeforeUnmount,\n  onMounted,\n  ref,\n  watch,\n} from 'vue';\n\n// import { useAntdDesignTokens } from '@vben/hooks';\n// import { initPreferences } from '@vben/preferences';\nimport { ConfigProvider, theme } from 'ant-design-vue';\nimport mediumZoom from 'medium-zoom';\nimport { useRoute } from 'vitepress';\nimport DefaultTheme from 'vitepress/theme';\n\nconst { Layout } = DefaultTheme;\nconst route = useRoute();\n// const { tokens } = useAntdDesignTokens();\n\nconst initZoom = () => {\n  // mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' });\n  mediumZoom('.VPContent img', { background: 'var(--vp-c-bg)' });\n};\n\nconst isDark = ref(true);\n\nwatch(\n  () => route.path,\n  () => nextTick(() => initZoom()),\n);\n\n// initPreferences({\n//   namespace: 'docs',\n// });\n\nonMounted(() => {\n  initZoom();\n});\n\n// 使用该函数\nconst observer = watchDarkModeChange((dark) => {\n  isDark.value = dark;\n});\n\nonBeforeUnmount(() => {\n  observer?.disconnect();\n});\n\nfunction watchDarkModeChange(callback: (isDark: boolean) => void) {\n  if (typeof window === 'undefined') {\n    return;\n  }\n  const htmlElement = document.documentElement;\n\n  const observer = new MutationObserver(() => {\n    const isDark = htmlElement.classList.contains('dark');\n    callback(isDark);\n  });\n\n  observer.observe(htmlElement, {\n    attributeFilter: ['class'],\n    attributes: true,\n  });\n\n  const initialIsDark = htmlElement.classList.contains('dark');\n  callback(initialIsDark);\n\n  return observer;\n}\n\nconst tokenTheme = computed(() => {\n  const algorithm = isDark.value\n    ? [theme.darkAlgorithm]\n    : [theme.defaultAlgorithm];\n\n  return {\n    algorithm,\n    // token: tokens,\n  };\n});\n</script>\n\n<template>\n  <ConfigProvider :theme=\"tokenTheme\">\n    <Layout />\n  </ConfigProvider>\n</template>\n\n<style>\n.medium-zoom-overlay,\n.medium-zoom-image--opened {\n  z-index: 2147483647;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/theme/components/vben-contributors.vue",
    "content": "<script setup lang=\"ts\"></script>\n\n<template>\n  <div class=\"vp-doc vben-contributors\">\n    <p>Contributors</p>\n    <a href=\"https://github.com/vbenjs/vue-vben-admin/graphs/contributors\">\n      <img\n        alt=\"Contributors\"\n        src=\"https://opencollective.com/vbenjs/contributors.svg?button=false\"\n      />\n    </a>\n  </div>\n</template>\n\n<style scoped>\n.vben-contributors {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  padding-top: 60px;\n\n  p {\n    margin-bottom: 50px;\n    font-size: 30px;\n    font-weight: 700;\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/theme/index.ts",
    "content": "// https://vitepress.dev/guide/custom-theme\nimport type { EnhanceAppContext, Theme } from 'vitepress';\n\nimport { NolebaseGitChangelogPlugin } from '@nolebase/vitepress-plugin-git-changelog/client';\nimport DefaultTheme from 'vitepress/theme';\n\nimport { DemoPreview } from '../components';\nimport SiteLayout from './components/site-layout.vue';\nimport VbenContributors from './components/vben-contributors.vue';\nimport { initHmPlugin } from './plugins/hm';\n\nimport './styles';\n\nimport 'virtual:group-icons.css';\nimport '@nolebase/vitepress-plugin-git-changelog/client/style.css';\n\nexport default {\n  async enhanceApp(ctx: EnhanceAppContext) {\n    const { app } = ctx;\n    app.component('VbenContributors', VbenContributors);\n    app.component('DemoPreview', DemoPreview);\n    app.use(NolebaseGitChangelogPlugin);\n\n    // 百度统计\n    initHmPlugin();\n  },\n  extends: DefaultTheme,\n  Layout: SiteLayout,\n} satisfies Theme;\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/theme/plugins/hm.ts",
    "content": "import { inBrowser } from 'vitepress';\n\nconst SITE_ID = '2e443a834727c065877c01d89921545e';\n\ndeclare global {\n  interface Window {\n    _hmt: any;\n  }\n}\n\nfunction registerAnalytics() {\n  window._hmt = window._hmt || [];\n  const script = document.createElement('script');\n  script.innerHTML = `var _hmt = _hmt || [];\n      (function() {\n        var hm = document.createElement(\"script\");\n        hm.src = \"https://hm.baidu.com/hm.js?${SITE_ID}\";\n        var s = document.getElementsByTagName(\"script\")[0];\n        s.parentNode.insertBefore(hm, s);\n      })()`;\n  document.querySelector('head')?.append(script);\n}\n\nexport function initHmPlugin() {\n  if (inBrowser && import.meta.env.PROD) {\n    registerAnalytics();\n  }\n}\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/theme/styles/base.css",
    "content": "html.dark {\n  color-scheme: dark;\n}\n\n.dark .VPContent {\n  /* background-color: #14161a; */\n}\n\n.form-valid-error p {\n  margin: 0;\n}\n\n/* 顶部导航栏选中项样式 */\n.VPNavBarMenuLink,\n.VPNavBarMenuGroup {\n  border-bottom: 1px solid transparent;\n}\n\n.VPNavBarMenuLink.active,\n.VPNavBarMenuGroup.active {\n  border-bottom-color: var(--vp-c-brand-1);\n}\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/theme/styles/index.ts",
    "content": "import '@vben/styles';\n\nimport './variables.css';\nimport './base.css';\n"
  },
  {
    "path": "hiauth-front/docs/.vitepress/theme/styles/variables.css",
    "content": "/**\n * Customize default theme styling by overriding CSS variables:\n * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css\n */\n\n/**\n * Colors\n *\n * Each colors have exact same color scale system with 3 levels of solid\n * colors with different brightness, and 1 soft color.\n *\n * - `XXX-1`: The most solid color used mainly for colored text. It must\n *   satisfy the contrast ratio against when used on top of `XXX-soft`.\n *\n * - `XXX-2`: The color used mainly for hover state of the button.\n *\n * - `XXX-3`: The color for solid background, such as bg color of the button.\n *   It must satisfy the contrast ratio with pure white (#ffffff) text on\n *   top of it.\n *\n * - `XXX-soft`: The color used for subtle background such as custom container\n *   or badges. It must satisfy the contrast ratio when putting `XXX-1` colors\n *   on top of it.\n *\n *   The soft color must be semi transparent alpha channel. This is crucial\n *   because it allows adding multiple \"soft\" colors on top of each other\n *   to create a accent, such as when having inline code block inside\n *   custom containers.\n *\n * - `default`: The color used purely for subtle indication without any\n *   special meanings attched to it such as bg color for menu hover state.\n *\n * - `brand`: Used for primary brand colors, such as link text, button with\n *   brand theme, etc.\n *\n * - `tip`: Used to indicate useful information. The default theme uses the\n *   brand color for this by default.\n *\n * - `warning`: Used to indicate warning to the users. Used in custom\n *   container, badges, etc.\n *\n * - `danger`: Used to show error, or dangerous message to the users. Used\n *   in custom container, badges, etc.\n * -------------------------------------------------------------------------- */\n\n:root {\n  /* --vp-c-indigo-1: #4f69fd; */\n  --vp-c-default-1: var(--vp-c-gray-1);\n  --vp-c-default-2: var(--vp-c-gray-2);\n  --vp-c-default-3: var(--vp-c-gray-3);\n  --vp-c-default-soft: var(--vp-c-gray-soft);\n  --vp-c-brand-1: var(--vp-c-indigo-1);\n  --vp-c-brand-2: var(--vp-c-indigo-2);\n  --vp-c-brand-3: var(--vp-c-indigo-3);\n  --vp-c-brand-soft: var(--vp-c-indigo-soft);\n  --vp-c-tip-1: var(--vp-c-brand-1);\n  --vp-c-tip-2: var(--vp-c-brand-2);\n  --vp-c-tip-3: var(--vp-c-brand-3);\n  --vp-c-tip-soft: var(--vp-c-brand-soft);\n  --vp-c-warning-1: var(--vp-c-yellow-1);\n  --vp-c-warning-2: var(--vp-c-yellow-2);\n  --vp-c-warning-3: var(--vp-c-yellow-3);\n  --vp-c-warning-soft: var(--vp-c-yellow-soft);\n  --vp-c-danger-1: var(--vp-c-red-1);\n  --vp-c-danger-2: var(--vp-c-red-2);\n  --vp-c-danger-3: var(--vp-c-red-3);\n  --vp-c-danger-soft: var(--vp-c-red-soft);\n\n  /**\n * Component: Button\n * -------------------------------------------------------------------------- */\n\n  --vp-button-brand-border: transparent;\n  --vp-button-brand-text: var(--vp-c-white);\n  --vp-button-brand-bg: var(--vp-c-brand-3);\n  --vp-button-brand-hover-border: transparent;\n  --vp-button-brand-hover-text: var(--vp-c-white);\n  --vp-button-brand-hover-bg: var(--vp-c-brand-2);\n  --vp-button-brand-active-border: transparent;\n  --vp-button-brand-active-text: var(--vp-c-white);\n  --vp-button-brand-active-bg: var(--vp-c-brand-1);\n\n  /**\n * Component: Home\n * -------------------------------------------------------------------------- */\n\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: linear-gradient(\n    120deg,\n    var(--vp-c-indigo-1) 30%,\n    #18cefe\n  );\n  --vp-home-hero-image-background-image: linear-gradient(\n    -45deg,\n    #18cefe 50%,\n    #c279ed 50%\n  );\n  --vp-home-hero-image-filter: blur(44px);\n\n  /**\n * Component: Custom Block\n * -------------------------------------------------------------------------- */\n  --vp-custom-block-tip-border: transparent;\n  --vp-custom-block-tip-text: var(--vp-c-text-1);\n  --vp-custom-block-tip-bg: var(--vp-c-brand-soft);\n  --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);\n\n  /**\n  * modal zIndex\n  */\n  --popup-z-index: 1000;\n}\n\n@media (min-width: 640px) {\n  :root {\n    --vp-home-hero-image-filter: blur(56px);\n  }\n}\n\n@media (min-width: 960px) {\n  :root {\n    --vp-home-hero-image-filter: blur(68px);\n  }\n}\n\n/**\n * Component: Algolia\n * -------------------------------------------------------------------------- */\n\n.DocSearch {\n  --docsearch-primary-color: var(--vp-c-brand-1) !important;\n}\n"
  },
  {
    "path": "hiauth-front/docs/package.json",
    "content": "{\n  \"name\": \"@vben/docs\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"vitepress build\",\n    \"dev\": \"vitepress dev\",\n    \"docs:preview\": \"vitepress preview\"\n  },\n  \"imports\": {\n    \"#/*\": {\n      \"node\": \"./src/_env/node/*\",\n      \"default\": \"./src/_env/*\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben/common-ui\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/plugins\": \"workspace:*\",\n    \"@vben/styles\": \"workspace:*\",\n    \"ant-design-vue\": \"catalog:\",\n    \"lucide-vue-next\": \"catalog:\",\n    \"medium-zoom\": \"catalog:\",\n    \"radix-vue\": \"catalog:\",\n    \"vitepress-plugin-group-icons\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@nolebase/vitepress-plugin-git-changelog\": \"catalog:\",\n    \"@vben/vite-config\": \"workspace:*\",\n    \"@vite-pwa/vitepress\": \"catalog:\",\n    \"vitepress\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/docs/src/_env/adapter/component.ts",
    "content": "/**\n * 通用组件共同的使用的基础组件，原先放在 adapter/form 内部，限制了使用范围，这里提取出来，方便其他地方使用\n * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,\n */\n\nimport type { Component, SetupContext } from 'vue';\n\nimport type { BaseFormComponentType } from '@vben/common-ui';\n\nimport { h } from 'vue';\n\nimport { globalShareState } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport {\n  AutoComplete,\n  Button,\n  Checkbox,\n  CheckboxGroup,\n  DatePicker,\n  Divider,\n  Input,\n  InputNumber,\n  InputPassword,\n  Mentions,\n  notification,\n  Radio,\n  RadioGroup,\n  RangePicker,\n  Rate,\n  Select,\n  Space,\n  Switch,\n  Textarea,\n  TimePicker,\n  TreeSelect,\n  Upload,\n} from 'ant-design-vue';\n\nconst withDefaultPlaceholder = <T extends Component>(\n  component: T,\n  type: 'input' | 'select',\n) => {\n  return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {\n    const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);\n    return h(component, { ...props, ...attrs, placeholder }, slots);\n  };\n};\n\n// 这里需要自行根据业务组件库进行适配，需要用到的组件都需要在这里类型说明\nexport type ComponentType =\n  | 'AutoComplete'\n  | 'Checkbox'\n  | 'CheckboxGroup'\n  | 'DatePicker'\n  | 'DefaultButton'\n  | 'Divider'\n  | 'Input'\n  | 'InputNumber'\n  | 'InputPassword'\n  | 'Mentions'\n  | 'PrimaryButton'\n  | 'Radio'\n  | 'RadioGroup'\n  | 'RangePicker'\n  | 'Rate'\n  | 'Select'\n  | 'Space'\n  | 'Switch'\n  | 'Textarea'\n  | 'TimePicker'\n  | 'TreeSelect'\n  | 'Upload'\n  | BaseFormComponentType;\n\nasync function initComponentAdapter() {\n  const components: Partial<Record<ComponentType, Component>> = {\n    // 如果你的组件体积比较大，可以使用异步加载\n    // Button: () =>\n    // import('xxx').then((res) => res.Button),\n\n    AutoComplete,\n    Checkbox,\n    CheckboxGroup,\n    DatePicker,\n    // 自定义默认按钮\n    DefaultButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'default' }, slots);\n    },\n    Divider,\n    Input: withDefaultPlaceholder(Input, 'input'),\n    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),\n    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),\n    Mentions: withDefaultPlaceholder(Mentions, 'input'),\n    // 自定义主要按钮\n    PrimaryButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'primary' }, slots);\n    },\n    Radio,\n    RadioGroup,\n    RangePicker,\n    Rate,\n    Select: withDefaultPlaceholder(Select, 'select'),\n    Space,\n    Switch,\n    Textarea: withDefaultPlaceholder(Textarea, 'input'),\n    TimePicker,\n    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),\n    Upload,\n  };\n\n  // 将组件注册到全局共享状态中\n  globalShareState.setComponents(components);\n\n  // 定义全局共享状态中的消息提示\n  globalShareState.defineMessage({\n    // 复制成功消息提示\n    copyPreferencesSuccess: (title, content) => {\n      notification.success({\n        description: content,\n        message: title,\n        placement: 'bottomRight',\n      });\n    },\n  });\n}\n\nexport { initComponentAdapter };\n"
  },
  {
    "path": "hiauth-front/docs/src/_env/adapter/form.ts",
    "content": "import type {\n  VbenFormSchema as FormSchema,\n  VbenFormProps,\n} from '@vben/common-ui';\n\nimport type { ComponentType } from './component';\n\nimport { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { initComponentAdapter } from './component';\n\ninitComponentAdapter();\nsetupVbenForm<ComponentType>({\n  config: {\n    baseModelPropName: 'value',\n    // naive-ui组件的空值为null,不能是undefined，否则重置表单时不生效\n    emptyStateValue: null,\n    modelPropNameMap: {\n      Checkbox: 'checked',\n      Radio: 'checked',\n      Switch: 'checked',\n      Upload: 'fileList',\n    },\n  },\n  defineRules: {\n    required: (value, _params, ctx) => {\n      if (value === undefined || value === null || value.length === 0) {\n        return $t('ui.formRules.required', [ctx.label]);\n      }\n      return true;\n    },\n    selectRequired: (value, _params, ctx) => {\n      if (value === undefined || value === null) {\n        return $t('ui.formRules.selectRequired', [ctx.label]);\n      }\n      return true;\n    },\n  },\n});\n\nconst useVbenForm = useForm<ComponentType>;\n\nexport { useVbenForm, z };\n\nexport type VbenFormSchema = FormSchema<ComponentType>;\nexport type { VbenFormProps };\n"
  },
  {
    "path": "hiauth-front/docs/src/_env/adapter/vxe-table.ts",
    "content": "import { h } from 'vue';\n\nimport { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';\n\nimport { Button, Image } from 'ant-design-vue';\n\nimport { useVbenForm } from './form';\n\nif (!import.meta.env.SSR) {\n  setupVbenVxeTable({\n    configVxeTable: (vxeUI) => {\n      vxeUI.setConfig({\n        grid: {\n          align: 'center',\n          border: false,\n          columnConfig: {\n            resizable: true,\n          },\n\n          formConfig: {\n            // 全局禁用vxe-table的表单配置，使用formOptions\n            enabled: false,\n          },\n          minHeight: 180,\n          proxyConfig: {\n            autoLoad: true,\n            response: {\n              result: 'items',\n              total: 'total',\n              list: 'items',\n            },\n            showActiveMsg: true,\n            showResponseMsg: false,\n          },\n          round: true,\n          showOverflow: true,\n          size: 'small',\n        },\n      });\n\n      // 表格配置项可以用 cellRender: { name: 'CellImage' },\n      vxeUI.renderer.add('CellImage', {\n        renderTableDefault(_renderOpts, params) {\n          const { column, row } = params;\n          return h(Image, { src: row[column.field] });\n        },\n      });\n\n      // 表格配置项可以用 cellRender: { name: 'CellLink' },\n      vxeUI.renderer.add('CellLink', {\n        renderTableDefault(renderOpts) {\n          const { props } = renderOpts;\n          return h(\n            Button,\n            { size: 'small', type: 'link' },\n            { default: () => props?.text },\n          );\n        },\n      });\n\n      // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化\n      // vxeUI.formats.add\n    },\n    useVbenForm,\n  });\n}\n\nexport { useVbenVxeGrid };\n\nexport type * from '@vben/plugins/vxe-table';\n"
  },
  {
    "path": "hiauth-front/docs/src/_env/node/adapter/form.ts",
    "content": "export const useVbenForm = () => {};\nexport const z = {};\nexport type VbenFormSchema = any;\nexport type VbenFormProps = any;\n"
  },
  {
    "path": "hiauth-front/docs/src/_env/node/adapter/vxe-table.ts",
    "content": "export type * from '@vben/plugins/vxe-table';\n\nexport const useVbenVxeGrid = () => {};\n"
  },
  {
    "path": "hiauth-front/docs/src/commercial/community.md",
    "content": "# 社区交流\n\n社区交流群主要是为了方便大家交流，提问，解答问题，分享经验等。偏自助方式，如果你有问题，可以通过以下方式加入社区交流群：\n\n- [QQ频道](https://pd.qq.com/s/16p8lvvob)：推荐！！！主要提供问题解答，分享经验等。\n- QQ群：[大群](https://qm.qq.com/q/MEmHoCLbG0)，[1群](https://qm.qq.com/q/YacMHPYAMu)、[2群](https://qm.qq.com/q/ajVKZvFICk)、[3群](https://qm.qq.com/q/36zdwThP2E)，[4群](https://qm.qq.com/q/sCzSlm3504)，[5群](https://qm.qq.com/q/ya9XrtbS6s)，主要的使用者交流群。\n- [Discord](https://discord.com/invite/VU62jTecad): 主要提供问题解答，分享经验等。\n\n::: tip\n\n免费QQ群人数上限200，将会不定期清理。推荐加入QQ频道进行交流\n\n:::\n\n## 微信群\n\n作者主要通过微信群提供帮助，如果你有问题，可以通过以下方式加入微信群。\n\n通过微信联系作者，注明加群来意：\n\n::: tip\n\n因为微信群人数有限制，加微信群要求：\n\n- 通过[赞助](../sponsor/personal.md)任意金额。\n- 发送赞助`截图`，备注`加入微信群`即可。\n\n:::\n\n<img src=\"https://unpkg.com/@vbenjs/static-source@0.1.7/source/wechat.jpg\" style=\"width: 300px;\"/>\n"
  },
  {
    "path": "hiauth-front/docs/src/commercial/customized.md",
    "content": "# 定制开发\n\n我们提供基于 Vben Admin 的技术支持服务及定制开发，基本需求我们都可以满足。\n\n详细需求可添加作者了解，并注明来意：\n\n- 通过邮箱联系开发者： [ann.vben@gmail.com](mailto:ann.vben@gmail.com)\n- 通过微信联系开发者：\n\n <img src=\"https://unpkg.com/@vbenjs/static-source@0.1.7/source/wechat.jpg\" style=\"width: 300px;\"/>\n\n我们会在第一时间回复您，定制费用根据需求而定。\n"
  },
  {
    "path": "hiauth-front/docs/src/commercial/technical-support.md",
    "content": "# 技术支持\n\n## 问题反馈\n\n在使用项目的过程中，如果遇到问题，你可以先详细阅读本文档，未找到解决方案时，可以通过以下方式获取技术支持：\n\n- 通过 [GitHub Issues](https://github.com/vbenjs/vue-vben-admin/issues)\n- 通过 [GitHub Discussions](https://github.com/vbenjs/vue-vben-admin/discussions)\n"
  },
  {
    "path": "hiauth-front/docs/src/components/common-ui/vben-alert.md",
    "content": "---\noutline: deep\n---\n\n# Vben Alert 轻量提示框\n\n框架提供的一些用于轻量提示的弹窗，仅使用js代码即可快速动态创建提示而不需要在template写任何代码。\n\n::: info 应用场景\n\nAlert提供的功能与Modal类似，但只适用于简单应用场景。例如临时性、动态地弹出模态确认框、输入框等。如果对弹窗有更复杂的需求，请使用VbenModal\n\n:::\n\n::: tip 注意\n\nAlert提供的快捷方法alert、confirm、prompt动态创建的弹窗在已打开的情况下，不支持HMR（热更新），代码变更后需要关闭这些弹窗后重新打开。\n\n:::\n\n::: tip README\n\n下方示例代码中的，存在一些主题色未适配、样式缺失的问题，这些问题只在文档内会出现，实际使用并不会有这些问题，可忽略，不必纠结。\n\n:::\n\n## 基础用法\n\n使用 `alert` 创建只有一个确认按钮的提示框。\n\n<DemoPreview dir=\"demos/vben-alert/alert\" />\n\n使用 `confirm` 创建有确认和取消按钮的提示框。\n\n<DemoPreview dir=\"demos/vben-alert/confirm\" />\n\n使用 `prompt` 创建有确认和取消按钮、接受用户输入的提示框。\n\n<DemoPreview dir=\"demos/vben-alert/prompt\" />\n\n## useAlertContext\n\n当弹窗的content、footer、icon使用自定义组件时，在这些组件中可以使用 `useAlertContext` 获取当前弹窗的上下文对象，用来主动控制弹窗。\n\n::: tip 注意\n\n`useAlertContext`只能用在setup或者函数式组件中。\n\n:::\n\n### Methods\n\n| 方法      | 描述               | 类型     | 版本要求 |\n| --------- | ------------------ | -------- | -------- |\n| doConfirm | 调用弹窗的确认操作 | ()=>void | >5.5.4   |\n| doCancel  | 调用弹窗的取消操作 | ()=>void | >5.5.4   |\n\n## 类型说明\n\n```ts\n/** 预置的图标类型 */\nexport type IconType = 'error' | 'info' | 'question' | 'success' | 'warning';\n\nexport type BeforeCloseScope = {\n  /** 是否为点击确认按钮触发的关闭 */\n  isConfirm: boolean;\n};\n\n/**\n * alert 属性\n */\nexport type AlertProps = {\n  /** 关闭前的回调，如果返回false，则终止关闭 */\n  beforeClose?: (\n    scope: BeforeCloseScope,\n  ) => boolean | Promise<boolean | undefined> | undefined;\n  /** 边框 */\n  bordered?: boolean;\n  /** 按钮对齐方式 */\n  buttonAlign?: 'center' | 'end' | 'start';\n  /** 取消按钮的标题 */\n  cancelText?: string;\n  /** 是否居中显示 */\n  centered?: boolean;\n  /** 确认按钮的标题 */\n  confirmText?: string;\n  /** 弹窗容器的额外样式 */\n  containerClass?: string;\n  /** 弹窗提示内容 */\n  content: Component | string;\n  /** 弹窗内容的额外样式 */\n  contentClass?: string;\n  /** 执行beforeClose回调期间，在内容区域显示一个loading遮罩*/\n  contentMasking?: boolean;\n  /** 弹窗底部内容（与按钮在同一个容器中） */\n  footer?: Component | string;\n  /** 弹窗的图标（在标题的前面） */\n  icon?: Component | IconType;\n  /**\n   * 弹窗遮罩模糊效果\n   */\n  overlayBlur?: number;\n  /** 是否显示取消按钮 */\n  showCancel?: boolean;\n  /** 弹窗标题 */\n  title?: string;\n};\n\n/** prompt 属性 */\nexport type PromptProps<T = any> = {\n  /** 关闭前的回调，如果返回false，则终止关闭 */\n  beforeClose?: (scope: {\n    isConfirm: boolean;\n    value: T | undefined;\n  }) => boolean | Promise<boolean | undefined> | undefined;\n  /** 用于接受用户输入的组件 */\n  component?: Component;\n  /** 输入组件的属性 */\n  componentProps?: Recordable<any>;\n  /** 输入组件的插槽 */\n  componentSlots?: Recordable<Component>;\n  /** 默认值 */\n  defaultValue?: T;\n  /** 输入组件的值属性名 */\n  modelPropName?: string;\n} & Omit<AlertProps, 'beforeClose'>;\n\n/**\n * 函数签名\n * alert和confirm的函数签名相同。\n * confirm默认会显示取消按钮，而alert默认只有一个按钮\n *  */\nexport function alert(options: AlertProps): Promise<void>;\nexport function alert(\n  message: string,\n  options?: Partial<AlertProps>,\n): Promise<void>;\nexport function alert(\n  message: string,\n  title?: string,\n  options?: Partial<AlertProps>,\n): Promise<void>;\n\n/**\n * 弹出输入框的函数签名。\n * beforeClose的参数会传入用户当前输入的值\n * component指定接受用户输入的组件，默认为Input\n * componentProps 为输入组件设置的属性数据\n * defaultValue 默认的值\n * modelPropName 输入组件的值属性名称。默认为modelValue\n */\nexport async function prompt<T = any>(\n  options: Omit<AlertProps, 'beforeClose'> & {\n    beforeClose?: (\n      scope: BeforeCloseScope & {\n        /** 输入组件的当前值 */\n        value: T;\n      },\n    ) => boolean | Promise<boolean | undefined> | undefined;\n    component?: Component;\n    componentProps?: Recordable<any>;\n    defaultValue?: T;\n    modelPropName?: string;\n  },\n): Promise<T | undefined>;\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/components/common-ui/vben-api-component.md",
    "content": "---\noutline: deep\n---\n\n# Vben ApiComponent Api组件包装器\n\n框架提供的API“包装器”，它一般不独立使用，主要用于包装其它组件，为目标组件提供自动获取远程数据的能力，但仍然保持了目标组件的原始用法。\n\n::: info 写在前面\n\n我们在各个应用的组件适配器中，使用ApiComponent包装了Select、TreeSelect组件，使得这些组件可以自动获取远程数据并生成选项。其它类似的组件（比如Cascader）如有需要也可以参考示例代码自行进行包装。\n\n:::\n\n## 基础用法\n\n通过 `component` 传入其它组件的定义，并配置相关的其它属性（主要是一些名称映射）。包装组件将通过`api`获取数据（`beforerFetch`、`afterFetch`将分别在`api`运行前、运行后被调用），使用`resultField`从中提取数组，使用`valueField`、`labelField`等来从数据中提取value和label（如果提供了`childrenField`，会将其作为树形结构递归处理每一级数据），之后将处理好的数据通过`optionsPropName`指定的属性传递给目标组件。\n\n::: details 包装级联选择器,点击下拉时开始加载远程数据\n\n```vue\n<script lang=\"ts\" setup>\nimport { ApiComponent } from '@vben/common-ui';\n\nimport { Cascader } from 'ant-design-vue';\n\nconst treeData: Record<string, any> = [\n  {\n    label: '浙江',\n    value: 'zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: '杭州',\n        children: [\n          {\n            value: 'xihu',\n            label: '西湖',\n          },\n          {\n            value: 'sudi',\n            label: '苏堤',\n          },\n        ],\n      },\n      {\n        value: 'jiaxing',\n        label: '嘉兴',\n        children: [\n          {\n            value: 'wuzhen',\n            label: '乌镇',\n          },\n          {\n            value: 'meihuazhou',\n            label: '梅花洲',\n          },\n        ],\n      },\n      {\n        value: 'zhoushan',\n        label: '舟山',\n        children: [\n          {\n            value: 'putuoshan',\n            label: '普陀山',\n          },\n          {\n            value: 'taohuadao',\n            label: '桃花岛',\n          },\n        ],\n      },\n    ],\n  },\n  {\n    label: '江苏',\n    value: 'jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: '南京',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: '中华门',\n          },\n          {\n            value: 'zijinshan',\n            label: '紫金山',\n          },\n          {\n            value: 'yuhuatai',\n            label: '雨花台',\n          },\n        ],\n      },\n    ],\n  },\n];\n/**\n * 模拟请求接口\n */\nfunction fetchApi(): Promise<Record<string, any>> {\n  return new Promise((resolve) => {\n    setTimeout(() => {\n      resolve(treeData);\n    }, 1000);\n  });\n}\n</script>\n<template>\n  <ApiComponent\n    :api=\"fetchApi\"\n    :component=\"Cascader\"\n    :immediate=\"false\"\n    children-field=\"children\"\n    loading-slot=\"suffixIcon\"\n    visible-event=\"onDropdownVisibleChange\"\n  />\n</template>\n```\n\n:::\n\n## 并发和缓存\n\n有些场景下可能需要使用多个ApiComponent，它们使用了相同的远程数据源（例如用在可编辑的表格中）。如果直接将请求后端接口的函数传递给api属性，则每一个实例都会访问一次接口，这会造成资源浪费，是完全没有必要的。Tanstack Query提供了并发控制、缓存、重试等诸多特性，我们可以将接口请求函数用useQuery包装一下再传递给ApiComponent，这样的话无论页面有多少个使用相同数据源的ApiComponent实例，都只会发起一次远程请求。演示效果请参考 [Playground vue-query](https://www.vben.pro/#/demos/features/vue-query)，具体代码请查看项目文件[concurrency-caching](https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/views/demos/features/vue-query/concurrency-caching.vue)\n\n## API\n\n### Props\n\n| 属性名 | 描述 | 类型 | 默认值 | 版本要求 |\n| --- | --- | --- | --- | --- |\n| modelValue(v-model) | 当前值 | `any` | - | - |\n| component | 欲包装的组件（以下称为目标组件） | `Component` | - | - |\n| numberToString | 是否将value从数字转为string | `boolean` | `false` | - |\n| api | 获取数据的函数 | `(arg?: any) => Promise<OptionsItem[] \\| Record<string, any>>` | - | - |\n| params | 传递给api的参数 | `Record<string, any>` | - | - |\n| resultField | 从api返回的结果中提取options数组的字段名 | `string` | - | - |\n| labelField | label字段名 | `string` | `label` | - |\n| childrenField | 子级数据字段名，需要层级数据的组件可用 | `string` | `` | - |\n| valueField | value字段名 | `string` | `value` | - |\n| optionsPropName | 目标组件接收options数据的属性名称 | `string` | `options` | - |\n| modelPropName | 目标组件的双向绑定属性名，默认为modelValue。部分组件可能为value | `string` | `modelValue` | - |\n| immediate | 是否立即调用api | `boolean` | `true` | - |\n| alwaysLoad | 每次`visibleEvent`事件发生时都重新请求数据 | `boolean` | `false` | - |\n| beforeFetch | 在api请求之前的回调函数 | `AnyPromiseFunction<any, any>` | - | - |\n| afterFetch | 在api请求之后的回调函数 | `AnyPromiseFunction<any, any>` | - | - |\n| options | 直接传入选项数据，也作为api返回空数据时的后备数据 | `OptionsItem[]` | - | - |\n| visibleEvent | 触发重新请求数据的事件名 | `string` | - | - |\n| loadingSlot | 目标组件的插槽名称，用来显示一个\"加载中\"的图标 | `string` | - | - |\n| autoSelect | 自动设置选项 | `'first' \\| 'last' \\| 'one'\\| ((item: OptionsItem[]) => OptionsItem) \\| false` | `false` | >5.5.4 |\n\n#### autoSelect 自动设置选项\n\n如果当前值为undefined，在选项数据成功加载之后，自动从备选项中选择一个作为当前值。默认值为`false`，即不自动选择选项。注意：该属性不应用于多选组件。可选值有：\n\n- `\"first\"`：自动选择第一个选项\n- `\"last\"`：自动选择最后一个选项\n- `\"one\"`：有且仅有一个选项时，自动选择它\n- `自定义函数`：自定义选择逻辑，函数的参数为options，返回值为选择的选项\n- `false`：不自动选择选项\n\n### Methods\n\n| 方法 | 描述 | 类型 | 版本要求 |\n| --- | --- | --- | --- |\n| getComponentRef | 获取被包装的组件的实例 | ()=>T | >5.5.4 |\n| updateParam | 设置接口请求参数（将与params属性合并） | (newParams: Record<string, any>)=>void | >5.5.4 |\n| getOptions | 获取已加载的选项数据 | ()=>OptionsItem[] | >5.5.4 |\n| getValue | 获取当前值 | ()=>any | >5.5.4 |\n"
  },
  {
    "path": "hiauth-front/docs/src/components/common-ui/vben-count-to-animator.md",
    "content": "---\noutline: deep\n---\n\n# Vben CountToAnimator 数字动画\n\n框架提供的数字动画组件，支持数字动画效果。\n\n> 如果文档内没有参数说明，可以尝试在在线示例内寻找\n\n::: info 写在前面\n\n如果你觉得现有组件的封装不够理想，或者不完全符合你的需求，大可以直接使用原生组件，亦或亲手封装一个适合的组件。框架提供的组件并非束缚，使用与否，完全取决于你的需求与自由。\n\n:::\n\n## 基础用法\n\n通过 `start-val` 和 `end-val`设置数字动画的开始值和结束值， 持续时间`3000`ms。\n\n<DemoPreview dir=\"demos/vben-count-to-animator/basic\" />\n\n## 自定义前缀及分隔符\n\n通过 `prefix` 和 `separator` 设置数字动画的前缀和分隔符。\n\n<DemoPreview dir=\"demos/vben-count-to-animator/custom\" />\n\n### Props\n\n| 属性名     | 描述           | 类型      | 默认值   |\n| ---------- | -------------- | --------- | -------- |\n| startVal   | 起始值         | `number`  | `0`      |\n| endVal     | 结束值         | `number`  | `2021`   |\n| duration   | 动画持续时间   | `number`  | `1500`   |\n| autoplay   | 自动执行       | `boolean` | `true`   |\n| prefix     | 前缀           | `string`  | -        |\n| suffix     | 后缀           | `string`  | -        |\n| separator  | 分隔符         | `string`  | `,`      |\n| color      | 字体颜色       | `string`  | -        |\n| useEasing  | 是否开启动画   | `boolean` | `true`   |\n| transition | 动画效果       | `string`  | `linear` |\n| decimals   | 保留小数点位数 | `number`  | `0`      |\n\n### Events\n\n| 事件名         | 描述           | 类型           |\n| -------------- | -------------- | -------------- |\n| started        | 动画已开始     | `()=>void`     |\n| finished       | 动画已结束     | `()=>void`     |\n| ~~onStarted~~  | ~~动画已开始~~ | ~~`()=>void`~~ |\n| ~~onFinished~~ | ~~动画已结束~~ | ~~`()=>void`~~ |\n\n### Methods\n\n| 方法名 | 描述         | 类型       |\n| ------ | ------------ | ---------- |\n| start  | 开始执行动画 | `()=>void` |\n| reset  | 重置         | `()=>void` |\n"
  },
  {
    "path": "hiauth-front/docs/src/components/common-ui/vben-drawer.md",
    "content": "---\noutline: deep\n---\n\n# Vben Drawer 抽屉\n\n框架提供的抽屉组件，支持`自动高度`、`loading`等功能。\n\n> 如果文档内没有参数说明，可以尝试在在线示例内寻找\n\n::: info 写在前面\n\n如果你觉得现有组件的封装不够理想，或者不完全符合你的需求，大可以直接使用原生组件，亦或亲手封装一个适合的组件。框架提供的组件并非束缚，使用与否，完全取决于你的需求与自由。\n\n:::\n\n::: tip README\n\n下方示例代码中的，存在一些国际化、主题色未适配问题，这些问题只在文档内会出现，实际使用并不会有这些问题，可忽略，不必纠结。\n\n:::\n\n## 基础用法\n\n使用 `useVbenDrawer` 创建最基础的抽屉。\n\n<DemoPreview dir=\"demos/vben-drawer/basic\" />\n\n## 组件抽离\n\nDrawer 内的内容一般业务中，会比较复杂，所以我们可以将 drawer 内的内容抽离出来，也方便复用。通过 `connectedComponent` 参数，可以将内外组件进行连接，而不用其他任何操作。\n\n<DemoPreview dir=\"demos/vben-drawer/extra\" />\n\n## 自动计算高度\n\n弹窗会自动计算内容高度，超过一定高度会出现滚动条，同时结合 `loading` 效果以及使用 `prepend-footer` 插槽。\n\n<DemoPreview dir=\"demos/vben-drawer/auto-height\" />\n\n## 使用 Api\n\n通过 `drawerApi` 可以调用 drawer 的方法以及使用 `setState` 更新 drawer 的状态。\n\n<DemoPreview dir=\"demos/vben-drawer/dynamic\" />\n\n## 数据共享\n\n如果你使用了 `connectedComponent` 参数，那么内外组件会共享数据，比如一些表单回填等操作。可以用 `drawerApi` 来获取数据和设置数据，配合 `onOpenChange`，可以满足大部分的需求。\n\n<DemoPreview dir=\"demos/vben-drawer/shared-data\" />\n\n::: info 注意\n\n- `VbenDrawer` 组件对于参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenDrawer参数)。如果你已经传入了 `slot` 或者 `props`，那么 `setState` 将不会生效，这种情况下你可以通过 `slot` 或者 `props` 来更新状态。\n- 如果你使用到了 `connectedComponent` 参数，那么会存在 2 个`useVbenDrawer`, 此时，如果同时设置了相同的参数，那么以内部为准（也就是没有设置 connectedComponent 的代码）。比如 同时设置了 `onConfirm`，那么以内部的 `onConfirm` 为准。`onOpenChange`事件除外，内外都会触发。\n- 使用了`connectedComponent`参数时，可以配置`destroyOnClose`属性来决定当关闭弹窗时，是否要销毁`connectedComponent`组件（重新创建`connectedComponent`组件，这将会把其内部所有的变量、状态、数据等恢复到初始状态。）。\n- 如果抽屉的默认行为不符合你的预期，可以在`src\\bootstrap.ts`中修改`setDefaultDrawerProps`的参数来设置默认的属性，如默认隐藏全屏按钮，修改默认ZIndex等。\n\n:::\n\n## API\n\n```ts\n// Drawer 为弹窗组件\n// drawerApi 为弹窗的方法\nconst [Drawer, drawerApi] = useVbenDrawer({\n  // 属性\n  // 事件\n});\n```\n\n### Props\n\n所有属性都可以传入 `useVbenDrawer` 的第一个参数中。\n\n| 属性名 | 描述 | 类型 | 默认值 |\n| --- | --- | --- | --- |\n| appendToMain | 是否挂载到内容区域（默认挂载到body） | `boolean` | `false` |\n| connectedComponent | 连接另一个Drawer组件 | `Component` | - |\n| destroyOnClose | 关闭时销毁 | `boolean` | `false` |\n| title | 标题 | `string\\|slot` | - |\n| titleTooltip | 标题提示信息 | `string\\|slot` | - |\n| description | 描述信息 | `string\\|slot` | - |\n| isOpen | 弹窗打开状态 | `boolean` | `false` |\n| loading | 弹窗加载状态 | `boolean` | `false` |\n| closable | 显示关闭按钮 | `boolean` | `true` |\n| closeIconPlacement | 关闭按钮位置 | `'left'\\|'right'` | `right` |\n| modal | 显示遮罩 | `boolean` | `true` |\n| header | 显示header | `boolean` | `true` |\n| footer | 显示footer | `boolean\\|slot` | `true` |\n| confirmLoading | 确认按钮loading状态 | `boolean` | `false` |\n| closeOnClickModal | 点击遮罩关闭弹窗 | `boolean` | `true` |\n| closeOnPressEscape | esc 关闭弹窗 | `boolean` | `true` |\n| confirmText | 确认按钮文本 | `string\\|slot` | `确认` |\n| cancelText | 取消按钮文本 | `string\\|slot` | `取消` |\n| placement | 抽屉弹出位置 | `'left'\\|'right'\\|'top'\\|'bottom'` | `right` |\n| showCancelButton | 显示取消按钮 | `boolean` | `true` |\n| showConfirmButton | 显示确认按钮 | `boolean` | `true` |\n| class | modal的class，宽度通过这个配置 | `string` | - |\n| contentClass | modal内容区域的class | `string` | - |\n| footerClass | modal底部区域的class | `string` | - |\n| headerClass | modal顶部区域的class | `string` | - |\n| zIndex | 抽屉的ZIndex层级 | `number` | `1000` |\n| overlayBlur | 遮罩模糊度 | `number` | - |\n\n::: info appendToMain\n\n`appendToMain`可以指定将抽屉挂载到内容区域，打开抽屉时，内容区域以外的部分（标签栏、导航菜单等等）不会被遮挡。默认情况下，抽屉会挂载到body上。但是：挂载到内容区域时，作为页面根容器的`Page`组件，需要设置`auto-content-height`属性，以便抽屉能够正确计算高度。\n\n:::\n\n### Event\n\n以下事件，只有在 `useVbenDrawer({onCancel:()=>{}})` 中传入才会生效。\n\n| 事件名 | 描述 | 类型 | 版本限制 |\n| --- | --- | --- | --- |\n| onBeforeClose | 关闭前触发，返回 `false`则禁止关闭 | `()=>boolean` | --- |\n| onCancel | 点击取消按钮触发 | `()=>void` | --- |\n| onClosed | 关闭动画播放完毕时触发 | `()=>void` | >5.5.2 |\n| onConfirm | 点击确认按钮触发 | `()=>void` | --- |\n| onOpenChange | 关闭或者打开弹窗时触发 | `(isOpen:boolean)=>void` | --- |\n| onOpened | 打开动画播放完毕时触发 | `()=>void` | >5.5.2 |\n\n### Slots\n\n除了上面的属性类型包含`slot`，还可以通过插槽来自定义弹窗的内容。\n\n| 插槽名         | 描述                                               |\n| -------------- | -------------------------------------------------- |\n| default        | 默认插槽 - 弹窗内容                                |\n| prepend-footer | 取消按钮左侧                                       |\n| center-footer  | 取消按钮和确认按钮中间（不使用 footer 插槽时有效） |\n| append-footer  | 确认按钮右侧                                       |\n| close-icon     | 关闭按钮图标                                       |\n| extra          | 额外内容(标题右侧)                                 |\n\n### drawerApi\n\n| 方法 | 描述 | 类型 | 版本限制 |\n| --- | --- | --- | --- |\n| setState | 动态设置弹窗状态属性 | `(((prev: ModalState) => Partial<ModalState>)\\| Partial<ModalState>)=>drawerApi` |\n| open | 打开弹窗 | `()=>void` | --- |\n| close | 关闭弹窗 | `()=>void` | --- |\n| setData | 设置共享数据 | `<T>(data:T)=>drawerApi` | --- |\n| getData | 获取共享数据 | `<T>()=>T` | --- |\n| useStore | 获取可响应式状态 | - | --- |\n| lock | 将抽屉标记为提交中，锁定当前状态 | `(isLock:boolean)=>drawerApi` | >5.5.3 |\n| unlock | lock方法的反操作，解除抽屉的锁定状态，也是lock(false)的别名 | `()=>drawerApi` | >5.5.3 |\n\n::: info lock\n\n`lock`方法用于锁定抽屉的状态，一般用于提交数据的过程中防止用户重复提交或者抽屉被意外关闭、表单数据被改变等等。当处于锁定状态时，抽屉的确认按钮会变为loading状态，同时禁用取消按钮和关闭按钮、禁止ESC或者点击遮罩等方式关闭抽屉、开启抽屉的spinner动画以遮挡弹窗内容。调用`close`方法关闭处于锁定状态的抽屉时，会自动解锁。要主动解除这种状态，可以调用`unlock`方法或者再次调用lock方法并传入false参数。\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/components/common-ui/vben-ellipsis-text.md",
    "content": "---\noutline: deep\n---\n\n# Vben EllipsisText 省略文本\n\n框架提供的文本展示组件，可配置超长省略、tooltip提示、展开收起等功能。\n\n> 如果文档内没有参数说明，可以尝试在在线示例内寻找\n\n## 基础用法\n\n通过默认插槽设置文本内容，`maxWidth`属性设置最大宽度。\n\n<DemoPreview dir=\"demos/vben-ellipsis-text/line\" />\n\n## 可折叠的文本块\n\n通过`line`设置折叠后的行数，`expand`属性设置是否支持展开收起。\n\n<DemoPreview dir=\"demos/vben-ellipsis-text/expand\" />\n\n## 自定义提示浮层\n\n通过名为`tooltip`的插槽定制提示信息。\n\n<DemoPreview dir=\"demos/vben-ellipsis-text/tooltip\" />\n\n## 自动显示 tooltip\n\n通过`tooltip-when-ellipsis`设置，仅在文本长度超出导致省略号出现时才触发 tooltip。\n\n<DemoPreview dir=\"demos/vben-ellipsis-text/auto-display\" />\n\n## API\n\n### Props\n\n| 属性名 | 描述 | 类型 | 默认值 |\n| --- | --- | --- | --- |\n| expand | 支持点击展开或收起 | `boolean` | `false` |\n| line | 文本最大行数 | `number` | `1` |\n| maxWidth | 文本区域最大宽度 | `number \\| string` | `'100%'` |\n| placement | 提示浮层的位置 | `'bottom'\\|'left'\\|'right'\\|'top'` | `'top'` |\n| tooltip | 启用文本提示 | `boolean` | `true` |\n| tooltipWhenEllipsis | 内容超出，自动启用文本提示 | `boolean` | `false` |\n| ellipsisThreshold | 设置 tooltipWhenEllipsis 后才生效，文本截断检测的像素差异阈值，越大则判断越严格，如果碰见异常情况可以自己设置阈值 | `number` | `3` |\n| tooltipBackgroundColor | 提示文本的背景颜色 | `string` | - |\n| tooltipColor | 提示文本的颜色 | `string` | - |\n| tooltipFontSize | 提示文本的大小 | `string` | - |\n| tooltipMaxWidth | 提示浮层的最大宽度。如不设置则保持与文本宽度一致 | `number` | - |\n| tooltipOverlayStyle | 提示框内容区域样式 | `CSSProperties` | `{ textAlign: 'justify' }` |\n\n### Events\n\n| 事件名       | 描述         | 类型                       |\n| ------------ | ------------ | -------------------------- |\n| expandChange | 展开状态改变 | `(isExpand:boolean)=>void` |\n\n### Slots\n\n| 插槽名  | 描述                             |\n| ------- | -------------------------------- |\n| tooltip | 启用文本提示时，用来定制提示内容 |\n"
  },
  {
    "path": "hiauth-front/docs/src/components/common-ui/vben-form.md",
    "content": "---\noutline: deep\n---\n\n# Vben Form 表单\n\n框架提供的表单组件，可适配 `Element Plus`、`Ant Design Vue`、`Naive UI` 等框架。\n\n> 如果文档内没有参数说明，可以尝试在在线示例内寻找\n\n::: info 写在前面\n\n如果你觉得现有组件的封装不够理想，或者不完全符合你的需求，大可以直接使用原生组件，亦或亲手封装一个适合的组件。框架提供的组件并非束缚，使用与否，完全取决于你的需求与自由。\n\n:::\n\n## 适配器\n\n表单底层使用 [vee-validate](https://vee-validate.logaretm.com/v4/) 进行表单验证，所以你可以使用 `vee-validate` 的所有功能。对于不同的 UI 框架，我们提供了适配器，以便更好的适配不同的 UI 框架。\n\n### 适配器说明\n\n每个应用都有不同的 UI 框架，所以在应用的 `src/adapter/form` 和 `src/adapter/component` 内部，你可以根据自己的需求，进行组件适配。下面是 `Ant Design Vue` 的适配器示例代码，可根据注释查看说明：\n\n::: details ant design vue 表单适配器\n\n```ts\nimport type {\n  VbenFormSchema as FormSchema,\n  VbenFormProps,\n} from '@vben/common-ui';\n\nimport type { ComponentType } from './component';\n\nimport { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nsetupVbenForm<ComponentType>({\n  config: {\n    // ant design vue组件库默认都是 v-model:value\n    baseModelPropName: 'value',\n    // 一些组件是 v-model:checked 或者 v-model:fileList\n    modelPropNameMap: {\n      Checkbox: 'checked',\n      Radio: 'checked',\n      Switch: 'checked',\n      Upload: 'fileList',\n    },\n  },\n  defineRules: {\n    // 输入项目必填国际化适配\n    required: (value, _params, ctx) => {\n      if (value === undefined || value === null || value.length === 0) {\n        return $t('ui.formRules.required', [ctx.label]);\n      }\n      return true;\n    },\n    // 选择项目必填国际化适配\n    selectRequired: (value, _params, ctx) => {\n      if (value === undefined || value === null) {\n        return $t('ui.formRules.selectRequired', [ctx.label]);\n      }\n      return true;\n    },\n  },\n});\n\nconst useVbenForm = useForm<ComponentType>;\n\nexport { useVbenForm, z };\nexport type VbenFormSchema = FormSchema<ComponentType>;\nexport type { VbenFormProps };\n```\n\n:::\n\n::: details ant design vue 组件适配器\n\n```ts\n/**\n * 通用组件共同的使用的基础组件，原先放在 adapter/form 内部，限制了使用范围，这里提取出来，方便其他地方使用\n * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,\n */\n\nimport type { BaseFormComponentType } from '@vben/common-ui';\n\nimport type { Component, SetupContext } from 'vue';\nimport { h } from 'vue';\n\nimport { globalShareState, IconPicker } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nconst AutoComplete = defineAsyncComponent(\n  () => import('ant-design-vue/es/auto-complete'),\n);\nconst Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));\nconst Checkbox = defineAsyncComponent(\n  () => import('ant-design-vue/es/checkbox'),\n);\nconst CheckboxGroup = defineAsyncComponent(() =>\n  import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),\n);\nconst DatePicker = defineAsyncComponent(\n  () => import('ant-design-vue/es/date-picker'),\n);\nconst Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));\nconst Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));\nconst InputNumber = defineAsyncComponent(\n  () => import('ant-design-vue/es/input-number'),\n);\nconst InputPassword = defineAsyncComponent(() =>\n  import('ant-design-vue/es/input').then((res) => res.InputPassword),\n);\nconst Mentions = defineAsyncComponent(\n  () => import('ant-design-vue/es/mentions'),\n);\nconst Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));\nconst RadioGroup = defineAsyncComponent(() =>\n  import('ant-design-vue/es/radio').then((res) => res.RadioGroup),\n);\nconst RangePicker = defineAsyncComponent(() =>\n  import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),\n);\nconst Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));\nconst Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));\nconst Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));\nconst Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));\nconst Textarea = defineAsyncComponent(() =>\n  import('ant-design-vue/es/input').then((res) => res.Textarea),\n);\nconst TimePicker = defineAsyncComponent(\n  () => import('ant-design-vue/es/time-picker'),\n);\nconst TreeSelect = defineAsyncComponent(\n  () => import('ant-design-vue/es/tree-select'),\n);\nconst Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));\n\n\nconst withDefaultPlaceholder = <T extends Component>(\n  component: T,\n  type: 'input' | 'select',\n) => {\n  return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {\n    const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);\n    return h(component, { ...props, ...attrs, placeholder }, slots);\n  };\n};\n\n// 这里需要自行根据业务组件库进行适配，需要用到的组件都需要在这里类型说明\nexport type ComponentType =\n  | 'AutoComplete'\n  | 'Checkbox'\n  | 'CheckboxGroup'\n  | 'DatePicker'\n  | 'DefaultButton'\n  | 'Divider'\n  | 'Input'\n  | 'InputNumber'\n  | 'InputPassword'\n  | 'Mentions'\n  | 'PrimaryButton'\n  | 'Radio'\n  | 'RadioGroup'\n  | 'RangePicker'\n  | 'Rate'\n  | 'Select'\n  | 'Space'\n  | 'Switch'\n  | 'Textarea'\n  | 'TimePicker'\n  | 'TreeSelect'\n  | 'Upload'\n  | 'IconPicker';\n  | BaseFormComponentType;\n\nasync function initComponentAdapter() {\n  const components: Partial<Record<ComponentType, Component>> = {\n    // 如果你的组件体积比较大，可以使用异步加载\n    // Button: () =>\n    // import('xxx').then((res) => res.Button),\n\n    AutoComplete,\n    Checkbox,\n    CheckboxGroup,\n    DatePicker,\n    // 自定义默认按钮\n    DefaultButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'default' }, slots);\n    },\n    Divider,\n    IconPicker,\n    Input: withDefaultPlaceholder(Input, 'input'),\n    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),\n    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),\n    Mentions: withDefaultPlaceholder(Mentions, 'input'),\n    // 自定义主要按钮\n    PrimaryButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'primary' }, slots);\n    },\n    Radio,\n    RadioGroup,\n    RangePicker,\n    Rate,\n    Select: withDefaultPlaceholder(Select, 'select'),\n    Space,\n    Switch,\n    Textarea: withDefaultPlaceholder(Textarea, 'input'),\n    TimePicker,\n    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),\n    Upload,\n  };\n\n  // 将组件注册到全局共享状态中\n  globalShareState.setComponents(components);\n\n  // 定义全局共享状态中的消息提示\n  globalShareState.defineMessage({\n    // 复制成功消息提示\n    copyPreferencesSuccess: (title, content) => {\n      notification.success({\n        description: content,\n        message: title,\n        placement: 'bottomRight',\n      });\n    },\n  });\n}\n\nexport { initComponentAdapter };\n```\n\n:::\n\n## 基础用法\n\n::: tip README\n\n下方示例代码中的，存在一些国际化、主题色未适配问题，这些问题只在文档内会出现，实际使用并不会有这些问题，可忽略，不必纠结。\n\n:::\n\n使用 `useVbenForm` 创建最基础的表单。\n\n<DemoPreview dir=\"demos/vben-form/basic\" />\n\n## 查询表单\n\n查询表单是一种特殊的表单，用于查询数据。查询表单不会触发表单验证，只会触发查询事件。\n\n<DemoPreview dir=\"demos/vben-form/query\" />\n\n## 表单校验\n\n表单校验是一个非常重要的功能，可以通过 `rules` 属性进行校验。\n\n<DemoPreview dir=\"demos/vben-form/rules\" />\n\n## 表单联动\n\n表单联动是一个非常常见的功能，可以通过 `dependencies` 属性进行联动。\n\n_注意_ 需要指定 `dependencies` 的 `triggerFields` 属性，设置由谁的改动来触发，以便表单组件能够正确的联动。\n\n<DemoPreview dir=\"demos/vben-form/dynamic\" />\n\n## 自定义组件\n\n如果你的业务组件库没有提供某个组件，你可以自行封装一个组件，然后加到表单内部。\n\n<DemoPreview dir=\"demos/vben-form/custom\" />\n\n## 操作\n\n一些常见的表单操作。\n\n<DemoPreview dir=\"demos/vben-form/api\" />\n\n## API\n\n`useVbenForm` 返回一个数组，第一个元素是表单组件，第二个元素是表单的方法。\n\n```vue\n<script setup lang=\"ts\">\nimport { useVbenForm } from '#/adapter/form';\n\n// Form 为弹窗组件\n// formApi 为弹窗的方法\nconst [Form, formApi] = useVbenForm({\n  // 属性\n  // 事件\n});\n</script>\n\n<template>\n  <Form />\n</template>\n```\n\n### FormApi\n\nuseVbenForm 返回的第二个参数，是一个对象，包含了一些表单的方法。\n\n| 方法名 | 描述 | 类型 | 版本号 |\n| --- | --- | --- | --- |\n| submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` | - |\n| validateAndSubmitForm | 提交并校验表单 | `(e:Event)=>Promise<Record<string,any>>` | - |\n| resetForm | 重置表单 | `()=>Promise<void>` | - |\n| setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record<string, any>, filterFields?: boolean, shouldValidate?: boolean) => Promise<void>` | - |\n| getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` | - |\n| validate | 表单校验 | `()=>Promise<void>` | - |\n| validateField | 校验指定字段 | `(fieldName: string)=>Promise<ValidationResult<unknown>>` | - |\n| isFieldValid | 检查某个字段是否已通过校验 | `(fieldName: string)=>Promise<boolean>` | - |\n| resetValidate | 重置表单校验 | `()=>Promise<void>` | - |\n| updateSchema | 更新formSchema | `(schema:FormSchema[])=>void` | - |\n| setFieldValue | 设置字段值 | `(field: string, value: any, shouldValidate?: boolean)=>Promise<void>` | - |\n| setState | 设置组件状态（props） | `(stateOrFn:\\| ((prev: VbenFormProps) => Partial<VbenFormProps>)\\| Partial<VbenFormProps>)=>Promise<void>` | - |\n| getState | 获取组件状态（props） | `()=>Promise<VbenFormProps>` | - |\n| form | 表单对象实例，可以操作表单，见 [useForm](https://vee-validate.logaretm.com/v4/api/use-form/) | - | - |\n| getFieldComponentRef | 获取指定字段的组件实例 | `<T=unknown>(fieldName: string)=>T` | >5.5.3 |\n| getFocusedField | 获取当前已获得焦点的字段 | `()=>string\\|undefined` | >5.5.3 |\n\n## Props\n\n所有属性都可以传入 `useVbenForm` 的第一个参数中。\n\n| 属性名 | 描述 | 类型 | 默认值 |\n| --- | --- | --- | --- |\n| layout | 表单项布局 | `'horizontal' \\| 'vertical'\\| 'inline'` | `horizontal` |\n| showCollapseButton | 是否显示折叠按钮 | `boolean` | `false` |\n| wrapperClass | 表单的布局，基于tailwindcss | `any` | - |\n| actionWrapperClass | 表单操作区域class | `any` | - |\n| actionLayout | 表单操作按钮位置 | `'newLine' \\| 'rowEnd' \\| 'inline'` | `rowEnd` |\n| actionPosition | 表单操作按钮对齐方式 | `'left' \\| 'center' \\| 'right'` | `right` |\n| handleReset | 表单重置回调 | `(values: Record<string, any>,) => Promise<void> \\| void` | - |\n| handleSubmit | 表单提交回调 | `(values: Record<string, any>,) => Promise<void> \\| void` | - |\n| handleValuesChange | 表单值变化回调 | `(values: Record<string, any>, fieldsChanged: string[]) => void` | - |\n| actionButtonsReverse | 调换操作按钮位置 | `boolean` | `false` |\n| resetButtonOptions | 重置按钮组件参数 | `ActionButtonOptions` | - |\n| submitButtonOptions | 提交按钮组件参数 | `ActionButtonOptions` | - |\n| showDefaultActions | 是否显示默认操作按钮 | `boolean` | `true` |\n| collapsed | 是否折叠，在`showCollapseButton`为`true`时生效 | `boolean` | `false` |\n| collapseTriggerResize | 折叠时，触发`resize`事件 | `boolean` | `false` |\n| collapsedRows | 折叠时保持的行数 | `number` | `1` |\n| fieldMappingTime | 用于将表单内的数组值映射成 2 个字段 | `[string, [string, string],Nullable<string>\\|[string,string]\\|((any,string)=>any)?][]` | - |\n| commonConfig | 表单项的通用配置，每个配置都会传递到每个表单项，表单项可覆盖 | `FormCommonConfig` | - |\n| schema | 表单项的每一项配置 | `FormSchema[]` | - |\n| submitOnEnter | 按下回车健时提交表单 | `boolean` | false |\n| submitOnChange | 字段值改变时提交表单(内部防抖，这个属性一般用于表格的搜索表单) | `boolean` | false |\n| compact | 是否紧凑模式(忽略为校验信息所预留的空间) | `boolean` | false |\n| scrollToFirstError | 表单验证失败时是否自动滚动到第一个错误字段 | `boolean` | false |\n\n::: tip handleValuesChange\n\n`handleValuesChange` 回调函数的第一个参数`values`装载了表单改变后的当前值对象，第二个参数`fieldsChanged`是一个数组，包含了所有被改变的字段名。注意：第二个参数仅在v5.5.4(不含)以上版本可用，并且传递的是已在schema中定义的字段名。如果你使用了字段映射并且需要检查是哪些字段发生了变化的话，请注意该参数并不会包含映射后的字段名。\n\n:::\n\n::: tip fieldMappingTime\n\n此属性用于将表单内的数组值映射成 2 个字段，它应当传入一个数组，数组的每一项是一个映射规则，规则的第一个成员是一个字符串，表示需要映射的字段名，第二个成员是一个数组，表示映射后的字段名，第三个成员是一个可选的格式掩码，用于格式化日期时间字段；也可以提供一个格式化函数（参数分别为当前值和当前字段名，返回格式化后的值）。如果明确地将格式掩码设为null，则原值映射而不进行格式化（适用于非日期时间字段）。例如：`[['timeRange', ['startTime', 'endTime'], 'YYYY-MM-DD']]`，`timeRange`应当是一个至少具有2个成员的数组类型的值。Form会将`timeRange`的值前两个值分别按照格式掩码`YYYY-MM-DD`格式化后映射到`startTime`和`endTime`字段上。每一项的第三个参数是一个可选的格式掩码，\n\n:::\n\n### TS 类型说明\n\n::: details ActionButtonOptions\n\n```ts\nexport interface ActionButtonOptions {\n  /** 样式 */\n  class?: ClassType;\n  /** 是否禁用 */\n  disabled?: boolean;\n  /** 是否加载中 */\n  loading?: boolean;\n  /** 按钮大小 */\n  size?: ButtonVariantSize;\n  /** 按钮类型 */\n  variant?: ButtonVariants;\n  /** 是否显示 */\n  show?: boolean;\n  /** 按钮文本 */\n  content?: string;\n  /** 任意属性 */\n  [key: string]: any;\n}\n```\n\n:::\n\n::: details FormCommonConfig\n\n```ts\nexport interface FormCommonConfig {\n  /**\n   * 所有表单项的props\n   */\n  componentProps?: ComponentProps;\n  /**\n   * 所有表单项的控件样式\n   */\n  controlClass?: string;\n  /**\n   * 在表单项的Label后显示一个冒号\n   */\n  colon?: boolean;\n  /**\n   * 所有表单项的禁用状态\n   * @default false\n   */\n  disabled?: boolean;\n  /**\n   * 所有表单项的控件样式\n   * @default {}\n   */\n  formFieldProps?: Partial<typeof Field>;\n  /**\n   * 所有表单项的栅格布局\n   * @default \"\"\n   */\n  formItemClass?: (() => string) | string;\n  /**\n   * 隐藏所有表单项label\n   * @default false\n   */\n  hideLabel?: boolean;\n  /**\n   * 是否隐藏必填标记\n   * @default false\n   */\n  hideRequiredMark?: boolean;\n  /**\n   * 所有表单项的label样式\n   * @default \"\"\n   */\n  labelClass?: string;\n  /**\n   * 所有表单项的label宽度\n   */\n  labelWidth?: number;\n  /**\n   * 所有表单项的model属性名。使用自定义组件时可通过此配置指定组件的model属性名。已经在modelPropNameMap中注册的组件不受此配置影响\n   * @default \"modelValue\"\n   */\n  modelPropName?: string;\n  /**\n   * 所有表单项的wrapper样式\n   */\n  wrapperClass?: string;\n}\n```\n\n:::\n\n::: details FormSchema\n\n```ts\nexport interface FormSchema<\n  T extends BaseFormComponentType = BaseFormComponentType,\n> extends FormCommonConfig {\n  /** 组件 */\n  component: Component | T;\n  /** 组件参数 */\n  componentProps?: ComponentProps;\n  /** 默认值 */\n  defaultValue?: any;\n  /** 依赖 */\n  dependencies?: FormItemDependencies;\n  /** 描述 */\n  description?: string;\n  /** 字段名，也作为自定义插槽的名称 */\n  fieldName: string;\n  /** 帮助信息 */\n  help?: CustomRenderType;\n  /** 是否隐藏表单项 */\n  hide?: boolean;\n  /** 表单的标签（如果是一个string，会用于默认必选规则的消息提示） */\n  label?: CustomRenderType;\n  /** 自定义组件内部渲染  */\n  renderComponentContent?: RenderComponentContentType;\n  /** 字段规则 */\n  rules?: FormSchemaRuleType;\n  /** 后缀 */\n  suffix?: CustomRenderType;\n}\n```\n\n:::\n\n### 表单联动\n\n表单联动需要通过 schema 内的 `dependencies` 属性进行联动，允许您添加字段之间的依赖项，以根据其他字段的值控制字段。\n\n```ts\ndependencies: {\n  // 触发字段。只有这些字段值变动时，联动才会触发\n  triggerFields: ['name'],\n  // 动态判断当前字段是否需要显示，不显示则直接销毁\n  if(values,formApi){},\n  // 动态判断当前字段是否需要显示，不显示用css隐藏\n  show(values,formApi){},\n  // 动态判断当前字段是否需要禁用\n  disabled(values,formApi){},\n  // 字段变更时，都会触发该函数\n  trigger(values,formApi){},\n  // 动态rules\n  rules(values,formApi){},\n  // 动态必填\n  required(values,formApi){},\n  // 动态组件参数\n  componentProps(values,formApi){},\n}\n```\n\n### 表单校验\n\n表单校验需要通过 schema 内的 `rules` 属性进行配置。\n\nrules的值可以是字符串（预定义的校验规则名称），也可以是一个zod的schema。\n\n#### 预定义的校验规则\n\n```ts\n// 表示字段必填，默认会根据适配器的required进行国际化\n{\n  rules: 'required';\n}\n\n// 表示字段必填，默认会根据适配器的required进行国际化，用于下拉选择之类\n{\n  rules: 'selectRequired';\n}\n```\n\n#### zod\n\nrules也支持 zod 的 schema，可以进行更复杂的校验，zod 的使用请查看 [zod文档](https://zod.dev/)。\n\n```ts\nimport { z } from '#/adapter/form';\n\n// 基础类型\n{\n  rules: z.string().min(1, { message: '请输入字符串' });\n}\n\n// 可选(可以是undefined)，并且携带默认值。注意zod的optional不包括空字符串''\n{\n  rules: z.string().default('默认值').optional();\n}\n\n// 可以是空字符串、undefined或者一个邮箱地址(两种不同的用法)\n{\n  rules: z.union([z.string().email().optional(), z.literal('')]);\n}\n\n{\n  rules: z.string().email().or(z.literal('')).optional();\n}\n\n// 复杂校验\n{\n  z.string()\n    .min(1, { message: '请输入' })\n    .refine((value) => value === '123', {\n      message: '值必须为123',\n    });\n}\n```\n\n## Slots\n\n可以使用以下插槽在表单中插入自定义的内容\n\n| 插槽名        | 描述               |\n| ------------- | ------------------ |\n| reset-before  | 重置按钮之前的位置 |\n| submit-before | 提交按钮之前的位置 |\n| expand-before | 展开按钮之前的位置 |\n| expand-after  | 展开按钮之后的位置 |\n\n::: tip 字段插槽\n\n除了以上内置插槽之外，`schema`属性中每个字段的`fieldName`都可以作为插槽名称，这些字段插槽的优先级高于`component`定义的组件。也就是说，当提供了与`fieldName`同名的插槽时，这些插槽的内容将会作为这些字段的组件，此时`component`的值将会被忽略。\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/components/common-ui/vben-modal.md",
    "content": "---\noutline: deep\n---\n\n# Vben Modal 模态框\n\n框架提供的模态框组件，支持`拖拽`、`全屏`、`自动高度`、`loading`等功能。\n\n> 如果文档内没有参数说明，可以尝试在在线示例内寻找\n\n::: info 写在前面\n\n如果你觉得现有组件的封装不够理想，或者不完全符合你的需求，大可以直接使用原生组件，亦或亲手封装一个适合的组件。框架提供的组件并非束缚，使用与否，完全取决于你的需求与自由。\n\n:::\n\n::: tip README\n\n下方示例代码中的，存在一些国际化、主题色未适配问题，这些问题只在文档内会出现，实际使用并不会有这些问题，可忽略，不必纠结。\n\n:::\n\n## 基础用法\n\n使用 `useVbenModal` 创建最基础的模态框。\n\n<DemoPreview dir=\"demos/vben-modal/basic\" />\n\n## 组件抽离\n\nModal 内的内容一般业务中，会比较复杂，所以我们可以将 modal 内的内容抽离出来，也方便复用。通过 `connectedComponent` 参数，可以将内外组件进行连接，而不用其他任何操作。\n\n<DemoPreview dir=\"demos/vben-modal/extra\" />\n\n## 开启拖拽\n\n通过 `draggable` 参数，可开启拖拽功能。\n\n<DemoPreview dir=\"demos/vben-modal/draggable\" />\n\n## 自动计算高度\n\n弹窗会自动计算内容高度，超过一定高度会出现滚动条，同时结合 `loading` 效果以及使用 `prepend-footer` 插槽。\n\n<DemoPreview dir=\"demos/vben-modal/auto-height\" />\n\n## 使用 Api\n\n通过 `modalApi` 可以调用 modal 的方法以及使用 `setState` 更新 modal 的状态。\n\n<DemoPreview dir=\"demos/vben-modal/dynamic\" />\n\n## 数据共享\n\n如果你使用了 `connectedComponent` 参数，那么内外组件会共享数据，比如一些表单回填等操作。可以用 `modalApi` 来获取数据和设置数据，配合 `onOpenChange`，可以满足大部分的需求。\n\n<DemoPreview dir=\"demos/vben-modal/shared-data\" />\n\n## 动画类型\n\n通过 `animationType` 属性可以控制弹窗的动画效果：\n\n- `slide`（默认）：从顶部向下滑动进入/退出\n- `scale`：缩放淡入/淡出效果\n\n<DemoPreview dir=\"demos/vben-modal/animation-type\" />\n\n::: info 注意\n\n- `VbenModal` 组件对与参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenModal参数)。如果你已经传入了 `slot` 或者 `props`，那么 `setState` 将不会生效，这种情况下你可以通过 `slot` 或者 `props` 来更新状态。\n- 如果你使用到了 `connectedComponent` 参数，那么会存在 2 个`useVbenModal`, 此时，如果同时设置了相同的参数，那么以内部为准（也就是没有设置 connectedComponent 的代码）。比如 同时设置了 `onConfirm`，那么以内部的 `onConfirm` 为准。`onOpenChange`事件除外，内外都会触发。另外，如果设置了`destroyOnClose`，内部Modal及其子组件会在被关闭后<b>完全销毁</b>。\n- 如果弹窗的默认行为不符合你的预期，可以在`src\\bootstrap.ts`中修改`setDefaultModalProps`的参数来设置默认的属性，如默认隐藏全屏按钮，修改默认ZIndex等。\n\n:::\n\n## API\n\n```ts\n// Modal 为弹窗组件\n// modalApi 为弹窗的方法\nconst [Modal, modalApi] = useVbenModal({\n  // 属性\n  // 事件\n});\n```\n\n### Props\n\n所有属性都可以传入 `useVbenModal` 的第一个参数中。\n\n| 属性名 | 描述 | 类型 | 默认值 |\n| --- | --- | --- | --- |\n| appendToMain | 是否挂载到内容区域（默认挂载到body） | `boolean` | `false` |\n| connectedComponent | 连接另一个Modal组件 | `Component` | - |\n| destroyOnClose | 关闭时销毁 | `boolean` | `false` |\n| title | 标题 | `string\\|slot` | - |\n| titleTooltip | 标题提示信息 | `string\\|slot` | - |\n| description | 描述信息 | `string\\|slot` | - |\n| isOpen | 弹窗打开状态 | `boolean` | `false` |\n| loading | 弹窗加载状态 | `boolean` | `false` |\n| fullscreen | 全屏显示 | `boolean` | `false` |\n| fullscreenButton | 显示全屏按钮 | `boolean` | `true` |\n| draggable | 可拖拽 | `boolean` | `false` |\n| closable | 显示关闭按钮 | `boolean` | `true` |\n| centered | 居中显示 | `boolean` | `false` |\n| modal | 显示遮罩 | `boolean` | `true` |\n| header | 显示header | `boolean` | `true` |\n| footer | 显示footer | `boolean\\|slot` | `true` |\n| confirmDisabled | 禁用确认按钮 | `boolean` | `false` |\n| confirmLoading | 确认按钮loading状态 | `boolean` | `false` |\n| closeOnClickModal | 点击遮罩关闭弹窗 | `boolean` | `true` |\n| closeOnPressEscape | esc 关闭弹窗 | `boolean` | `true` |\n| confirmText | 确认按钮文本 | `string\\|slot` | `确认` |\n| cancelText | 取消按钮文本 | `string\\|slot` | `取消` |\n| showCancelButton | 显示取消按钮 | `boolean` | `true` |\n| showConfirmButton | 显示确认按钮 | `boolean` | `true` |\n| class | modal的class，宽度通过这个配置 | `string` | - |\n| contentClass | modal内容区域的class | `string` | - |\n| footerClass | modal底部区域的class | `string` | - |\n| headerClass | modal顶部区域的class | `string` | - |\n| bordered | 是否显示border | `boolean` | `false` |\n| zIndex | 弹窗的ZIndex层级 | `number` | `1000` |\n| overlayBlur | 遮罩模糊度 | `number` | - |\n| animationType | 动画类型 | `'slide' \\| 'scale'` | `'slide'` |\n| submitting | 标记为提交中，锁定弹窗当前状态 | `boolean` | `false` |\n\n::: info appendToMain\n\n`appendToMain`可以指定将弹窗挂载到内容区域，打开这种弹窗时，内容区域以外的部分（标签栏、导航菜单等等）不会被遮挡。默认情况下，弹窗会挂载到body上。但是：挂载到内容区域时，作为页面根容器的`Page`组件，需要设置`auto-content-height`属性，以便弹窗能够正确计算高度。\n\n:::\n\n### Event\n\n以下事件，只有在 `useVbenModal({onCancel:()=>{}})` 中传入才会生效。\n\n| 事件名 | 描述 | 类型 | 版本号 |\n| --- | --- | --- | --- |\n| onBeforeClose | 关闭前触发，返回 `false`或者被`reject`则禁止关闭 | `()=>Promise<boolean>\\|boolean` | >5.5.2支持Promise |\n| onCancel | 点击取消按钮触发 | `()=>void` |  |\n| onClosed | 关闭动画播放完毕时触发 | `()=>void` | >5.4.3 |\n| onConfirm | 点击确认按钮触发 | `()=>void` |  |\n| onOpenChange | 关闭或者打开弹窗时触发 | `(isOpen:boolean)=>void` |  |\n| onOpened | 打开动画播放完毕时触发 | `()=>void` | >5.4.3 |\n\n### Slots\n\n除了上面的属性类型包含`slot`，还可以通过插槽来自定义弹窗的内容。\n\n| 插槽名         | 描述                                               |\n| -------------- | -------------------------------------------------- |\n| default        | 默认插槽 - 弹窗内容                                |\n| prepend-footer | 取消按钮左侧                                       |\n| center-footer  | 取消按钮和确认按钮中间（不使用 footer 插槽时有效） |\n| append-footer  | 确认按钮右侧                                       |\n\n### modalApi\n\n| 方法 | 描述 | 类型 | 版本 |\n| --- | --- | --- | --- |\n| setState | 动态设置弹窗状态属性 | `(((prev: ModalState) => Partial<ModalState>)\\| Partial<ModalState>)=>modalApi` | - |\n| open | 打开弹窗 | `()=>void` | - |\n| close | 关闭弹窗 | `()=>void` | - |\n| setData | 设置共享数据 | `<T>(data:T)=>modalApi` | - |\n| getData | 获取共享数据 | `<T>()=>T` | - |\n| useStore | 获取可响应式状态 | - | - |\n| lock | 将弹窗标记为提交中，锁定当前状态 | `(isLock:boolean)=>modalApi` | >5.5.2 |\n| unlock | lock方法的反操作，解除弹窗的锁定状态，也是lock(false)的别名 | `()=>modalApi` | >5.5.3 |\n\n::: info lock\n\n`lock`方法用于锁定当前弹窗的状态，一般用于提交数据的过程中防止用户重复提交或者弹窗被意外关闭、表单数据被改变等等。当处于锁定状态时，弹窗的确认按钮会变为loading状态，同时禁用取消按钮和关闭按钮、禁止ESC或者点击遮罩等方式关闭弹窗、开启弹窗的spinner动画以遮挡弹窗内容。调用`close`方法关闭处于锁定状态的弹窗时，会自动解锁。要主动解除这种状态，可以调用`unlock`方法或者再次调用lock方法并传入false参数。\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/components/common-ui/vben-vxe-table.md",
    "content": "---\noutline: deep\n---\n\n# Vben Vxe Table 表格\n\n框架提供的Table 列表组件基于 [vxe-table](https://vxetable.cn/v4/#/grid/api?apiKey=grid)，结合`Vben Form 表单`进行了二次封装。\n\n其中，表头的 **表单搜索** 部分采用了`Vben Form表单`，表格主体部分使用了`vxe-grid`组件，支持表格的分页、排序、筛选等功能。\n\n> 如果文档内没有参数说明，可以尝试在在线示例或者在 [vxe-grid 官方API 文档](https://vxetable.cn/v4/#/grid/api?apiKey=grid) 内寻找\n\n::: info 写在前面\n\n如果你觉得现有组件的封装不够理想，或者不完全符合你的需求，大可以直接使用原生组件，亦或亲手封装一个适合的组件。框架提供的组件并非束缚，使用与否，完全取决于你的需求与自由。\n\n:::\n\n## 适配器\n\n表格底层使用 [vxe-table](https://vxetable.cn/#/start/install) 进行实现，所以你可以使用 `vxe-table` 的所有功能。对于不同的 UI 框架，我们提供了适配器，以便更好的适配不同的 UI 框架。\n\n### 适配器说明\n\n每个应用都可以自己配置`vxe-table`的适配器，你可以根据自己的需求。下面是一个简单的配置示例：\n\n::: details vxe-table 表格适配器\n\n```ts\nimport { h } from 'vue';\n\nimport { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';\n\nimport { Button, Image } from 'ant-design-vue';\n\nimport { useVbenForm } from './form';\n\nsetupVbenVxeTable({\n  configVxeTable: (vxeUI) => {\n    vxeUI.setConfig({\n      grid: {\n        align: 'center',\n        border: false,\n        columnConfig: {\n          resizable: true,\n        },\n        minHeight: 180,\n        formConfig: {\n          // 全局禁用vxe-table的表单配置，使用formOptions\n          enabled: false,\n        },\n        proxyConfig: {\n          autoLoad: true,\n          response: {\n            result: 'items',\n            total: 'total',\n            list: 'items',\n          },\n          showActiveMsg: true,\n          showResponseMsg: false,\n        },\n        round: true,\n        showOverflow: true,\n        size: 'small',\n      },\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellImage' },\n    vxeUI.renderer.add('CellImage', {\n      renderTableDefault(_renderOpts, params) {\n        const { column, row } = params;\n        return h(Image, { src: row[column.field] });\n      },\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellLink' },\n    vxeUI.renderer.add('CellLink', {\n      renderTableDefault(renderOpts) {\n        const { props } = renderOpts;\n        return h(\n          Button,\n          { size: 'small', type: 'link' },\n          { default: () => props?.text },\n        );\n      },\n    });\n\n    // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化\n    // vxeUI.formats.add\n  },\n  useVbenForm,\n});\n\nexport { useVbenVxeGrid };\n\nexport type * from '@vben/plugins/vxe-table';\n```\n\n:::\n\n## 基础表格\n\n使用 `useVbenVxeGrid` 创建最基础的表格。\n\n<DemoPreview dir=\"demos/vben-vxe-table/basic\" />\n\n## 远程加载\n\n通过指定 `proxyConfig.ajax` 的 `query` 方法，可以实现远程加载数据。\n\n<DemoPreview dir=\"demos/vben-vxe-table/remote\" />\n\n## 树形表格\n\n树形表格的数据源为扁平结构，可以指定`treeConfig`配置项，实现树形表格。\n\n```typescript\ntreeConfig: {\n  transform: true, // 指定表格为树形表格\n  parentField: 'parentId', // 父节点字段名\n  rowField: 'id', // 行数据字段名\n},\n```\n\n<DemoPreview dir=\"demos/vben-vxe-table/tree\" />\n\n## 固定表头/列\n\n列固定可选参数： `'left' | 'right' | '' | null`\n\n<DemoPreview dir=\"demos/vben-vxe-table/fixed\" />\n\n## 自定义单元格\n\n自定义单元格有两种实现方式\n\n- 通过 `slots` 插槽\n- 通过 `customCell` 自定义单元格，但是要先添加渲染器\n\n```typescript\n// 表格配置项可以用 cellRender: { name: 'CellImage' },\nvxeUI.renderer.add('CellImage', {\n  renderDefault(_renderOpts, params) {\n    const { column, row } = params;\n    return h(Image, { src: row[column.field] } as any); // 注意此处的Image 组件，来源于Antd，需要自行引入,否则会使用js的Image类\n  },\n});\n\n// 表格配置项可以用 cellRender: { name: 'CellLink' },\nvxeUI.renderer.add('CellLink', {\n  renderDefault(renderOpts) {\n    const { props } = renderOpts;\n    return h(\n      Button,\n      { size: 'small', type: 'link' },\n      { default: () => props?.text },\n    );\n  },\n});\n```\n\n<DemoPreview dir=\"demos/vben-vxe-table/custom-cell\" />\n\n## 搜索表单\n\n**表单搜索** 部分采用了`Vben Form 表单`，参考 [Vben Form 表单文档](/components/common-ui/vben-form)。\n\n当启用了表单搜索时，可以在toolbarConfig中配置`search`为`true`来让表格在工具栏区域显示一个搜索表单控制按钮。表格的所有以`form-`开头的命名插槽都会被传递给搜索表单。\n\n### 定制分隔条\n\n当你启用表单搜索时，在表单和表格之间会显示一个分隔条。这个分隔条使用了默认的组件背景色，并且横向贯穿整个Vben Vxe Table在视觉上融入了页面的默认背景中。如果你在Vben Vxe Table的外层包裹了一个不同背景色的容器（如将其放在一个Card内），默认的表单和表格之间的分隔条可能就显得格格不入了，下面的代码演示了如何定制这个分隔条。\n\n```ts\nconst [Grid] = useVbenVxeGrid({\n  formOptions: {},\n  gridOptions: {},\n  // 完全移除分隔条\n  separator: false,\n  // 你也可以使用下面的代码来移除分隔条\n  // separator: { show: false },\n  // 或者使用下面的代码来改变分隔条的颜色\n  // separator: { backgroundColor: 'rgba(100,100,0,0.5)' },\n});\n```\n\n<DemoPreview dir=\"demos/vben-vxe-table/form\" />\n\n## 单元格编辑\n\n通过指定`editConfig.mode`为`cell`，可以实现单元格编辑。\n\n<DemoPreview dir=\"demos/vben-vxe-table/edit-cell\" />\n\n## 行编辑\n\n通过指定`editConfig.mode`为`row`，可以实现行编辑。\n\n<DemoPreview dir=\"demos/vben-vxe-table/edit-row\" />\n\n## 虚拟滚动\n\n通过 scroll-y.enabled 与 scroll-y.gt 组合开启，其中 enabled 为总开关，gt 是指当总行数大于指定行数时自动开启。\n\n> 参考 [vxe-table 官方文档 - 虚拟滚动](https://vxetable.cn/v4/#/component/grid/scroll/vertical)。\n\n<DemoPreview dir=\"demos/vben-vxe-table/virtual\" />\n\n## API\n\n`useVbenVxeGrid` 返回一个数组，第一个元素是表格组件，第二个元素是表格的方法。\n\n```vue\n<script setup lang=\"ts\">\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\n// Grid 为表格组件\n// gridApi 为表格的方法\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions: {},\n  formOptions: {},\n  gridEvents: {},\n  // 属性\n  // 事件\n});\n</script>\n\n<template>\n  <Grid />\n</template>\n```\n\n### GridApi\n\nuseVbenVxeGrid 返回的第二个参数，是一个对象，包含了一些表单的方法。\n\n| 方法名 | 描述 | 类型 | 说明 |\n| --- | --- | --- | --- |\n| setLoading | 设置loading状态 | `(loading)=>void` | - |\n| setGridOptions | 设置vxe-table grid组件参数 | `(options: Partial<VxeGridProps['gridOptions'])=>void` | - |\n| reload | 重载表格，会进行初始化 | `(params:any)=>void` | - |\n| query | 重载表格，会保留当前分页 | `(params:any)=>void` | - |\n| grid | vxe-table grid实例 | `VxeGridInstance` | - |\n| formApi | vbenForm api实例 | `FormApi` | - |\n| toggleSearchForm | 设置搜索表单显示状态 | `(show?: boolean)=>boolean` | 当省略参数时，则将表单在显示和隐藏两种状态之间切换 |\n\n## Props\n\n所有属性都可以传入 `useVbenVxeGrid` 的第一个参数中。\n\n| 属性名 | 描述 | 类型 | 版本要求 |\n| --- | --- | --- | --- |\n| tableTitle | 表格标题 | `string` | - |\n| tableTitleHelp | 表格标题帮助信息 | `string` | - |\n| gridClass | grid组件的class | `string` | - |\n| gridOptions | grid组件的参数 | `VxeTableGridProps` | - |\n| gridEvents | grid组件的触发的事件 | `VxeGridListeners` | - |\n| formOptions | 表单参数 | `VbenFormProps` | - |\n| showSearchForm | 是否显示搜索表单 | `boolean` | - |\n| separator | 搜索表单与表格主体之间的分隔条 | `boolean\\|SeparatorOptions` | >5.5.4 |\n\n## Slots\n\n大部分插槽的说明请参考 [vxe-table 官方文档](https://vxetable.cn/v4/#/grid/api)，但工具栏部分由于做了一些定制封装，需使用以下插槽定制表格的工具栏：\n\n| 插槽名          | 描述                                         |\n| --------------- | -------------------------------------------- |\n| toolbar-actions | 工具栏左侧部分（表格标题附近）               |\n| toolbar-tools   | 工具栏右侧部分（vxeTable原生工具按钮的左侧） |\n| table-title     | 表格标题插槽                                 |\n\n::: info 搜索表单的插槽\n\n对于使用了搜索表单的表格来说，所有以`form-`开头的命名插槽都会传递给表单。\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/components/introduction.md",
    "content": "# 介绍\n\n::: info README\n\n该文档介绍的是框架组件的使用方法、属性、事件等。如果你觉得现有组件的封装不够理想，或者不完全符合你的需求，大可以直接使用原生组件，亦或亲手封装一个适合的组件。框架提供的组件并非束缚，使用与否，完全取决于你的需求与自由。\n\n:::\n\n## 布局组件\n\n布局组件一般在页面内容区域用作顶层容器组件，提供一些统一的布局样式和基本功能。\n\n## 通用组件\n\n通用组件是一些常用的组件，比如弹窗、抽屉、表单等。大部分基于 `Tailwind CSS` 实现，可适用于不同 UI 组件库的应用。\n"
  },
  {
    "path": "hiauth-front/docs/src/components/layout-ui/page.md",
    "content": "---\noutline: deep\n---\n\n# Page 常规页面组件\n\n提供一个常规页面布局的组件，包括头部、内容区域、底部三个部分。\n\n::: info 写在前面\n\n本组件是一个基本布局组件。如果有更多的通用页面布局需求（比如双列布局等），可以根据实际需求自行封装。\n\n:::\n\n## 基础用法\n\n将`Page`作为你的业务页面的根组件即可。\n\n### Props\n\n| 属性名 | 描述 | 类型 | 默认值 | 说明 |\n| --- | --- | --- | --- | --- |\n| title | 页面标题 | `string\\|slot` | - | - |\n| description | 页面描述（标题下的内容） | `string\\|slot` | - | - |\n| contentClass | 内容区域的class | `string` | - | - |\n| headerClass | 头部区域的class | `string` | - | - |\n| footerClass | 底部区域的class | `string` | - | - |\n| autoContentHeight | 自动调整内容区域的高度 | `boolean` | `false` | - |\n\n::: tip 注意\n\n如果`title`、`description`、`extra`三者均未提供有效内容（通过`props`或者`slots`均可），则页面头部区域不会渲染。\n\n:::\n\n### Slots\n\n| 插槽名称    | 描述         |\n| ----------- | ------------ |\n| default     | 页面内容     |\n| title       | 页面标题     |\n| description | 页面描述     |\n| extra       | 页面头部右侧 |\n| footer      | 页面底部     |\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-alert/alert/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h } from 'vue';\n\nimport { alert, VbenButton } from '@vben/common-ui';\n\nimport { Result } from 'ant-design-vue';\n\nfunction showAlert() {\n  alert('This is an alert message');\n}\n\nfunction showIconAlert() {\n  alert({\n    content: 'This is an alert message with icon',\n    icon: 'success',\n  });\n}\n\nfunction showCustomAlert() {\n  alert({\n    buttonAlign: 'center',\n    content: h(Result, {\n      status: 'success',\n      subTitle: '已成功创建订单。订单ID：2017182818828182881',\n      title: '操作成功',\n    }),\n  });\n}\n</script>\n<template>\n  <div class=\"flex gap-4\">\n    <VbenButton @click=\"showAlert\">Alert</VbenButton>\n    <VbenButton @click=\"showIconAlert\">Alert With Icon</VbenButton>\n    <VbenButton @click=\"showCustomAlert\">Alert With Custom Content</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-alert/confirm/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h, ref } from 'vue';\n\nimport { alert, confirm, VbenButton } from '@vben/common-ui';\n\nimport { Checkbox, message } from 'ant-design-vue';\n\nfunction showConfirm() {\n  confirm('This is an alert message')\n    .then(() => {\n      alert('Confirmed');\n    })\n    .catch(() => {\n      alert('Canceled');\n    });\n}\n\nfunction showIconConfirm() {\n  confirm({\n    content: 'This is an alert message with icon',\n    icon: 'success',\n  });\n}\n\nfunction showfooterConfirm() {\n  const checked = ref(false);\n  confirm({\n    cancelText: '不要虾扯蛋',\n    confirmText: '是的，我们都是NPC',\n    content:\n      '刚才发生的事情，为什么我似乎早就经历过一般？\\n我甚至能在事情发生过程中潜意识里预知到接下来会发生什么。\\n\\n听起来挺玄乎的，你有过这种感觉吗？',\n    footer: () =>\n      h(\n        Checkbox,\n        {\n          checked: checked.value,\n          class: 'flex-1',\n          'onUpdate:checked': (v) => (checked.value = v),\n        },\n        '不再提示',\n      ),\n    icon: 'question',\n    title: '未解之谜',\n  }).then(() => {\n    if (checked.value) {\n      message.success('我不会再拿这个问题烦你了');\n    } else {\n      message.info('下次还要继续问你哟');\n    }\n  });\n}\n\nfunction showAsyncConfirm() {\n  confirm({\n    beforeClose({ isConfirm }) {\n      if (isConfirm) {\n        // 这里可以执行一些异步操作。如果最终返回了false，将阻止关闭弹窗\n        return new Promise((resolve) => setTimeout(resolve, 2000));\n      }\n    },\n    content: 'This is an alert message with async confirm',\n    icon: 'success',\n  }).then(() => {\n    alert('Confirmed');\n  });\n}\n</script>\n<template>\n  <div class=\"flex gap-4\">\n    <VbenButton @click=\"showConfirm\">Confirm</VbenButton>\n    <VbenButton @click=\"showIconConfirm\">Confirm With Icon</VbenButton>\n    <VbenButton @click=\"showfooterConfirm\">Confirm With Footer</VbenButton>\n    <VbenButton @click=\"showAsyncConfirm\">Async Confirm</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-alert/prompt/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h } from 'vue';\n\nimport { alert, prompt, useAlertContext, VbenButton } from '@vben/common-ui';\n\nimport { Input, RadioGroup, Select } from 'ant-design-vue';\nimport { BadgeJapaneseYen } from 'lucide-vue-next';\n\nfunction showPrompt() {\n  prompt({\n    content: '请输入一些东西',\n  })\n    .then((val) => {\n      alert(`已收到你的输入：${val}`);\n    })\n    .catch(() => {\n      alert('Canceled');\n    });\n}\n\nfunction showSlotsPrompt() {\n  prompt({\n    component: () => {\n      // 获取弹窗上下文。注意：只能在setup或者函数式组件中调用\n      const { doConfirm } = useAlertContext();\n      return h(\n        Input,\n        {\n          onKeydown(e: KeyboardEvent) {\n            if (e.key === 'Enter') {\n              e.preventDefault();\n              // 调用弹窗提供的确认方法\n              doConfirm();\n            }\n          },\n          placeholder: '请输入',\n          prefix: '充值金额：',\n          type: 'number',\n        },\n        {\n          addonAfter: () => h(BadgeJapaneseYen),\n        },\n      );\n    },\n    content:\n      '此弹窗演示了如何使用自定义插槽，并且可以使用useAlertContext获取到弹窗的上下文。\\n在输入框中按下回车键会触发确认操作。',\n    icon: 'question',\n    modelPropName: 'value',\n  }).then((val) => {\n    if (val) alert(`你输入的是${val}`);\n  });\n}\n\nfunction showSelectPrompt() {\n  prompt({\n    component: Select,\n    componentProps: {\n      options: [\n        { label: 'Option A', value: 'Option A' },\n        { label: 'Option B', value: 'Option B' },\n        { label: 'Option C', value: 'Option C' },\n      ],\n      placeholder: '请选择',\n      // 弹窗会设置body的pointer-events为none，这回影响下拉框的点击事件\n      popupClassName: 'pointer-events-auto',\n    },\n    content: '此弹窗演示了如何使用component传递自定义组件',\n    icon: 'question',\n    modelPropName: 'value',\n  }).then((val) => {\n    if (val) {\n      alert(`你选择了${val}`);\n    }\n  });\n}\n\nfunction sleep(ms: number) {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction showAsyncPrompt() {\n  prompt({\n    async beforeClose(scope) {\n      if (scope.isConfirm) {\n        if (scope.value) {\n          // 模拟异步操作，如果不成功，可以返回false\n          await sleep(2000);\n        } else {\n          alert('请选择一个选项');\n          return false;\n        }\n      }\n    },\n    component: RadioGroup,\n    componentProps: {\n      class: 'flex flex-col',\n      options: [\n        { label: 'Option 1', value: 'option1' },\n        { label: 'Option 2', value: 'option2' },\n        { label: 'Option 3', value: 'option3' },\n      ],\n    },\n    content: '选择一个选项后再点击[确认]',\n    icon: 'question',\n    modelPropName: 'value',\n  }).then((val) => {\n    alert(`${val} 已设置。`);\n  });\n}\n</script>\n<template>\n  <div class=\"flex gap-4\">\n    <VbenButton @click=\"showPrompt\">Prompt</VbenButton>\n    <VbenButton @click=\"showSlotsPrompt\"> Prompt With slots </VbenButton>\n    <VbenButton @click=\"showSelectPrompt\">Prompt With Select</VbenButton>\n    <VbenButton @click=\"showAsyncPrompt\">Prompt With Async</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-api-component/cascader/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ApiComponent } from '@vben/common-ui';\n\nimport { Cascader } from 'ant-design-vue';\n\nconst treeData: Record<string, any> = [\n  {\n    label: '浙江',\n    value: 'zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: '杭州',\n        children: [\n          {\n            value: 'xihu',\n            label: '西湖',\n          },\n          {\n            value: 'sudi',\n            label: '苏堤',\n          },\n        ],\n      },\n      {\n        value: 'jiaxing',\n        label: '嘉兴',\n        children: [\n          {\n            value: 'wuzhen',\n            label: '乌镇',\n          },\n          {\n            value: 'meihuazhou',\n            label: '梅花洲',\n          },\n        ],\n      },\n      {\n        value: 'zhoushan',\n        label: '舟山',\n        children: [\n          {\n            value: 'putuoshan',\n            label: '普陀山',\n          },\n          {\n            value: 'taohuadao',\n            label: '桃花岛',\n          },\n        ],\n      },\n    ],\n  },\n  {\n    label: '江苏',\n    value: 'jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: '南京',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: '中华门',\n          },\n          {\n            value: 'zijinshan',\n            label: '紫金山',\n          },\n          {\n            value: 'yuhuatai',\n            label: '雨花台',\n          },\n        ],\n      },\n    ],\n  },\n];\n/**\n * 模拟请求接口\n */\nfunction fetchApi(): Promise<Record<string, any>> {\n  return new Promise((resolve) => {\n    setTimeout(() => {\n      resolve(treeData);\n    }, 1000);\n  });\n}\n</script>\n<template>\n  <ApiComponent\n    :api=\"fetchApi\"\n    :component=\"Cascader\"\n    :immediate=\"false\"\n    children-field=\"children\"\n    loading-slot=\"suffixIcon\"\n    visible-event=\"onDropdownVisibleChange\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-count-to-animator/basic/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { VbenCountToAnimator } from '@vben/common-ui';\n</script>\n<template>\n  <VbenCountToAnimator :duration=\"3000\" :end-val=\"30000\" :start-val=\"1\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-count-to-animator/custom/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { VbenCountToAnimator } from '@vben/common-ui';\n</script>\n<template>\n  <VbenCountToAnimator\n    :duration=\"3000\"\n    :end-val=\"2000000\"\n    :start-val=\"1\"\n    prefix=\"$\"\n    separator=\"/\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/auto-height/drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer, VbenButton } from '@vben/common-ui';\n\nconst list = ref<number[]>([]);\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm() {\n    console.log('onConfirm');\n  },\n  onOpenChange(isOpen) {\n    if (isOpen) {\n      handleUpdate(10);\n    }\n  },\n});\n\nfunction handleUpdate(len: number) {\n  drawerApi.setState({ loading: true });\n  setTimeout(() => {\n    list.value = Array.from({ length: len }, (_v, k) => k + 1);\n    drawerApi.setState({ loading: false });\n  }, 2000);\n}\n</script>\n<template>\n  <Drawer title=\"自动计算高度\">\n    <div\n      v-for=\"item in list\"\n      :key=\"item\"\n      class=\"even:bg-heavy bg-muted flex-center h-[220px] w-full\"\n    >\n      {{ item }}\n    </div>\n    <template #prepend-footer>\n      <VbenButton type=\"link\" @click=\"handleUpdate(6)\">\n        点击更新数据\n      </VbenButton>\n    </template>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/auto-height/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer, VbenButton } from '@vben/common-ui';\n\nimport ExtraDrawer from './drawer.vue';\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  // 连接抽离的组件\n  connectedComponent: ExtraDrawer,\n});\n\nfunction open() {\n  drawerApi.open();\n}\n</script>\n\n<template>\n  <div>\n    <Drawer />\n    <VbenButton @click=\"open\">Open</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/basic/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer, VbenButton } from '@vben/common-ui';\n\nconst [Drawer, drawerApi] = useVbenDrawer();\n</script>\n<template>\n  <div>\n    <VbenButton @click=\"() => drawerApi.open()\">Open</VbenButton>\n    <Drawer class=\"w-[600px]\" title=\"基础示例\"> drawer content </Drawer>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/dynamic/drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer, VbenButton } from '@vben/common-ui';\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm() {\n    console.info('onConfirm');\n  },\n  title: '动态修改配置示例',\n});\n\nfunction handleUpdateTitle() {\n  drawerApi.setState({ title: '内部动态标题' });\n}\n</script>\n<template>\n  <Drawer>\n    <div class=\"flex-col-center\">\n      <VbenButton class=\"mb-3\" type=\"primary\" @click=\"handleUpdateTitle()\">\n        内部动态修改标题\n      </VbenButton>\n    </div>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/dynamic/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer, VbenButton } from '@vben/common-ui';\n\nimport ExtraDrawer from './drawer.vue';\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  // 连接抽离的组件\n  connectedComponent: ExtraDrawer,\n});\n\nfunction open() {\n  drawerApi.open();\n}\n\nfunction handleUpdateTitle() {\n  drawerApi.setState({ title: '外部动态标题' }).open();\n}\n</script>\n\n<template>\n  <div>\n    <Drawer />\n\n    <VbenButton @click=\"open\">Open</VbenButton>\n    <VbenButton class=\"ml-2\" type=\"primary\" @click=\"handleUpdateTitle\">\n      从外部修改标题并打开\n    </VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/extra/drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer } from '@vben/common-ui';\n\nconst [Drawer] = useVbenDrawer();\n</script>\n<template>\n  <Drawer title=\"组件抽离示例\"> extra drawer content </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/extra/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer, VbenButton } from '@vben/common-ui';\n\nimport ExtraDrawer from './drawer.vue';\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  // 连接抽离的组件\n  connectedComponent: ExtraDrawer,\n});\n\nfunction open() {\n  drawerApi.open();\n}\n</script>\n\n<template>\n  <div>\n    <Drawer />\n    <VbenButton @click=\"open\">Open</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/shared-data/drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nconst data = ref();\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm() {\n    console.info('onConfirm');\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      data.value = drawerApi.getData<Record<string, any>>();\n    }\n  },\n});\n</script>\n<template>\n  <Drawer title=\"数据共享示例\">\n    <div class=\"flex-col-center\">外部传递数据： {{ data }}</div>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-drawer/shared-data/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer, VbenButton } from '@vben/common-ui';\n\nimport ExtraDrawer from './drawer.vue';\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  // 连接抽离的组件\n  connectedComponent: ExtraDrawer,\n});\n\nfunction open() {\n  drawerApi\n    .setData({\n      content: '外部传递的数据 content',\n      payload: '外部传递的数据 payload',\n    })\n    .open();\n}\n</script>\n\n<template>\n  <div>\n    <Drawer />\n\n    <VbenButton @click=\"open\">Open</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-ellipsis-text/auto-display/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { EllipsisText } from '@vben/common-ui';\n\nconst text = `\nVben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。\n`;\n</script>\n<template>\n  <EllipsisText :line=\"2\" :tooltip-when-ellipsis=\"true\">\n    {{ text }}\n  </EllipsisText>\n\n  <EllipsisText :line=\"3\" :tooltip-when-ellipsis=\"true\">\n    {{ text }}\n  </EllipsisText>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-ellipsis-text/expand/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { EllipsisText } from '@vben/common-ui';\n\nconst text = `\nVben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。\n`;\n</script>\n<template>\n  <EllipsisText :line=\"3\" expand>{{ text }}</EllipsisText>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-ellipsis-text/line/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { EllipsisText } from '@vben/common-ui';\n\nconst text = `\nVben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。\n`;\n</script>\n<template>\n  <EllipsisText :max-width=\"500\">{{ text }}</EllipsisText>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-ellipsis-text/tooltip/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { EllipsisText } from '@vben/common-ui';\n</script>\n<template>\n  <EllipsisText :max-width=\"240\">\n    住在我心里孤独的 孤独的海怪 痛苦之王 开始厌倦 深海的光 停滞的海浪\n    <template #tooltip>\n      <div style=\"text-align: center\">\n        《秦皇岛》<br />住在我心里孤独的<br />孤独的海怪 痛苦之王<br />开始厌倦\n        深海的光 停滞的海浪\n      </div>\n    </template>\n  </EllipsisText>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-form/api/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Button, message, Space } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst [BaseForm, formApi] = useVbenForm({\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 使用 tailwindcss grid布局\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  layout: 'horizontal',\n  // 水平布局，label和input在同一行\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      // 字段名\n      fieldName: 'field1',\n      // 界面显示的label\n      label: 'field1',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      fieldName: 'fieldOptions',\n      label: '下拉选',\n    },\n  ],\n  wrapperClass: 'grid-cols-1 md:grid-cols-2',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n\nfunction handleClick(\n  action:\n    | 'batchAddSchema'\n    | 'batchDeleteSchema'\n    | 'disabled'\n    | 'hiddenAction'\n    | 'hiddenResetButton'\n    | 'hiddenSubmitButton'\n    | 'labelWidth'\n    | 'resetDisabled'\n    | 'resetLabelWidth'\n    | 'showAction'\n    | 'showResetButton'\n    | 'showSubmitButton'\n    | 'updateActionAlign'\n    | 'updateResetButton'\n    | 'updateSchema'\n    | 'updateSubmitButton',\n) {\n  switch (action) {\n    case 'batchAddSchema': {\n      formApi.setState((prev) => {\n        const currentSchema = prev?.schema ?? [];\n        const newSchema = [];\n        for (let i = 0; i < 2; i++) {\n          newSchema.push({\n            component: 'Input',\n            componentProps: {\n              placeholder: '请输入',\n            },\n            fieldName: `field${i}${Date.now()}`,\n            label: `field+`,\n          });\n        }\n        return {\n          schema: [...currentSchema, ...newSchema],\n        };\n      });\n      break;\n    }\n\n    case 'batchDeleteSchema': {\n      formApi.setState((prev) => {\n        const currentSchema = prev?.schema ?? [];\n        return {\n          schema: currentSchema.slice(0, -2),\n        };\n      });\n      break;\n    }\n    case 'disabled': {\n      formApi.setState({ commonConfig: { disabled: true } });\n      break;\n    }\n    case 'hiddenAction': {\n      formApi.setState({ showDefaultActions: false });\n      break;\n    }\n    case 'hiddenResetButton': {\n      formApi.setState({ resetButtonOptions: { show: false } });\n      break;\n    }\n    case 'hiddenSubmitButton': {\n      formApi.setState({ submitButtonOptions: { show: false } });\n      break;\n    }\n    case 'labelWidth': {\n      formApi.setState({\n        commonConfig: {\n          labelWidth: 150,\n        },\n      });\n      break;\n    }\n    case 'resetDisabled': {\n      formApi.setState({ commonConfig: { disabled: false } });\n      break;\n    }\n    case 'resetLabelWidth': {\n      formApi.setState({\n        commonConfig: {\n          labelWidth: 100,\n        },\n      });\n      break;\n    }\n    case 'showAction': {\n      formApi.setState({ showDefaultActions: true });\n      break;\n    }\n    case 'showResetButton': {\n      formApi.setState({ resetButtonOptions: { show: true } });\n      break;\n    }\n    case 'showSubmitButton': {\n      formApi.setState({ submitButtonOptions: { show: true } });\n      break;\n    }\n    case 'updateActionAlign': {\n      formApi.setState({\n        // 可以自行调整class\n        actionWrapperClass: 'text-center',\n      });\n      break;\n    }\n    case 'updateResetButton': {\n      formApi.setState({\n        resetButtonOptions: { disabled: true },\n      });\n      break;\n    }\n    case 'updateSchema': {\n      formApi.updateSchema([\n        {\n          componentProps: {\n            options: [\n              {\n                label: '选项1',\n                value: '1',\n              },\n              {\n                label: '选项2',\n                value: '2',\n              },\n              {\n                label: '选项3',\n                value: '3',\n              },\n            ],\n          },\n          fieldName: 'fieldOptions',\n        },\n      ]);\n      message.success('字段 `fieldOptions` 下拉选项更新成功。');\n      break;\n    }\n    case 'updateSubmitButton': {\n      formApi.setState({\n        submitButtonOptions: { loading: true },\n      });\n      break;\n    }\n  }\n}\n</script>\n\n<template>\n  <div>\n    <Space class=\"mb-5 flex-wrap\">\n      <Button @click=\"handleClick('updateSchema')\">updateSchema</Button>\n      <Button @click=\"handleClick('labelWidth')\">更改labelWidth</Button>\n      <Button @click=\"handleClick('resetLabelWidth')\">还原labelWidth</Button>\n      <Button @click=\"handleClick('disabled')\">禁用表单</Button>\n      <Button @click=\"handleClick('resetDisabled')\">解除禁用</Button>\n      <Button @click=\"handleClick('hiddenAction')\">隐藏操作按钮</Button>\n      <Button @click=\"handleClick('showAction')\">显示操作按钮</Button>\n      <Button @click=\"handleClick('hiddenResetButton')\">隐藏重置按钮</Button>\n      <Button @click=\"handleClick('showResetButton')\">显示重置按钮</Button>\n      <Button @click=\"handleClick('hiddenSubmitButton')\">隐藏提交按钮</Button>\n      <Button @click=\"handleClick('showSubmitButton')\">显示提交按钮</Button>\n      <Button @click=\"handleClick('updateResetButton')\">修改重置按钮</Button>\n      <Button @click=\"handleClick('updateSubmitButton')\">修改提交按钮</Button>\n      <Button @click=\"handleClick('updateActionAlign')\">\n        调整操作按钮位置\n      </Button>\n      <Button @click=\"handleClick('batchAddSchema')\"> 批量添加表单项 </Button>\n      <Button @click=\"handleClick('batchDeleteSchema')\">\n        批量删除表单项\n      </Button>\n    </Space>\n    <BaseForm />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-form/basic/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst [BaseForm] = useVbenForm({\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'horizontal',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      // 字段名\n      fieldName: 'username',\n      // 界面显示的label\n      label: '字符串',\n    },\n    {\n      component: 'InputPassword',\n      componentProps: {\n        placeholder: '请输入密码',\n      },\n      fieldName: 'password',\n      label: '密码',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'number',\n      label: '数字(带后缀)',\n      suffix: () => '¥',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      fieldName: 'options',\n      label: '下拉选',\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n      },\n      fieldName: 'radioGroup',\n      label: '单选组',\n    },\n    {\n      component: 'Radio',\n      fieldName: 'radio',\n      label: '',\n      renderComponentContent: () => {\n        return {\n          default: () => ['Radio'],\n        };\n      },\n    },\n    {\n      component: 'CheckboxGroup',\n      componentProps: {\n        name: 'cname',\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n      },\n      fieldName: 'checkboxGroup',\n      label: '多选组',\n    },\n    {\n      component: 'Checkbox',\n      fieldName: 'checkbox',\n      label: '',\n      renderComponentContent: () => {\n        return {\n          default: () => ['我已阅读并同意'],\n        };\n      },\n    },\n    {\n      component: 'Mentions',\n      componentProps: {\n        options: [\n          {\n            label: 'afc163',\n            value: 'afc163',\n          },\n          {\n            label: 'zombieJ',\n            value: 'zombieJ',\n          },\n        ],\n        placeholder: '请输入',\n      },\n      fieldName: 'mentions',\n      label: '提及',\n    },\n    {\n      component: 'Rate',\n      fieldName: 'rate',\n      label: '评分',\n    },\n    {\n      component: 'Switch',\n      componentProps: {\n        class: 'w-auto',\n      },\n      fieldName: 'switch',\n      label: '开关',\n    },\n    {\n      component: 'DatePicker',\n      fieldName: 'datePicker',\n      label: '日期选择框',\n    },\n    {\n      component: 'RangePicker',\n      fieldName: 'rangePicker',\n      label: '范围选择器',\n    },\n    {\n      component: 'TimePicker',\n      fieldName: 'timePicker',\n      label: '时间选择框',\n    },\n    {\n      component: 'TreeSelect',\n      componentProps: {\n        allowClear: true,\n        placeholder: '请选择',\n        showSearch: true,\n        treeData: [\n          {\n            label: 'root 1',\n            value: 'root 1',\n            children: [\n              {\n                label: 'parent 1',\n                value: 'parent 1',\n                children: [\n                  {\n                    label: 'parent 1-0',\n                    value: 'parent 1-0',\n                    children: [\n                      {\n                        label: 'my leaf',\n                        value: 'leaf1',\n                      },\n                      {\n                        label: 'your leaf',\n                        value: 'leaf2',\n                      },\n                    ],\n                  },\n                  {\n                    label: 'parent 1-1',\n                    value: 'parent 1-1',\n                  },\n                ],\n              },\n              {\n                label: 'parent 2',\n                value: 'parent 2',\n              },\n            ],\n          },\n        ],\n        treeNodeFilterProp: 'label',\n      },\n      fieldName: 'treeSelect',\n      label: '树选择',\n    },\n  ],\n  wrapperClass: 'grid-cols-1',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <BaseForm />\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-form/custom/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h } from 'vue';\n\nimport { Input, message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst [Form] = useVbenForm({\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n    labelClass: 'w-2/6',\n  },\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'horizontal',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      fieldName: 'field',\n      label: '自定义后缀',\n      suffix: () => h('span', { class: 'text-red-600' }, '元'),\n    },\n    {\n      component: 'Input',\n      fieldName: 'field1',\n      label: '自定义组件slot',\n      renderComponentContent: () => ({\n        prefix: () => 'prefix',\n        suffix: () => 'suffix',\n      }),\n    },\n    {\n      component: h(Input, { placeholder: '请输入' }),\n      fieldName: 'field2',\n      label: '自定义组件',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      fieldName: 'field3',\n      label: '自定义组件(slot)',\n      rules: 'required',\n    },\n  ],\n  wrapperClass: 'grid-cols-1',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <Form>\n    <template #field3=\"slotProps\">\n      <Input placeholder=\"请输入\" v-bind=\"slotProps\" />\n    </template>\n  </Form>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-form/dynamic/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst [Form] = useVbenForm({\n  // 提交函数\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      defaultValue: 'hidden value',\n      dependencies: {\n        show: false,\n        // 随意一个字段改变时，都会触发\n        triggerFields: ['field1Switch'],\n      },\n      fieldName: 'hiddenField',\n      label: '隐藏字段',\n    },\n    {\n      component: 'Switch',\n      defaultValue: true,\n      fieldName: 'field1Switch',\n      help: '通过Dom控制销毁',\n      label: '显示字段1',\n    },\n    {\n      component: 'Switch',\n      defaultValue: true,\n      fieldName: 'field2Switch',\n      help: '通过css控制隐藏',\n      label: '显示字段2',\n    },\n    {\n      component: 'Switch',\n      fieldName: 'field3Switch',\n      label: '禁用字段3',\n    },\n    {\n      component: 'Switch',\n      fieldName: 'field4Switch',\n      label: '字段4必填',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        if(values) {\n          return !!values.field1Switch;\n        },\n        // 只有指定的字段改变时，才会触发\n        triggerFields: ['field1Switch'],\n      },\n      // 字段名\n      fieldName: 'field1',\n      // 界面显示的label\n      label: '字段1',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        show(values) {\n          return !!values.field2Switch;\n        },\n        triggerFields: ['field2Switch'],\n      },\n      fieldName: 'field2',\n      label: '字段2',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        disabled(values) {\n          return !!values.field3Switch;\n        },\n        triggerFields: ['field3Switch'],\n      },\n      fieldName: 'field3',\n      label: '字段3',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        required(values) {\n          return !!values.field4Switch;\n        },\n        triggerFields: ['field4Switch'],\n      },\n      fieldName: 'field4',\n      label: '字段4',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        rules(values) {\n          if (values.field1 === '123') {\n            return 'required';\n          }\n          return null;\n        },\n        triggerFields: ['field1'],\n      },\n      fieldName: 'field5',\n      help: '当字段1的值为`123`时，必填',\n      label: '动态rules',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        class: 'w-full',\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      dependencies: {\n        componentProps(values) {\n          if (values.field2 === '123') {\n            return {\n              options: [\n                {\n                  label: '选项1',\n                  value: '1',\n                },\n                {\n                  label: '选项2',\n                  value: '2',\n                },\n                {\n                  label: '选项3',\n                  value: '3',\n                },\n              ],\n            };\n          }\n          return {};\n        },\n        triggerFields: ['field2'],\n      },\n      fieldName: 'field6',\n      help: '当字段2的值为`123`时，更改下拉选项',\n      label: '动态配置',\n    },\n  ],\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <Form />\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-form/query/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst [QueryForm] = useVbenForm({\n  // 默认展开\n  collapsed: false,\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'horizontal',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      // 字段名\n      fieldName: 'username',\n      // 界面显示的label\n      label: '字符串',\n    },\n    {\n      component: 'InputPassword',\n      componentProps: {\n        placeholder: '请输入密码',\n      },\n      fieldName: 'password',\n      label: '密码',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'number',\n      label: '数字(带后缀)',\n      suffix: () => '¥',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      fieldName: 'options',\n      label: '下拉选',\n    },\n    {\n      component: 'DatePicker',\n      fieldName: 'datePicker',\n      label: '日期选择框',\n    },\n  ],\n  // 是否可展开\n  showCollapseButton: true,\n  submitButtonOptions: {\n    content: '查询',\n  },\n  wrapperClass: 'grid-cols-1 md:grid-cols-2',\n});\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <QueryForm />\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-form/rules/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { message } from 'ant-design-vue';\n\nimport { useVbenForm, z } from '#/adapter/form';\n\nconst [Form] = useVbenForm({\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  scrollToFirstError: true,\n  layout: 'horizontal',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入',\n      },\n      // 字段名\n      fieldName: 'field1',\n      // 界面显示的label\n      label: '字段1',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      defaultValue: '默认值',\n      fieldName: 'field2',\n      label: '默认值(必填)',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field3',\n      label: '默认值(非必填)',\n      rules: z.string().default('默认值').optional(),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field31',\n      label: '自定义信息',\n      rules: z.string().min(1, { message: '最少输入1个字符' }),\n    },\n    {\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入',\n      },\n      // 字段名\n      fieldName: 'field4',\n      // 界面显示的label\n      label: '邮箱',\n      rules: z.string().email('请输入正确的邮箱'),\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'number',\n      label: '数字',\n      rules: 'required',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      defaultValue: undefined,\n      fieldName: 'options',\n      label: '下拉选',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n      },\n      fieldName: 'radioGroup',\n      label: '单选组',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'CheckboxGroup',\n      componentProps: {\n        name: 'cname',\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n      },\n      fieldName: 'checkboxGroup',\n      label: '多选组',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'Checkbox',\n      fieldName: 'checkbox',\n      label: '',\n      renderComponentContent: () => {\n        return {\n          default: () => ['我已阅读并同意'],\n        };\n      },\n      rules: 'selectRequired',\n    },\n    {\n      component: 'DatePicker',\n      defaultValue: undefined,\n      fieldName: 'datePicker',\n      label: '日期选择框',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'RangePicker',\n      defaultValue: undefined,\n      fieldName: 'rangePicker',\n      label: '区间选择框',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'InputPassword',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'password',\n      label: '密码',\n      rules: 'required',\n    },\n  ],\n  wrapperClass: 'grid-cols-1',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <Form />\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/animation-type/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nconst [SlideModal, slideModalApi] = useVbenModal({\n  animationType: 'slide',\n});\n\nconst [ScaleModal, scaleModalApi] = useVbenModal({\n  animationType: 'scale',\n});\n\nfunction openSlideModal() {\n  slideModalApi.open();\n}\n\nfunction openScaleModal() {\n  scaleModalApi.open();\n}\n</script>\n\n<template>\n  <div class=\"space-y-4\">\n    <div class=\"flex gap-4\">\n      <VbenButton @click=\"openSlideModal\">滑动动画</VbenButton>\n      <VbenButton @click=\"openScaleModal\">缩放动画</VbenButton>\n    </div>\n\n    <SlideModal title=\"滑动动画示例\" class=\"w-[500px]\">\n      <p>这是使用滑动动画的弹窗，从顶部向下滑动进入。</p>\n    </SlideModal>\n\n    <ScaleModal title=\"缩放动画示例\" class=\"w-[500px]\">\n      <p>这是使用缩放动画的弹窗，以缩放淡入淡出的方式显示。</p>\n    </ScaleModal>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/auto-height/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nimport ExtraModal from './modal.vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: ExtraModal,\n});\n\nfunction openModal() {\n  modalApi.open();\n}\n</script>\n\n<template>\n  <div>\n    <Modal />\n    <VbenButton @click=\"openModal\">Open</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/auto-height/modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nconst list = ref<number[]>([]);\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm() {\n    console.log('onConfirm');\n  },\n  onOpenChange(isOpen) {\n    if (isOpen) {\n      handleUpdate(10);\n    }\n  },\n});\n\nfunction handleUpdate(len: number) {\n  modalApi.setState({ loading: true });\n  setTimeout(() => {\n    list.value = Array.from({ length: len }, (_v, k) => k + 1);\n    modalApi.setState({ loading: false });\n  }, 2000);\n}\n</script>\n<template>\n  <Modal title=\"自动计算高度\">\n    <div\n      v-for=\"item in list\"\n      :key=\"item\"\n      class=\"even:bg-heavy bg-muted flex-center h-[220px] w-full\"\n    >\n      {{ item }}\n    </div>\n    <template #prepend-footer>\n      <VbenButton type=\"link\" @click=\"handleUpdate(6)\">\n        点击更新数据\n      </VbenButton>\n    </template>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/basic/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nconst [Modal, modalApi] = useVbenModal();\n</script>\n<template>\n  <div>\n    <VbenButton @click=\"() => modalApi.open()\">Open</VbenButton>\n    <Modal class=\"w-[600px]\" title=\"基础示例\"> modal content </Modal>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/draggable/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nimport ExtraModal from './modal.vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: ExtraModal,\n});\n\nfunction openModal() {\n  modalApi.open();\n}\n</script>\n\n<template>\n  <div>\n    <Modal />\n    <VbenButton @click=\"openModal\">Open</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/draggable/modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nconst [Modal] = useVbenModal({\n  draggable: true,\n});\n</script>\n<template>\n  <Modal title=\"拖拽示例\"> modal content </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/dynamic/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nimport ExtraModal from './modal.vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: ExtraModal,\n});\n\nfunction openModal() {\n  modalApi.open();\n}\n\nfunction handleUpdateTitle() {\n  modalApi.setState({ title: '外部动态标题' }).open();\n}\n</script>\n\n<template>\n  <div>\n    <Modal />\n\n    <VbenButton @click=\"openModal\">Open</VbenButton>\n    <VbenButton class=\"ml-2\" type=\"primary\" @click=\"handleUpdateTitle\">\n      从外部修改标题并打开\n    </VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/dynamic/modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nconst [Modal, modalApi] = useVbenModal({\n  draggable: true,\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm() {\n    console.info('onConfirm');\n  },\n  title: '动态修改配置示例',\n});\n\nconst state = modalApi.useStore();\n\nfunction handleUpdateTitle() {\n  modalApi.setState({ title: '内部动态标题' });\n}\n\nfunction handleToggleFullscreen() {\n  modalApi.setState((prev) => {\n    return { ...prev, fullscreen: !prev.fullscreen };\n  });\n}\n</script>\n<template>\n  <Modal>\n    <div class=\"flex-col-center\">\n      <VbenButton class=\"mb-3\" type=\"primary\" @click=\"handleUpdateTitle()\">\n        内部动态修改标题\n      </VbenButton>\n      <VbenButton class=\"mb-3\" @click=\"handleToggleFullscreen()\">\n        {{ state.fullscreen ? '退出全屏' : '打开全屏' }}\n      </VbenButton>\n    </div>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/extra/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nimport ExtraModal from './modal.vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: ExtraModal,\n});\n\nfunction openModal() {\n  modalApi.open();\n}\n</script>\n\n<template>\n  <div>\n    <Modal />\n    <VbenButton @click=\"openModal\">Open</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/extra/modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nconst [Modal] = useVbenModal();\n</script>\n<template>\n  <Modal title=\"组件抽离示例\"> extra modal content </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/shared-data/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal, VbenButton } from '@vben/common-ui';\n\nimport ExtraModal from './modal.vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: ExtraModal,\n});\n\nfunction openModal() {\n  modalApi\n    .setData({\n      content: '外部传递的数据 content',\n      payload: '外部传递的数据 payload',\n    })\n    .open();\n}\n</script>\n\n<template>\n  <div>\n    <Modal />\n\n    <VbenButton @click=\"openModal\">Open</VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-modal/shared-data/modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenModal } from '@vben/common-ui';\n\nconst data = ref();\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm() {\n    console.info('onConfirm');\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      data.value = modalApi.getData<Record<string, any>>();\n    }\n  },\n});\n</script>\n<template>\n  <Modal title=\"数据共享示例\">\n    <div class=\"flex-col-center\">外部传递数据： {{ data }}</div>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/basic/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Button, message } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { MOCK_TABLE_DATA } from '../table-data';\n\ninterface RowType {\n  address: string;\n  age: number;\n  id: number;\n  name: string;\n  nickname: string;\n  role: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'name', title: 'Name' },\n    { field: 'age', sortable: true, title: 'Age' },\n    { field: 'nickname', title: 'Nickname' },\n    { field: 'role', title: 'Role' },\n    { field: 'address', showOverflow: true, title: 'Address' },\n  ],\n  data: MOCK_TABLE_DATA,\n  pagerConfig: {\n    enabled: false,\n  },\n  sortConfig: {\n    multiple: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<RowType> = {\n  cellClick: ({ row }) => {\n    message.info(`cell-click: ${row.name}`);\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({ gridEvents, gridOptions });\n\nconst showBorder = gridApi.useStore((state) => state.gridOptions?.border);\nconst showStripe = gridApi.useStore((state) => state.gridOptions?.stripe);\n\nfunction changeBorder() {\n  gridApi.setGridOptions({\n    border: !showBorder.value,\n  });\n}\n\nfunction changeStripe() {\n  gridApi.setGridOptions({\n    stripe: !showStripe.value,\n  });\n}\n\nfunction changeLoading() {\n  gridApi.setLoading(true);\n  setTimeout(() => {\n    gridApi.setLoading(false);\n  }, 2000);\n}\n</script>\n\n<template>\n  <!-- 此处的`vp-raw` 是为了适配文档的展示效果，实际使用时不需要 -->\n  <div class=\"vp-raw w-full\">\n    <Grid>\n      <template #toolbar-tools>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"changeBorder\">\n          {{ showBorder ? '隐藏' : '显示' }}边框\n        </Button>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"changeLoading\">\n          显示loading\n        </Button>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"changeStripe\">\n          {{ showStripe ? '隐藏' : '显示' }}斑马纹\n        </Button>\n      </template>\n    </Grid>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/custom-cell/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Button, Image, Switch, Tag } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { getExampleTableApi } from '../mock-api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  imageUrl: string;\n  open: boolean;\n  price: string;\n  productName: string;\n  releaseDate: string;\n  status: 'error' | 'success' | 'warning';\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  checkboxConfig: {\n    highlight: true,\n    labelField: 'name',\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'category', title: 'Category', width: 100 },\n    {\n      field: 'imageUrl',\n      slots: { default: 'image-url' },\n      title: 'Image',\n      width: 100,\n    },\n    {\n      cellRender: { name: 'CellImage' },\n      field: 'imageUrl2',\n      title: 'Render Image',\n      width: 130,\n    },\n    {\n      field: 'open',\n      slots: { default: 'open' },\n      title: 'Open',\n      width: 100,\n    },\n    {\n      field: 'status',\n      slots: { default: 'status' },\n      title: 'Status',\n      width: 100,\n    },\n    { field: 'color', title: 'Color', width: 100 },\n    { field: 'productName', title: 'Product Name', width: 200 },\n    { field: 'price', title: 'Price', width: 100 },\n    {\n      field: 'releaseDate',\n      formatter: 'formatDateTime',\n      title: 'Date',\n      width: 200,\n    },\n    {\n      cellRender: { name: 'CellLink', props: { text: '编辑' } },\n      field: 'action',\n      fixed: 'right',\n      title: '操作',\n      width: 120,\n    },\n  ],\n  keepSource: true,\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n};\n\nconst [Grid] = useVbenVxeGrid({ gridOptions });\n</script>\n\n<template>\n  <div class=\"vp-raw w-full\">\n    <Grid>\n      <template #image-url=\"{ row }\">\n        <Image :src=\"row.imageUrl\" height=\"30\" width=\"30\" />\n      </template>\n      <template #open=\"{ row }\">\n        <Switch v-model:checked=\"row.open\" />\n      </template>\n      <template #status=\"{ row }\">\n        <Tag :color=\"row.color\">{{ row.status }}</Tag>\n      </template>\n      <template #action>\n        <Button type=\"link\">编辑</Button>\n      </template>\n    </Grid>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/edit-cell/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { getExampleTableApi } from '../mock-api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { editRender: { name: 'input' }, field: 'category', title: 'Category' },\n    { editRender: { name: 'input' }, field: 'color', title: 'Color' },\n    {\n      editRender: { name: 'input' },\n      field: 'productName',\n      title: 'Product Name',\n    },\n    { field: 'price', title: 'Price' },\n    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },\n  ],\n  editConfig: {\n    mode: 'cell',\n    trigger: 'click',\n  },\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n  showOverflow: true,\n};\n\nconst [Grid] = useVbenVxeGrid({ gridOptions });\n</script>\n\n<template>\n  <div class=\"vp-raw w-full\">\n    <Grid />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/edit-row/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Button, message } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { getExampleTableApi } from '../mock-api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { editRender: { name: 'input' }, field: 'category', title: 'Category' },\n    { editRender: { name: 'input' }, field: 'color', title: 'Color' },\n    {\n      editRender: { name: 'input' },\n      field: 'productName',\n      title: 'Product Name',\n    },\n    { field: 'price', title: 'Price' },\n    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },\n    { slots: { default: 'action' }, title: '操作' },\n  ],\n  editConfig: {\n    mode: 'row',\n    trigger: 'click',\n  },\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n  showOverflow: true,\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({ gridOptions });\n\nfunction hasEditStatus(row: RowType) {\n  return gridApi.grid?.isEditByRow(row);\n}\n\nfunction editRowEvent(row: RowType) {\n  gridApi.grid?.setEditRow(row);\n}\n\nasync function saveRowEvent(row: RowType) {\n  await gridApi.grid?.clearEdit();\n\n  gridApi.setLoading(true);\n  setTimeout(() => {\n    gridApi.setLoading(false);\n    message.success({\n      content: `保存成功！category=${row.category}`,\n    });\n  }, 600);\n}\n\nconst cancelRowEvent = (_row: RowType) => {\n  gridApi.grid?.clearEdit();\n};\n</script>\n\n<template>\n  <div class=\"vp-raw w-full\">\n    <Grid>\n      <template #action=\"{ row }\">\n        <template v-if=\"hasEditStatus(row)\">\n          <Button type=\"link\" @click=\"saveRowEvent(row)\">保存</Button>\n          <Button type=\"link\" @click=\"cancelRowEvent(row)\">取消</Button>\n        </template>\n        <template v-else>\n          <Button type=\"link\" @click=\"editRowEvent(row)\">编辑</Button>\n        </template>\n      </template>\n    </Grid>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/fixed/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Button } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { getExampleTableApi } from '../mock-api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { fixed: 'left', title: '序号', type: 'seq', width: 50 },\n    { field: 'category', title: 'Category', width: 300 },\n    { field: 'color', title: 'Color', width: 300 },\n    { field: 'productName', title: 'Product Name', width: 300 },\n    { field: 'price', title: 'Price', width: 300 },\n    {\n      field: 'releaseDate',\n      formatter: 'formatDateTime',\n      title: 'DateTime',\n      width: 500,\n    },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 120,\n    },\n  ],\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n  rowConfig: {\n    isHover: true,\n  },\n};\n\nconst [Grid] = useVbenVxeGrid({ gridOptions });\n</script>\n\n<template>\n  <div class=\"vp-raw w-full\">\n    <Grid>\n      <template #action>\n        <Button type=\"link\">编辑</Button>\n      </template>\n    </Grid>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/form/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormProps } from '#/adapter/form';\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { message } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { getExampleTableApi } from '../mock-api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst formOptions: VbenFormProps = {\n  // 默认展开\n  collapsed: false,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: 'Please enter category',\n      },\n      defaultValue: '1',\n      fieldName: 'category',\n      label: 'Category',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: 'Please enter productName',\n      },\n      fieldName: 'productName',\n      label: 'ProductName',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: 'Please enter price',\n      },\n      fieldName: 'price',\n      label: 'Price',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        options: [\n          {\n            label: 'Color1',\n            value: '1',\n          },\n          {\n            label: 'Color2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n      },\n      fieldName: 'color',\n      label: 'Color',\n    },\n    {\n      component: 'DatePicker',\n      fieldName: 'datePicker',\n      label: 'Date',\n    },\n  ],\n  // 控制表单是否显示折叠按钮\n  showCollapseButton: true,\n  submitButtonOptions: {\n    content: '查询',\n  },\n  // 是否在字段值改变时提交表单\n  submitOnChange: false,\n  // 按下回车时是否提交表单\n  submitOnEnter: false,\n};\n\nconst gridOptions: VxeGridProps<RowType> = {\n  checkboxConfig: {\n    highlight: true,\n    labelField: 'name',\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { align: 'left', title: 'Name', type: 'checkbox', width: 100 },\n    { field: 'category', title: 'Category' },\n    { field: 'color', title: 'Color' },\n    { field: 'productName', title: 'Product Name' },\n    { field: 'price', title: 'Price' },\n    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },\n  ],\n  keepSource: true,\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }, formValues) => {\n        message.success(`Query params: ${JSON.stringify(formValues)}`);\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n          ...formValues,\n        });\n      },\n    },\n  },\n  toolbarConfig: {\n    // 是否显示搜索表单控制按钮\n    // @ts-ignore 正式环境时有完整的类型声明\n    search: true,\n  },\n};\n\nconst [Grid] = useVbenVxeGrid({ formOptions, gridOptions });\n</script>\n\n<template>\n  <div class=\"vp-raw w-full\">\n    <Grid />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/mock-api.ts",
    "content": "import { MOCK_API_DATA } from './table-data';\n\nexport namespace DemoTableApi {\n  export interface PageFetchParams {\n    [key: string]: any;\n    page: number;\n    pageSize: number;\n  }\n}\n\nexport function sleep(time = 1000) {\n  return new Promise((resolve) => {\n    setTimeout(() => {\n      resolve(true);\n    }, time);\n  });\n}\n\n/**\n * 获取示例表格数据\n */\nasync function getExampleTableApi(params: DemoTableApi.PageFetchParams) {\n  return new Promise<{ items: any; total: number }>((resolve) => {\n    const { page, pageSize } = params;\n    const items = MOCK_API_DATA.slice((page - 1) * pageSize, page * pageSize);\n\n    sleep(1000).then(() => {\n      resolve({\n        total: items.length,\n        items,\n      });\n    });\n  });\n}\n\nexport { getExampleTableApi };\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/remote/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DemoTableApi } from '../mock-api';\n\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Button } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { MOCK_API_DATA } from '../table-data';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\n// 数据实例\n// const MOCK_TREE_TABLE_DATA = [\n//   {\n//     date: '2020-08-01',\n//     id: 10_000,\n//     name: 'Test1',\n//     parentId: null,\n//     size: 1024,\n//     type: 'mp3',\n//   },\n// ]\n\nconst sleep = (time = 1000) => {\n  return new Promise((resolve) => {\n    setTimeout(() => {\n      resolve(true);\n    }, time);\n  });\n};\n\n/**\n * 获取示例表格数据\n */\nasync function getExampleTableApi(params: DemoTableApi.PageFetchParams) {\n  return new Promise<{ items: any; total: number }>((resolve) => {\n    const { page, pageSize } = params;\n    const items = MOCK_API_DATA.slice((page - 1) * pageSize, page * pageSize);\n\n    sleep(1000).then(() => {\n      resolve({\n        total: items.length,\n        items,\n      });\n    });\n  });\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  checkboxConfig: {\n    highlight: true,\n    labelField: 'name',\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { align: 'left', title: 'Name', type: 'checkbox', width: 100 },\n    { field: 'category', title: 'Category' },\n    { field: 'color', title: 'Color' },\n    { field: 'productName', title: 'Product Name' },\n    { field: 'price', title: 'Price' },\n    { field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },\n  ],\n  exportConfig: {},\n  // height: 'auto', // 如果设置为 auto，则必须确保存在父节点且不允许存在相邻元素，否则会出现高度闪动问题\n  keepSource: true,\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    export: true,\n    // import: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions,\n});\n</script>\n\n<template>\n  <div class=\"vp-raw w-full\">\n    <Grid>\n      <template #toolbar-tools>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"() => gridApi.query()\">\n          刷新当前页面\n        </Button>\n        <Button type=\"primary\" @click=\"() => gridApi.reload()\">\n          刷新并返回第一页\n        </Button>\n      </template>\n    </Grid>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/table-data.ts",
    "content": "interface TableRowData {\n  address: string;\n  age: number;\n  id: number;\n  name: string;\n  nickname: string;\n  role: string;\n}\n\nconst roles = ['User', 'Admin', 'Manager', 'Guest'];\n\nexport const MOCK_TABLE_DATA: TableRowData[] = (() => {\n  const data: TableRowData[] = [];\n  for (let i = 0; i < 10; i++) {\n    data.push({\n      address: `New York${i}`,\n      age: i + 1,\n      id: i,\n      name: `Test${i}`,\n      nickname: `Test${i}`,\n      role: roles[Math.floor(Math.random() * roles.length)] as string,\n    });\n  }\n  return data;\n})();\n\nexport const MOCK_TREE_TABLE_DATA = [\n  {\n    date: '2020-08-01',\n    id: 10_000,\n    name: 'Test1',\n    parentId: null,\n    size: 1024,\n    type: 'mp3',\n  },\n  {\n    date: '2021-04-01',\n    id: 10_050,\n    name: 'Test2',\n    parentId: null,\n    size: 0,\n    type: 'mp4',\n  },\n  {\n    date: '2020-03-01',\n    id: 24_300,\n    name: 'Test3',\n    parentId: 10_050,\n    size: 1024,\n    type: 'avi',\n  },\n  {\n    date: '2021-04-01',\n    id: 20_045,\n    name: 'Test4',\n    parentId: 24_300,\n    size: 600,\n    type: 'html',\n  },\n  {\n    date: '2021-04-01',\n    id: 10_053,\n    name: 'Test5',\n    parentId: 24_300,\n    size: 0,\n    type: 'avi',\n  },\n  {\n    date: '2021-10-01',\n    id: 24_330,\n    name: 'Test6',\n    parentId: 10_053,\n    size: 25,\n    type: 'txt',\n  },\n  {\n    date: '2020-01-01',\n    id: 21_011,\n    name: 'Test7',\n    parentId: 10_053,\n    size: 512,\n    type: 'pdf',\n  },\n  {\n    date: '2021-06-01',\n    id: 22_200,\n    name: 'Test8',\n    parentId: 10_053,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2020-11-01',\n    id: 23_666,\n    name: 'Test9',\n    parentId: null,\n    size: 2048,\n    type: 'xlsx',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_677,\n    name: 'Test10',\n    parentId: 23_666,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_671,\n    name: 'Test11',\n    parentId: 23_677,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_672,\n    name: 'Test12',\n    parentId: 23_677,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_688,\n    name: 'Test13',\n    parentId: 23_666,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_681,\n    name: 'Test14',\n    parentId: 23_688,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_682,\n    name: 'Test15',\n    parentId: 23_688,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2020-10-01',\n    id: 24_555,\n    name: 'Test16',\n    parentId: null,\n    size: 224,\n    type: 'avi',\n  },\n  {\n    date: '2021-06-01',\n    id: 24_566,\n    name: 'Test17',\n    parentId: 24_555,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 24_577,\n    name: 'Test18',\n    parentId: 24_555,\n    size: 1024,\n    type: 'js',\n  },\n];\n\nexport const MOCK_API_DATA = [\n  {\n    available: true,\n    category: 'Computers',\n    color: 'purple',\n    currency: 'NAD',\n    description:\n      'Ergonomic executive chair upholstered in bonded black leather and PVC padded seat and back for all-day comfort and support',\n    id: '45a613df-227a-4907-a89f-4a7f1252ca0c',\n    imageUrl: 'https://avatars.githubusercontent.com/u/62715097',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/75395683',\n    inProduction: false,\n    open: true,\n    price: '48.89',\n    productName: 'Handcrafted Steel Salad',\n    quantity: 70,\n    rating: 3.780_582_329_574_367,\n    releaseDate: '2024-09-09T04:06:57.793Z',\n    status: 'error',\n    tags: ['Bespoke', 'Handmade', 'Luxurious'],\n    weight: 1.031_015_671_912_002_5,\n  },\n  {\n    available: true,\n    category: 'Toys',\n    color: 'green',\n    currency: 'CZK',\n    description:\n      'The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J',\n    id: 'd02e5ee9-bc98-4de2-98fa-25a6567ecc19',\n    imageUrl: 'https://avatars.githubusercontent.com/u/51512330',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/58698113',\n    inProduction: false,\n    open: false,\n    price: '68.15',\n    productName: 'Generic Cotton Gloves',\n    quantity: 3,\n    rating: 1.681_749_367_682_703_3,\n    releaseDate: '2024-06-16T09:00:36.806Z',\n    status: 'warning',\n    tags: ['Rustic', 'Handcrafted', 'Recycled'],\n    weight: 9.601_076_149_300_575,\n  },\n  {\n    available: true,\n    category: 'Beauty',\n    color: 'teal',\n    currency: 'OMR',\n    description:\n      'The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design',\n    id: '2b72521c-225c-4e64-8030-611b76b10b37',\n    imageUrl: 'https://avatars.githubusercontent.com/u/50300075',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/36541691',\n    inProduction: true,\n    open: true,\n    price: '696.94',\n    productName: 'Gorgeous Soft Ball',\n    quantity: 50,\n    rating: 2.361_581_777_372_057_5,\n    releaseDate: '2024-06-03T13:24:19.809Z',\n    status: 'warning',\n    tags: ['Gorgeous', 'Ergonomic', 'Licensed'],\n    weight: 8.882_340_049_286_19,\n  },\n  {\n    available: true,\n    category: 'Games',\n    color: 'silver',\n    currency: 'SOS',\n    description:\n      'Carbonite web goalkeeper gloves are ergonomically designed to give easy fit',\n    id: 'bafab694-3801-452c-b102-9eb519bd1143',\n    imageUrl: 'https://avatars.githubusercontent.com/u/89827115',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/55952747',\n    inProduction: false,\n    open: false,\n    price: '553.84',\n    productName: 'Bespoke Soft Computer',\n    quantity: 29,\n    rating: 2.176_412_873_760_271_7,\n    releaseDate: '2024-09-17T12:16:27.034Z',\n    status: 'error',\n    tags: ['Elegant', 'Rustic', 'Recycled'],\n    weight: 9.653_285_869_978_038,\n  },\n  {\n    available: true,\n    category: 'Toys',\n    color: 'indigo',\n    currency: 'BIF',\n    description:\n      'Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals',\n    id: 'bf6dea6b-2a55-441d-8773-937e03d99389',\n    imageUrl: 'https://avatars.githubusercontent.com/u/21431092',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/3771350',\n    inProduction: true,\n    open: true,\n    price: '237.39',\n    productName: 'Handcrafted Cotton Mouse',\n    quantity: 54,\n    rating: 4.363_265_388_265_461,\n    releaseDate: '2023-10-23T13:42:34.947Z',\n    status: 'error',\n    tags: ['Unbranded', 'Handmade', 'Generic'],\n    weight: 9.513_203_612_535_571,\n  },\n  {\n    available: false,\n    category: 'Tools',\n    color: 'violet',\n    currency: 'TZS',\n    description:\n      'New ABC 13 9370, 13.3, 5th Gen CoreA5-8250U, 8GB RAM, 256GB SSD, power UHD Graphics, OS 10 Home, OS Office A & J 2016',\n    id: '135ba6ab-32ee-4989-8189-5cfa658ef970',\n    imageUrl: 'https://avatars.githubusercontent.com/u/29946092',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/23842994',\n    inProduction: false,\n    open: false,\n    price: '825.25',\n    productName: 'Awesome Bronze Ball',\n    quantity: 94,\n    rating: 4.251_159_804_726_753,\n    releaseDate: '2023-12-30T07:31:43.464Z',\n    status: 'warning',\n    tags: ['Handmade', 'Elegant', 'Unbranded'],\n    weight: 2.247_473_385_732_636_8,\n  },\n  {\n    available: true,\n    category: 'Automotive',\n    color: 'teal',\n    currency: 'BOB',\n    description: 'The Football Is Good For Training And Recreational Purposes',\n    id: '652ef256-7d4e-48b7-976c-7afaa781ea92',\n    imageUrl: 'https://avatars.githubusercontent.com/u/2531904',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/15215990',\n    inProduction: false,\n    open: false,\n    price: '780.49',\n    productName: 'Oriental Rubber Pants',\n    quantity: 70,\n    rating: 2.636_323_417_377_916,\n    releaseDate: '2024-02-23T23:30:49.628Z',\n    status: 'success',\n    tags: ['Unbranded', 'Elegant', 'Unbranded'],\n    weight: 4.812_965_858_018_838,\n  },\n  {\n    available: false,\n    category: 'Garden',\n    color: 'plum',\n    currency: 'LRD',\n    description:\n      'The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality',\n    id: '3ea24798-6589-40cc-85f0-ab78752244a0',\n    imageUrl: 'https://avatars.githubusercontent.com/u/23165285',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/14595665',\n    inProduction: false,\n    open: true,\n    price: '583.85',\n    productName: 'Handcrafted Concrete Hat',\n    quantity: 15,\n    rating: 1.371_600_527_752_802_7,\n    releaseDate: '2024-03-02T19:40:50.255Z',\n    status: 'error',\n    tags: ['Rustic', 'Sleek', 'Ergonomic'],\n    weight: 4.926_949_366_405_728_4,\n  },\n  {\n    available: false,\n    category: 'Industrial',\n    color: 'salmon',\n    currency: 'AUD',\n    description:\n      'The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design',\n    id: '997113dd-f6e4-4acc-9790-ef554c7498d1',\n    imageUrl: 'https://avatars.githubusercontent.com/u/49021914',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/4690621',\n    inProduction: true,\n    open: false,\n    price: '67.99',\n    productName: 'Generic Rubber Bacon',\n    quantity: 68,\n    rating: 4.129_840_682_128_08,\n    releaseDate: '2023-12-17T01:40:25.415Z',\n    status: 'error',\n    tags: ['Oriental', 'Small', 'Handcrafted'],\n    weight: 1.080_114_331_801_906_4,\n  },\n  {\n    available: false,\n    category: 'Tools',\n    color: 'sky blue',\n    currency: 'NOK',\n    description:\n      'The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J',\n    id: 'f697a250-6cb2-46c8-b0f7-871ab1f2fa8d',\n    imageUrl: 'https://avatars.githubusercontent.com/u/95928385',\n    imageUrl2: 'https://avatars.githubusercontent.com/u/47588244',\n    inProduction: false,\n    open: false,\n    price: '613.89',\n    productName: 'Gorgeous Frozen Ball',\n    quantity: 55,\n    rating: 1.646_947_205_998_534_6,\n    releaseDate: '2024-10-13T12:31:04.929Z',\n    status: 'warning',\n    tags: ['Handmade', 'Unbranded', 'Unbranded'],\n    weight: 9.430_690_557_758_114,\n  },\n];\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/tree/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Button } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { MOCK_TREE_TABLE_DATA } from '../table-data';\n\ninterface RowType {\n  date: string;\n  id: number;\n  name: string;\n  parentId: null | number;\n  size: number;\n  type: string;\n}\n\n// 数据实例\n// const MOCK_TREE_TABLE_DATA = [\n//   {\n//     date: '2020-08-01',\n//     id: 10_000,\n//     name: 'Test1',\n//     parentId: null,\n//     size: 1024,\n//     type: 'mp3',\n//   },\n//   {\n//     date: '2021-04-01',\n//     id: 10_050,\n//     name: 'Test2',\n//     parentId: 10_000,\n//     size: 0,\n//     type: 'mp4',\n//   },\n// ];\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { type: 'seq', width: 70 },\n    { field: 'name', minWidth: 300, title: 'Name', treeNode: true },\n    { field: 'size', title: 'Size' },\n    { field: 'type', title: 'Type' },\n    { field: 'date', title: 'Date' },\n  ],\n  data: MOCK_TREE_TABLE_DATA,\n  pagerConfig: {\n    enabled: false,\n  },\n  treeConfig: {\n    parentField: 'parentId',\n    rowField: 'id',\n    transform: true,\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({ gridOptions });\n\nconst expandAll = () => {\n  gridApi.grid?.setAllTreeExpand(true);\n};\n\nconst collapseAll = () => {\n  gridApi.grid?.setAllTreeExpand(false);\n};\n</script>\n\n<template>\n  <div class=\"vp-raw h-[300px] w-full\">\n    <Grid>\n      <template #toolbar-tools>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"expandAll\">\n          展开全部\n        </Button>\n        <Button type=\"primary\" @click=\"collapseAll\"> 折叠全部 </Button>\n      </template>\n    </Grid>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/demos/vben-vxe-table/virtual/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { onMounted } from 'vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\ninterface RowType {\n  id: number;\n  name: string;\n  role: string;\n  sex: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { type: 'seq', width: 70 },\n    { field: 'name', title: 'Name' },\n    { field: 'role', title: 'Role' },\n    { field: 'sex', title: 'Sex' },\n  ],\n  data: [],\n  height: 'auto',\n  pagerConfig: {\n    enabled: false,\n  },\n  scrollY: {\n    enabled: true,\n    gt: 0,\n  },\n  showOverflow: true,\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({ gridOptions });\n\n// 模拟行数据\nconst loadList = (size = 200) => {\n  try {\n    const dataList: RowType[] = [];\n    for (let i = 0; i < size; i++) {\n      dataList.push({\n        id: 10_000 + i,\n        name: `Test${i}`,\n        role: 'Developer',\n        sex: '男',\n      });\n    }\n    gridApi.setGridOptions({ data: dataList });\n  } catch (error) {\n    console.error('Failed to load data:', error);\n    // Implement user-friendly error handling\n  }\n};\n\nonMounted(() => {\n  loadList(1000);\n});\n</script>\n\n<template>\n  <div class=\"vp-raw h-[500px] w-full\">\n    <Grid />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/build.md",
    "content": "# Build and Deployment\n\n::: tip Preface\n\nSince this is a demonstration project, the package size after building is relatively large. If there are plugins in the project that are not used, you can delete the corresponding files or routes. If they are not referenced, they will not be packaged.\n\n:::\n\n## Building\n\nAfter the project development is completed, execute the following command to build:\n\n**Note:** Please execute the following command in the project root directory.\n\n```bash\npnpm build\n```\n\nAfter the build is successful, a `dist` folder for the corresponding application will be generated in the root directory, which contains the built and packaged files, for example: `apps/web-antd/dist/`\n\n## Preview\n\nBefore publishing, you can preview it locally in several ways, here are two:\n\n- Using the project's custom command for preview (recommended)\n\n**Note：** Please execute the following command in the project root directory.\n\n```bash\npnpm preview\n```\n\nAfter waiting for the build to succeed, visit `http://localhost:4173` to view the effect.\n\n- Local server preview\n\nYou can globally install a `serve` service on your computer, such as `live-server`,\n\n```bash\nnpm i -g live-server\n```\n\nThen execute the `live-server` command in the `dist` directory to view the effect locally.\n\n```bash\ncd apps/web-antd/dist\n# Local preview, default port 8080\nlive-server\n# Specify port\nlive-server --port 9000\n```\n\n## Compression\n\n### Enable `gzip` Compression\n\nTo enable during the build process, change the `.env.production` configuration:\n\n```bash\nVITE_COMPRESS=gzip\n```\n\n### Enable `brotli` Compression\n\nTo enable during the build process, change the `.env.production` configuration:\n\n```bash\nVITE_COMPRESS=brotli\n```\n\n### Enable Both `gzip` and `brotli` Compression\n\nTo enable during the build process, change the `.env.production` configuration:\n\n```bash\nVITE_COMPRESS=gzip,brotli\n```\n\n::: tip Note\n\nBoth `gzip` and `brotli` require specific modules to be installed for use.\n\n:::\n\n::: details gzip 与 brotli 在 nginx 内的配置\n\n```bash\nhttp {\n  # Enable gzip\n  gzip on;\n  # Enable gzip_static\n  # After enabling gzip_static, there might be errors, requiring the installation of specific modules. The installation method can be researched independently.\n  # Only with this enabled, the .gz files packaged by vue files will be effective; otherwise, there is no need to enable gzip for packaging.\n  gzip_static on;\n  gzip_proxied any;\n  gzip_min_length 1k;\n  gzip_buffers 4 16k;\n  # If nginx uses multiple layers of proxy, this must be set to enable gzip.\n  gzip_http_version 1.0;\n  gzip_comp_level 2;\n  gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;\n  gzip_vary off;\n  gzip_disable \"MSIE [1-6]\\.\";\n\n  # Enable brotli compression\n  # Requires the installation of the corresponding nginx module, which can be researched independently.\n  # Can coexist with gzip without conflict.\n  brotli on;\n  brotli_comp_level 6;\n  brotli_buffers 16 8k;\n  brotli_min_length 20;\n  brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;\n}\n```\n\n:::\n\n## Build Analysis\n\nIf your build files are large, you can optimize your code by analyzing the code size with the built-in [rollup-plugin-analyzer](https://github.com/doesdev/rollup-plugin-analyzer) plugin. Just execute the following command in the `root directory`:\n\n```bash\npnpm run build:analyze\n```\n\nAfter running, you can see the specific distribution of sizes on the automatically opened page to analyze which dependencies are problematic.\n\n![Build analysis report](/guide/report.png)\n\n## Deployment\n\nA simple deployment only requires publishing the final static files, the static files in the dist folder, to your CDN or static server. It's important to note that the index.html is usually the entry page for your backend service. After determining the static js and css, you may need to change the page's import path.\n\nFor example, to upload to an nginx server, you can upload the files under the dist folder to the server's `/srv/www/project/index.html` directory, and then access the configured domain name.\n\n```bash\n# nginx configuration\nlocation / {\n  # Do not cache html to prevent cache from continuing to be effective after program updates\n  if ($request_filename ~* .*\\.(?:htm|html)$) {\n    add_header Cache-Control \"private, no-store, no-cache, must-revalidate, proxy-revalidate\";\n    access_log on;\n  }\n  # This is the storage path for the files inside the vue packaged dist folder\n  root   /srv/www/project/;\n  index  index.html index.htm;\n}\n```\n\nIf you find the resource path is incorrect during deployment, you just need to modify the `.env.production` file.\n\n```bash\n# Configure the change according to your own path\n# Note that it needs to start and end with /\nVITE_BASE=/\nVITE_BASE=/xxx/\n```\n\n### Integration of Frontend Routing and Server\n\nThe project uses vue-router for frontend routing, so you can choose between two modes: history and hash.\n\n- `hash` mode will append `#` to the URL by default.\n- `history` mode will not, but `history` mode requires server-side support.\n\nYou can modify the mode in `.env.production`:\n\n```bash\nVITE_ROUTER_HISTORY=hash\n```\n\n### Server Configuration for History Mode Routing\n\nEnabling `history` mode requires server configuration. For more details on server configuration, see [history-mode](https://router.vuejs.org/guide/essentials/history-mode.html#html5-mode)\n\nHere is an example of `nginx` configuration:\n\n#### Deployment at the Root Directory\n\n```bash {5}\nserver {\n  listen 80;\n  location / {\n    # For use with History mode\n    try_files $uri $uri/ /index.html;\n  }\n}\n```\n\n#### Deployment to a Non-root Directory\n\n- First, you need to change the `.env.production` configuration during packaging:\n\n```bash\nVITE_BASE = /sub/\n```\n\n- Then configure in the nginx configuration file\n\n```bash {8}\nserver {\n    listen       80;\n    server_name  localhost;\n    location /sub/ {\n      # This is the path where the vue packaged dist files are stored\n      alias   /srv/www/project/;\n      index index.html index.htm;\n      try_files $uri $uri/ /sub/index.html;\n    }\n}\n```\n\n## Cross-Domain Handling\n\nUsing nginx to handle cross-domain issues after project deployment\n\n1. Configure the frontend project API address in the `.env.production` file in the project directory:\n\n```bash\nVITE_GLOB_API_URL=/api\n```\n\n2. Configure nginx to forward requests to the backend\n\n```bash {10-11}\nserver {\n  listen       8080;\n  server_name  localhost;\n  # API proxy for solving cross-domain issues\n  location /api {\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    # Backend API address\n    proxy_pass http://110.110.1.1:8080/api;\n    rewrite \"^/api/(.*)$\" /$1 break;\n    proxy_redirect default;\n    add_header Access-Control-Allow-Origin *;\n    add_header Access-Control-Allow-Headers X-Requested-With;\n    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;\n  }\n}\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/concept.md",
    "content": "# Basic Concepts\n\nIn the new version, the entire project has been restructured. Now, we will introduce some basic concepts to help you better understand the entire document. Please make sure to read this section first.\n\n## Monorepo\n\nMonorepo refers to the repository of the entire project, which includes all code, packages, applications, standards, documentation, configurations, etc., that is, the entire content of a `Monorepo` directory.\n\n## Applications\n\nApplications refer to a complete project; a project can contain multiple applications, which can reuse the code, packages, standards, etc., within the monorepo. Applications are placed in the `apps` directory. Each application is independent and can be run, built, tested, and deployed separately; it can also include different component libraries, etc.\n\n::: tip\n\nApplications are not limited to front-end applications; they can also be back-end applications, mobile applications, etc. For example, `apps/backend-mock` is a back-end service.\n\n:::\n\n## Packages\n\nA package refers to an independent module, which can be a component, a tool, a library, etc. Packages can be referenced by multiple applications or other packages. Packages are placed in the `packages` directory.\n\nYou can consider these packages as independent `npm` packages, and they are used in the same way as `npm` packages.\n\n### Package Import\n\nImporting a package in `package.json`:\n\n```json {3}\n{\n  \"dependencies\": {\n    \"@vben/utils\": \"workspace:*\"\n  }\n}\n```\n\n### Package Usage\n\nImporting a package in the code:\n\n```ts\nimport { isString } from '@vben/utils';\n```\n\n## Aliases\n\nIn the project, you can see some paths starting with `#`, such as `#/api`, `#/views`. These paths are aliases, used for quickly locating a certain directory. They are not implemented through `vite`'s `alias`, but through the principle of [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) in `Node.js` itself. You only need to configure the `imports` field in `package.json`.\n\n```json {3}\n{\n  \"imports\": {\n    \"#/*\": \"./src/*\"\n  }\n}\n```\n\nTo make these aliases recognizable by the IDE, we also need to configure them in `tsconfig.json`:\n\n```json {5}\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"#/*\": [\"src/*\"]\n    }\n  }\n}\n```\n\nThis way, you can use aliases in your code.\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/development.md",
    "content": "# Local Development {#development}\n\n::: tip Code Acquisition\n\nIf you haven't acquired the code yet, you can start by reading the documentation from [Quick Start](../introduction/quick-start.md).\n\n:::\n\n## Prerequisites\n\nFor a better development experience, we provide some tool configurations and project descriptions to facilitate your development.\n\n### Required Basic Knowledge\n\nThis project requires some basic frontend knowledge. Please ensure you are familiar with the basics of Vue to handle common issues. It is recommended to learn the following topics before development. Understanding these will be very helpful for the project:\n\n- [Vue3](https://vuejs.org/)\n- [Tailwind CSS](https://tailwindcss.com/)\n- [TypeScript](https://www.typescriptlang.org/)\n- [Vue Router](https://router.vuejs.org/)\n- [Vitejs](https://vitejs.dev/)\n- [Pnpm](https://pnpm.io/)\n- [Turbo](https://turbo.build/)\n\n### Tool Configuration\n\nIf you are using [vscode](https://code.visualstudio.com/) (recommended) as your IDE, you can install the following tools to improve development efficiency and code formatting:\n\n- [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) - Official Vue plugin (essential).\n- [Tailwind CSS](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) - Tailwind CSS autocomplete plugin.\n- [CSS Variable Autocomplete](https://marketplace.visualstudio.com/items?itemName=vunguyentuan.vscode-css-variables) - CSS variable autocomplete plugin.\n- [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) - Iconify icon plugin.\n- [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) - i18n plugin.\n- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Script code linting.\n- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code formatting.\n- [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - CSS formatting.\n- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - Spelling checker.\n- [DotENV](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) - .env file highlighting.\n\n## Npm Scripts\n\nNpm scripts are common configurations used in the project to perform common tasks such as starting the project, building the project, etc. The following scripts can be found in the `package.json` file at the root of the project.\n\nThe execution command is: `pnpm run [script]` or `npm run [script]`.\n\n```json\n{\n  \"scripts\": {\n    // Build the project\n    \"build\": \"cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build\",\n    // Build the project with analysis\n    \"build:analyze\": \"turbo build:analyze\",\n    // Build a local Docker image\n    \"build:docker\": \"./build-local-docker-image.sh\",\n    // Build the web-antd application separately\n    \"build:antd\": \"pnpm run build --filter=@vben/web-antd\",\n    // Build the documentation separately\n    \"build:docs\": \"pnpm run build --filter=@vben/docs\",\n    // Build the web-ele application separately\n    \"build:ele\": \"pnpm run build --filter=@vben/web-ele\",\n    // Build the web-naive application separately\n    \"build:naive\": \"pnpm run build --filter=@vben/naive\",\n    // Build the playground application separately\n    \"build:play\": \"pnpm run build --filter=@vben/playground\",\n    // Changeset version management\n    \"changeset\": \"pnpm exec changeset\",\n    // Check for various issues in the project\n    \"check\": \"pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell\",\n    // Check for circular dependencies\n    \"check:circular\": \"vsh check-circular\",\n    // Check spelling\n    \"check:cspell\": \"cspell lint **/*.ts **/README.md .changeset/*.md --no-progress\"\n    // Check dependencies\n    \"check:dep\": \"vsh check-dep\",\n    // Check types\n    \"check:type\": \"turbo run typecheck\",\n    // Clean the project (delete node_modules, dist, .turbo, etc.)\n    \"clean\": \"node ./scripts/clean.mjs\",\n    // Commit code\n    \"commit\": \"czg\",\n    // Start the project (by default, the dev scripts of all packages in the entire repository will run)\n    \"dev\": \"turbo-run dev\",\n    // Start the web-antd application\n    \"dev:antd\": \"pnpm -F @vben/web-antd run dev\",\n    // Start the documentation\n    \"dev:docs\": \"pnpm -F @vben/docs run dev\",\n    // Start the web-ele application\n    \"dev:ele\": \"pnpm -F @vben/web-ele run dev\",\n    // Start the web-naive application\n    \"dev:naive\": \"pnpm -F @vben/web-naive run dev\",\n    // Start the playground application\n    \"dev:play\": \"pnpm -F @vben/playground run dev\",\n    // Format code\n    \"format\": \"vsh lint --format\",\n    // Lint code\n    \"lint\": \"vsh lint\",\n    // After installing dependencies, execute the stub script for all packages\n    \"postinstall\": \"pnpm -r run stub --if-present\",\n    // Only allow using pnpm\n    \"preinstall\": \"npx only-allow pnpm\",\n    // Install lefthook\n    \"prepare\": \"is-ci || lefthook install\",\n    // Preview the application\n    \"preview\": \"turbo-run preview\",\n    // Package specification check\n    \"publint\": \"vsh publint\",\n    // Delete all node_modules, yarn.lock, package.lock.json, and reinstall dependencies\n    \"reinstall\": \"pnpm clean --del-lock && pnpm install\",\n    // Run vitest unit tests\n    \"test:unit\": \"vitest run --dom\",\n    // Update project dependencies\n    \"update:deps\": \" pnpm update --latest --recursive\",\n    // Changeset generation and versioning\n    \"version\": \"pnpm exec changeset version && pnpm install --no-frozen-lockfile\"\n  }\n}\n```\n\n## Running the Project Locally\n\nTo run the documentation locally and make adjustments, you can execute the following command. This command allows you to select the application you want to develop:\n\n```bash\npnpm dev\n```\n\nIf you want to run a specific application directly, you can execute the following commands:\n\nTo run the `web-antd` application:\n\n```bash\npnpm dev:antd\n```\n\nTo run the `web-naive` application:\n\n```bash\npnpm dev:naive\n```\n\nTo run the `web-ele` application:\n\n```bash\npnpm dev:ele\n```\n\nTo run the `docs` application:\n\n```bash\npnpm dev:docs\n```\n\n### Distinguishing Build Environments\n\nIn actual business development, multiple environments are usually distinguished during the build process, such as the test environment `test` and the production environment `build`.\n\nAt this point, you can modify three files and add corresponding script configurations to distinguish between production environments.\n\nTake the addition of the test environment `test` to `@vben/web-antd` as an example:\n\n- `apps\\web-antd\\package.json`\n\n```json\n\"scripts\": {\n  \"build:prod\": \"pnpm vite build --mode production\",\n  \"build:test\": \"pnpm vite build --mode test\",\n  \"build:analyze\": \"pnpm vite build --mode analyze\",\n  \"dev\": \"pnpm vite --mode development\",\n  \"preview\": \"vite preview\",\n  \"typecheck\": \"vue-tsc --noEmit --skipLibCheck\"\n}\n```\n\nAdd the command `\"build:test\"` and change the original `\"build\"` to `\"build:prod\"` to avoid building packages for two environments simultaneously.\n\n- `package.json`\n\n```json\n\"scripts\": {\n    \"build\": \"cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build\",\n    \"build:analyze\": \"turbo build:analyze\",\n    \"build:antd\": \"pnpm run build --filter=@vben/web-antd\",\n    \"build-test:antd\": \"pnpm run build --filter=@vben/web-antd build:test\",\n\n    ······\n}\n```\n\nAdd the command to build the test environment in the root directory `package.json`.\n\n- `turbo.json`\n\n```json\n\"tasks\": {\n    \"build\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\n        \"dist/**\",\n        \"dist.zip\",\n        \".vitepress/dist.zip\",\n        \".vitepress/dist/**\"\n      ]\n    },\n\n    \"build-test:antd\": {\n      \"dependsOn\": [\"@vben/web-antd#build:test\"],\n      \"outputs\": [\"dist/**\"]\n    },\n\n    \"@vben/web-antd#build:test\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\"dist/**\"]\n    },\n\n    ······\n```\n\nAdd the relevant dependent commands in `turbo.json`.\n\n## Public Static Resources\n\nIf you need to use public static resources in the project, such as images, static HTML, etc., and you want to directly import them in the development process through `src=\"/xxx.png\"`.\n\nYou need to put the resource in the corresponding project's `public/static` directory. The import path for the resource should be `src=\"/static/xxx.png\"`.\n\n## DevTools\n\nThe project has a built-in [Vue DevTools](https://github.com/vuejs/devtools-next) plugin, which can be used during development. It is disabled by default, but can be enabled in the `.env.development` file. After enabling it, restart the project:\n\n```bash\nVITE_DEVTOOLS=true\n```\n\nOnce enabled, a Vue DevTools icon will appear at the bottom of the page during project runtime. Click it to open the DevTools.\n\n![Vue DevTools](/guide/devtools.png)\n\n## Running Documentation Locally\n\nTo run the documentation locally and make adjustments, you can execute the following command:\n\n```bash\npnpm dev:docs\n```\n\n## Troubleshooting\n\nIf you encounter dependency-related issues, you can try reinstalling the dependencies:\n\n```bash\n# Execute this command at the root of the project.\n# This command will delete all node_modules, yarn.lock, and package.lock.json files\n# and then reinstall dependencies (this process will be noticeably slower).\npnpm reinstall\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/external-module.md",
    "content": "# External Modules\n\nIn addition to the external modules that are included by default in the project, sometimes we need to import other external modules. Let's take [ant-design-vue](https://antdv.com/components/overview) as an example:\n\n## Installing Dependencies\n\n::: tip Install dependencies into a specific package\n\n- Since the project uses [pnpm](https://pnpm.io/) as the package management tool, we need to use the `pnpm` command to install dependencies.\n- As the project is managed using a Monorepo module, we need to install dependencies under a specific package. Please make sure you have entered the specific package directory before installing dependencies.\n\n:::\n\n```bash\n# cd /path/to/your/package\npnpm add ant-design-vue\n```\n\n## Usage\n\n### Global Import\n\n```ts\nimport { createApp } from 'vue';\nimport Antd from 'ant-design-vue';\nimport App from './App';\nimport 'ant-design-vue/dist/reset.css';\n\nconst app = createApp(App);\n\napp.use(Antd).mount('#app');\n```\n\n#### Usage\n\n```vue\n<template>\n  <a-button>text</a-button>\n</template>\n```\n\n### Partial Import\n\n```vue\n<script setup lang=\"ts\">\nimport { Button } from 'ant-design-vue';\n</script>\n\n<template>\n  <Button>text</Button>\n</template>\n```\n\n::: warning Note\n\n- If the component depends on styles, you also need to import the style file.\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/icons.md",
    "content": "# Icons\n\n::: tip About Icon Management\n\n- The icons in the project are mainly provided by the `@vben/icons` package. It is recommended to manage them within this package for unified management and maintenance.\n- If you are using `Vscode`, it is recommended to install the [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) plugin, which makes it easy to find and use icons.\n\n:::\n\nThere are several ways to use icons in the project, you can choose according to the actual situation:\n\n## Iconify Icons <Badge text=\"Recommended\" type=\"tip\"/>\n\nIntegrated with the [iconify](https://github.com/iconify/iconify) icon library\n\n### Adding New Icons\n\nYou can add new icons in the `packages/icons/src/iconify` directory:\n\n```ts\n// packages/icons/src/iconify/index.ts\nimport { createIconifyIcon } from '@vben-core/icons';\n\nexport const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');\n```\n\n### Usage\n\n```vue\n<script setup lang=\"ts\">\nimport { MdiKeyboardEsc } from '@vben/icons';\n</script>\n\n<template>\n  <!-- An icon with a width and height of 20px -->\n  <MdiKeyboardEsc class=\"size-5\" />\n</template>\n```\n\n## SVG Icons <Badge text=\"Recommended\" type=\"tip\"/>\n\nInstead of using Svg Sprite, SVG icons are directly imported,\n\n### Adding New Icons\n\nYou can add new icon files `test.svg` in the `packages/icons/src/svg/icons` directory, and then import it in `packages/icons/src/svg/index.ts`:\n\n```ts\n// packages/icons/src/svg/index.ts\nimport { createIconifyIcon } from '@vben-core/icons';\n\nconst SvgTestIcon = createIconifyIcon('svg:test');\n\nexport { SvgTestIcon };\n```\n\n### Usage\n\n```vue\n<script setup lang=\"ts\">\nimport { SvgTestIcon } from '@vben/icons';\n</script>\n\n<template>\n  <!-- An icon with a width and height of 20px -->\n  <SvgTestIcon class=\"size-5\" />\n</template>\n```\n\n## Tailwind CSS Icons <Badge text=\"Not Recommended\" type=\"danger\"/>\n\n### Usage\n\nYou can use the icons by directly adding the Tailwind CSS icon class names, which can be found on [iconify](https://github.com/iconify/iconify) ：\n\n```vue\n<span class=\"icon-[mdi--ab-testing]\"></span>\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/route.md",
    "content": "---\noutline: deep\n---\n\n# Routes and Menus\n\n::: info\n\nThis page is translated by machine translation and may not be very accurate.\n\n:::\n\nIn the project, the framework provides a basic routing system and **automatically generates the corresponding menu structure based on the routing files**.\n\n## Types of Routes\n\nRoutes are divided into core routes, static routes, and dynamic routes. Core routes are built-in routes of the framework, including root routes, login routes, 404 routes, etc.; static routes are routes that are determined when the project starts; dynamic routes are generally generated dynamically based on the user's permissions after the user logs in.\n\nBoth static and dynamic routes go through permission control, which can be controlled by configuring the `authority` field in the `meta` property of the route.\n\n### Core Routes\n\nCore routes are built-in routes of the framework, including root routes, login routes, 404 routes, etc. The configuration of core routes is in the `src/router/routes/core` directory under the application.\n\n::: tip\n\nCore routes are mainly used for the basic functions of the framework, so it is not recommended to put business-related routes in core routes. It is recommended to put business-related routes in static or dynamic routes.\n\n:::\n\n### Static Routes\n\nThe configuration of static routes is in the `src/router/routes/index` directory under the application. Open the commented file content:\n\n::: tip\n\nPermission control is controlled by the `authority` field in the `meta` property of the route. If your page project does not require permission control, you can omit the `authority` field.\n\n:::\n\n```ts\n// Uncomment if needed and create the folder\n// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true }); // [!code --]\nconst staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true }); // [!code ++]\n/** Dynamic routes */\nconst dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);\n\n/** External route list, these pages can be accessed without Layout, possibly used for embedding in other systems */\n// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles) // [!code --]\nconst externalRoutes: RouteRecordRaw[] = []; // [!code --]\nconst externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles); // [!code ++]\n```\n\n### Dynamic Routes\n\nThe configuration of dynamic routes is in the `src/router/routes/modules` directory under the corresponding application. This directory contains all the route files. The content format of each file is consistent with the Vue Router route configuration format. Below is the configuration of secondary and multi-level routes.\n\n## Route Definition\n\nThe configuration method of static routes and dynamic routes is the same. Below is the configuration of secondary and multi-level routes:\n\n### Secondary Routes\n\n::: details Secondary Route Example Code\n\n```ts\nimport type { RouteRecordRaw } from 'vue-router';\n\nimport { VBEN_LOGO_URL } from '@vben/constants';\n\nimport { BasicLayout } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      badgeType: 'dot',\n      badgeVariants: 'destructive',\n      icon: VBEN_LOGO_URL,\n      order: 9999,\n      title: $t('page.vben.title'),\n    },\n    name: 'VbenProject',\n    path: '/vben-admin',\n    redirect: '/vben-admin/about',\n    children: [\n      {\n        name: 'VbenAbout',\n        path: '/vben-admin/about',\n        component: () => import('#/views/_core/about/index.vue'),\n        meta: {\n          badgeType: 'dot',\n          badgeVariants: 'destructive',\n          icon: 'lucide:copyright',\n          title: $t('page.vben.about'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n```\n\n:::\n\n### Multi-level Routes\n\n::: tip\n\n- The parent route of multi-level routes does not need to set the `component` property, just set the `children` property. Unless you really need to display content nested under the parent route.\n- In most cases, the `redirect` property of the parent route does not need to be specified, it will default to the first child route.\n\n:::\n\n::: details Multi-level Route Example Code\n\n```ts\nimport type { RouteRecordRaw } from 'vue-router';\n\nimport { BasicLayout } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'ic:baseline-view-in-ar',\n      keepAlive: true,\n      order: 1000,\n      title: $t('demos.title'),\n    },\n    name: 'Demos',\n    path: '/demos',\n    redirect: '/demos/access',\n    children: [\n      // Nested menu\n      {\n        meta: {\n          icon: 'ic:round-menu',\n          title: $t('demos.nested.title'),\n        },\n        name: 'NestedDemos',\n        path: '/demos/nested',\n        redirect: '/demos/nested/menu1',\n        children: [\n          {\n            name: 'Menu1Demo',\n            path: '/demos/nested/menu1',\n            component: () => import('#/views/demos/nested/menu-1.vue'),\n            meta: {\n              icon: 'ic:round-menu',\n              keepAlive: true,\n              title: $t('demos.nested.menu1'),\n            },\n          },\n          {\n            name: 'Menu2Demo',\n            path: '/demos/nested/menu2',\n            meta: {\n              icon: 'ic:round-menu',\n              keepAlive: true,\n              title: $t('demos.nested.menu2'),\n            },\n            redirect: '/demos/nested/menu2/menu2-1',\n            children: [\n              {\n                name: 'Menu21Demo',\n                path: '/demos/nested/menu2/menu2-1',\n                component: () => import('#/views/demos/nested/menu-2-1.vue'),\n                meta: {\n                  icon: 'ic:round-menu',\n                  keepAlive: true,\n                  title: $t('demos.nested.menu2_1'),\n                },\n              },\n            ],\n          },\n          {\n            name: 'Menu3Demo',\n            path: '/demos/nested/menu3',\n            meta: {\n              icon: 'ic:round-menu',\n              title: $t('demos.nested.menu3'),\n            },\n            redirect: '/demos/nested/menu3/menu3-1',\n            children: [\n              {\n                name: 'Menu31Demo',\n                path: 'menu3-1',\n                component: () => import('#/views/demos/nested/menu-3-1.vue'),\n                meta: {\n                  icon: 'ic:round-menu',\n                  keepAlive: true,\n                  title: $t('demos.nested.menu3_1'),\n                },\n              },\n              {\n                name: 'Menu32Demo',\n                path: 'menu3-2',\n                meta: {\n                  icon: 'ic:round-menu',\n                  title: $t('demos.nested.menu3_2'),\n                },\n                redirect: '/demos/nested/menu3/menu3-2/menu3-2-1',\n                children: [\n                  {\n                    name: 'Menu321Demo',\n                    path: '/demos/nested/menu3/menu3-2/menu3-2-1',\n                    component: () =>\n                      import('#/views/demos/nested/menu-3-2-1.vue'),\n                    meta: {\n                      icon: 'ic:round-menu',\n                      keepAlive: true,\n                      title: $t('demos.nested.menu3_2_1'),\n                    },\n                  },\n                ],\n              },\n            ],\n          },\n        ],\n      },\n    ],\n  },\n];\n\nexport default routes;\n```\n\n:::\n\n## Adding a New Page\n\nTo add a new page, you only need to add a route and the corresponding page component.\n\n### Adding a Route\n\nAdd a route object in the corresponding route file, as follows:\n\n```ts\nimport type { RouteRecordRaw } from 'vue-router';\n\nimport { VBEN_LOGO_URL } from '@vben/constants';\n\nimport { BasicLayout } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'mdi:home',\n      title: $t('page.home.title'),\n    },\n    name: 'Home',\n    path: '/home',\n    redirect: '/home/index',\n    children: [\n      {\n        name: 'HomeIndex',\n        path: '/home/index',\n        component: () => import('#/views/home/index.vue'),\n        meta: {\n          icon: 'mdi:home',\n          title: $t('page.home.index'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n```\n\n### Adding a Page Component\n\nIn `#/views/home/`, add a new `index.vue` file, as follows:\n\n```vue\n<template>\n  <div>\n    <h1>home page</h1>\n  </div>\n</template>\n```\n\n### Verification\n\nAt this point, the page has been added. Visit `http://localhost:5555/home/index` to see the corresponding page.\n\n## Route Configuration\n\nThe route configuration items are mainly in the `meta` property of the route object. The following are common configuration items:\n\n```ts {5-8}\nconst routes = [\n  {\n    name: 'HomeIndex',\n    path: '/home/index',\n    meta: {\n      icon: 'mdi:home',\n      title: $t('page.home.index'),\n    },\n  },\n];\n```\n\n::: details Route Meta Configuration Type Definition\n\n```ts\ninterface RouteMeta {\n  /**\n   * Active icon (menu)\n   */\n  activeIcon?: string;\n  /**\n   * The currently active menu, sometimes you don't want to activate the existing menu, use this to activate the parent menu\n   */\n  activePath?: string;\n  /**\n   * Whether to fix the tab\n   * @default false\n   */\n  affixTab?: boolean;\n  /**\n   * The order of fixed tabs\n   * @default 0\n   */\n  affixTabOrder?: number;\n  /**\n   * Specific roles required to access\n   * @default []\n   */\n  authority?: string[];\n  /**\n   * Badge\n   */\n  badge?: string;\n  /**\n   * Badge type\n   */\n  badgeType?: 'dot' | 'normal';\n  /**\n   * Badge color\n   */\n  badgeVariants?:\n    | 'default'\n    | 'destructive'\n    | 'primary'\n    | 'success'\n    | 'warning'\n    | string;\n  /**\n   * The children of the current route are not displayed in the menu\n   * @default false\n   */\n  hideChildrenInMenu?: boolean;\n  /**\n   * The current route is not displayed in the breadcrumb\n   * @default false\n   */\n  hideInBreadcrumb?: boolean;\n  /**\n   * The current route is not displayed in the menu\n   * @default false\n   */\n  hideInMenu?: boolean;\n  /**\n   * The current route is not displayed in the tab\n   * @default false\n   */\n  hideInTab?: boolean;\n  /**\n   * Icon (menu/tab)\n   */\n  icon?: string;\n  /**\n   * iframe address\n   */\n  iframeSrc?: string;\n  /**\n   * Ignore permissions, can be accessed directly\n   * @default false\n   */\n  ignoreAccess?: boolean;\n  /**\n   * Enable KeepAlive cache\n   */\n  keepAlive?: boolean;\n  /**\n   * External link - jump path\n   */\n  link?: string;\n  /**\n   * Whether the route has been loaded\n   */\n  loaded?: boolean;\n  /**\n   * Maximum number of open tabs\n   * @default false\n   */\n  maxNumOfOpenTab?: number;\n  /**\n   * The menu can be seen, but access will be redirected to 403\n   */\n  menuVisibleWithForbidden?: boolean;\n  /**\n   * Open in a new window\n   */\n  openInNewWindow?: boolean;\n  /**\n   * Used for route -> menu sorting\n   */\n  order?: number;\n  /**\n   * Parameters carried by the menu\n   */\n  query?: Recordable;\n  /**\n   * Title name\n   */\n  title: string;\n}\n```\n\n:::\n\n### title\n\n- Type: `string`\n- Default: `''`\n\nUsed to configure the title of the page, which will be displayed in the menu and tab. Generally used with internationalization.\n\n### icon\n\n- Type: `string`\n- Default: `''`\n\nUsed to configure the icon of the page, which will be displayed in the menu and tab. Generally used with an icon library, if it is an `http` link, the image will be loaded automatically.\n\n### activeIcon\n\n- Type: `string`\n- Default: `''`\n\nUsed to configure the active icon of the page, which will be displayed in the menu. Generally used with an icon library, if it is an `http` link, the image will be loaded automatically.\n\n### keepAlive\n\n- Type: `boolean`\n- Default: `false`\n\nUsed to configure whether the page cache is enabled. When enabled, the page will be cached and will not reload, only effective when the tab is enabled.\n\n### hideInMenu\n\n- Type: `boolean`\n- Default: `false`\n\nUsed to configure whether the page is hidden in the menu. When hidden, the page will not be displayed in the menu.\n\n### hideInTab\n\n- Type: `boolean`\n- Default: `false`\n\nUsed to configure whether the page is hidden in the tab. When hidden, the page will not be displayed in the tab.\n\n### hideInBreadcrumb\n\n- Type: `boolean`\n- Default: `false`\n\nUsed to configure whether the page is hidden in the breadcrumb. When hidden, the page will not be displayed in the breadcrumb.\n\n### hideChildrenInMenu\n\n- Type: `boolean`\n- Default: `false`\n\nUsed to configure whether the subpages of the page are hidden in the menu. When hidden, the subpages will not be displayed in the menu.\n\n### authority\n\n- Type: `string[]`\n- Default: `[]`\n\nUsed to configure the permissions of the page. Only users with the corresponding permissions can access the page. If not configured, no permissions are required.\n\n### badge\n\n- Type: `string`\n- Default: `''`\n\nUsed to configure the badge of the page, which will be displayed in the menu.\n\n### badgeType\n\n- Type: `'dot' | 'normal'`\n- Default: `'normal'`\n\nUsed to configure the badge type of the page. `dot` is a small red dot, `normal` is text.\n\n### badgeVariants\n\n- Type: `'default' | 'destructive' | 'primary' | 'success' | 'warning' | string`\n- Default: `'success'`\n\nUsed to configure the badge color of the page.\n\n### activePath\n\n- Type: `string`\n- Default: `''`\n\nUsed to configure the currently active menu. Sometimes the page is not displayed in the menu, and this is used to activate the parent menu.\n\n### affixTab\n\n- Type: `boolean`\n- Default: `false`\n\nUsed to configure whether the page is fixed in the tab. When fixed, the page cannot be closed.\n\n### affixTabOrder\n\n- Type: `number`\n- Default: `0`\n\nUsed to configure the order of fixed tabs, sorted in ascending order.\n\n### iframeSrc\n\n- Type: `string`\n- Default: `''`\n\nUsed to configure the `iframe` address of the embedded page. When set, the corresponding page will be embedded in the current page.\n\n### ignoreAccess\n\n- Type: `boolean`\n- Default: `false`\n\nUsed to configure whether the page ignores permissions and can be accessed directly.\n\n### link\n\n- Type: `string`\n- Default: `''`\n\nUsed to configure the external link jump path, which will open in a new window.\n\n### maxNumOfOpenTab\n\n- Type: `number`\n- Default: `-1`\n\nUsed to configure the maximum number of open tabs. When set, the earliest opened tab will be automatically closed when opening a new tab (only effective when opening tabs with the same name).\n\n### menuVisibleWithForbidden\n\n- Type: `boolean`\n- Default: `false`\n\nUsed to configure whether the page can be seen in the menu, but access will be redirected to 403.\n\n### openInNewWindow\n\n- Type: `boolean`\n- Default: `false`\n\nWhen set to `true`, the page will open in a new window.\n\n### order\n\n- Type: `number`\n- Default: `0`\n\nUsed to configure the sorting of the page, used for route to menu sorting.\n\n_Note:_ Sorting is only effective for first-level menus. The sorting of second-level menus needs to be set in the corresponding first-level menu in code order.\n\n### query\n\n- Type: `Recordable`\n- Default: `{}`\n\nUsed to configure the menu parameters of the page, which will be passed to the page in the menu.\n\n## Route Refresh\n\nThe route refresh method is as follows:\n\n```vue\n<script setup lang=\"ts\">\nimport { useRefresh } from '@vben/hooks';\n\nconst { refresh } = useRefresh();\n\n// Refresh the current route\nrefresh();\n</script>\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/server.md",
    "content": "# Server Interaction and Data Mocking\n\n::: tip Note\n\nThis document explains how to use Mock data and interact with the server in a development environment, involving technologies such as:\n\n- [Nitro](https://nitro.unjs.io/) A lightweight backend server that can be deployed anywhere, used as a Mock server in the project.\n- [axios](https://axios-http.com/docs/intro) Used to send HTTP requests to interact with the server.\n\n:::\n\n## Interaction in Development Environment\n\nIf the frontend application and the backend API server are not running on the same host, you need to proxy the API requests to the API server in the development environment. If they are on the same host, you can directly request the specific API endpoint.\n\n### Local Development CORS Configuration\n\n::: tip Hint\n\nThe CORS configuration for local development has already been set up. If you have other requirements, you can add or adjust the configuration as needed.\n\n:::\n\n#### Configuring Local Development API Endpoint\n\nConfigure the API endpoint in the `.env.development` file at the project root directory, here it is set to `/api`:\n\n```bash\nVITE_GLOB_API_URL=/api\n```\n\n#### Configuring Development Server Proxy\n\nIn the development environment, if you need to handle CORS, configure the API endpoint in the `vite.config.mts` file under the corresponding application directory:\n\n```ts{8-16}\n// apps/web-antd/vite.config.mts\nimport { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    vite: {\n      server: {\n        proxy: {// [!code focus:11]\n          '/api': {\n            changeOrigin: true,\n            rewrite: (path) => path.replace(/^\\/api/, ''),\n            // mock proxy\n            target: 'http://localhost:5320/api',\n            ws: true,\n          },\n        },\n      },\n    },\n  };\n});\n```\n\n#### API Requests\n\nBased on the above configuration, we can use `/api` as the prefix for API requests in our frontend project, for example:\n\n```ts\nimport axios from 'axios';\n\naxios.get('/api/user').then((res) => {\n  console.log(res);\n});\n```\n\nAt this point, the request will be proxied to `http://localhost:5320/api/user`.\n\n::: warning Note\n\nFrom the browser's console Network tab, the request appears as `http://localhost:5555/api/user`. This is because the proxy configuration does not change the local request's URL.\n\n:::\n\n### Configuration Without CORS\n\nIf there is no CORS issue, you can directly ignore the [Configure Development Server Proxy](./server.md#configure-development-server-proxy) settings and set the API endpoint directly in `VITE_GLOB_API_URL`.\n\nConfigure the API endpoint in the `.env.development` file at the project root directory:\n\n```bash\nVITE_GLOB_API_URL=https://mock-napi.vben.pro/api\n```\n\n## Production Environment Interaction\n\n### API Endpoint Configuration\n\nConfigure the API endpoint in the `.env.production` file at the project root directory:\n\n```bash\nVITE_GLOB_API_URL=https://mock-napi.vben.pro/api\n```\n\n::: tip How to Dynamically Modify API Endpoint in Production\n\nVariables starting with `VITE_GLOB_*` in the `.env` file are injected into the `_app.config.js` file during packaging. After packaging, you can modify the corresponding API addresses in `dist/_app.config.js` and refresh the page to apply the changes. This eliminates the need to package multiple times for different environments, allowing a single package to be deployed across multiple API environments.\n\n:::\n\n### Cross-Origin Resource Sharing (CORS) Handling\n\nIn the production environment, if CORS issues arise, you can use `nginx` to proxy the API address or enable `cors` on the backend to handle it (refer to the mock service for examples).\n\n## API Request Configuration\n\nThe project comes with a default basic request configuration based on `axios`, provided by the `@vben/request` package. The project does not overly complicate things but simply wraps some common configurations. If there are other requirements, you can add or adjust the configurations as needed. Depending on the app, different component libraries and `store` might be used, so under the `src/api/request.ts` folder in the application directory, there are corresponding request configuration files. For example, in the `web-antd` project, there's a `src/api/request.ts` file where you can configure according to your needs.\n\n### Request Examples\n\n#### GET Request\n\n```ts\nimport { requestClient } from '#/api/request';\n\nexport async function getUserInfoApi() {\n  return requestClient.get<UserInfo>('/user/info');\n}\n```\n\n#### POST/PUT Request\n\n```ts\nimport { requestClient } from '#/api/request';\n\nexport async function saveUserApi(user: UserInfo) {\n  return requestClient.post<UserInfo>('/user', user);\n}\n\nexport async function saveUserApi(user: UserInfo) {\n  return requestClient.put<UserInfo>('/user', user);\n}\n\nexport async function saveUserApi(user: UserInfo) {\n  const url = user.id ? `/user/${user.id}` : '/user/';\n  return requestClient.request<UserInfo>(url, {\n    data: user,\n    // OR PUT\n    method: user.id ? 'PUT' : 'POST',\n  });\n}\n```\n\n#### DELETE Request\n\n```ts\nimport { requestClient } from '#/api/request';\n\nexport async function deleteUserApi(userId: number) {\n  return requestClient.delete<boolean>(`/user/${userId}`);\n}\n```\n\n### Request Configuration\n\nThe `src/api/request.ts` within the application can be configured according to the needs of your application:\n\n```ts\n/**\n * This file can be adjusted according to business logic\n */\nimport type { HttpResponse } from '@vben/request';\n\nimport { useAppConfig } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\nimport {\n  authenticateResponseInterceptor,\n  errorMessageResponseInterceptor,\n  RequestClient,\n} from '@vben/request';\nimport { useAccessStore } from '@vben/stores';\n\nimport { message } from 'ant-design-vue';\n\nimport { useAuthStore } from '#/store';\n\nimport { refreshTokenApi } from './core';\n\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n\nfunction createRequestClient(baseURL: string) {\n  const client = new RequestClient({\n    baseURL,\n  });\n\n  /**\n   * Re-authentication Logic\n   */\n  async function doReAuthenticate() {\n    console.warn('Access token or refresh token is invalid or expired. ');\n    const accessStore = useAccessStore();\n    const authStore = useAuthStore();\n    accessStore.setAccessToken(null);\n    if (preferences.app.loginExpiredMode === 'modal') {\n      accessStore.setLoginExpired(true);\n    } else {\n      await authStore.logout();\n    }\n  }\n\n  /**\n   * Refresh token Logic\n   */\n  async function doRefreshToken() {\n    const accessStore = useAccessStore();\n    const resp = await refreshTokenApi();\n    const newToken = resp.data;\n    accessStore.setAccessToken(newToken);\n    return newToken;\n  }\n\n  function formatToken(token: null | string) {\n    return token ? `Bearer ${token}` : null;\n  }\n\n  // Request Header Processing\n  client.addRequestInterceptor({\n    fulfilled: async (config) => {\n      const accessStore = useAccessStore();\n\n      config.headers.Authorization = formatToken(accessStore.accessToken);\n      config.headers['Accept-Language'] = preferences.app.locale;\n      return config;\n    },\n  });\n\n  // Deal Response Data\n  client.addResponseInterceptor<HttpResponse>({\n    fulfilled: (response) => {\n      const { data: responseData, status } = response;\n\n      const { code, data } = responseData;\n\n      if (status >= 200 && status < 400 && code === 0) {\n        return data;\n      }\n      throw Object.assign({}, response, { response });\n    },\n  });\n\n  // Handling Token Expiration\n  client.addResponseInterceptor(\n    authenticateResponseInterceptor({\n      client,\n      doReAuthenticate,\n      doRefreshToken,\n      enableRefreshToken: preferences.app.enableRefreshToken,\n      formatToken,\n    }),\n  );\n\n  // Generic error handling; if none of the above error handling logic is triggered, it will fall back to this.\n  client.addResponseInterceptor(\n    errorMessageResponseInterceptor((msg: string, error) => {\n      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg\n      // 当前mock接口返回的错误字段是 error 或者 message\n      const responseData = error?.response?.data ?? {};\n      const errorMessage = responseData?.error ?? responseData?.message ?? '';\n      // 如果没有错误信息，则会根据状态码进行提示\n      message.error(errorMessage || msg);\n    }),\n  );\n\n  return client;\n}\n\nexport const requestClient = createRequestClient(apiURL);\n\nexport const baseRequestClient = new RequestClient({ baseURL: apiURL });\n```\n\n### Multiple API Endpoints\n\nTo handle multiple API endpoints, simply create multiple `requestClient` instances, as follows:\n\n```ts\nconst { apiURL, otherApiURL } = useAppConfig(\n  import.meta.env,\n  import.meta.env.PROD,\n);\n\nexport const requestClient = createRequestClient(apiURL);\n\nexport const otherRequestClient = createRequestClient(otherApiURL);\n```\n\n## Refresh Token\n\nThe project provides a default logic for refreshing tokens. To enable it, follow the configuration below:\n\n- Ensure the refresh token feature is enabled\n\nAdjust the `preferences.ts` in the corresponding application directory to ensure `enableRefreshToken='true'`.\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    enableRefreshToken: true,\n  },\n});\n```\n\nConfigure the `doRefreshToken` method in `src/api/request.ts` as follows:\n\n```ts\n// Adjust this to your token format\nfunction formatToken(token: null | string) {\n  return token ? `Bearer ${token}` : null;\n}\n\n/**\n * Refresh token logic\n */\nasync function doRefreshToken() {\n  const accessStore = useAccessStore();\n  // Adjust this to your refresh token API\n  const resp = await refreshTokenApi();\n  const newToken = resp.data;\n  accessStore.setAccessToken(newToken);\n  return newToken;\n}\n```\n\n## Data Mocking\n\n::: tip Production Environment Mock\n\nThe new version no longer supports mock in the production environment. Please use real interfaces.\n\n:::\n\nMock data is an indispensable part of frontend development, serving as a key link in separating frontend and backend development. By agreeing on interfaces with the server side in advance and simulating request data and even logic, frontend development can proceed independently, without being blocked by the backend development process.\n\nThe project uses [Nitro](https://nitro.unjs.io/) for local mock data processing. The principle is to start an additional backend service locally, which is a real backend service that can handle requests and return data.\n\n### Using Nitro\n\nThe mock service code is located in the `apps/backend-mock` directory. It does not need to be started manually and is already integrated into the project. You only need to run `pnpm dev` in the project root directory. After running successfully, the console will print `http://localhost:5320/api`, and you can access this address to view the mock service.\n\n[Nitro](https://nitro.unjs.io/) syntax is simple, and you can configure and develop according to your needs. For specific configurations, you can refer to the [Nitro documentation](https://nitro.unjs.io/).\n\n## Disabling Mock Service\n\nSince mock is essentially a real backend service, if you do not need the mock service, you can configure `VITE_NITRO_MOCK=false` in the `.env.development` file in the project root directory to disable the mock service.\n\n```bash\n# .env.development\nVITE_NITRO_MOCK=false\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/settings.md",
    "content": "# Configuration\n\n## Environment Variable Configuration\n\nThe project's environment variable configuration is located in the application directory under `.env`, `.env.development`, `.env.production`.\n\nThe rules are consistent with [Vite Env Variables and Modes](https://vitejs.dev/guide/env-and-mode.html). The format is as follows:\n\n```bash\n.env                # Loaded in all environments\n.env.local          # Loaded in all environments, but ignored by git\n.env.[mode]         # Only loaded in the specified mode\n.env.[mode].local   # Only loaded in the specified mode, but ignored by git\n```\n\n::: tip\n\n- Only variables starting with `VITE_` will be embedded into the client-side package. You can access them in the project code like this:\n\n  ```ts\n  console.log(import.meta.env.VITE_PROT);\n  ```\n\n- Variables starting with `VITE_GLOB_*` will be added to the `_app.config.js` configuration file during packaging.\n\n:::\n\n## Environment Configuration Description\n\n::: code-group\n\n```bash [.env]\n# Application title\nVITE_APP_TITLE=Vben Admin\n\n# Application namespace, used as a prefix for caching, store, etc., to ensure isolation\nVITE_APP_NAMESPACE=vben-web-antd\n```\n\n```bash [.env.development]\n# Port Number\nVITE_PORT=5555\n\n# Public Path for Resources, must start and end with /\nVITE_BASE=/\n\n# API URL\nVITE_GLOB_API_URL=/api\n\n# Whether to enable Nitro Mock service, true to enable, false to disable\nVITE_NITRO_MOCK=true\n\n# Whether to open devtools, true to open, false to close\nVITE_DEVTOOLS=true\n\n# Whether to inject global loading\nVITE_INJECT_APP_LOADING=true\n\n# Whether to generate after packaging dist.zip\nVITE_ARCHIVER=true\n```\n\n```bash [.env.production]\n# Public Path for Resources, must start and end with /\nVITE_BASE=/\n\n# API URL\nVITE_GLOB_API_URL=https://mock-napi.vben.pro/api\n\n# Whether to enable compression, can be set to none, brotli, gzip\nVITE_COMPRESS=gzip\n\n# Whether to enable PWA\nVITE_PWA=false\n\n# vue-router mode\nVITE_ROUTER_HISTORY=hash\n\n# Whether to inject global loading\nVITE_INJECT_APP_LOADING=true\n\n# Whether to generate dist.zip after packaging\nVITE_ARCHIVER=true\n```\n\n:::\n\n## Dynamic Configuration in Production Environment\n\nWhen executing `pnpm build` in the root directory of the monorepo, a `dist/_app.config.js` file will be automatically generated in the corresponding application and inserted into `index.html`.\n\n`_app.config.js` is a dynamic configuration file that allows for modifications to the configuration dynamically based on different environments after the project has been built. The content is as follows:\n\n```ts\nwindow._VBEN_ADMIN_PRO_APP_CONF_ = {\n  VITE_GLOB_API_URL: 'https://mock-napi.vben.pro/api',\n};\nObject.freeze(window._VBEN_ADMIN_PRO_APP_CONF_);\nObject.defineProperty(window, '_VBEN_ADMIN_PRO_APP_CONF_', {\n  configurable: false,\n  writable: false,\n});\n```\n\n### Purpose\n\n`_app.config.js` is used for projects that need to dynamically modify configurations after packaging, such as API endpoints. There's no need to repackage; you can simply modify the variables in `/dist/_app.config.js` after packaging, and refresh to update the variables in the code. A `js` file is used to ensure that the configuration file is loaded early in the order.\n\n### Usage\n\nTo access the variables inside `_app.config.js`, you need to use the `useAppConfig` method provided by `@vben/hooks`.\n\n```ts\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n```\n\n### Adding New\n\nTo add a new dynamically modifiable configuration item, simply follow the steps below:\n\n- First, add the variable that needs to be dynamically configurable in the `.env` file or the corresponding development environment configuration file. The variable must start with `VITE_GLOB_*`, for example:\n\n  ```bash\n  VITE_GLOB_OTHER_API_URL=https://mock-napi.vben.pro/other-api\n  ```\n\n- In `packages/types/global.d.ts`, add the corresponding type definition, such as:\n\n  ```ts\n  export interface VbenAdminProAppConfigRaw {\n    VITE_GLOB_API_URL: string;\n    VITE_GLOB_OTHER_API_URL: string; // [!code ++]\n  }\n\n  export interface ApplicationConfig {\n    apiURL: string;\n    otherApiURL: string; // [!code ++]\n  }\n  ```\n\n- In `packages/effects/hooks/src/use-app-config.ts`, add the corresponding configuration item, such as:\n\n  ```ts\n  export function useAppConfig(\n    env: Record<string, any>,\n    isProduction: boolean,\n  ): ApplicationConfig {\n    // In production environment, directly use the window._VBEN_ADMIN_PRO_APP_CONF_ global variable\n    const config = isProduction\n      ? window._VBEN_ADMIN_PRO_APP_CONF_\n      : (env as VbenAdminProAppConfigRaw);\n\n    const { VITE_GLOB_API_URL, VITE_GLOB_OTHER_API_URL } = config; // [!code ++]\n\n    return {\n      apiURL: VITE_GLOB_API_URL,\n      otherApiURL: VITE_GLOB_OTHER_API_URL, // [!code ++]\n    };\n  }\n  ```\n\nAt this point, you can use the `useAppConfig` method within the project to access the newly added configuration item.\n\n```ts\nconst { otherApiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n```\n\n::: warning Warning\n\nThe `useAppConfig` method should only be used within the application and not be coupled with the internals of a package. The reason for passing `import.meta.env` and `import.meta.env.PROD` is to avoid such coupling. A pure package should avoid using variables specific to a particular build tool.\n\n:::\n\n## Preferences\n\nThe project offers a wide range of preference settings for dynamically configuring various features of the project:\n\n![](/guide/preferences.png)\n\nIf you cannot find documentation for a setting, you can try configuring it yourself and then click `Copy Preferences` to override the project defaults. The configuration file is located in the application directory under `preferences.ts`, where you can override the framework's default configurations to achieve custom settings.\n\n```ts\nimport { useAppConfig } from '@vben/hooks';\nimport { defineOverridesPreferences } from '@vben/preferences';\n\n/**\n * @description Project configuration file\n * Only a part of the configuration in the project needs to be covered, and unnecessary configurations do not need to be covered. The default configuration will be automatically used\n * !!! Please clear the cache after changing the configuration, otherwise it may not take effect\n */\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n});\n```\n\n### Framework default configuration\n\n::: details View the default configuration of the framework\n\n```ts\nconst defaultPreferences: Preferences = {\n  app: {\n    accessMode: 'frontend',\n    authPageLayout: 'panel-right',\n    checkUpdatesInterval: 1,\n    colorGrayMode: false,\n    colorWeakMode: false,\n    compact: false,\n    contentCompact: 'wide',\n    contentCompactWidth: 1200,\n    contentPadding: 0,\n    contentPaddingBottom: 0,\n    contentPaddingLeft: 0,\n    contentPaddingRight: 0,\n    contentPaddingTop: 0,\n    defaultAvatar:\n      'https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp',\n    defaultHomePath: '/analytics',\n    dynamicTitle: true,\n    enableCheckUpdates: true,\n    enablePreferences: true,\n    enableRefreshToken: false,\n    isMobile: false,\n    layout: 'sidebar-nav',\n    locale: 'zh-CN',\n    loginExpiredMode: 'page',\n    name: 'Vben Admin',\n    preferencesButtonPosition: 'auto',\n    watermark: false,\n    zIndex: 200,\n  },\n  breadcrumb: {\n    enable: true,\n    hideOnlyOne: false,\n    showHome: false,\n    showIcon: true,\n    styleType: 'normal',\n  },\n  copyright: {\n    companyName: 'Vben',\n    companySiteLink: 'https://www.vben.pro',\n    date: '2024',\n    enable: true,\n    icp: '',\n    icpLink: '',\n    settingShow: true,\n  },\n  footer: {\n    enable: false,\n    fixed: false,\n    height: 32,\n  },\n  header: {\n    enable: true,\n    height: 50,\n    hidden: false,\n    menuAlign: 'start',\n    mode: 'fixed',\n  },\n  logo: {\n    enable: true,\n    fit: 'contain',\n    source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n  },\n  navigation: {\n    accordion: true,\n    split: true,\n    styleType: 'rounded',\n  },\n  shortcutKeys: {\n    enable: true,\n    globalLockScreen: true,\n    globalLogout: true,\n    globalPreferences: true,\n    globalSearch: true,\n  },\n  sidebar: {\n    autoActivateChild: false,\n    collapsed: false,\n    collapsedButton: true,\n    collapsedShowTitle: false,\n    collapseWidth: 60,\n    enable: true,\n    expandOnHover: true,\n    extraCollapse: false,\n    extraCollapsedWidth: 60,\n    fixedButton: true,\n    hidden: false,\n    mixedWidth: 80,\n    width: 224,\n  },\n  tabbar: {\n    draggable: true,\n    enable: true,\n    height: 38,\n    keepAlive: true,\n    maxCount: 0,\n    middleClickToClose: false,\n    persist: true,\n    showIcon: true,\n    showMaximize: true,\n    showMore: true,\n    styleType: 'chrome',\n    wheelable: true,\n  },\n  theme: {\n    builtinType: 'default',\n    colorDestructive: 'hsl(348 100% 61%)',\n    colorPrimary: 'hsl(212 100% 45%)',\n    colorSuccess: 'hsl(144 57% 58%)',\n    colorWarning: 'hsl(42 84% 61%)',\n    mode: 'dark',\n    radius: '0.5',\n    semiDarkHeader: false,\n    semiDarkSidebar: false,\n  },\n  transition: {\n    enable: true,\n    loading: true,\n    name: 'fade-slide',\n    progress: true,\n  },\n  widget: {\n    fullscreen: true,\n    globalSearch: true,\n    languageToggle: true,\n    lockScreen: true,\n    notification: true,\n    refresh: true,\n    sidebarToggle: true,\n    themeToggle: true,\n  },\n};\n```\n\n:::\n\n::: details View the default configuration type of the framework\n\n```ts\ninterface AppPreferences {\n  /** Permission mode */\n  accessMode: AccessModeType;\n  /** Layout of the login/registration page */\n  authPageLayout: AuthPageLayoutType;\n  /** Interval for checking updates */\n  checkUpdatesInterval: number;\n  /** Whether to enable gray mode */\n  colorGrayMode: boolean;\n  /** Whether to enable color weakness mode */\n  colorWeakMode: boolean;\n  /** Whether to enable compact mode */\n  compact: boolean;\n  /** Whether to enable content compact mode */\n  contentCompact: ContentCompactType;\n  /** Content compact width */\n  contentCompactWidth: number;\n  /** Content padding */\n  contentPadding: number;\n  /** Content bottom padding */\n  contentPaddingBottom: number;\n  /** Content left padding */\n  contentPaddingLeft: number;\n  /** Content right padding */\n  contentPaddingRight: number;\n  /** Content top padding */\n  contentPaddingTop: number;\n  // /** Default application avatar */\n  defaultAvatar: string;\n  /** Default homepage path */\n  defaultHomePath: string;\n  // /** Enable dynamic title */\n  dynamicTitle: boolean;\n  /** Whether to enable update checks */\n  enableCheckUpdates: boolean;\n  /** Whether to display preferences */\n  enablePreferences: boolean;\n  /**\n   * @zh_CN Whether to enable refreshToken\n   */\n  enableRefreshToken: boolean;\n  /** Whether it's mobile */\n  isMobile: boolean;\n  /** Layout method */\n  layout: LayoutType;\n  /** Supported languages */\n  locale: SupportedLanguagesType;\n  /** Login expiration mode */\n  loginExpiredMode: LoginExpiredModeType;\n  /** Application name */\n  name: string;\n  /** Position of the preferences button */\n  preferencesButtonPosition: PreferencesButtonPositionType;\n  /**\n   * @zh_CN Whether to enable watermark\n   */\n  watermark: boolean;\n  /** z-index */\n  zIndex: number;\n}\ninterface BreadcrumbPreferences {\n  /** Whether breadcrumbs are enabled */\n  enable: boolean;\n  /** Whether to hide breadcrumbs when there is only one */\n  hideOnlyOne: boolean;\n  /** Whether the home icon in breadcrumbs is visible */\n  showHome: boolean;\n  /** Whether the icon in breadcrumbs is visible */\n  showIcon: boolean;\n  /** Breadcrumb style */\n  styleType: BreadcrumbStyleType;\n}\n\ninterface CopyrightPreferences {\n  /** Copyright company name */\n  companyName: string;\n  /** Link to the copyright company's site */\n  companySiteLink: string;\n  /** Copyright date */\n  date: string;\n  /** Whether copyright is visible */\n  enable: boolean;\n  /** ICP number */\n  icp: string;\n  /** Link to the ICP */\n  icpLink: string;\n  /** Whether to show in settings panel */\n  settingShow?: boolean;\n}\n\ninterface FooterPreferences {\n  /** Whether the footer is visible */\n  enable: boolean;\n  /** Whether the footer is fixed */\n  fixed: boolean;\n  /** Footer height */\n  height: number;\n}\n\ninterface HeaderPreferences {\n  /** Whether the header is enabled */\n  enable: boolean;\n  /** Header height */\n  height: number;\n  /** Whether the header is hidden, css-hidden */\n  hidden: boolean;\n  /** Header menu alignment */\n  menuAlign: LayoutHeaderMenuAlignType;\n  /** Header display mode */\n  mode: LayoutHeaderModeType;\n}\n\ninterface LogoPreferences {\n  /** Whether the logo is visible */\n  enable: boolean;\n  /** Logo image fitting method */\n  fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\n  /** Logo URL */\n  source: string;\n}\n\ninterface NavigationPreferences {\n  /** Navigation menu accordion mode */\n  accordion: boolean;\n  /** Whether the navigation menu is split, only effective in layout=mixed-nav */\n  split: boolean;\n  /** Navigation menu style */\n  styleType: NavigationStyleType;\n}\ninterface SidebarPreferences {\n  /** Automatically activate child menu when clicking on directory */\n  autoActivateChild: boolean;\n  /** Whether the sidebar is collapsed */\n  collapsed: boolean;\n  /** Whether the sidebar collapse button is visible */\n  collapsedButton: boolean;\n  /** Whether to show title when sidebar is collapsed */\n  collapsedShowTitle: boolean;\n  /** Sidebar collapse width */\n  collapseWidth: number;\n  /** Whether the sidebar is visible */\n  enable: boolean;\n  /** Menu auto-expand state */\n  expandOnHover: boolean;\n  /** Whether the sidebar extension area is collapsed */\n  extraCollapse: boolean;\n  /** Sidebar extension area collapse width */\n  extraCollapsedWidth: number;\n  /** Whether the sidebar fixed button is visible */\n  fixedButton: boolean;\n  /** Whether the sidebar is hidden - css */\n  hidden: boolean;\n  /** Mixed sidebar width */\n  mixedWidth: number;\n  /** Sidebar width */\n  width: number;\n}\n\ninterface ShortcutKeyPreferences {\n  /** Whether shortcut keys are enabled globally */\n  enable: boolean;\n  /** Whether the global lock screen shortcut is enabled */\n  globalLockScreen: boolean;\n  /** Whether the global logout shortcut is enabled */\n  globalLogout: boolean;\n  /** Whether the global preferences shortcut is enabled */\n  globalPreferences: boolean;\n  /** Whether the global search shortcut is enabled */\n  globalSearch: boolean;\n}\n\ninterface TabbarPreferences {\n  /** Whether dragging of multiple tabs is enabled */\n  draggable: boolean;\n  /** Whether multiple tabs are enabled */\n  enable: boolean;\n  /** Tab height */\n  height: number;\n  /** Whether tab caching is enabled */\n  keepAlive: boolean;\n  /** Maximum number of tabs */\n  maxCount: number;\n  /** Whether to close tab when middle-clicked */\n  middleClickToClose: boolean;\n  /** Whether tabs are persistent */\n  persist: boolean;\n  /** Whether icons in multiple tabs are enabled */\n  showIcon: boolean;\n  /** Whether to show the maximize button */\n  showMaximize: boolean;\n  /** Whether to show the more button */\n  showMore: boolean;\n  /** Tab style */\n  styleType: TabsStyleType;\n  /** Whether mouse wheel response is enabled */\n  wheelable: boolean;\n}\ninterface ThemePreferences {\n  /** Built-in theme name */\n  builtinType: BuiltinThemeType;\n  /** Destructive color */\n  colorDestructive: string;\n  /** Primary color */\n  colorPrimary: string;\n  /** Success color */\n  colorSuccess: string;\n  /** Warning color */\n  colorWarning: string;\n  /** Current theme */\n  mode: ThemeModeType;\n  /** Radius */\n  radius: string;\n  /** Whether to enable semi-dark header (only effective when theme='light') */\n  semiDarkHeader: boolean;\n  /** Whether to enable semi-dark sidebar (only effective when theme='light') */\n  semiDarkSidebar: boolean;\n}\n\ninterface TransitionPreferences {\n  /** Whether page transition animations are enabled */\n  enable: boolean;\n  // /** Whether page loading loading is enabled */\n  loading: boolean;\n  /** Page transition animation */\n  name: PageTransitionType | string;\n  /** Whether page loading progress animation is enabled */\n  progress: boolean;\n}\n\ninterface WidgetPreferences {\n  /** Whether fullscreen widgets are enabled */\n  fullscreen: boolean;\n  /** Whether global search widget is enabled */\n  globalSearch: boolean;\n  /** Whether language switch widget is enabled */\n  languageToggle: boolean;\n  /** Whether lock screen functionality is enabled */\n  lockScreen: boolean;\n  /** Whether notification widget is displayed */\n  notification: boolean;\n  /** Whether to show the refresh button */\n  refresh: boolean;\n  /** Whether sidebar show/hide widget is displayed */\n  sidebarToggle: boolean;\n  /** Whether theme switch widget is displayed */\n  themeToggle: boolean;\n}\ninterface Preferences {\n  /** Global configuration */\n  app: AppPreferences;\n  /** Header configuration */\n  breadcrumb: BreadcrumbPreferences;\n  /** Copyright configuration */\n  copyright: CopyrightPreferences;\n  /** Footer configuration */\n  footer: FooterPreferences;\n  /** Breadcrumb configuration */\n  header: HeaderPreferences;\n  /** Logo configuration */\n  logo: LogoPreferences;\n  /** Navigation configuration */\n  navigation: NavigationPreferences;\n  /** Shortcut key configuration */\n  shortcutKeys: ShortcutKeyPreferences;\n  /** Sidebar configuration */\n  sidebar: SidebarPreferences;\n  /** Tab bar configuration */\n  tabbar: TabbarPreferences;\n  /** Theme configuration */\n  theme: ThemePreferences;\n  /** Animation configuration */\n  transition: TransitionPreferences;\n  /** Widget configuration */\n  widget: WidgetPreferences;\n}\n```\n\n:::\n\n::: warning Warning\n\n- The `overridesPreferences` method only needs to override a part of the configurations in the project. There's no need to override configurations that are not needed; they will automatically use the default settings.\n- Any configuration item can be overridden. You just need to override it within the `overridesPreferences` method. Do not modify the default configuration file.\n- Please clear the cache after changing the configuration, otherwise it may not take effect.\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/essentials/styles.md",
    "content": "# Styles\n\n::: tip Preface\n\nFor Vue projects, the [official documentation](https://vuejs.org/api/sfc-css-features.html#deep-selectors) already provides a detailed introduction to the syntax. Here, we mainly introduce the structure and usage of style files in the project.\n\n:::\n\n## Project Structure\n\nThe style files in the project are stored in `@vben/styles`, which includes some global styles, such as reset styles, global variables, etc. It inherits the styles and capabilities of `@vben-core/design` and can be overridden according to project needs.\n\n## Scss\n\nThe project uses `scss` as the style preprocessor, allowing the use of `scss` features such as variables, functions, mixins, etc., within the project.\n\n```vue\n<style lang=\"scss\" scoped>\n$font-size: 30px;\n\n.box {\n  .title {\n    color: green;\n    font-size: $font-size;\n  }\n}\n</style>\n```\n\n## Postcss\n\nIf you're not accustomed to using `scss`, you can also use `postcss`, which is a more powerful style processor that supports a wider range of plugins. The project includes the [postcss-nested](https://github.com/postcss/postcss-nested) plugin and is configured with `Css Variables`, making it a complete substitute for `scss`.\n\n```vue\n<style scoped>\n.box {\n  --font-size: 30px;\n  .title {\n    color: green;\n    font-size: var(--font-size);\n  }\n}\n</style>\n```\n\n## Tailwind CSS\n\nThe project integrates [Tailwind CSS](https://tailwindcss.com/), allowing the use of `tailwindcss` class names to quickly build pages.\n\n```vue\n<template>\n  <div class=\"bg-white p-4\">\n    <p class=\"text-green\">hello world</p>\n  </div>\n</template>\n```\n\n## BEM Standard\n\nAnother option to avoid style conflicts is to use the `BEM` standard. If you choose `scss`, it is recommended to use the `BEM` naming convention for better style management. The project provides a default `useNamespace` function to easily generate namespaces.\n\n```vue\n<script lang=\"ts\" setup>\nimport { useNamespace } from '@vben/hooks';\n\nconst { b, e, is } = useNamespace('menu');\n</script>\n<template>\n  <div :class=\"[b()]\">\n    <div :class=\"[e('item'), is('active', true)]\">item1</div>\n  </div>\n</template>\n<style lang=\"scss\" scoped>\n// If you use it within the application, this line of code can be omitted as it has already been globally introduced in all applications\n@use '@vben/styles/global' as *;\n@include b('menu') {\n  color: black;\n\n  @include e('item') {\n    background-color: black;\n\n    @include is('active') {\n      background-color: red;\n    }\n  }\n}\n</style>\n```\n\n## CSS Modules\n\nAnother solution to address style conflicts is to use the `CSS Modules` modular approach. The usage method is as follows.\n\n```vue\n<template>\n  <p :class=\"$style.red\">This should be red</p>\n</template>\n\n<style module>\n.red {\n  color: red;\n}\n</style>\n```\n\nFor more usage, see the [CSS Modules official documentation](https://vuejs.org/api/sfc-css-features.html#css-modules).\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/access.md",
    "content": "---\noutline: deep\n---\n\n# Access Control\n\nThe framework has built-in three types of access control methods:\n\n- Determining whether a menu or button can be accessed based on user roles\n- Determining whether a menu or button can be accessed through an API\n- Mixed mode: Using both frontend and backend access control simultaneously\n\n## Frontend Access Control\n\n**Implementation Principle**: The permissions for routes are hardcoded on the frontend, specifying which permissions are required to view certain routes. Only general routes are initialized, and routes that require permissions are not added to the route table. After logging in or obtaining user roles through other means, the roles are used to traverse the route table to generate a route table that the role can access. This table is then added to the router instance using `router.addRoute`, achieving permission filtering.\n\n**Disadvantage**: The permissions are relatively inflexible; if the backend changes roles, the frontend needs to be adjusted accordingly. This is suitable for systems with relatively fixed roles.\n\n### Steps\n\n- Ensure the current mode is set to frontend access control\n\nAdjust `preferences.ts` in the corresponding application directory to ensure `accessMode='frontend'`.\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    // Default value, optional\n    accessMode: 'frontend',\n  },\n});\n```\n\n- Configure route permissions\n\n#### If not configured, it is visible by default\n\n```ts {3}\n {\n    meta: {\n      authority: ['super'],\n    },\n},\n```\n\n- Ensure the roles returned by the interface match the permissions in the route table\n\nYou can look under `src/store/auth` in the application to find the following code:\n\n```ts\n// Set the login user information, ensuring that userInfo.roles is an array and contains permissions from the route table\n// For example: userInfo.roles=['super', 'admin']\nauthStore.setUserInfo(userInfo);\n```\n\nAt this point, the configuration is complete. You need to ensure that the roles returned by the interface after login match the permissions in the route table; otherwise, access will not be possible.\n\n### Menu Visible but Access Forbidden\n\nSometimes, we need the menu to be visible but access to it forbidden. This can be achieved by setting `menuVisibleWithForbidden` to `true`. In this case, the menu will be visible, but access will be forbidden, redirecting to a 403 page.\n\n```ts\n{\n    meta: {\n      menuVisibleWithForbidden: true,\n    },\n},\n```\n\n## Backend Access Control\n\n**Implementation Principle**: It is achieved by dynamically generating a routing table through an API, which returns data following a certain structure. The frontend processes this data into a recognizable structure, then adds it to the routing instance using `router.addRoute`, realizing the dynamic generation of permissions.\n\n**Disadvantage**: The backend needs to provide a data structure that meets the standards, and the frontend needs to process this structure. This is suitable for systems with more complex permissions.\n\n### Steps\n\n- Ensure the current mode is set to backend access control\n\nAdjust `preferences.ts` in the corresponding application directory to ensure `accessMode='backend'`.\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    accessMode: 'backend',\n  },\n});\n```\n\n- Ensure the structure of the menu data returned by the interface is correct\n\nYou can look under `src/router/access.ts` in the application to find the following code:\n\n```ts\nasync function generateAccess(options: GenerateMenuAndRoutesOptions) {\n  return await generateAccessible(preferences.app.accessMode, {\n    fetchMenuListAsync: async () => {\n      // This interface is for the menu data returned by the backend\n      return await getAllMenus();\n    },\n  });\n}\n```\n\n- Interface returns menu data, see comments for explanation\n\n::: details Example of Interface Returning Menu Data\n\n```ts\nconst dashboardMenus = [\n  {\n    // Here, 'BasicLayout' is hardcoded and cannot be changed\n    component: 'BasicLayout',\n    meta: {\n      order: -1,\n      title: 'page.dashboard.title',\n    },\n    name: 'Dashboard',\n    path: '/',\n    redirect: '/analytics',\n    children: [\n      {\n        name: 'Analytics',\n        path: '/analytics',\n        // Here is the path of the page, need to remove 'views/' and '.vue'\n        component: '/dashboard/analytics/index',\n        meta: {\n          affixTab: true,\n          title: 'page.dashboard.analytics',\n        },\n      },\n      {\n        name: 'Workspace',\n        path: '/workspace',\n        component: '/dashboard/workspace/index',\n        meta: {\n          title: 'page.dashboard.workspace',\n        },\n      },\n    ],\n  },\n];\n```\n\n:::\n\nAt this point, the configuration is complete. You need to ensure that after logging in, the format of the menu returned by the interface is correct; otherwise, access will not be possible.\n\n## Mixed Access Control\n\n**Implementation Principle**: Mixed mode combines both frontend access control and backend access control methods. The system processes frontend fixed route permissions and backend dynamic menu data in parallel, ultimately merging both parts of routes to provide a more flexible access control solution.\n\n**Advantages**: Combines the performance advantages of frontend control with the flexibility of backend control, suitable for complex business scenarios requiring permission management.\n\n### Steps\n\n- Ensure the current mode is set to mixed access control\n\nAdjust `preferences.ts` in the corresponding application directory to ensure `accessMode='mixed'`.\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    accessMode: 'mixed',\n  },\n});\n```\n\n- Configure frontend route permissions\n\nSame as the route permission configuration method in [Frontend Access Control](#frontend-access-control) mode.\n\n- Configure backend menu interface\n\nSame as the interface configuration method in [Backend Access Control](#backend-access-control) mode.\n\n- Ensure roles and permissions match\n\nMust satisfy both frontend route permission configuration and backend menu data return requirements, ensuring user roles match the permission configurations of both modes.\n\nAt this point, the configuration is complete. Mixed mode will automatically merge frontend and backend routes, providing complete access control functionality.\n\n## Fine-grained Control of Buttons\n\nIn some cases, we need to control the display of buttons with fine granularity. We can control the display of buttons through interfaces or roles.\n\n### Permission Code\n\nThe permission code is the code returned by the interface. The logic to determine whether a button is displayed is located under `src/store/auth`:\n\n```ts\nconst [fetchUserInfoResult, accessCodes] = await Promise.all([\n  fetchUserInfo(),\n  getAccessCodes(),\n]);\n\nuserInfo = fetchUserInfoResult;\nauthStore.setUserInfo(userInfo);\naccessStore.setAccessCodes(accessCodes);\n```\n\nLocate the `getAccessCodes` corresponding interface, which can be adjusted according to business logic.\n\nThe data structure returned by the permission code is an array of strings, for example: `['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`\n\nWith the permission codes, you can use the `AccessControl` component and API provided by `@vben/access` to show and hide buttons.\n\n#### Component Method\n\n```vue\n<script lang=\"ts\" setup>\nimport { AccessControl, useAccess } from '@vben/access';\n\nconst { accessMode, hasAccessByCodes } = useAccess();\n</script>\n\n<template>\n  <!-- You need to specify type=\"code\" -->\n  <AccessControl :codes=\"['AC_100100']\" type=\"code\">\n    <Button> Visible to Super account [\"AC_1000001\"] </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['AC_100030']\" type=\"code\">\n    <Button> Visible to Admin account [\"AC_100010\"] </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['AC_1000001']\" type=\"code\">\n    <Button> Visible to User account [\"AC_1000001\"] </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['AC_100100', 'AC_100010']\" type=\"code\">\n    <Button>\n      Visible to Super & Admin account [\"AC_100100\",\"AC_1000001\"]\n    </Button>\n  </AccessControl>\n</template>\n```\n\n#### API Method\n\n```vue\n<script lang=\"ts\" setup>\nimport { AccessControl, useAccess } from '@vben/access';\n\nconst { hasAccessByCodes } = useAccess();\n</script>\n\n<template>\n  <Button v-if=\"hasAccessByCodes(['AC_100100'])\">\n    Visible to Super account [\"AC_1000001\"]\n  </Button>\n  <Button v-if=\"hasAccessByCodes(['AC_100030'])\">\n    Visible to Admin account [\"AC_100010\"]\n  </Button>\n  <Button v-if=\"hasAccessByCodes(['AC_1000001'])\">\n    Visible to User account [\"AC_1000001\"]\n  </Button>\n  <Button v-if=\"hasAccessByCodes(['AC_100100', 'AC_1000001'])\">\n    Visible to Super & Admin account [\"AC_100100\",\"AC_1000001\"]\n  </Button>\n</template>\n```\n\n#### Directive Method\n\n> The directive supports binding single or multiple permission codes. For a single one, you can pass a string or an array containing one permission code, and for multiple permission codes, you can pass an array.\n\n```vue\n<template>\n  <Button class=\"mr-4\" v-access:code=\"'AC_100100'\">\n    Visible to Super account 'AC_100100'\n  </Button>\n  <Button class=\"mr-4\" v-access:code=\"['AC_100030']\">\n    Visible to Admin account [\"AC_100010\"]\n  </Button>\n  <Button class=\"mr-4\" v-access:code=\"['AC_1000001']\">\n    Visible to User account [\"AC_1000001\"]\n  </Button>\n  <Button class=\"mr-4\" v-access:code=\"['AC_100100', 'AC_1000001']\">\n    Visible to Super & Admin account [\"AC_100100\",\"AC_1000001\"]\n  </Button>\n</template>\n```\n\n### Roles\n\nThe method of determining roles does not require permission codes returned by the interface; it directly determines whether buttons are displayed based on roles.\n\n#### Component Method\n\n```vue\n<script lang=\"ts\" setup>\nimport { AccessControl } from '@vben/access';\n</script>\n\n<template>\n  <AccessControl :codes=\"['super']\">\n    <Button> Visible to Super account </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['admin']\">\n    <Button> Visible to Admin account </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['user']\">\n    <Button> Visible to User account </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['super', 'admin']\">\n    <Button> Super & Visible to Admin account </Button>\n  </AccessControl>\n</template>\n```\n\n#### API Method\n\n```vue\n<script lang=\"ts\" setup>\nimport { useAccess } from '@vben/access';\n\nconst { hasAccessByRoles } = useAccess();\n</script>\n\n<template>\n  <Button v-if=\"hasAccessByRoles(['super'])\"> Visible to Super account </Button>\n  <Button v-if=\"hasAccessByRoles(['admin'])\"> Visible to Admin account </Button>\n  <Button v-if=\"hasAccessByRoles(['user'])\"> Visible to User account </Button>\n  <Button v-if=\"hasAccessByRoles(['super', 'admin'])\">\n    Super & Visible to Admin account\n  </Button>\n</template>\n```\n\n#### Directive Method\n\n> The directive supports binding single or multiple permission codes. For a single one, you can pass a string or an array containing one permission code, and for multiple permission codes, you can pass an array.\n\n```vue\n<template>\n  <Button class=\"mr-4\" v-access:role=\"'super'\">\n    Visible to Super account\n  </Button>\n  <Button class=\"mr-4\" v-access:role=\"['admin']\">\n    Visible to Admin account\n  </Button>\n  <Button class=\"mr-4\" v-access:role=\"['user']\">\n    Visible to User account\n  </Button>\n  <Button class=\"mr-4\" v-access:role=\"['super', 'admin']\">\n    Super & Visible to Admin account\n  </Button>\n</template>\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/check-updates.md",
    "content": "# Check Updates\n\n## Introduction\n\nWhen there are updates to the website, you might need to check for updates. The framework provides this functionality. By periodically checking for updates, you can configure the `checkUpdatesInterval` and `enableCheckUpdates` fields in your application's preferences.ts file to enable and set the interval for checking updates (in minutes).\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    // Whether to enable check for updates\n    enableCheckUpdates: true,\n    // The interval for checking updates, in minutes\n    checkUpdatesInterval: 1,\n  },\n});\n```\n\n## Effect\n\nWhen an update is detected, a prompt will pop up asking the user whether to refresh the page:\n\n![check-updates](/guide/update-notice.png)\n\n## Replacing with Other Update Checking Methods\n\nIf you need to check for updates in other ways, such as through an API to more flexibly control the update logic (such as force refresh, display update content, etc.), you can do so by modifying the `src/widgets/check-updates/check-updates.vue` file under `@vben/layouts`.\n\n```ts\n// Replace this with your update checking logic\nasync function getVersionTag() {\n  try {\n    const response = await fetch('/', {\n      cache: 'no-cache',\n      method: 'HEAD',\n    });\n\n    return (\n      response.headers.get('etag') || response.headers.get('last-modified')\n    );\n  } catch {\n    console.error('Failed to fetch version tag');\n    return null;\n  }\n}\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/features.md",
    "content": "# Common Features\n\nA collection of some commonly used features.\n\n## Login Authentication Expiry\n\nWhen the interface returns a `401` status code, the framework will consider the login authentication to have expired. Upon login timeout, it will redirect to the login page or open a login popup. This can be configured in `preferences.ts` in the application directory:\n\n### Redirect to Login Page\n\nUpon login timeout, it will redirect to the login page.\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    loginExpiredMode: 'page',\n  },\n});\n```\n\n### Open Login Popup\n\nWhen login times out, a login popup will open.\n\n![login-expired](/guide/login-expired.png)\n\nConfiguration:\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    loginExpiredMode: 'modal',\n  },\n});\n```\n\n## Dynamic Title\n\n- Default value: `true`\n\nWhen enabled, the webpage title changes according to the route's `title`. You can enable or disable this in the `preferences.ts` file in your application directory.\n\n```ts\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    dynamicTitle: true,\n  },\n});\n```\n\n## Page Watermark\n\n- Default value: `false`\n\nWhen enabled, the webpage will display a watermark. You can enable or disable this in the `preferences.ts` file in your application directory.\n\n```ts\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    watermark: true,\n  },\n});\n```\n\nIf you want to update the content of the watermark, you can do so. The parameters can be referred to [watermark-js-plus](https://zhensherlock.github.io/watermark-js-plus/):\n\n```ts\nimport { useWatermark } from '@vben/hooks';\n\nconst { destroyWatermark, updateWatermark } = useWatermark();\n\nawait updateWatermark({\n  // watermark content\n  content: 'hello my watermark',\n});\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/layout.md",
    "content": "# Layout\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/loading.md",
    "content": "# Global Loading\n\nGlobal loading refers to the loading effect that appears when the page is refreshed, usually a spinning icon:\n\n![Global loading spinner](/guide/loading.png)\n\n## Principle\n\nImplemented by the `vite-plugin-inject-app-loading` plugin, the plugin injects a global `loading html` into each application.\n\n## Disable\n\nIf you do not need global loading, you can disable it in the `.env` file:\n\n```bash\nVITE_INJECT_APP_LOADING=false\n```\n\n## Customization\n\nIf you want to customize the global loading, you can create a `loading.html` file in the application directory, at the same level as `index.html`. The plugin will automatically read and inject this HTML. You can define the style and animation of this HTML as you wish.\n\n::: tip\n\n- You can use the same syntax as in `index.html`, such as the `VITE_APP_TITLE` variable, to get the application's title.\n- You must ensure there is an element with `id=\"__app-loading__\"`.\n- Add a `hidden` class to the element with `id=\"__app-loading__\"`.\n- You must ensure there is a `style[data-app-loading=\"inject-css\"]` element.\n\n```html{1,4}\n<style data-app-loading=\"inject-css\">\n  #__app-loading__.hidden {\n    pointer-events: none;\n    visibility: hidden;\n    opacity: 0;\n    transition: all 1s ease-out;\n  }\n  /* ... */\n</style>\n<div id=\"__app-loading__\">\n  <!-- ... -->\n  <div class=\"title\"><%= VITE_APP_TITLE %></div>\n</div>\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/locale.md",
    "content": "# Internationalization\n\nThe project has integrated [Vue i18n](https://kazupon.github.io/vue-i18n/), and Chinese and English language packs have been configured.\n\n## IDE Plugin\n\nIf you are using vscode as your development tool, it is recommended to install the [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) plugin. It can help you manage internationalization copy more conveniently. After installing this plugin, you can see the corresponding language content in your code in real-time:\n\n![](/public/guide/locale.png)\n\n## Configure Default Language\n\nYou just need to override the default preferences. In the corresponding application, find the `src/preferences.ts` file and modify the value of `locale`:\n\n```ts {3}\nexport const overridesPreferences = defineOverridesPreferences({\n  app: {\n    locale: 'en-US',\n  },\n});\n```\n\n## Dynamic Language Switching\n\nSwitching languages consists of two parts:\n\n- Updating preferences\n- Loading the corresponding language pack\n\n```ts\nimport type { SupportedLanguagesType } from '@vben/locales';\nimport { loadLocaleMessages } from '@vben/locales';\nimport { updatePreferences } from '@vben/preferences';\n\nasync function updateLocale(value: string) {\n  // 1. Update preferences\n  const locale = value as SupportedLanguagesType;\n  updatePreferences({\n    app: {\n      locale,\n    },\n  });\n  // 2. Load the corresponding language pack\n  await loadLocaleMessages(locale);\n}\n\nupdateLocale('en-US');\n```\n\n## Adding Translation Texts\n\n::: warning Attention\n\n- Do not place business translation texts inside `@vben/locales` to better manage business and general translation texts.\n- When adding new translation texts and multiple language packs are available, ensure to add the corresponding texts in all language packs.\n\n:::\n\nTo add new translation texts, simply find `src/locales/langs/` in the corresponding application and add the texts accordingly, for example:\n\n**src/locales/langs/zh-CN/\\*.json**\n\n````ts\n```json\n{\n  \"about\": {\n    \"desc\": \"Vben Admin 是一个现代的管理模版。\"\n  }\n}\n````\n\n**src/locales/langs/en-US.ts**\n\n````ts\n```json\n{\n  \"about\": {\n    \"desc\": \"Vben Admin is a modern management template.\"\n  }\n}\n````\n\n## Using Translation Texts\n\nWith `@vben/locales`, you can easily use translation texts:\n\n### In Code\n\n```vue\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { $t } from '@vben/locales';\n\nconst items = computed(() => [{ title: $t('about.desc') }]);\n</script>\n<template>\n  <div>{{ $t('about.desc') }}</div>\n  <template v-for=\"item in items.value\">\n    <div>{{ item.title }}</div>\n  </template>\n</template>\n```\n\n## Adding a New Language Pack\n\nIf you need to add a new language pack, follow these steps:\n\n- Add the corresponding language pack file in the `packages/locales/langs` directory, for example, `zh-TW.json`, and translate the respective texts.\n- In the corresponding application, locate the `src/locales/langs` file and add the new language pack `zh-TW.json`.\n- Add the corresponding language in `packages/constants/src/core.ts`:\n\n  ```ts\n  export interface LanguageOption {\n    label: string;\n    value: 'en-US' | 'zh-CN'; // [!code --]\n    value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]\n  }\n  export const SUPPORT_LANGUAGES: LanguageOption[] = [\n    {\n      label: '简体中文',\n      value: 'zh-CN',\n    },\n    {\n      label: 'English',\n      value: 'en-US',\n    },\n    {\n      label: '繁体中文', // [!code ++]\n      value: 'zh-TW', // [!code ++]\n    },\n  ];\n  ```\n\n- In `packages/locales/typing.ts`, add a new TypeScript type:\n\n  ```ts\n  export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --]\n  export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]\n  ```\n\nAt this point, you can use the newly added language pack in the project.\n\n## Interface Language Switching Function\n\nIf you want to disable the language switching display button on the interface, in the corresponding application, find the `src/preferences.ts` file and modify the value of `locale` accordingly:\n\n```ts {3}\nexport const overridesPreferences = defineOverridesPreferences({\n  widget: {\n    languageToggle: false,\n  },\n});\n```\n\n## Remote Loading of Language Packs\n\n::: tip Tip\n\nWhen making interface requests through the project's built-in `request` tool, the default request header will include [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language), allowing the server to dynamically internationalize data based on the request header.\n\n:::\n\nEach application has an independent language pack that can override the general language configuration. You can remotely load the corresponding language pack by finding the `src/locales/index.ts` file in the corresponding application and modifying the `loadMessages` method accordingly:\n\n```ts {3-4}\nasync function loadMessages(lang: SupportedLanguagesType) {\n  const [appLocaleMessages] = await Promise.all([\n    // Modify here to load data via a remote interface\n    localesMap[lang](),\n    loadThirdPartyMessage(lang),\n  ]);\n  return appLocaleMessages.default;\n}\n```\n\n## Third-Party Language Packs\n\nDifferent applications may use third-party component libraries or plugins with varying internationalization methods, so they need to be handled differently. If you need to introduce a third-party language pack, you can find the `src/locales/index.ts` file in the corresponding application and modify the `loadThirdPartyMessage` method accordingly:\n\n```ts\n/**\n * Load the dayjs language pack\n * @param lang\n */\nasync function loadDayjsLocale(lang: SupportedLanguagesType) {\n  let locale;\n  switch (lang) {\n    case 'zh-CN': {\n      locale = await import('dayjs/locale/zh-cn');\n      break;\n    }\n    case 'en-US': {\n      locale = await import('dayjs/locale/en');\n      break;\n    }\n    // Default to using English\n    default: {\n      locale = await import('dayjs/locale/en');\n    }\n  }\n  if (locale) {\n    dayjs.locale(locale);\n  } else {\n    console.error(`Failed to load dayjs locale for ${lang}`);\n  }\n}\n```\n\n## Removing Internationalization\n\nFirstly, it is not recommended to remove internationalization, as it is a good development practice. However, if you really need to remove it, you can directly use Chinese copy and then retain the project's built-in language pack, which will not affect the overall development experience. The steps to remove internationalization are as follows:\n\n- Hide the language switching button on the interface, see: [Interface Language Switching Function](#interface-language-switching-function)\n- Modify the default language, see: [Configure Default Language](#configure-default-language)\n- Disable `vue-i18n` warning prompts, in the `src/locales/index.ts` file, modify `missingWarn` to `false`:\n\n  ```ts\n  async function setupI18n(app: App, options: LocaleSetupOptions = {}) {\n    await coreSetup(app, {\n      defaultLocale: preferences.app.locale,\n      loadMessages,\n      missingWarn: !import.meta.env.PROD, // [!code --]\n      missingWarn: false, // [!code ++]\n      ...options,\n    });\n  }\n  ```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/login.md",
    "content": "# Login\n\nThis document explains how to customize the login page of your application.\n\n## Login Page Adjustment\n\nIf you want to adjust the title, description, icon, and toolbar of the login page, you can do so by configuring the `props` parameter of the `AuthPageLayout` component.\n\n![login](/guide/login.png)\n\nYou just need to configure the `props` parameter of `AuthPageLayout` in `src/router/routes/core.ts` within your application:\n\n```ts {4-8}\n {\n    component: AuthPageLayout,\n    props: {\n      sloganImage: \"xxx/xxx.png\",\n      pageTitle: \"开箱即用的大型中后台管理系统\",\n      pageDescription: \"工程化、高性能、跨组件库的前端模版\",\n      toolbar: true,\n      toolbarList: ['color', 'language', 'layout', 'theme'],\n    }\n    // ...\n  },\n```\n\n::: tip\n\nIf these configurations do not meet your needs, you can implement your own login page. Simply implement your own `AuthPageLayout`.\n\n:::\n\n## Login Form Adjustment\n\nIf you want to adjust the content of the login form, you can configure the `AuthenticationLogin` component parameters in `src/views/_core/authentication/login.vue` within your application:\n\n```vue\n<AuthenticationLogin\n  :loading=\"authStore.loginLoading\"\n  @submit=\"authStore.authLogin\"\n/>\n```\n\n::: details AuthenticationLogin Component Props\n\n```ts\n{\n  /**\n   * @en Verification code login path\n   */\n  codeLoginPath?: string;\n  /**\n   * @en Forget password path\n   */\n  forgetPasswordPath?: string;\n\n  /**\n   * @en Whether it is in loading state\n   */\n  loading?: boolean;\n\n  /**\n   * @en QR code login path\n   */\n  qrCodeLoginPath?: string;\n\n  /**\n   * @en Registration path\n   */\n  registerPath?: string;\n\n  /**\n   * @en Whether to show verification code login\n   */\n  showCodeLogin?: boolean;\n  /**\n   * @en Whether to show forget password\n   */\n  showForgetPassword?: boolean;\n\n  /**\n   * @en Whether to show QR code login\n   */\n  showQrcodeLogin?: boolean;\n\n  /**\n   * @en Whether to show registration button\n   */\n  showRegister?: boolean;\n\n  /**\n   * @en Whether to show remember account\n   */\n  showRememberMe?: boolean;\n\n  /**\n   * @en Whether to show third-party login\n   */\n  showThirdPartyLogin?: boolean;\n\n  /**\n   * @en Login box subtitle\n   */\n  subTitle?: string;\n\n  /**\n   * @en Login box title\n   */\n  title?: string;\n}\n```\n\n:::\n\n::: tip\n\nIf these configurations do not meet your needs, you can implement your own login form and related login logic.\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/theme.md",
    "content": "# Theme\n\nThe framework is built on [shadcn-vue](https://www.shadcn-vue.com/themes.html) and [tailwindcss](https://tailwindcss.com/), offering a rich theme configuration. You can easily switch between various themes through simple configuration to meet personalized needs. You can choose to use CSS variables or Tailwind CSS utility classes for theme settings.\n\n## CSS Variables\n\nThe project follows the theme configuration of [shadcn-vue](https://www.shadcn-vue.com/themes.html), for example:\n\n```html\n<div class=\"bg-background text-foreground\" />\n```\n\nWe use a simple convention for colors. The `background` variable is used for the background color of components, and the `foreground` variable is used for text color.\n\nFor the following components, `background` will be `hsl(var(--primary))`, and `foreground` will be `hsl(var(--primary-foreground))`.\n\n## Detailed List of CSS Variables\n\n::: warning Note\n\nThe colors inside CSS variables must use the `hsl` format, such as `0 0% 100%`, without adding `hsl()` and `,`.\n\n:::\n\nYou can check the list below to understand all the available variables.\n\n::: details Default theme CSS variables\n\n```css\n:root {\n  --font-family:\n    -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, 'Helvetica Neue',\n    arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',\n    'Segoe UI Symbol', 'Noto Color Emoji';\n\n  /* Default background color of <body />...etc */\n  --background: 0 0% 100%;\n\n  /* Main area background color */\n  --background-deep: 216 20.11% 95.47%;\n  --foreground: 210 6% 21%;\n\n  /* Background color for <Card /> */\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n\n  /* Theme Colors */\n\n  --primary: 212 100% 45%;\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 0 78% 68%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* Secondary colors for <Button /> */\n\n  --secondary: 240 5% 96%;\n  --secondary-foreground: 240 6% 10%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 240 5% 96%;\n  --accent-hover: 200deg 10% 90%;\n  --accent-foreground: 240 6% 10%;\n\n  /* Darker color */\n  --heavy: 192deg 9.43% 89.61%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 5.9% 90%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 240deg 5.88% 90%;\n  --input-placeholder: 217 10.6% 65%;\n  --input-background: 0 0% 100%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* Border radius for card, input and buttons */\n  --radius: 0.5rem;\n\n  /* ============= custom ============= */\n\n  /* overlay color */\n  --overlay: 0deg 0% 0% / 30%;\n\n  /* base font size */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  /* menu */\n  --sidebar: 0 0% 100%;\n  --sidebar-deep: 216 20.11% 95.47%;\n  --menu: var(--sidebar);\n\n  /* header */\n  --header: 0 0% 100%;\n\n  accent-color: var(--primary);\n  color-scheme: light;\n}\n```\n\n:::\n\n::: details Default theme dark mode CSS variables\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  /* Default background color of <body />...etc */\n  --background: 222.34deg 10.43% 12.27%;\n\n  /* Main area background color */\n  --background-deep: 220deg 13.06% 9%;\n  --foreground: 0 0% 95%;\n\n  /* Background color for <Card /> */\n  --card: 222.34deg 10.43% 12.27%;\n\n  /* --card: 222.2 84% 4.9%; */\n  --card-foreground: 210 40% 98%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 222.82deg 8.43% 12.27%;\n  --popover-foreground: 210 40% 98%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n  --muted: 220deg 6.82% 17.25%;\n  --muted-foreground: 215 20.2% 65.1%;\n\n  /* Theme Colors */\n\n  /* --primary: 245 82% 67%; */\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 0 78% 68%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* secondary color */\n  --secondary: 240 5% 17%;\n  --secondary-foreground: 0 0% 98%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 0deg 0% 100% / 8%;\n  --accent-hover: 0deg 0% 100% / 12%;\n  --accent-foreground: 0 0% 98%;\n\n  /* Darker color */\n  --heavy: 0deg 0% 100% / 12%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 3.7% 15.9%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 0deg 0% 100% / 10%;\n  --input-placeholder: 218deg 11% 65%;\n  --input-background: 0deg 0% 100% / 5%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* base radius */\n  --radius: 0.5rem;\n\n  /* ============= Custom ============= */\n\n  /* overlay color */\n  --overlay: 0deg 0% 0% / 40%;\n\n  /* base font size */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  --sidebar: 222.34deg 10.43% 12.27%;\n  --sidebar-deep: 220deg 13.06% 9%;\n  --menu: var(--sidebar);\n  --header: 222.34deg 10.43% 12.27%;\n\n  color-scheme: dark;\n}\n```\n\n:::\n\n## Overriding Default CSS Variables\n\nYou only need to override the CSS variables you want to change in your project. For example, to change the default card background color, you can add the following content to your CSS file to override it:\n\n### Under the Default Theme\n\n```css\n:root {\n  /* Background color for <Card /> */\n  --card: 0 0% 30%;\n}\n```\n\n### In Dark Mode\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  /* Background color for <Card /> */\n  --card: 222.34deg 10.43% 12.27%;\n}\n```\n\n## Changing the Brand Primary Color\n\n::: tip\n\n- You need to use the `hsl` color format.\n- You must clear the cache for the changes to take effect.\n- You can use [third-party tools](https://www.w3schools.com/colors/colors_hsl.asp) to convert colors.\n\n:::\n\nYou only need to customize the primary color in the `preferences.ts` file under the application directory:\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  theme: {\n    // Error color\n    colorDestructive: 'hsl(348 100% 61%)',\n    // Primary color\n    colorPrimary: 'hsl(212 100% 45%)',\n    // Success color\n    colorSuccess: 'hsl(144 57% 58%)',\n    // Warning color\n    colorWarning: 'hsl(42 84% 61%)',\n  },\n});\n```\n\n## Built-in Themes\n\nThe framework includes a variety of built-in themes, which you can configure in the `preferences.ts` file:\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  theme: {\n    builtinType: 'default',\n  },\n});\n```\n\n### Built-in Theme List\n\nThe framework includes 16 built-in themes and also supports custom themes. Theoretically, you can expand the themes without limit.\n\n::: details List of Built-in Theme Types\n\n```ts\ntype BuiltinThemeType =\n  | 'custom'\n  | 'deep-blue'\n  | 'deep-green'\n  | 'default'\n  | 'gray'\n  | 'green'\n  | 'neutral'\n  | 'orange'\n  | 'pink'\n  | 'red'\n  | 'rose'\n  | 'sky-blue'\n  | 'slate'\n  | 'stone'\n  | 'violet'\n  | 'yellow'\n  | 'zinc'\n  | (Record<never, never> & string);\n```\n\n:::\n\n::: details Built-in Theme CSS Variables - Light\n\n```css\n:root {\n  --font-family:\n    -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, 'Helvetica Neue',\n    arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',\n    'Segoe UI Symbol', 'Noto Color Emoji';\n\n  /* Default background color of <body />...etc */\n  --background: 0 0% 100%;\n\n  /* Main area background color */\n  --background-deep: 216 20.11% 95.47%;\n  --foreground: 222 84% 5%;\n\n  /* Background color for <Card /> */\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n\n  /* --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%; */\n\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n\n  /* Theme Colors */\n\n  --primary: 212 100% 45%;\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 0 78% 68%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* Secondary colors for <Button /> */\n\n  --secondary: 240 5% 96%;\n  --secondary-foreground: 240 6% 10%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 240 5% 96%;\n  --accent-hover: 200deg 10% 90%;\n  --accent-foreground: 240 6% 10%;\n\n  /* Darker color */\n  --heavy: 192deg 9.43% 89.61%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 5.9% 90%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 240deg 5.88% 90%;\n  --input-placeholder: 217 10.6% 65%;\n  --input-background: 0 0% 100%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* Border radius for card, input and buttons */\n  --radius: 0.5rem;\n\n  /* ============= custom ============= */\n\n  /* overlay color */\n  --overlay: 0deg 0% 0% / 30%;\n\n  /* base font size */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  /* menu */\n  --sidebar: 0 0% 100%;\n  --sidebar-deep: 0 0% 100%;\n  --menu: var(--sidebar);\n\n  /* header */\n  --header: 0 0% 100%;\n\n  accent-color: var(--primary);\n  color-scheme: light;\n}\n\n[data-theme='violet'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 224 71.4% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 224 71.4% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 224 71.4% 4.1%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 220 14.3% 95.9%;\n  --secondary-foreground: 220.9 39.3% 11%;\n  --muted: 220 14.3% 95.9%;\n  --muted-foreground: 220 8.9% 46.1%;\n  --accent: 220 14.3% 95.9%;\n  --accent-foreground: 220.9 39.3% 11%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 220 13% 91%;\n  --input: 220 13% 91%;\n  --ring: 262.1 83.3% 57.8%;\n}\n\n[data-theme='pink'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 346.8 77.2% 49.8%;\n}\n\n[data-theme='rose'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 346.8 77.2% 49.8%;\n}\n\n[data-theme='sky-blue'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 221.2 83.2% 53.3%;\n}\n\n[data-theme='deep-blue'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 221.2 83.2% 53.3%;\n}\n\n[data-theme='green'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 142.1 76.2% 36.3%;\n}\n\n[data-theme='deep-green'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 142.1 76.2% 36.3%;\n}\n\n[data-theme='orange'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 20 14.3% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 20 14.3% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 20 14.3% 4.1%;\n  --primary-foreground: 60 9.1% 97.8%;\n  --secondary: 60 4.8% 95.9%;\n  --secondary-foreground: 24 9.8% 10%;\n  --muted: 60 4.8% 95.9%;\n  --muted-foreground: 25 5.3% 44.7%;\n  --accent: 60 4.8% 95.9%;\n  --accent-foreground: 24 9.8% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 20 5.9% 90%;\n  --input: 20 5.9% 90%;\n  --ring: 24.6 95% 53.1%;\n}\n\n[data-theme='yellow'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 20 14.3% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 20 14.3% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 20 14.3% 4.1%;\n  --primary-foreground: 26 83.3% 14.1%;\n  --secondary: 60 4.8% 95.9%;\n  --secondary-foreground: 24 9.8% 10%;\n  --muted: 60 4.8% 95.9%;\n  --muted-foreground: 25 5.3% 44.7%;\n  --accent: 60 4.8% 95.9%;\n  --accent-foreground: 24 9.8% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 20 5.9% 90%;\n  --input: 20 5.9% 90%;\n  --ring: 20 14.3% 4.1%;\n}\n\n[data-theme='zinc'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 0 0% 98%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 240 5.9% 10%;\n}\n\n[data-theme='neutral'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 0 0% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 0 0% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 0 0% 3.9%;\n  --primary-foreground: 0 0% 98%;\n  --secondary: 0 0% 96.1%;\n  --secondary-foreground: 0 0% 9%;\n  --muted: 0 0% 96.1%;\n  --muted-foreground: 0 0% 45.1%;\n  --accent: 0 0% 96.1%;\n  --accent-foreground: 0 0% 9%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 89.8%;\n  --input: 0 0% 89.8%;\n  --ring: 0 0% 3.9%;\n}\n\n[data-theme='slate'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 222.2 84% 4.9%;\n}\n\n[data-theme='gray'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 224 71.4% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 224 71.4% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 224 71.4% 4.1%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 220 14.3% 95.9%;\n  --secondary-foreground: 220.9 39.3% 11%;\n  --muted: 220 14.3% 95.9%;\n  --muted-foreground: 220 8.9% 46.1%;\n  --accent: 220 14.3% 95.9%;\n  --accent-foreground: 220.9 39.3% 11%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 220 13% 91%;\n  --input: 220 13% 91%;\n  --ring: 224 71.4% 4.1%;\n}\n```\n\n:::\n\n::: details 内置主题css变量 - dark\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  /* Default background color of <body />...etc */\n  --background: 222.34deg 10.43% 12.27%;\n\n  /* 主体区域背景色 */\n  --background-deep: 220deg 13.06% 9%;\n  --foreground: 0 0% 95%;\n\n  /* Background color for <Card /> */\n  --card: 222.34deg 10.43% 12.27%;\n\n  /* --card: 222.2 84% 4.9%; */\n  --card-foreground: 210 40% 98%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 222.82deg 8.43% 12.27%;\n  --popover-foreground: 210 40% 98%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n\n  /* --muted: 220deg 6.82% 17.25%; */\n\n  /* --muted-foreground: 215 20.2% 65.1%; */\n\n  --muted: 240 3.7% 15.9%;\n  --muted-foreground: 240 5% 64.9%;\n\n  /* 主题颜色 */\n\n  /* --primary: 245 82% 67%; */\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 0 78% 68%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* 颜色次要 */\n  --secondary: 240 5% 17%;\n  --secondary-foreground: 0 0% 98%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 216 5% 19%;\n  --accent-hover: 216 5% 24%;\n  --accent-foreground: 0 0% 98%;\n\n  /* Darker color */\n  --heavy: 216 5% 24%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 3.7% 22%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 0deg 0% 100% / 10%;\n  --input-placeholder: 218deg 11% 65%;\n  --input-background: 0deg 0% 100% / 5%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* 基本圆角大小 */\n  --radius: 0.5rem;\n\n  /* ============= Custom ============= */\n\n  /* overlay color */\n  --overlay: 0deg 0% 0% / 40%;\n\n  /* base font size */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  --sidebar: 222.34deg 10.43% 12.27%;\n  --sidebar-deep: 220deg 13.06% 9%;\n  --menu: var(--sidebar);\n\n  /* header */\n  --header: 222.34deg 10.43% 12.27%;\n\n  color-scheme: dark;\n}\n\n.dark[data-theme='violet'],\n[data-theme='violet'] .dark {\n  --background: 224 71.4% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 210 20% 98%;\n  --card: 224 71.4% 4.1%;\n  --card-foreground: 210 20% 98%;\n  --popover: 224 71.4% 4.1%;\n  --popover-foreground: 210 20% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 215 27.9% 16.9%;\n  --secondary-foreground: 210 20% 98%;\n  --muted: 215 27.9% 16.9%;\n  --muted-foreground: 217.9 10.6% 64.9%;\n  --accent: 215 27.9% 16.9%;\n  --accent-foreground: 210 20% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 215 27.9% 16.9%;\n  --input: 215 27.9% 16.9%;\n  --ring: 263.4 70% 50.4%;\n  --sidebar: 224 71.4% 4.1%;\n  --sidebar-deep: 224 71.4% 4.1%;\n  --header: 224 71.4% 4.1%;\n}\n\n.dark[data-theme='pink'],\n[data-theme='pink'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 0 0% 9%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 346.8 77.2% 49.8%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='rose'],\n[data-theme='rose'] .dark {\n  --background: 0 0% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 0 0% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 0 0% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 0 85.7% 97.3%;\n  --secondary: 0 0% 14.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 14.9%;\n  --muted-foreground: 0 0% 63.9%;\n  --accent: 0 0% 14.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 14.9%;\n  --input: 0 0% 14.9%;\n  --ring: 0 72.2% 50.6%;\n  --sidebar: 0 0% 3.9%;\n  --sidebar-deep: 0 0% 3.9%;\n  --header: 0 0% 3.9%;\n}\n\n.dark[data-theme='sky-blue'],\n[data-theme='sky-blue'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 224.3 76.3% 48%;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='deep-blue'],\n[data-theme='deep-blue'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 224.3 76.3% 48%;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='green'],\n[data-theme='green'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 24 9.8% 6%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 142.4 71.8% 29.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='deep-green'],\n[data-theme='deep-green'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 24 9.8% 6%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 142.4 71.8% 29.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='orange'],\n[data-theme='orange'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 60 9.1% 97.8%;\n  --card: 20 14.3% 4.1%;\n  --card-foreground: 60 9.1% 97.8%;\n  --popover: 20 14.3% 4.1%;\n  --popover-foreground: 60 9.1% 97.8%;\n  --primary-foreground: 60 9.1% 97.8%;\n  --secondary: 12 6.5% 15.1%;\n  --secondary-foreground: 60 9.1% 97.8%;\n  --muted: 12 6.5% 15.1%;\n  --muted-foreground: 24 5.4% 63.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 60 9.1% 97.8%;\n  --destructive: 0 72.2% 50.6%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 12 6.5% 15.1%;\n  --input: 12 6.5% 15.1%;\n  --ring: 20.5 90.2% 48.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='yellow'],\n[data-theme='yellow'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 60 9.1% 97.8%;\n  --card: 20 14.3% 4.1%;\n  --card-foreground: 60 9.1% 97.8%;\n  --popover: 20 14.3% 4.1%;\n  --popover-foreground: 60 9.1% 97.8%;\n  --primary-foreground: 26 83.3% 14.1%;\n  --secondary: 12 6.5% 15.1%;\n  --secondary-foreground: 60 9.1% 97.8%;\n  --muted: 12 6.5% 15.1%;\n  --muted-foreground: 24 5.4% 63.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 60 9.1% 97.8%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 12 6.5% 15.1%;\n  --input: 12 6.5% 15.1%;\n  --ring: 35.5 91.7% 32.9%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='zinc'],\n[data-theme='zinc'] .dark {\n  --background: 240 10% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 240 10% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 240 10% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 240 5.9% 10%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 240 3.7% 15.9%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 240 3.7% 15.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 240 4.9% 83.9%;\n  --sidebar: 240 10% 3.9%;\n  --sidebar-deep: 240 10% 3.9%;\n  --header: 240 4.9% 83.9%;\n}\n\n.dark[data-theme='neutral'],\n[data-theme='neutral'] .dark {\n  --background: 0 0% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 0 0% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 0 0% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 0 0% 9%;\n  --secondary: 0 0% 14.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 14.9%;\n  --muted-foreground: 0 0% 63.9%;\n  --accent: 0 0% 14.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 14.9%;\n  --input: 0 0% 14.9%;\n  --ring: 0 0% 83.1%;\n  --sidebar: 0 0% 3.9%;\n  --sidebar-deep: 0 0% 3.9%;\n  --header: 0 0% 3.9%;\n}\n\n.dark[data-theme='slate'],\n[data-theme='slate'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 222.2 47.4% 11.2%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 212.7 26.8% 83.9;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='gray'],\n[data-theme='gray'] .dark {\n  --background: 224 71.4% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 210 20% 98%;\n  --card: 224 71.4% 4.1%;\n  --card-foreground: 210 20% 98%;\n  --popover: 224 71.4% 4.1%;\n  --popover-foreground: 210 20% 98%;\n  --primary-foreground: 220.9 39.3% 11%;\n  --secondary: 215 27.9% 16.9%;\n  --secondary-foreground: 210 20% 98%;\n  --muted: 215 27.9% 16.9%;\n  --muted-foreground: 217.9 10.6% 64.9%;\n  --accent: 215 27.9% 16.9%;\n  --accent-foreground: 210 20% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 215 27.9% 16.9%;\n  --input: 215 27.9% 16.9%;\n  --ring: 216 12.2% 83.9%;\n  --sidebar: 224 71.4% 4.1%;\n  --sidebar-deep: 224 71.4% 4.1%;\n  --header: 224 71.4% 4.1%;\n}\n```\n\n:::\n\n## Adding a New Theme\n\nTo add a new theme, simply follow these steps:\n\n- Add a new theme configuration in the application's `src/preferences.ts`.\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  theme: {\n    builtinType: 'my-theme',\n  },\n});\n```\n\n- Add the theme's CSS variables to your CSS file.\n\n```css\n/* light */\n[data-theme='my-theme'] {\n  --foreground: 224 71.4% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 224 71.4% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 224 71.4% 4.1%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 220 14.3% 95.9%;\n  --secondary-foreground: 220.9 39.3% 11%;\n  --muted: 220 14.3% 95.9%;\n  --muted-foreground: 220 8.9% 46.1%;\n  --accent: 220 14.3% 95.9%;\n  --accent-foreground: 220.9 39.3% 11%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 220 13% 91%;\n  --input: 220 13% 91%;\n  --ring: 262.1 83.3% 57.8%;\n}\n\n/* dark */\n.dark[data-theme='my-theme'],\n[data-theme='my-theme'] .dark {\n  --background: 224 71.4% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 210 20% 98%;\n  --card: 224 71.4% 4.1%;\n  --card-foreground: 210 20% 98%;\n  --popover: 224 71.4% 4.1%;\n  --popover-foreground: 210 20% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 215 27.9% 16.9%;\n  --secondary-foreground: 210 20% 98%;\n  --muted: 215 27.9% 16.9%;\n  --muted-foreground: 217.9 10.6% 64.9%;\n  --accent: 215 27.9% 16.9%;\n  --accent-foreground: 210 20% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 215 27.9% 16.9%;\n  --input: 215 27.9% 16.9%;\n  --ring: 263.4 70% 50.4%;\n  --sidebar: 224 71.4% 4.1%;\n  --sidebar-deep: 224 71.4% 4.1%;\n}\n```\n\n## Dark Mode\n\nThe framework includes a variety of built-in themes, which you can configure in `preferences.ts`. The dark theme also uses CSS variables for configuration:\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  theme: {\n    mode: 'dark',\n  },\n});\n```\n\n## Customizing Sidebar Color\n\nThe sidebar color is configured through the `--sidebar` variable.\n\n### Under the Default Theme\n\n```css\n:root {\n  --sidebar: 0 0% 100%;\n}\n```\n\n### In Dark Mode\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  --sidebar: 222.34deg 10.43% 12.27%;\n}\n```\n\n## Customizing Header Color\n\nThe header color is configured through the `--header` variable.\n\n### Under the Default Theme\n\n```css\n:root {\n  --header: 0 0% 100%;\n}\n```\n\n### In Dark Mode\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  --header: 222.34deg 10.43% 12.27%;\n}\n```\n\n## Color Weakness Mode\n\nTypically used in special scenarios, you can set the application to color weakness mode. This can be configured in `preferences.ts`:\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    colorWeakMode: true,\n  },\n});\n```\n\n## Gray Mode\n\nTypically used in special scenarios, this mode grays out the webpage. You can configure it in `preferences.ts`:\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    colorGrayMode: true,\n  },\n});\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/in-depth/ui-framework.md",
    "content": "# UI Framework Switching\n\n`Vue Admin` supports your freedom to choose the UI framework. The default UI framework for the demo site is `Ant Design Vue`, consistent with the older version. The framework also has built-in versions for `Element Plus` and `Naive UI`, allowing you to choose according to your preference.\n\n## Adding a New UI Framework\n\nIf you want to use a different UI framework, you only need to follow these steps:\n\n1. Create a new folder inside `apps`, for example, `apps/web-xxx`.\n2. Change the `name` field in `apps/web-xxx/package.json` to `web-xxx`.\n3. Remove dependencies and code from other UI frameworks and replace them with your chosen UI framework's logic, which requires minimal changes.\n4. Adjust the language files within `locales`.\n5. Adjust the components in `app.vue`.\n6. Adapt the theme of the UI framework to match `Vben Admin`.\n7. Adjust the application name in `.env`.\n8. Add a `dev:xxx` script in the root directory of the repository.\n9. Run `pnpm install` to install dependencies.\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/introduction/changelog.md",
    "content": "# CHANGE LOG\n\nTODO\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/introduction/quick-start.md",
    "content": "---\noutline: deep\n---\n\n# Quick Start {#quick-start}\n\n## Prerequisites\n\n::: info Environment Requirements\n\nBefore starting the project, ensure that your environment meets the following requirements:\n\n- [Node.js](https://nodejs.org/en) version 20.15.0 or above. It is recommended to use [fnm](https://github.com/Schniz/fnm), [nvm](https://github.com/nvm-sh/nvm), or directly use [pnpm](https://pnpm.io/cli/env) for version management.\n- [Git](https://git-scm.com/) any version.\n\nTo verify if your environment meets the above requirements, you can check the versions using the following commands:\n\n```bash\n# Ensure the correct node LTS version is displayed\nnode -v\n# Ensure the correct git version is displayed\ngit -v\n```\n\n:::\n\n## Starting the Project\n\n### Obtain the Source Code\n\n::: code-group\n\n```bash [GitHub]\n# Clone the code\ngit clone https://github.com/vbenjs/vue-vben-admin.git\n```\n\n```bash [Gitee]\n# Clone the code\n# The Gitee repository may not have the latest code\ngit clone https://gitee.com/annsion/vue-vben-admin.git\n```\n\n:::\n\n::: danger Caution\n\nEnsure that the directory where you store the code and all its parent directories do not contain Chinese, Korean, Japanese characters, or spaces, as this may cause errors when installing dependencies and starting the project.\n\n:::\n\n### Install Dependencies\n\nOpen a terminal in your code directory and execute the following commands:\n\n```bash\n# Enter the project directory\ncd vue-vben-admin\n\n# Enable the project-specified version of pnpm\nnpm i -g corepack\n\n# Install dependencies\npnpm install\n```\n\n::: tip Note\n\nThe project only supports using `pnpm` for installing dependencies. By default, `corepack` will be used to install the specified version of `pnpm`.\n\n:::\n\n### Run the Project\n\nExecute the following command to run the project:\n\n```bash\n# Start the project\npnpm dev\n```\n\nYou will see an output similar to the following, allowing you to select the project you want to run:\n\n```bash\n│\n◆  Select the app you need to run [dev]:\n│  ● @vben/web-antd\n│  ○ @vben/web-ele\n│  ○ @vben/web-naive\n│  ○ @vben/docs\n│  ○ @vben/playground\n└\n```\n\nNow, you can visit `http://localhost:5555` in your browser to view the project.\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/introduction/roadmap.md",
    "content": "# Roadmap\n\nTODO:\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/introduction/thin.md",
    "content": "# Slimmed-Down Version\n\nStarting from version `5.0`, we no longer provide slimmed-down repositories or branches. Our goal is to offer a more consistent development experience while reducing maintenance costs. Here’s how we introduce our project, slim down, and remove unnecessary features.\n\n## Application Slimming\n\nFirst, identify the version of the `UI` component library you need, and then delete the corresponding applications. For example, if you choose to use `Ant Design Vue`, you can delete the other applications. Simply remove the following two folders:\n\n```bash\napps/web-ele\napps/web-native\n\n```\n\n::: tip\n\nIf your project doesn’t include the `UI` component library you need, you can delete all other applications and create your own new application as needed.\n\n:::\n\n## Demo Code Slimming\n\nIf you don’t need demo code, you can simply delete the `playground` folder\n\n## Documentation Slimming\n\nIf you don’t need documentation, you can delete the `docs` folder.\n\n## Remove Mock Service\n\nIf you don’t need the `Mock` service, you can delete the `apps/backend-mock` folder. Also, remove the `VITE_NITRO_MOCK` variable from the `.env.development` file in your application.\n\n```bash\n# Whether to enable Nitro Mock service, true to enable, false to disable\nVITE_NITRO_MOCK=false\n```\n\n## Installing Dependencies\n\nNow that you’ve completed the slimming operations, you can install the dependencies and start your project:\n\n```bash\n# Run in the root directory\npnpm install\n\n```\n\n## Adjusting Commands\n\nAfter slimming down, you may need to adjust commands according to your project. In the `package.json` file in the root directory, you can adjust the `scripts` field and remove any commands you don’t need.\n\n```json\n{\n  \"scripts\": {\n    \"build:antd\": \"pnpm run build --filter=@vben/web-antd\",\n    \"build:docs\": \"pnpm run build --filter=@vben/docs\",\n    \"build:ele\": \"pnpm run build --filter=@vben/web-ele\",\n    \"build:naive\": \"pnpm run build --filter=@vben/web-naive\",\n    \"build:play\": \"pnpm run build --filter=@vben/playground\",\n    \"dev:antd\": \"pnpm -F @vben/web-antd run dev\",\n    \"dev:docs\": \"pnpm -F @vben/docs run dev\",\n    \"dev:ele\": \"pnpm -F @vben/web-ele run dev\",\n    \"dev:play\": \"pnpm -F @vben/playground run dev\",\n    \"dev:naive\": \"pnpm -F @vben/web-naive run dev\"\n  }\n}\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/introduction/vben.md",
    "content": "# About Vben Admin\n\n::: info You are reading the documentation for [Vben Admin](https://github.com/vbenjs/vue-vben-admin) version `5.0`!\n\n- Vben Admin 2.x is currently archived and only receives critical fixes.\n- The new version is not compatible with the old version. If you are using the old version (v2, v3), please refer to the [Vue Vben Admin 2.x Documentation](https://doc.vvbin.cn).\n- If you find any errors in the documentation, feel free to submit an issue to help us improve.\n- If you just want to experience it, you can check out the [Quick Start](./quick-start.md).\n\n:::\n\n[Vben Admin](https://github.com/vbenjs/vue-vben-admin) is a backend solution based on [Vue 3.0](https://github.com/vuejs/core), [Vite](https://github.com/vitejs/vite), and [TypeScript](https://www.typescriptlang.org/), aimed at providing an out-of-the-box solution for developing medium to large-scale projects. It includes features like component re-encapsulation, utilities, hooks, dynamic menus, permission validation, multi-theme configurations, and button-level permission control. The project uses the latest frontend technology stack, making it a good starting template for quickly building enterprise-level mid- to backend product prototypes. It can also serve as an example for learning `vue3`, `vite`, `ts`, and other mainstream technologies. The project will continue to follow the latest technologies and apply them within the project.\n\n## Features\n\n- **Latest Technology Stack**: Developed using cutting-edge frontend technologies like `Vue 3`, `Vite`, and `TypeScript`.\n- **Internationalization**: Built-in comprehensive internationalization solutions with multi-language support.\n- **Permission Validation**: Comprehensive permission validation solutions, including button-level permission control.\n- **Multi-Theme**: Built-in multiple theme configurations & dark mode to meet personalized needs.\n- **Dynamic Menu**: Supports dynamic menus that can display based on permissions.\n- **Mock Data**: High-performance local Mock data solution based on `Nitro`.\n- **Rich Components**: Provides a wide range of components to meet most business needs.\n- **Standardization**: Code quality is ensured with tools like `ESLint`, `Prettier`, `Stylelint`, `Publint`, and `CSpell`.\n- **Engineering**: Development efficiency is improved with tools like `Pnpm Monorepo`, `TurboRepo`, and `Changeset`.\n- **Multi-UI Library Support**: Supports mainstream UI libraries like `Ant Design Vue`, `Element Plus`, and `Vuetify`, without being restricted to a specific framework.\n\n## Browser Support\n\n- **Local development** is recommended using the **latest version of Chrome**. **Versions below Chrome 80 are not supported**.\n\n- **Production environment** supports modern browsers, IE is not supported.\n\n| [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png\" alt=\"IE\" width=\"24px\" height=\"24px\"  />](http://godban.github.io/browsers-support-badges/)IE | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\" alt=\" Edge\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)Edge | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)Firefox | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)Chrome | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)Safari |\n| :-: | :-: | :-: | :-: | :-: |\n| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |\n\n## Contribution\n\n- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) is still being actively updated. Contributions are welcome to help maintain and improve the project, aiming to create a better mid- to backend solution.\n- If you wish to join us, you can start by contributing in the following ways, and we will invite you to join based on your activity.\n\n::: info Join Us\n\n- Regularly submit `PRs`.\n- Provide valuable suggestions.\n- Participate in discussions and help resolve some `issues`.\n- Help maintain the documentation.\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/introduction/why.md",
    "content": "# Why Choose Us?\n\nFirst of all, we do not compare ourselves with other frameworks. We believe that every framework has its own characteristics and is suited for different scenarios. Our goal is to provide a simple and easy-to-use framework that allows developers to get started quickly and focus on developing business logic. Therefore, we will continue to improve and optimize our framework to offer a better experience.\n\n## Framework History\n\nStarting from Vue Vben Admin version 1.x, the framework has undergone numerous iterations and optimizations. From initially using `Vite 0.x` when there were no ready-made plugins available, we developed many custom plugins to bridge the gap between Webpack and Vite. Although many of these have since been replaced, our original intention has remained the same: to provide a simple and easy-to-use framework.\n\nAlthough the community maintained the project for a period, we have always closely monitored the development of Vue Vben Admin. We have witnessed many developers use Vben Admin and provide valuable suggestions and feedback. We are very grateful for everyone's support and contributions, which continue to drive us to improve Vben Admin. In the new version, we have continuously collected user feedback, started anew, and optimized the framework to provide a better user experience. Our goal is to enable developers to get started quickly and focus on developing business logic.\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/other/faq.md",
    "content": "# Frequently Asked Questions #{faq}\n\n::: tip Listed are some common questions\n\nIf you have a question, you can first look here. If not found, you can search or submit your question on [GitHub Issue](https://github.com/vbenjs/vue-vben-admin/issues), or if it's a discussion-type question, you can go to [GitHub Discussions](https://github.com/vbenjs/vue-vben-admin/discussions)\n\n:::\n\n## Instructions\n\nIf you encounter a problem, you can start looking from the following aspects:\n\n1. Search the corresponding module's GitHub repository [issue](https://github.com/vbenjs/vue-vben-admin/issues)\n2. Search for the problem on [Google](https://www.google.com)\n3. Search for the problem on [Baidu](https://www.baidu.com)\n4. If you can't find the issue in the list below, you can ask in [issues](https://github.com/vbenjs/vue-vben-admin/issues)\n5. If it's not a problem type and needs discussion, please go to [discussions](https://github.com/vbenjs/vue-vben-admin/discussions) to discuss\n\n## Dependency Issues\n\nIn a `Monorepo` project, it's important to get into the habit of running `pnpm install` after every `git pull` because new dependencies are often added. The project has configured automatic execution of `pnpm install` in `lefthook.yml`, but sometimes there might be issues. If it does not execute automatically, it is recommended to execute it manually once.\n\n## About Cache Update Issues\n\nThe project configuration is by default cached in `localStorage`, so some configurations may not change after a version update.\n\nThe solution is to modify the `version` number in `package.json` each time the code is updated. This is because the key for `localStorage` is based on the version number. Therefore, after an update, the configurations from a previous version will become invalid. Simply re-login to apply the new settings.\n\n## About Modifying Configuration Files\n\nWhen modifying environment files such as `.env` or the `vite.config.ts` file, Vite will automatically restart the service.\n\nThere's a chance that automatic restarts may encounter issues. Simply rerunning the project can resolve these problems.\n\n## Errors When Running Locally\n\nSince Vite does not transform code locally and the code uses relatively new syntax such as optional chaining, local development requires using a higher version of the browser (`Chrome 90+`).\n\n## Blank Page After Switching Pages\n\nThis issue occurs because route switching animations are enabled, and the corresponding page component has multiple root nodes. Adding a `<div></div>` at the outermost layer of the page can solve this problem.\n\n**Incorrect Example**\n\n```vue\n<template>\n  <!-- Annotations are also considered a node -->\n  <h1>text h1</h1>\n  <h2>text h2</h2>\n</template>\n```\n\n**正确示例**\n\n```vue\n<template>\n  <div>\n    <h1>text h1</h1>\n    <h2>text h2</h2>\n  </div>\n</template>\n```\n\n::: tip Tip\n\n- If you want to use multiple root tags, you can disable route switching animations.\n- Root comment nodes under `template` are also counted as a node.\n\n:::\n\n## My code works locally but not when packaged\n\nThe reason for this issue could be one of the following. You can check these reasons, and if there are other possibilities, feel free to add them:\n\n- The variable `ctx` was used, which is not exposed in the instance type. The Vue official documentation also advises against using this property as it is intended for internal use only.\n\n```ts\nimport { getCurrentInstance } from 'vue';\ngetCurrentInstance().ctx.xxxx;\n```\n\n## Dependency Installation Issues\n\n- If you cannot install dependencies or the startup reports an error, you can try executing `pnpm run reinstall`.\n- If you cannot install dependencies or encounter errors, you can try switching to a mobile hotspot for installing dependencies.\n- If that still doesn't work, you can configure a domestic mirror for installation.\n- You can also create a `.npmrc` file in the project root directory with the following content:\n\n```bash\n# .npmrc\nregistry = https://registry.npmmirror.com/\n```\n\n## Package File Too Large\n\n- First, the full version will be larger because it includes many library files. You can use the simplified version for development.\n\n- Secondly, it is recommended to enable gzip, which can reduce the size to about 1/3 of the original. Gzip can be enabled directly by the server. If so, the frontend does not need to build `.gz` format files. If the frontend has built `.gz` files, for example, with nginx, you need to enable the `gzip_static: on` option.\n\n- While enabling gzip, you can also enable `brotli` for better compression than gzip. Both can coexist.\n\n**Note**\n\n- gzip_static: This module requires additional installation in nginx, as the default nginx does not include this module.\n\n- Enabling `brotli` also requires additional nginx module installation.\n\n## Runtime Errors\n\nIf you encounter errors similar to the following, please check that the full project path (including all parent paths) does not contain Chinese, Japanese, or Korean characters. Otherwise, you will encounter a 404 error for the path, leading to the following issue:\n\n```ts\n[vite] Failed to resolve module import \"ant-design-vue/dist/antd.css-vben-adminode_modulesant-design-vuedistantd.css\". (imported by /@/setup/ant-design-vue/index.ts)\n```\n\n## Console Route Warning Issue\n\nIf you see the following warning in the console, and the page `can open normally`, you can ignore this warning.\n\nFuture versions of `vue-router` may provide an option to disable this warning.\n\n```ts\n[Vue Router warn]: No match found for location with path \"xxxx\"\n```\n\n## Startup Error\n\nIf you encounter the following error message, please check if your nodejs version meets the requirements.\n\n```bash\nTypeError: str.matchAll is not a function\nat Object.extractor (vue-vben-admin-main\\node_modules@purge-icons\\core\\dist\\index.js:146:27)\nat Extract (vue-vben-admin-main\\node_modules@purge-icons\\core\\dist\\index.js:173:54)\n```\n\n## nginx Deployment\n\nAfter deploying to `nginx`，you might encounter the following error:\n\n```bash\nFailed to load module script: Expected a JavaScript module script but the server responded with a MIME type of \"application/octet-stream\". Strict MIME type checking is enforced for module scripts per HTML spec.\n```\n\nSolution 1:\n\n```bash\nhttp {\n    #If there is such a configuration, it needs to be commented out\n    #include       mime.types;\n\n    types {\n      application/javascript js mjs;\n    }\n}\n```\n\nSolution 2：\n\nOpen the `mime.types` file under `nginx` and change `application/javascript js;` to `application/javascript js mjs;`\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/other/project-update.md",
    "content": "# PROJECT UPDATE\n\n## Why Can't It Be Updated Like a npm Plugin\n\nBecause the project is a complete project template, not a plugin or a package, it cannot be updated like a plugin. After you use the code, you will develop it further based on business needs, and you need to manually merge and upgrade.\n\n## What Should I Do\n\nThe project is managed using a `Monorepo` approach and has abstracted some of the more core code, such as `packages/@core`, `packages/effects`. As long as the business code has not modified this part of the code, you can directly pull the latest code and then merge it into your branch. You only need to handle some conflicts simply. Other folders will only make some minor adjustments, which will not affect the business code.\n\n::: tip Recommendation\n\nIt is recommended to follow the repository updates actively and merge them; do not accumulate over a long time, Otherwise, it will lead to too many merge conflicts and increase the difficulty of merging.\n\n:::\n\n## Updating Code Using Git\n\n1. Clone the code\n\n```bash\ngit clone https://github.com/vbenjs/vue-vben-admin.git\n```\n\n2. Add your company's git source address\n\n```bash\n# up is the source name, can be set arbitrarily\n# gitUrl is the latest open-source code\ngit remote add up gitUrl;\n```\n\n3. Push the code to your company's git\n\n```bash\n# Push the code to your company\n# main is the branch name, adjust according to your situation\ngit push up main\n# Sync the company's code\n# main is the branch name, adjust according to your situation\ngit pull up main\n```\n\n4. How to sync the latest open-source code\n\n```bash\ngit pull origin main\n```\n\n::: tip Tip\n\nWhen syncing the code, conflicts may occur. Just resolve the conflicts.\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/other/remove-code.md",
    "content": "# Remove Code\n\n## Remove Code\n\nIn the corresponding application's `index.html` file, find the following code and delete it:\n\n```html\n<!-- apps/web-antd -->\n<script>\n  var _hmt = _hmt || [];\n  (function () {\n    var hm = document.createElement('script');\n    hm.src = 'https://hm.baidu.com/hm.js?d20a01273820422b6aa2ee41b6c9414d';\n    var s = document.getElementsByTagName('script')[0];\n    s.parentNode.insertBefore(hm, s);\n  })();\n</script>\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/project/changeset.md",
    "content": "# Changeset\n\nThe project has integrated [changeset](https://github.com/changesets/changesets) as a version management tool. Changeset is a version management tool that helps us better manage versions, generate changelogs, and automate releases.\n\nFor detailed usage, please refer to the official documentation. If you do not need it, you can ignore it directly.\n\n## Command Line\n\nThe changeset command is already built into the project:\n\n### Interactively Add Changesets\n\n```bash\npnpm run changeset\n```\n\n### Uniformly Increment Version Numbers\n\n```bash\npnpm run version\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/project/cli.md",
    "content": "---\noutline: deep\n---\n\n# CLI\n\nIn the project, some command-line tools are provided for common operations, located in `scripts`.\n\n## vsh\n\nUsed for some project operations, such as cleaning the project, checking the project, etc.\n\n### Usage\n\n```bash\npnpm vsh [command] [options]\n```\n\n### vsh check-circular\n\nCheck for circular references throughout the project. If there are circular references, the modules involved will be output to the console.\n\n#### Usage\n\n```bash\npnpm vsh check-circular\n```\n\n#### Options\n\n| Option     | Description                                               |\n| ---------- | --------------------------------------------------------- |\n| `--staged` | Only check files in the git staging area, default `false` |\n\n### vsh check-dep\n\nCheck the dependency situation of the entire project and output `unused dependencies`, `uninstalled dependencies` information to the console.\n\n#### Usage\n\n```bash\npnpm vsh check-dep\n```\n\n### vsh lint\n\nLint checks the project to see if the code in the project conforms to standards.\n\n#### Usage\n\n```bash\npnpm vsh lint\n```\n\n#### Options\n\n| Option     | Description                                  |\n| ---------- | -------------------------------------------- |\n| `--format` | Check and try to fix errors, default `false` |\n\n### vsh publint\n\nPerform package standard checks on `Monorepo` projects to see if the packages in the project conform to standards.\n\n#### Usage\n\n```bash\npnpm vsh publint\n```\n\n#### Options\n\n| Option    | Description                          |\n| --------- | ------------------------------------ |\n| `--check` | Only perform checks, default `false` |\n\n### vsh code-workspace\n\nGenerate `vben-admin.code-workspace` file. Currently, it does not need to be executed manually and will be executed automatically when code is committed.\n\n#### Usage\n\n```bash\npnpm vsh code-workspace\n```\n\n#### Options\n\n| Option          | Description                                               |\n| --------------- | --------------------------------------------------------- |\n| `--auto-commit` | Automatically commit during `git commit`, default `false` |\n| `--spaces`      | Indentation format, default `2` spaces                    |\n\n## turbo-run\n\nUsed to quickly execute scripts in the large repository and provide option-based interactive selection.\n\n### Usage\n\n```bash\npnpm turbo-run [command]\n```\n\n### turbo-run dev\n\nQuickly execute the `dev` command and provide option-based interactive selection.\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/project/dir.md",
    "content": "# Directory Explanation\n\nThe directory uses Monorepo management, and the project structure is as follows:\n\n```bash\n.\n├── Dockerfile # Docker image build file\n├── README.md # Project documentation\n├── apps # Project applications directory\n│   ├── backend-mock # Backend mock service application\n│   ├── web-antd # Frontend application based on Ant Design Vue\n│   ├── web-ele # Frontend application based on Element Plus\n│   └── web-naive # Frontend application based on Naive UI\n├── build-local-docker-image.sh # Script for building Docker images locally\n├── cspell.json # CSpell configuration file\n├── docs # Project documentation directory\n├── eslint.config.mjs # ESLint configuration file\n├── internal # Internal tools directory\n│   ├── lint-configs # Code linting configurations\n│   │   ├── commitlint-config # Commitlint configuration\n│   │   ├── eslint-config # ESLint configuration\n│   │   ├── prettier-config # Prettier configuration\n│   │   └── stylelint-config # Stylelint configuration\n│   ├── node-utils # Node.js tools\n│   ├── tailwind-config # Tailwind configuration\n│   ├── tsconfig # Common tsconfig settings\n│   └── vite-config # Common Vite configuration\n├── package.json # Project dependency configuration\n├── packages # Project packages directory\n│   ├── @core # Core package\n│   │   ├── base # Base package\n│   │   │   ├── design # Design related\n│   │   │   ├── icons # Icons\n│   │   │   ├── shared # Shared\n│   │   │   └── typings # Type definitions\n│   │   ├── composables # Composable APIs\n│   │   ├── preferences # Preferences\n│   │   └── ui-kit # UI component collection\n│   │       ├── layout-ui # Layout UI\n│   │       ├── menu-ui  # Menu UI\n│   │       ├── shadcn-ui # shadcn UI\n│   │       └── tabs-ui # Tabs UI\n│   ├── constants # Constants\n│   ├── effects # Effects related packages\n│   │   ├── access # Access control\n│   │   ├── plugins # Plugins\n│   │   ├── common-ui # Common UI\n│   │   ├── hooks # Composable APIs\n│   │   ├── layouts # Layouts\n│   │   └── request # Request\n│   ├── icons # Icons\n│   ├── locales # Internationalization\n│   ├── preferences  # Preferences\n│   ├── stores # State management\n│   ├── styles # Styles\n│   ├── types # Type definitions\n│   └── utils # Utilities\n├── playground # Demo directory\n├── pnpm-lock.yaml # pnpm lock file\n├── pnpm-workspace.yaml # pnpm workspace configuration file\n├── scripts # Scripts directory\n│   ├── turbo-run # Turbo run script\n│   └── vsh # VSH script\n├── stylelint.config.mjs # Stylelint configuration file\n├── turbo.json # Turbo configuration file\n├── vben-admin.code-workspace # VS Code workspace configuration file\n└── vitest.config.ts # Vite configuration file\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/project/standard.md",
    "content": "# Standards\n\n::: tip Contributing Code\n\n- If you want to contribute code to the project, please ensure your code complies with the project's coding standards.\n- If you are using `vscode`, you need to install the following plugins:\n  - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Script code checking\n  - [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code formatting\n  - [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - Word syntax checking\n  - [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - CSS formatting\n\n:::\n\n## Purpose\n\nStudents with basic engineering literacy always pay attention to coding standards, and code style checking (Code Linting, simply called Lint) is an important means to ensure the consistency of coding standards.\n\nFollowing the corresponding coding standards has the following benefits:\n\n- Lower bug error rate\n- Efficient development efficiency\n- Higher readability\n\n## Tools\n\nThe project's configuration files are located in `internal/lint-configs`, where you can modify various lint configurations.\n\nThe project integrates the following code verification tools:\n\n- [ESLint](https://eslint.org/) for JavaScript code checking\n- [Stylelint](https://stylelint.io/) for CSS style checking\n- [Prettier](https://prettier.io/) for code formatting\n- [Commitlint](https://commitlint.js.org/) for checking the standard of git commit messages\n- [Publint](https://publint.dev/) for checking the standard of npm packages\n- [Cspell](https://cspell.org/) for checking spelling errors\n- [lefthook](https://github.com/evilmartians/lefthook) for managing Git hooks, automatically running code checks and formatting before commits\n\n## ESLint\n\nESLint is a code standard and error checking tool used to identify and report syntax errors in TypeScript code.\n\n### Command\n\n```bash\npnpm eslint .\n```\n\n### Configuration\n\nThe ESLint configuration file is `eslint.config.mjs`, with its core configuration located in the `internal/lint-configs/eslint-config` directory, which can be modified according to project needs.\n\n## Stylelint\n\nStylelint is used to check the style of CSS within the project. Coupled with the editor's auto-fix feature, it can effectively unify the CSS style within the project.\n\n### Command\n\n```bash\npnpm stylelint \"**/*.{vue,css,less.scss}\"\n```\n\n### Configuration\n\nThe Stylelint configuration file is `stylelint.config.mjs`, with its core configuration located in the `internal/lint-configs/stylelint-config` directory, which can be modified according to project needs.\n\n## Prettier\n\nPrettier Can be used to unify project code style, consistent indentation, single and double quotes, trailing commas, and other styles.\n\n### Command\n\n```bash\npnpm prettier .\n```\n\n### Configuration\n\nThe Prettier configuration file is `.prettier.mjs`, with its core configuration located in the `internal/lint-configs/prettier-config` directory, which can be modified according to project needs.\n\n## CommitLint\n\nIn a team, everyone's git commit messages can vary widely, making it difficult to ensure standardization without a mechanism. How can standardization be achieved? You might think of using git's hook mechanism to write shell scripts to implement this. Of course, this is possible, but actually, JavaScript has a great tool for implementing this template, which is commitlint (used for verifying the standard of git commit messages).\n\n### Configuration\n\nThe CommitLint configuration file is `.commitlintrc.mjs`, with its core configuration located in the `internal/lint-configs/commitlint-config` directory, which can be modified according to project needs.\n\n### Git Commit Standards\n\nRefer to [Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)\n\n- `feat` Add new features\n- `fix` Fix problems/BUGs\n- `style` Code style changes that do not affect the outcome\n- `perf` Optimization/performance improvement\n- `refactor` Refactoring\n- `revert` Revert changes\n- `test` Related to tests\n- `docs` Documentation/comments\n- `chore` Dependency updates/scaffold configuration modifications, etc.\n- `workflow` Workflow improvements\n- `ci` Continuous integration\n- `types` Type modifications\n\n### Disabling Git Commit Standard Checks\n\nIf you want to disable Git commit standard checks, there are two ways:\n\n::: code-group\n\n```bash [Temporary disable]\ngit commit -m 'feat: add home page' --no-verify\n```\n\n```bash [Permanent closed]\n# Comment out the following code in .husky/commit-msg to disable\npnpm exec commitlint --edit \"$1\" # [!code --]\n```\n\n:::\n\n## Publint\n\nPublint is a tool for checking the standard of npm packages, which can check whether the package version conforms to the standard, whether it conforms to the standard ESM package specification, etc.\n\n### Command\n\n```bash\npnpm vsh publint\n```\n\n## Cspell\n\nCspell is a tool for checking spelling errors, which can check for spelling errors in the code, avoiding bugs caused by spelling errors.\n\n### Command\n\n```bash\npnpm cspell lint \\\"**/*.ts\\\"  \\\"**/README.md\\\" \\\".changeset/*.md\\\" --no-progress\n```\n\n### Configuration\n\nThe cspell configuration file is `cspell.json`, which can be modified according to project needs.\n\n## Git Hook\n\nGit hooks are generally combined with various lints to check code style during git commits. If the check fails, the commit will not proceed. Developers need to modify and resubmit.\n\n### lefthook\n\nOne issue is that the check will verify all code, but we only want to check the code we are committing. This is where lefthook comes in.\n\nThe most effective solution is to perform Lint checks locally before committing. A common practice is to use lefthook to perform a Lint check before local submission.\n\nThe project defines corresponding hooks inside `lefthook.yml`:\n\n- `pre-commit`: Runs before commit, used for code formatting and checking\n  - `code-workspace`: Updates VSCode workspace configuration\n  - `lint-md`: Formats Markdown files\n  - `lint-vue`: Formats and checks Vue files\n  - `lint-js`: Formats and checks JavaScript/TypeScript files\n  - `lint-style`: Formats and checks style files\n  - `lint-package`: Formats package.json\n  - `lint-json`: Formats other JSON files\n\n- `post-merge`: Runs after merge, used for automatic dependency installation\n  - `install`: Runs `pnpm install` to install new dependencies\n\n- `commit-msg`: Runs during commit, used for checking commit message format\n  - `commitlint`: Uses commitlint to check commit messages\n\n#### How to Disable lefthook\n\nIf you want to disable lefthook, there are two ways:\n\n::: code-group\n\n```bash [Temporary disable]\ngit commit -m 'feat: add home page' --no-verify\n```\n\n```bash [Permanent disable]\n# Simply delete the lefthook.yml file\nrm lefthook.yml\n```\n\n:::\n\n#### How to Modify lefthook Configuration\n\nIf you want to modify lefthook's configuration, you can edit the `lefthook.yml` file. For example:\n\n```yaml\npre-commit:\n  parallel: true # Execute tasks in parallel\n  jobs:\n    - name: lint-js\n      run: pnpm prettier --cache --ignore-unknown --write {staged_files}\n      glob: '*.{js,jsx,ts,tsx}'\n```\n\nWhere:\n\n- `parallel`: Whether to execute tasks in parallel\n- `jobs`: Defines the list of tasks to execute\n- `name`: Task name\n- `run`: Command to execute\n- `glob`: File pattern to match\n- `{staged_files}`: Represents the list of staged files\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/project/tailwindcss.md",
    "content": "# Tailwind CSS\n\n[Tailwind CSS](https://tailwindcss.com/) is a utility-first CSS framework for quickly building custom designs.\n\n## Configuration\n\nThe project's configuration file is located in `internal/tailwind-config`, where you can modify the Tailwind CSS configuration.\n\n::: tip Restrictions on using tailwindcss in packages\n\nTailwind CSS compilation will only be enabled if there is a `tailwind.config.mjs` file present in the corresponding package. Otherwise, Tailwind CSS will not be enabled. If you have a pure SDK package that does not require Tailwind CSS, you do not need to create a `tailwind.config.mjs` file.\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/project/test.md",
    "content": "# Unit Testing\n\nThe project incorporates [Vitest](https://vitest.dev/) as the unit testing tool. Vitest is a test runner based on Vite, offering a simple API for writing test cases.\n\n## Writing Test Cases\n\nWithin the project, we follow the convention of naming test files with a `.test.ts` suffix or placing them inside a `__tests__` directory. For example, if you create a `utils.ts` file, then you would create a corresponding `utils.spec.ts` file in the same directory,\n\n```ts\n// utils.test.ts\nimport { expect, test } from 'vitest';\nimport { sum } from './sum';\n\ntest('adds 1 + 2 to equal 3', () => {\n  expect(sum(1, 2)).toBe(3);\n});\n```\n\n## Running Tests\n\nTo run the tests, execute the following command at the root of the monorepo:\n\n```bash\npnpm test:unit\n```\n\n## Existing Unit Tests\n\nThere are already some unit test cases in the project. You can search for files ending with .test.ts to view them. When you make changes to related code, you can run the unit tests to ensure the correctness of your code. It is recommended to maintain the coverage of unit tests during the development process and to run unit tests as part of the CI/CD process to ensure tests pass before deploying the project.\n\nExisting unit test status:\n\n![](/guide/test.png)\n"
  },
  {
    "path": "hiauth-front/docs/src/en/guide/project/vite.md",
    "content": "# Vite Config\n\nThe project encapsulates a layer of Vite configuration and integrates some plugins for easy reuse across multiple packages and applications. The usage is as follows:\n\n## Application\n\n```ts\n// vite.config.mts\nimport { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    application: {},\n    // Vite configuration, override according to the official Vite documentation\n    vite: {},\n  };\n});\n```\n\n## Package\n\n```ts\n// vite.config.mts\nimport { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    library: {},\n    // Vite configuration, override according to the official Vite documentation\n    vite: {},\n  };\n});\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/en/index.md",
    "content": "---\n# https://vitepress.dev/reference/default-theme-home-page\nlayout: home\nsidebar: false\n\nhero:\n  name: Vben Admin\n  text: Enterprise-Level Management System Framework\n  tagline: Fully Upgraded, Ready to Use, Simple and Efficient\n  image:\n    src: https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp\n    alt: Vben Admin\n  actions:\n    - theme: brand\n      text: Get Started ->\n      link: /en/guide/introduction/vben\n    - theme: alt\n      text: Live Preview\n      link: https://www.vben.pro\n    - theme: alt\n      text: View on GitHub\n      link: https://github.com/vbenjs/vue-vben-admin\n\nfeatures:\n  - icon: 🚀\n    title: Latest Technology Stack\n    details: Based on the latest technology stack, including Vue3, Pinia, Vue Router, TypeScript, etc.\n    link: /en/guide/introduction/quick-start\n    linkText: Get Started\n  - icon: 🦄\n    title: Rich Configurations\n    details: An enterprise-level frontend solution for middle and back-end systems, offering a wealth of components, templates, and various preference settings.\n    link: /en/guide/essentials/settings\n    linkText: Configuration Documentation\n  - icon: 🎨\n    title: Theme Customization\n    details: Easily switch between various themes through simple configurations, catering to personalized needs.\n    link: /en/guide/in-depth/theme\n    linkText: Theme Documentation\n  - icon: 🌐\n    title: Internationalization\n    details: Built-in internationalization support with multiple languages to meet global needs.\n    link: /en/guide/in-depth/locale\n    linkText: Internationalization Documentation\n  - icon: 🔐\n    title: Access Control\n    details: Built-in access control solutions supporting various permission management methods to meet different access requirements.\n    link: /en/guide/in-depth/access\n    linkText: Access Documentation\n  - title: Vite\n    icon:\n      src: /logos/vite.svg\n    details: Modern frontend build tool with fast cold start and instant hot updates.\n    link: https://vitejs.dev/\n    linkText: Official Site\n  - title: Shadcn UI\n    icon:\n      src: /logos/shadcn-ui.svg\n    details: Core built on Shadcn UI + Tailwindcss, with business support for any UI framework.\n    link: https://www.shadcn-vue.com/\n    linkText: Official Site\n  - title: Turbo Repo\n    icon:\n      src: /logos/turborepo.svg\n    details: Standardized monorepo architecture using pnpm + monorepo + turbo for enterprise-level development standards.\n    link: https://turbo.build/\n    linkText: Official Site\n  - title: Nitro Mock Server\n    icon:\n      src: /logos/nitro.svg\n    details: Built-in Nitro Mock service makes your mock service more powerful.\n    link: https://nitro.unjs.io/\n    linkText: Official Site\n---\n\n<VbenContributors />\n"
  },
  {
    "path": "hiauth-front/docs/src/friend-links/index.md",
    "content": "# 友情链接\n\n如果您的网站是与 Vben Admin 相关的，也属于开源项目，欢迎联系我们，我们会将与您的网站加入交换友情链接。\n\n## 交换方式\n\n### 添加作者，并注明来意\n\n- 通过邮箱联系作者： [ann.vben@gmail.com](mailto:ann.vben@gmail.com)\n- 通过微信联系作者：\n\n <img src=\"https://unpkg.com/@vbenjs/static-source@0.1.7/source/wechat.jpg\" style=\"width: 300px;\"/>\n\n### 提供资料\n\n提供您的网站名称、链接、描述、LOGO（可选）等信息，我们会在第一时间添加您的网站。\n\n### 友情链接\n\n- 在您的网站上添加我们的友情链接，链接如下：\n  - 名称：Vben Admin\n  - 链接：https://www.vben.pro\n  - 描述：Vben Admin 企业级开箱即用的中后台前端解决方案\n  - Logo：https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp\n\n我们将定期的检查友情链接，如果发现您的网站已经删除了我们的友情链接以及链接地址是否正确。\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/build.md",
    "content": "# 构建与部署\n\n::: tip 前言\n\n由于是展示项目，所以打包后相对较大，如果项目中没有用到的插件，可以删除对应的文件或者路由，不引用即可，没有引用就不会打包。\n\n:::\n\n## 构建\n\n项目开发完成之后，执行以下命令进行构建：\n\n**注意：** 请在项目根目录下执行以下命令\n\n```bash\npnpm build\n```\n\n构建打包成功之后，会在根目录生成对应的应用下的 `dist` 文件夹，里面就是构建打包好的文件，例如: `apps/web-antd/dist/`\n\n## 预览\n\n发布之前可以在本地进行预览，有多种方式，这里介绍两种：\n\n- 使用项目自定的命令进行预览(推荐)\n\n**注意：** 请在项目根目录下执行以下命令\n\n```bash\npnpm preview\n```\n\n等待构建成功后，访问 `http://localhost:4173` 即可查看效果。\n\n- 本地服务器预览\n\n可以在电脑全局安装 `serve` 服务，如 `live-server`,\n\n```bash\nnpm i -g live-server\n```\n\n然后在 `dist` 目录下执行 `live-server` 命令，即可在本地查看效果。\n\n```bash\ncd apps/web-antd/dist\n# 本地预览，默认端口8080\nlive-server\n# 指定端口\nlive-server --port=9000\n```\n\n## 压缩\n\n### 开启 `gzip` 压缩\n\n需要在打包的时候更改`.env.production`配置:\n\n```bash\nVITE_COMPRESS=gzip\n```\n\n### 开启 `brotli` 压缩\n\n需要在打包的时候更改`.env.production`配置:\n\n```bash\nVITE_COMPRESS=brotli\n```\n\n### 同时开启 `gzip` 和 `brotli` 压缩\n\n需要在打包的时候更改`.env.production`配置:\n\n```bash\nVITE_COMPRESS=gzip,brotli\n```\n\n::: tip 提示\n\n`gzip` 和 `brotli` 都需要安装特定模块才能使用。\n\n:::\n\n::: details gzip 与 brotli 在 nginx 内的配置\n\n```bash\nhttp {\n  # 开启gzip\n  gzip on;\n  # 开启gzip_static\n  # gzip_static 开启后可能会报错，需要安装相应的模块, 具体安装方式可以自行查询\n  # 只有这个开启，vue文件打包的.gz文件才会有效果，否则不需要开启gzip进行打包\n  gzip_static on;\n  gzip_proxied any;\n  gzip_min_length 1k;\n  gzip_buffers 4 16k;\n  #如果nginx中使用了多层代理 必须设置这个才可以开启gzip。\n  gzip_http_version 1.0;\n  gzip_comp_level 2;\n  gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;\n  gzip_vary off;\n  gzip_disable \"MSIE [1-6]\\.\";\n\n  # 开启 brotli压缩\n  # 需要安装对应的nginx模块,具体安装方式可以自行查询\n  # 可以与gzip共存不会冲突\n  brotli on;\n  brotli_comp_level 6;\n  brotli_buffers 16 8k;\n  brotli_min_length 20;\n  brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;\n}\n```\n\n:::\n\n## 构建分析\n\n如果你的构建文件很大，可以通过项目内置 [rollup-plugin-analyzer](https://github.com/doesdev/rollup-plugin-analyzer) 插件进行代码体积分析，从而优化你的代码。只需要在`根目录`下执行以下命令：\n\n```bash\npnpm run build:analyze\n```\n\n运行之后，在自动打开的页面可以看到具体的体积分布，以分析哪些依赖有问题。\n\n![Build analysis report](/guide/report.png)\n\n## 部署\n\n简单的部署只需要将最终生成的静态文件，dist 文件夹的静态文件发布到你的 cdn 或者静态服务器即可，需要注意的是其中的 index.html 通常会是你后台服务的入口页面，在确定了 js 和 css 的静态之后可能需要改变页面的引入路径。\n\n例如上传到 nginx 服务器，可以将 dist 文件夹下的文件上传到服务器的 `/srv/www/project/index.html` 目录下，然后访问配置好的域名即可。\n\n```bash\n# nginx配置\nlocation / {\n  # 不缓存html，防止程序更新后缓存继续生效\n  if ($request_filename ~* .*\\.(?:htm|html)$) {\n    add_header Cache-Control \"private, no-store, no-cache, must-revalidate, proxy-revalidate\";\n    access_log on;\n  }\n  # 这里是vue打包文件dist内的文件的存放路径\n  root   /srv/www/project/;\n  index  index.html index.htm;\n}\n```\n\n部署时可能会发现资源路径不对，只需要修改`.env.production`文件即可。\n\n```bash\n# 根据自己路径来配置更改\n# 注意需要以 / 开头和结尾\nVITE_BASE=/\nVITE_BASE=/xxx/\n```\n\n### 前端路由与服务端的结合\n\n项目前端路由使用的是 vue-router，所以你可以选择两种方式：history 和 hash。\n\n- `hash` 默认会在 url 后面拼接`#`\n- `history` 则不会，不过 `history` 需要服务器配合\n\n可在 `.env.production` 内进行 mode 修改\n\n```bash\nVITE_ROUTER_HISTORY=hash\n```\n\n### history 路由模式下服务端配置\n\n开启 `history` 模式需要服务器配置，更多的服务器配置详情可以看 [history-mode](https://router.vuejs.org/guide/essentials/history-mode.html#html5-mode)\n\n这里以 `nginx` 配置为例：\n\n#### 部署到根目录\n\n```bash {5}\nserver {\n  listen 80;\n  location / {\n    # 用于配合 History 使用\n    try_files $uri $uri/ /index.html;\n  }\n}\n```\n\n#### 部署到非根目录\n\n- 首先需要在打包的时候更改`.env.production`配置:\n\n```bash\nVITE_BASE = /sub/\n```\n\n- 然后在 nginx 配置文件中配置\n\n```bash {8}\nserver {\n    listen       80;\n    server_name  localhost;\n    location /sub/ {\n      # 这里是vue打包文件dist内的文件的存放路径\n      alias   /srv/www/project/;\n      index index.html index.htm;\n      try_files $uri $uri/ /sub/index.html;\n    }\n}\n```\n\n## 跨域处理\n\n使用 nginx 处理项目部署后的跨域问题\n\n1. 配置前端项目接口地址，在项目目录下的`.env.production`文件中配置：\n\n```bash\nVITE_GLOB_API_URL=/api\n```\n\n2. 在 nginx 配置请求转发到后台\n\n```bash {10-11}\nserver {\n  listen       8080;\n  server_name  localhost;\n  # 接口代理，用于解决跨域问题\n  location /api {\n    proxy_set_header Host $host;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    # 后台接口地址\n    proxy_pass http://110.110.1.1:8080/api;\n    rewrite \"^/api/(.*)$\" /$1 break;\n    proxy_redirect default;\n    add_header Access-Control-Allow-Origin *;\n    add_header Access-Control-Allow-Headers X-Requested-With;\n    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;\n  }\n}\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/concept.md",
    "content": "# 基础概念\n\n新版本中，整体工程进行了重构，现在我们将会介绍一些基础概念，以便于你更好的理解整个文档。请务必仔细阅读这一部分。\n\n## 大仓\n\n大仓指的是整个项目的仓库，包含了所有的代码、包、应用、规范、文档、配置等，也就是一整个 `Monorepo` 目录的所有内容。\n\n## 应用\n\n应用指的是一个完整的项目，一个项目可以包含多个应用，这些项目可以复用大仓内的代码、包、规范等。应用都被放置在 `apps` 目录下。每个应用都是独立的，可以单独运行、构建、测试、部署，可以引入不同的组件库等等。\n\n::: tip\n\n应用不限于前端应用，也可以是后端应用、移动端应用等，例如 `apps/backend-mock`就是一个后端服务。\n\n:::\n\n## 包\n\n包指的是一个独立的模块，可以是一个组件、一个工具、一个库等。包可以被多个应用引用，也可以被其他包引用。包都被放置在 `packages` 目录下。\n\n对于这些包，你可以把它看作是一个独立的 `npm` 包，使用方式与 `npm` 包一样。\n\n### 包引入\n\n在 `package.json` 中引入包：\n\n```json {3}\n{\n  \"dependencies\": {\n    \"@vben/utils\": \"workspace:*\"\n  }\n}\n```\n\n### 包使用\n\n在代码中引入包：\n\n```ts\nimport { isString } from '@vben/utils';\n```\n\n## 别名\n\n在项目中，你可以看到一些 `#` 开头的路径，例如： `#/api`、`#/views`, 这些路径都是别名，用于快速定位到某个目录。它不是通过 `vite` 的 `alias` 实现的，而是通过 `Node.js` 本身的 [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) 原理。只需要在 `package.json` 中配置 `imports` 字段即可。\n\n```json {3}\n{\n  \"imports\": {\n    \"#/*\": \"./src/*\"\n  }\n}\n```\n\n为了 IDE 能够识别这些别名，我们还需要在`tsconfig.json`内配置：\n\n```json {5}\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"#/*\": [\"src/*\"]\n    }\n  }\n}\n```\n\n这样，你就可以在代码中使用别名了。\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/development.md",
    "content": "# 本地开发 {#development}\n\n::: tip 代码获取\n\n如果你还没有获取代码，可以先从 [快速开始](../introduction/quick-start.md) 处开始阅读文档。\n\n:::\n\n## 前置准备\n\n为了更好的开发体验，我们提供了一些工具配置、项目说明，以便于您更好的开发。\n\n### 需要掌握的基础知识\n\n本项目需要一定前端基础知识，请确保掌握 Vue 的基础知识，以便能处理一些常见的问题。建议在开发前先学一下以下内容，提前了解和学习这些知识，会对项目理解非常有帮助:\n\n- [Vue3](https://vuejs.org/)\n- [Tailwind CSS](https://tailwindcss.com/)\n- [TypeScript](https://www.typescriptlang.org/)\n- [Vue Router](https://router.vuejs.org/)\n- [Vitejs](https://vitejs.dev/)\n- [Pnpm](https://pnpm.io/)\n- [Turbo](https://turbo.build/)\n\n### 工具配置\n\n如果您使用的 IDE 是[vscode](https://code.visualstudio.com/)(推荐)的话，可以安装以下工具来提高开发效率及代码格式化:\n\n- [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) - Vue 官方插件（必备）。\n- [Tailwind CSS](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) - Tailwindcss 提示插件。\n- [CSS Variable Autocomplete](https://marketplace.visualstudio.com/items?itemName=bradlc.vunguyentuan.vscode-css-variables) - Css 变量提示插件。\n- [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) - Iconify 图标插件\n- [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) - i18n 插件\n- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - 脚本代码检查\n- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - 代码格式化\n- [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - css 格式化\n- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - 单词语法检查\n- [DotENV](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) - .env 文件 高亮\n\n## Npm Scripts\n\nnpm 脚本是项目常见的配置，用于执行一些常见的任务，比如启动项目、打包项目等。以下的脚本都可以在项目根目录的 `package.json` 文件中找到。\n\n执行方式为：`pnpm run [script]` 或 `npm run [script]`。\n\n```json\n{\n  \"scripts\": {\n    // 构建项目\n    \"build\": \"cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build\",\n    // 构建项目并分析\n    \"build:analyze\": \"turbo build:analyze\",\n    // 构建本地 docker 镜像\n    \"build:docker\": \"./build-local-docker-image.sh\",\n    // 单独构建 web-antd 应用\n    \"build:antd\": \"pnpm run build --filter=@vben/web-antd\",\n    // 单独构建文档\n    \"build:docs\": \"pnpm run build --filter=@vben/docs\",\n    // 单独构建 web-ele 应用\n    \"build:ele\": \"pnpm run build --filter=@vben/web-ele\",\n    // 单独构建 web-naive 应用\n    \"build:naive\": \"pnpm run build --filter=@vben/naive\",\n    // 单独构建 playground 应用\n    \"build:play\": \"pnpm run build --filter=@vben/playground\",\n    // changeset 版本管理\n    \"changeset\": \"pnpm exec changeset\",\n    // 检查项目各种问题\n    \"check\": \"pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell\",\n    // 检查循环引用\n    \"check:circular\": \"vsh check-circular\",\n    // 检查拼写\n    \"check:cspell\": \"cspell lint **/*.ts **/README.md .changeset/*.md --no-progress\"\n    // 检查依赖\n    \"check:dep\": \"vsh check-dep\",\n    // 检查类型\n    \"check:type\": \"turbo run typecheck\",\n    // 清理项目（删除node_modules、dist、.turbo）等目录\n    \"clean\": \"node ./scripts/clean.mjs\",\n    // 提交代码\n    \"commit\": \"czg\",\n    // 启动项目（默认会运行整个仓库所有包的dev脚本）\n    \"dev\": \"turbo-run dev\",\n    // 启动web-antd应用\n    \"dev:antd\": \"pnpm -F @vben/web-antd run dev\",\n    // 启动文档\n    \"dev:docs\": \"pnpm -F @vben/docs run dev\",\n    // 启动web-ele应用\n    \"dev:ele\": \"pnpm -F @vben/web-ele run dev\",\n    // 启动web-naive应用\n    \"dev:naive\": \"pnpm -F @vben/web-naive run dev\",\n    // 启动演示应用\n    \"dev:play\": \"pnpm -F @vben/playground run dev\",\n    // 格式化代码\n    \"format\": \"vsh lint --format\",\n    // lint 代码\n    \"lint\": \"vsh lint\",\n    // 依赖安装完成之后，执行所有包的stub脚本\n    \"postinstall\": \"pnpm -r run stub --if-present\",\n    // 只允许使用pnpm\n    \"preinstall\": \"npx only-allow pnpm\",\n    // lefthook的安装\n    \"prepare\": \"is-ci || lefthook install\",\n    // 预览应用\n    \"preview\": \"turbo-run preview\",\n    // 包规范检查\n    \"publint\": \"vsh publint\",\n    // 删除所有的node_modules、yarn.lock、package.lock.json，重新安装依赖\n    \"reinstall\": \"pnpm clean --del-lock && pnpm install\",\n    // 运行 vitest 单元测试\n    \"test:unit\": \"vitest run --dom\",\n    // 更新项目依赖\n    \"update:deps\": \" pnpm update --latest --recursive\",\n    // changeset生成提交集\n    \"version\": \"pnpm exec changeset version && pnpm install --no-frozen-lockfile\"\n  }\n}\n```\n\n## 本地运行项目\n\n如需本地运行文档，并进行调整，可以执行以下命令，执行该命令，你可以选择需要的应用进行开发：\n\n```bash\npnpm dev\n```\n\n如果你想直接运行某个应用，可以执行以下命令：\n\n运行 `web-antd` 应用：\n\n```bash\npnpm dev:antd\n```\n\n运行 `web-naive` 应用：\n\n```bash\npnpm dev:naive\n```\n\n运行 `web-ele` 应用：\n\n```bash\npnpm dev:ele\n```\n\n运行 `docs` 应用：\n\n```bash\npnpm dev:docs\n```\n\n## 区分构建环境\n\n在实际的业务开发中，通常会在构建时区分多种环境，如测试环境`test`、生产环境`build`等。\n\n此时可以修改三个文件，在其中增加对应的脚本配置来达到区分生产环境的效果。\n\n以`@vben/web-antd`添加测试环境`test`为例：\n\n- `apps\\web-antd\\package.json`\n\n```json\n\"scripts\": {\n  \"build:prod\": \"pnpm vite build --mode production\",\n  \"build:test\": \"pnpm vite build --mode test\",\n  \"build:analyze\": \"pnpm vite build --mode analyze\",\n  \"dev\": \"pnpm vite --mode development\",\n  \"preview\": \"vite preview\",\n  \"typecheck\": \"vue-tsc --noEmit --skipLibCheck\"\n},\n```\n\n增加命令`\"build:test\"`, 并将原`\"build\"`改为`\"build:prod\"`以避免同时构建两个环境的包。\n\n- `package.json`\n\n```json\n\"scripts\": {\n    \"build\": \"cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build\",\n    \"build:analyze\": \"turbo build:analyze\",\n    \"build:antd\": \"pnpm run build --filter=@vben/web-antd\",\n    \"build-test:antd\": \"pnpm run build --filter=@vben/web-antd build:test\",\n\n    ······\n}\n```\n\n在根目录`package.json`中加入构建测试环境的命令\n\n- `turbo.json`\n\n```json\n\"tasks\": {\n    \"build\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\n        \"dist/**\",\n        \"dist.zip\",\n        \".vitepress/dist.zip\",\n        \".vitepress/dist/**\"\n      ]\n    },\n\n    \"build-test:antd\": {\n      \"dependsOn\": [\"@vben/web-antd#build:test\"],\n      \"outputs\": [\"dist/**\"]\n    },\n\n    \"@vben/web-antd#build:test\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\"dist/**\"]\n    },\n\n    ······\n```\n\n在`turbo.json`中加入相关依赖的命令\n\n## 公共静态资源\n\n项目中需要使用到的公共静态资源，如：图片、静态HTML等，需要在开发中通过 `src=\"/xxx.png\"` 直接引入的。\n\n需要将资源放在对应项目的 `public/static` 目录下。引入的路径为：`src=\"/static/xxx.png\"`。\n\n## DevTools\n\n项目内置了 [Vue DevTools](https://github.com/vuejs/devtools-next) 插件，可以在开发过程中使用。默认关闭，可在`.env.development` 内开启，并重新运行项目即可：\n\n```bash\nVITE_DEVTOOLS=true\n```\n\n开启后，项目运行会在页面底部显示一个 Vue DevTools 的图标，点击即可打开 DevTools。\n\n![Vue DevTools](/guide/devtools.png)\n\n## 本地运行文档\n\n如需本地运行文档，并进行调整，可以执行以下命令：\n\n```bash\npnpm dev:docs\n```\n\n## 问题解决\n\n如果你在使用过程中遇到依赖相关的问题，可以尝试以下重新安装依赖：\n\n```bash\n# 请在项目根目录下执行\n# 该命令会删除整个仓库所有的 node_modules、yarn.lock、package.lock.json后\n# 再进行依赖重新安装（安装速度会明显变慢）。\npnpm reinstall\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/external-module.md",
    "content": "# 外部模块\n\n除了项目默认引入的外部模块，有时我们还需要引入其他外部模块。我们以 [ant-design-vue](https://antdv.com/components/overview) 为例：\n\n## 安装依赖\n\n::: tip 安装依赖到指定包\n\n- 由于项目采用了 [pnpm](https://pnpm.io/) 作为包管理工具，所以我们需要使用 `pnpm` 命令来安装依赖。\n- 通过采用了 Monorepo 模块来管理项目，所以我们需要在指定包下安装依赖。安装依赖前请确保已经进入到指定包目录下。\n\n:::\n\n```bash\n# cd /path/to/your/package\npnpm add ant-design-vue\n```\n\n## 使用\n\n### 全局引入\n\n```ts\nimport { createApp } from 'vue';\nimport Antd from 'ant-design-vue';\nimport App from './App';\nimport 'ant-design-vue/dist/reset.css';\n\nconst app = createApp(App);\n\napp.use(Antd).mount('#app');\n```\n\n#### 使用\n\n```vue\n<template>\n  <a-button>text</a-button>\n</template>\n```\n\n### 局部引入\n\n```vue\n<script setup lang=\"ts\">\nimport { Button } from 'ant-design-vue';\n</script>\n\n<template>\n  <Button>text</Button>\n</template>\n```\n\n::: warning 注意\n\n- 如果组件有依赖样式，则需要再引入样式文件\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/icons.md",
    "content": "# 图标\n\n::: tip 关于图标的管理\n\n- 项目的图标主要由`@vben/icons`包提供，建议统一在该包内部管理，以便于统一管理和维护。\n- 如果你使用的是 `Vscode`，推荐安装 [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) 插件，可以方便的查找和使用图标。\n\n:::\n\n项目中有以下多种图标使用方式，可以根据实际情况选择使用：\n\n## Iconify 图标 <Badge text=\"推荐\" type=\"tip\"/>\n\n集成了 [iconify](https://github.com/iconify/iconify) 图标库\n\n### 新增\n\n可在 `packages/icons/src/iconify` 目录下新增图标：\n\n```ts\n// packages/icons/src/iconify/index.ts\nimport { createIconifyIcon } from '@vben-core/icons';\n\nexport const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');\n```\n\n### 使用\n\n```vue\n<script setup lang=\"ts\">\nimport { MdiKeyboardEsc } from '@vben/icons';\n</script>\n\n<template>\n  <!-- 一个宽高为20px的图标 -->\n  <MdiKeyboardEsc class=\"size-5\" />\n</template>\n```\n\n## Svg 图标 <Badge text=\"推荐\" type=\"tip\"/>\n\n没有采用 Svg Sprite 的方式，而是直接引入 Svg 图标，\n\n### 新增\n\n可以在 `packages/icons/src/svg/icons` 目录下新增图标文件`test.svg`, 然后在 `packages/icons/src/svg/index.ts` 中引入：\n\n```ts\n// packages/icons/src/svg/index.ts\nimport { createIconifyIcon } from '@vben-core/icons';\n\nconst SvgTestIcon = createIconifyIcon('svg:test');\n\nexport { SvgTestIcon };\n```\n\n### 使用\n\n```vue\n<script setup lang=\"ts\">\nimport { SvgTestIcon } from '@vben/icons';\n</script>\n\n<template>\n  <!-- 一个宽高为20px的图标 -->\n  <SvgTestIcon class=\"size-5\" />\n</template>\n```\n\n## Tailwind CSS 图标\n\n### 使用\n\n直接添加 Tailwind CSS 的图标类名即可使用，图标类名可查看 [iconify](https://github.com/iconify/iconify) ：\n\n```vue\n<span class=\"icon-[mdi--ab-testing]\"></span>\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/route.md",
    "content": "---\noutline: deep\n---\n\n# 路由和菜单\n\n在项目中，框架提供了一套基础的路由系统，并**根据路由文件自动生成对应的菜单结构**。\n\n## 路由类型\n\n路由分为核心路由、静态路由和动态路由，核心路由是框架内置的路由，包含了根路由、登录路由、404路由等；静态路由是在项目启动时就已经确定的路由；动态路由一般是在用户登录后，根据用户的权限动态生成的路由。\n\n静态路由和动态路由都会走权限控制，可以通过配置路由的 `meta` 属性中的 `authority` 字段来控制权限，可以参考[路由权限控制](https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/router/routes/modules/demos.ts)。\n\n### 核心路由\n\n核心路由是框架内置的路由，包含了根路由、登录路由、404路由等，核心路由的配置在应用下 `src/router/routes/core` 目录下\n\n::: tip\n\n核心路由主要用于框架的基础功能，因此不建议将业务相关的路由放在核心路由中，推荐将业务相关的路由放在静态路由或动态路由中。\n\n:::\n\n### 静态路由\n\n静态路由的配置在应用下 `src/router/routes/index` 目录下，打开注释的文件内容:\n\n::: tip\n\n权限控制是通过路由的 `meta` 属性中的 `authority` 字段来控制的，如果你的页面项目不需要权限控制，可以不设置 `authority` 字段。\n\n:::\n\n```ts\n// 有需要可以自行打开注释，并创建文件夹\n// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true }); // [!code --]\nconst staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true }); // [!code ++]\n/** 动态路由 */\nconst dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);\n\n/** 外部路由列表，访问这些页面可以不需要Layout，可能用于内嵌在别的系统 */\n// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles) // [!code --]\nconst externalRoutes: RouteRecordRaw[] = []; // [!code --]\nconst externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles); // [!code ++]\n```\n\n### 动态路由\n\n动态路由的配置在对应应用 `src/router/routes/modules` 目录下，这个目录下存放了所有的路由文件。每个文件的内容格式如下，与 Vue Router 的路由配置格式一致，以下为二级路由和多级路由的配置。\n\n## 路由定义\n\n静态路由与动态路由的配置方式一致，以下为二级路由和多级路由的配置：\n\n### 二级路由\n\n::: details 二级路由示例代码\n\n```ts\nimport type { RouteRecordRaw } from 'vue-router';\n\nimport { VBEN_LOGO_URL } from '@vben/constants';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      badgeType: 'dot',\n      badgeVariants: 'destructive',\n      icon: VBEN_LOGO_URL,\n      order: 9999,\n      title: $t('page.vben.title'),\n    },\n    name: 'VbenProject',\n    path: '/vben-admin',\n    redirect: '/vben-admin/about',\n    children: [\n      {\n        name: 'VbenAbout',\n        path: '/vben-admin/about',\n        component: () => import('#/views/_core/about/index.vue'),\n        meta: {\n          badgeType: 'dot',\n          badgeVariants: 'destructive',\n          icon: 'lucide:copyright',\n          title: $t('page.vben.about'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n```\n\n:::\n\n### 多级路由\n\n::: tip\n\n- 如果没有特殊情况，父级路由的 `redirect` 属性，不需要指定，默认会指向第一个子路由。\n\n:::\n\n::: details 多级路由示例代码\n\n```ts\nimport type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'ic:baseline-view-in-ar',\n      keepAlive: true,\n      order: 1000,\n      title: $t('demos.title'),\n    },\n    name: 'Demos',\n    path: '/demos',\n    redirect: '/demos/access',\n    children: [\n      // 嵌套菜单\n      {\n        meta: {\n          icon: 'ic:round-menu',\n          title: $t('demos.nested.title'),\n        },\n        name: 'NestedDemos',\n        path: '/demos/nested',\n        redirect: '/demos/nested/menu1',\n        children: [\n          {\n            name: 'Menu1Demo',\n            path: '/demos/nested/menu1',\n            component: () => import('#/views/demos/nested/menu-1.vue'),\n            meta: {\n              icon: 'ic:round-menu',\n              keepAlive: true,\n              title: $t('demos.nested.menu1'),\n            },\n          },\n          {\n            name: 'Menu2Demo',\n            path: '/demos/nested/menu2',\n            meta: {\n              icon: 'ic:round-menu',\n              keepAlive: true,\n              title: $t('demos.nested.menu2'),\n            },\n            redirect: '/demos/nested/menu2/menu2-1',\n            children: [\n              {\n                name: 'Menu21Demo',\n                path: '/demos/nested/menu2/menu2-1',\n                component: () => import('#/views/demos/nested/menu-2-1.vue'),\n                meta: {\n                  icon: 'ic:round-menu',\n                  keepAlive: true,\n                  title: $t('demos.nested.menu2_1'),\n                },\n              },\n            ],\n          },\n          {\n            name: 'Menu3Demo',\n            path: '/demos/nested/menu3',\n            meta: {\n              icon: 'ic:round-menu',\n              title: $t('demos.nested.menu3'),\n            },\n            redirect: '/demos/nested/menu3/menu3-1',\n            children: [\n              {\n                name: 'Menu31Demo',\n                path: 'menu3-1',\n                component: () => import('#/views/demos/nested/menu-3-1.vue'),\n                meta: {\n                  icon: 'ic:round-menu',\n                  keepAlive: true,\n                  title: $t('demos.nested.menu3_1'),\n                },\n              },\n              {\n                name: 'Menu32Demo',\n                path: 'menu3-2',\n                meta: {\n                  icon: 'ic:round-menu',\n                  title: $t('demos.nested.menu3_2'),\n                },\n                redirect: '/demos/nested/menu3/menu3-2/menu3-2-1',\n                children: [\n                  {\n                    name: 'Menu321Demo',\n                    path: '/demos/nested/menu3/menu3-2/menu3-2-1',\n                    component: () =>\n                      import('#/views/demos/nested/menu-3-2-1.vue'),\n                    meta: {\n                      icon: 'ic:round-menu',\n                      keepAlive: true,\n                      title: $t('demos.nested.menu3_2_1'),\n                    },\n                  },\n                ],\n              },\n            ],\n          },\n        ],\n      },\n    ],\n  },\n];\n\nexport default routes;\n```\n\n:::\n\n## 新增页面\n\n新增一个页面，你只需要添加一个路由及对应的页面组件即可。\n\n### 添加路由\n\n在对应的路由文件中添加一个路由对象，如下：\n\n```ts\nimport type { RouteRecordRaw } from 'vue-router';\n\nimport { VBEN_LOGO_URL } from '@vben/constants';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'mdi:home',\n      title: $t('page.home.title'),\n    },\n    name: 'Home',\n    path: '/home',\n    redirect: '/home/index',\n    children: [\n      {\n        name: 'HomeIndex',\n        path: '/home/index',\n        component: () => import('#/views/home/index.vue'),\n        meta: {\n          icon: 'mdi:home',\n          title: $t('page.home.index'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n```\n\n### 添加页面组件\n\n在`#/views/home/`下，新增一个`index.vue`文件，如下：\n\n```vue\n<template>\n  <div>\n    <h1>home page</h1>\n  </div>\n</template>\n```\n\n### 验证\n\n到这里页面已添加完成，访问 `http://localhost:5555/home/index` 出现对应的页面即可。\n\n## 路由配置\n\n路由配置项主要在对象路由的 `meta` 属性中，以下为常用的配置项：\n\n```ts {5-8}\nconst routes = [\n  {\n    name: 'HomeIndex',\n    path: '/home/index',\n    meta: {\n      icon: 'mdi:home',\n      title: $t('page.home.index'),\n    },\n  },\n];\n```\n\n::: details 路由Meta配置类型定义\n\n```ts\ninterface RouteMeta {\n  /**\n   * 激活图标（菜单）\n   */\n  activeIcon?: string;\n  /**\n   * 当前激活的菜单，有时候不想激活现有菜单，需要激活父级菜单时使用\n   */\n  activePath?: string;\n  /**\n   * 是否固定标签页\n   * @default false\n   */\n  affixTab?: boolean;\n  /**\n   * 固定标签页的顺序\n   * @default 0\n   */\n  affixTabOrder?: number;\n  /**\n   * 需要特定的角色标识才可以访问\n   * @default []\n   */\n  authority?: string[];\n  /**\n   * 徽标\n   */\n  badge?: string;\n  /**\n   * 徽标类型\n   */\n  badgeType?: 'dot' | 'normal';\n  /**\n   * 徽标颜色\n   */\n  badgeVariants?:\n    | 'default'\n    | 'destructive'\n    | 'primary'\n    | 'success'\n    | 'warning'\n    | string;\n  /**\n   * 路由的完整路径作为key（默认true）\n   */\n  fullPathKey?: boolean;\n  /**\n   * 当前路由的子级在菜单中不展现\n   * @default false\n   */\n  hideChildrenInMenu?: boolean;\n  /**\n   * 当前路由在面包屑中不展现\n   * @default false\n   */\n  hideInBreadcrumb?: boolean;\n  /**\n   * 当前路由在菜单中不展现\n   * @default false\n   */\n  hideInMenu?: boolean;\n  /**\n   * 当前路由在标签页不展现\n   * @default false\n   */\n  hideInTab?: boolean;\n  /**\n   * 图标（菜单/tab）\n   */\n  icon?: string;\n  /**\n   * iframe 地址\n   */\n  iframeSrc?: string;\n  /**\n   * 忽略权限，直接可以访问\n   * @default false\n   */\n  ignoreAccess?: boolean;\n  /**\n   * 开启KeepAlive缓存\n   */\n  keepAlive?: boolean;\n  /**\n   * 外链-跳转路径\n   */\n  link?: string;\n  /**\n   * 路由是否已经加载过\n   */\n  loaded?: boolean;\n  /**\n   * 标签页最大打开数量\n   * @default false\n   */\n  maxNumOfOpenTab?: number;\n  /**\n   * 菜单可以看到，但是访问会被重定向到403\n   */\n  menuVisibleWithForbidden?: boolean;\n  /**\n   * 当前路由不使用基础布局（仅在顶级生效）\n   */\n  noBasicLayout?: boolean;\n  /**\n   * 在新窗口打开\n   */\n  openInNewWindow?: boolean;\n  /**\n   * 用于路由->菜单排序\n   */\n  order?: number;\n  /**\n   * 菜单所携带的参数\n   */\n  query?: Recordable;\n  /**\n   * 标题名称\n   */\n  title: string;\n}\n```\n\n:::\n\n### title\n\n- 类型：`string`\n- 默认值：`''`\n\n用于配置页面的标题，会在菜单和标签页中显示。一般会配合国际化使用。\n\n### icon\n\n- 类型：`string`\n- 默认值：`''`\n\n用于配置页面的图标，会在菜单和标签页中显示。一般会配合图标库使用，如果是`http`链接，会自动加载图片。\n\n### activeIcon\n\n- 类型：`string`\n- 默认值：`''`\n\n用于配置页面的激活图标，会在菜单中显示。一般会配合图标库使用，如果是`http`链接，会自动加载图片。\n\n### keepAlive\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置页面是否开启缓存，开启后页面会缓存，不会重新加载，仅在标签页启用时有效。\n\n### hideInMenu\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置页面是否在菜单中隐藏，隐藏后页面不会在菜单中显示。\n\n### hideInTab\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置页面是否在标签页中隐藏，隐藏后页面不会在标签页中显示。\n\n### hideInBreadcrumb\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置页面是否在面包屑中隐藏，隐藏后页面不会在面包屑中显示。\n\n### hideChildrenInMenu\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置页面的子页面是否在菜单中隐藏，隐藏后子页面不会在菜单中显示。\n\n### authority\n\n- 类型：`string[]`\n- 默认值：`[]`\n\n用于配置页面的权限，只有拥有对应权限的用户才能访问页面，不配置则不需要权限。\n\n### badge\n\n- 类型：`string`\n- 默认值：`''`\n\n用于配置页面的徽标，会在菜单显示。\n\n### badgeType\n\n- 类型：`'dot' | 'normal'`\n- 默认值：`'normal'`\n\n用于配置页面的徽标类型，`dot` 为小红点，`normal` 为文本。\n\n### badgeVariants\n\n- 类型：`'default' | 'destructive' | 'primary' | 'success' | 'warning' | string`\n- 默认值：`'success'`\n\n用于配置页面的徽标颜色。\n\n### fullPathKey\n\n- 类型：`boolean`\n- 默认值：`true`\n\n是否将路由的完整路径作为tab key（默认true）\n\n### activePath\n\n- 类型：`string`\n- 默认值：`''`\n\n用于配置当前激活的菜单，有时候页面没有显示在菜单内，需要激活父级菜单时使用。\n\n### affixTab\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置页面是否固定标签页，固定后页面不可关闭。\n\n### affixTabOrder\n\n- 类型：`number`\n- 默认值：`0`\n\n用于配置页面固定标签页的排序, 采用升序排序。\n\n### iframeSrc\n\n- 类型：`string`\n- 默认值：`''`\n\n用于配置内嵌页面的 `iframe` 地址，设置后会在当前页面内嵌对应的页面。\n\n### ignoreAccess\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置页面是否忽略权限，直接可以访问。\n\n### link\n\n- 类型：`string`\n- 默认值：`''`\n\n用于配置外链跳转路径，会在新窗口打开。\n\n### maxNumOfOpenTab\n\n- 类型：`number`\n- 默认值：`-1`\n\n用于配置标签页最大打开数量，设置后会在打开新标签页时自动关闭最早打开的标签页(仅在打开同名标签页时生效)。\n\n### menuVisibleWithForbidden\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置页面在菜单可以看到，但是访问会被重定向到403。\n\n### openInNewWindow\n\n- 类型：`boolean`\n- 默认值：`false`\n\n设置为 `true` 时，会在新窗口打开页面。\n\n### order\n\n- 类型：`number`\n- 默认值：`0`\n\n用于配置页面的排序，用于路由到菜单排序。\n\n_注意:_ 排序仅针对一级菜单有效，二级菜单的排序需要在对应的一级菜单中按代码顺序设置。\n\n### query\n\n- 类型：`Recordable`\n- 默认值：`{}`\n\n用于配置页面的菜单参数，会在菜单中传递给页面。\n\n### noBasicLayout\n\n- 类型：`boolean`\n- 默认值：`false`\n\n用于配置当前路由不使用基础布局，仅在顶级时生效。默认情况下，所有的路由都会被包裹在基础布局中（包含顶部以及侧边等导航部件），如果你的页面不需要这些部件，可以设置 `noBasicLayout` 为 `true`。\n\n## 路由刷新\n\n路由刷新方式如下：\n\n```vue\n<script setup lang=\"ts\">\nimport { useRefresh } from '@vben/hooks';\n\nconst { refresh } = useRefresh();\n\n// 刷新当前路由\nrefresh();\n</script>\n```\n\n## 标签页与路由控制\n\n在某些场景下，需要单个路由打开多个标签页，或者修改路由的query不打开新的标签页\n\n每个标签页Tab使用唯一的key标识，设置Tab key有三种方式，优先级由高到低：\n\n- 使用路由query参数pageKey\n\n```vue\n<script setup lang=\"ts\">\nimport { useRouter } from 'vue-router';\n// 跳转路由\nconst router = useRouter();\nrouter.push({\n  path: 'path',\n  query: {\n    pageKey: 'key',\n  },\n});\n```\n\n- 路由的完整路径作为key\n\n`meta` 属性中的 `fullPathKey`不为false，则使用路由`fullPath`作为key\n\n- 路由的path作为key\n\n`meta` 属性中的 `fullPathKey`为false，则使用路由`path`作为key\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/server.md",
    "content": "# 服务端交互与数据Mock\n\n::: tip 说明\n\n本文档介绍如何在开发环境下使用 Mock 数据和与服务端进行交互，涉及到的技术有：\n\n- [Nitro](https://nitro.unjs.io/) 轻量级后端服务器，可部署在任何地方，项目用作于 Mock 服务器。\n- [axios](https://axios-http.com/docs/intro) 用于发送 HTTP 请求与服务端进行交互。\n\n:::\n\n## 开发环境交互\n\n如果前端应用和后端接口服务器没有运行在同一个主机上，你需要在开发环境下将接口请求代理到接口服务器。如果是同一个主机，可以直接请求具体的接口地址。\n\n### 本地开发跨域配置\n\n::: tip 提示\n\n本地开发跨域配置项目已经配置好了，如有其他需求，可以自行增加或者调整配置。\n\n:::\n\n#### 配置本地开发接口地址\n\n在项目根目录下的 `.env.development` 文件中配置接口地址，这里配置为 `/api`：\n\n```bash\nVITE_GLOB_API_URL=/api\n```\n\n#### 配置开发服务器代理\n\n开发环境时候，如果需要处理跨域，接口地址在对应的应用目录下的 `vite.config.mts` 文件中配置：\n\n```ts{8-16}\n// apps/web-antd/vite.config.mts\nimport { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    vite: {\n      server: {\n        proxy: {// [!code focus:11]\n          '/api': {\n            changeOrigin: true,\n            rewrite: (path) => path.replace(/^\\/api/, ''),\n            // mock代理目标地址\n            target: 'http://localhost:5320/api',\n            ws: true,\n          },\n        },\n      },\n    },\n  };\n});\n```\n\n#### 接口请求\n\n根据上面的配置，我们可以在前端项目中使用 `/api` 作为接口请求的前缀，例如：\n\n```ts\nimport axios from 'axios';\n\naxios.get('/api/user').then((res) => {\n  console.log(res);\n});\n```\n\n此时，请求会被代理到 `http://localhost:5320/api/user`。\n\n::: warning 注意\n\n从浏览器控制台的 Network 看，请求是 `http://localhost:5555/api/user`, 这是因为 proxy 配置不会改变本地请求的 url。\n\n:::\n\n### 没有跨域时的配置\n\n如果没有跨域问题，可以直接忽略 [配置开发服务器代理](./server.md#配置开发服务器代理) 配置，直接将接口地址设置在 `VITE_GLOB_API_URL`\n\n在项目根目录下的 `.env.development` 文件中配置接口地址：\n\n```bash\nVITE_GLOB_API_URL=https://mock-napi.vben.pro/api\n```\n\n## 生产环境交互\n\n### 接口地址配置\n\n在项目根目录下的 `.env.production` 文件中配置接口地址：\n\n```bash\nVITE_GLOB_API_URL=https://mock-napi.vben.pro/api\n```\n\n::: tip 打包如何动态修改接口地址\n\n`.env` 文件内的 `VITE_GLOB_*` 开头的变量会在打包的时候注入 `_app.config.js` 文件内。在 `dist/_app.config.js` 修改相应的接口地址后刷新页面即可，不需要在根据不同环境打包多次，一次打包可以用于多个不同接口环境的部署。\n\n:::\n\n### 跨域处理\n\n生产环境如果出现跨域问题，可以使用 `nginx` 代理接口地址 或者后台开启 `cors` 进行处理即可（可参考mock服务）。\n\n## 接口请求配置\n\n项目中默认自带了基于 `axios` 封装的基础的请求配置，核心由 `@vben/request` 包提供。项目没有过多的封装，只是简单的封装了一些常用的配置，如有其他需求，可以自行增加或者调整配置。针对不同的app，可能是用到了不同的组件库以及`store`,所以在应用目录下的`src/api/request.ts`文件夹下，有对应的请求配置文件,如`web-antd`项目下的`src/api/request.ts`文件,可以根据自己的需求进行配置。\n\n### 扩展的配置\n\n除了基础的Axios配置外，扩展了部分配置。\n\n```ts\ntype ExtendOptions<T = any> = {\n  /**\n   * 参数序列化方式。预置了几种针对数组的序列化类型\n   * - brackets: ids[]=1&ids[]=2&ids[]=3\n   * - comma: ids=1,2,3\n   * - indices: ids[0]=1&ids[1]=2&ids[2]=3\n   * - repeat: ids=1&ids=2&ids=3\n   * @default 'brackets'\n   */\n  paramsSerializer?:\n    | 'brackets'\n    | 'comma'\n    | 'indices'\n    | 'repeat'\n    | AxiosRequestConfig<T>['paramsSerializer'];\n  /**\n   * 响应数据的返回方式。\n   * - raw: 原始的AxiosResponse，包括headers、status等，不做是否成功请求的检查。\n   * - body: 返回响应数据的BODY部分（只会根据status检查请求是否成功，忽略对code的判断，这种情况下应由调用方检查请求是否成功）。\n   * - data: 解构响应的BODY数据，只返回其中的data节点数据（会检查status和code是否为成功状态）。\n   */\n  responseReturn?: 'body' | 'data' | 'raw';\n};\n```\n\n### 请求示例\n\n#### GET 请求\n\n```ts\nimport { requestClient } from '#/api/request';\n\nexport async function getUserInfoApi() {\n  return requestClient.get<UserInfo>('/user/info');\n}\n```\n\n#### POST/PUT 请求\n\n```ts\nimport { requestClient } from '#/api/request';\n\nexport async function saveUserApi(user: UserInfo) {\n  return requestClient.post<UserInfo>('/user', user);\n}\n\nexport async function saveUserApi(user: UserInfo) {\n  return requestClient.put<UserInfo>('/user', user);\n}\n\nexport async function saveUserApi(user: UserInfo) {\n  const url = user.id ? `/user/${user.id}` : '/user/';\n  return requestClient.request<UserInfo>(url, {\n    data: user,\n    // 或者 PUT\n    method: user.id ? 'PUT' : 'POST',\n  });\n}\n```\n\n#### DELETE 请求\n\n```ts\nimport { requestClient } from '#/api/request';\n\nexport async function deleteUserApi(userId: number) {\n  return requestClient.delete<boolean>(`/user/${userId}`);\n}\n```\n\n### 请求配置\n\n应用内的`src/api/request.ts`可以根据自己应用的情况的需求进行配置：\n\n```ts\n/**\n * 该文件可自行根据业务逻辑进行调整\n */\nimport type { HttpResponse } from '@vben/request';\n\nimport { useAppConfig } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\nimport {\n  authenticateResponseInterceptor,\n  errorMessageResponseInterceptor,\n  RequestClient,\n} from '@vben/request';\nimport { useAccessStore } from '@vben/stores';\n\nimport { message } from 'ant-design-vue';\n\nimport { useAuthStore } from '#/store';\n\nimport { refreshTokenApi } from './core';\n\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n\nfunction createRequestClient(baseURL: string) {\n  const client = new RequestClient({\n    baseURL,\n  });\n\n  /**\n   * 重新认证逻辑\n   */\n  async function doReAuthenticate() {\n    console.warn('Access token or refresh token is invalid or expired. ');\n    const accessStore = useAccessStore();\n    const authStore = useAuthStore();\n    accessStore.setAccessToken(null);\n    if (\n      preferences.app.loginExpiredMode === 'modal' &&\n      accessStore.isAccessChecked\n    ) {\n      accessStore.setLoginExpired(true);\n    } else {\n      await authStore.logout();\n    }\n  }\n\n  /**\n   * 刷新token逻辑\n   */\n  async function doRefreshToken() {\n    const accessStore = useAccessStore();\n    const resp = await refreshTokenApi();\n    const newToken = resp.data;\n    accessStore.setAccessToken(newToken);\n    return newToken;\n  }\n\n  function formatToken(token: null | string) {\n    return token ? `Bearer ${token}` : null;\n  }\n\n  // 请求头处理\n  client.addRequestInterceptor({\n    fulfilled: async (config) => {\n      const accessStore = useAccessStore();\n\n      config.headers.Authorization = formatToken(accessStore.accessToken);\n      config.headers['Accept-Language'] = preferences.app.locale;\n      return config;\n    },\n  });\n\n  // 处理返回的响应数据格式。会根据responseReturn指定的类型返回对应的数据\n  client.addResponseInterceptor(\n    defaultResponseInterceptor({\n      // 指定接口返回的数据中的 code 字段名\n      codeField: 'code',\n      // 指定接口返回的数据中装载了主要数据的字段名\n      dataField: 'data',\n      // 请求成功的 code 值，如果接口返回的 code 等于 successCode 则会认为是成功的请求\n      successCode: 0,\n    }),\n  );\n\n  // token过期的处理\n  client.addResponseInterceptor(\n    authenticateResponseInterceptor({\n      client,\n      doReAuthenticate,\n      doRefreshToken,\n      enableRefreshToken: preferences.app.enableRefreshToken,\n      formatToken,\n    }),\n  );\n\n  // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里\n  client.addResponseInterceptor(\n    errorMessageResponseInterceptor((msg: string, error) => {\n      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg\n      // 当前mock接口返回的错误字段是 error 或者 message\n      const responseData = error?.response?.data ?? {};\n      const errorMessage = responseData?.error ?? responseData?.message ?? '';\n      // 如果没有错误信息，则会根据状态码进行提示\n      message.error(errorMessage || msg);\n    }),\n  );\n\n  return client;\n}\n\nexport const requestClient = createRequestClient(apiURL);\n\nexport const baseRequestClient = new RequestClient({ baseURL: apiURL });\n```\n\n### 多个接口地址\n\n只需要创建多个 `requestClient` 即可，如：\n\n```ts\nconst { apiURL, otherApiURL } = useAppConfig(\n  import.meta.env,\n  import.meta.env.PROD,\n);\n\nexport const requestClient = createRequestClient(apiURL);\n\nexport const otherRequestClient = createRequestClient(otherApiURL);\n```\n\n## 刷新Token\n\n项目中默认提供了刷新 Token 的逻辑，只需要按照下面的配置即可开启：\n\n- 确保当前启用了刷新 Token 的配置\n\n调整对应应用目录下的`preferences.ts`，确保`enableRefreshToken='true'`。\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    enableRefreshToken: true,\n  },\n});\n```\n\n在 `src/api/request.ts` 中配置 `doRefreshToken` 方法即可:\n\n```ts\n// 这里调整为你的token格式\nfunction formatToken(token: null | string) {\n  return token ? `Bearer ${token}` : null;\n}\n\n/**\n * 刷新token逻辑\n */\nasync function doRefreshToken() {\n  const accessStore = useAccessStore();\n  // 这里调整为你的刷新token接口\n  const resp = await refreshTokenApi();\n  const newToken = resp.data;\n  accessStore.setAccessToken(newToken);\n  return newToken;\n}\n```\n\n## 数据 Mock\n\n::: tip 生产环境 Mock\n\n新版本不再支持生产环境 mock，请使用真实接口。\n\n:::\n\nMock 数据是前端开发过程中必不可少的一环，是分离前后端开发的关键链路。通过预先跟服务器端约定好的接口，模拟请求数据甚至逻辑，能够让前端开发独立自主，不会被服务端的开发进程所阻塞。\n\n项目使用 [Nitro](https://nitro.unjs.io/) 来进行本地 mock 数据处理。其原理是本地额外启动一个后端服务，是一个真实的后端服务，可以处理请求，返回数据。\n\n### Nitro 使用\n\nMock 服务代码位于`apps/backend-mock`目录下，无需手动启动，已经集成在项目中，只需要在项目根目录下运行`pnpm dev`即可，运行成功之后，控制台会打印 `http://localhost:5320/api`, 访问该地址即可查看 mock 服务。\n\n[Nitro](https://nitro.unjs.io/) 语法简单，可以根据自己的需求进行配置及开发，具体配置可以查看 [Nitro 文档](https://nitro.unjs.io/)。\n\n## 关闭 Mock 服务\n\nmock的本质是一个真实的后端服务，如果不需要 mock 服务，可以在项目根目录下的 `.env.development` 文件中配置 `VITE_NITRO_MOCK=false` 即可关闭 mock 服务。\n\n```bash\n# .env.development\nVITE_NITRO_MOCK=false\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/settings.md",
    "content": "# 配置\n\n## 环境变量配置\n\n项目的环境变量配置位于应用目录下的 `.env`、`.env.development`、`.env.production`。\n\n规则与 [Vite Env Variables and Modes](https://vitejs.dev/guide/env-and-mode.html) 一致。格式如下：\n\n```bash\n.env                # 在所有的环境中被载入\n.env.local          # 在所有的环境中被载入，但会被 git 忽略\n.env.[mode]         # 只在指定的模式中被载入\n.env.[mode].local   # 只在指定的模式中被载入，但会被 git 忽略\n```\n\n::: tip\n\n- 只有以 `VITE_` 开头的变量会被嵌入到客户端侧的包中，你可以在项目代码中这样访问它们：\n\n  ```ts\n  console.log(import.meta.env.VITE_PROT);\n  ```\n\n- 以 `VITE_GLOB_*` 开头的的变量，在打包的时候，会被加入 `_app.config.js`配置文件当中.\n\n:::\n\n## 环境配置说明\n\n::: code-group\n\n```bash [.env]\n# 应用标题\nVITE_APP_TITLE=Vben Admin\n\n# 应用命名空间，用于缓存、store等功能的前缀，确保隔离\nVITE_APP_NAMESPACE=vben-web-antd\n```\n\n```bash [.env.development]\n# 端口号\nVITE_PORT=5555\n\n# 资源公共路径,需要以 / 开头和结尾\nVITE_BASE=/\n\n# 接口地址\nVITE_GLOB_API_URL=/api\n\n# 是否开启 Nitro Mock服务，true 为开启，false 为关闭\nVITE_NITRO_MOCK=true\n\n# 是否打开 devtools，true 为打开，false 为关闭\nVITE_DEVTOOLS=true\n\n# 是否注入全局loading\nVITE_INJECT_APP_LOADING=true\n\n```\n\n```bash [.env.production]\n# 资源公共路径,需要以 / 开头和结尾\nVITE_BASE=/\n\n# 接口地址\nVITE_GLOB_API_URL=https://mock-napi.vben.pro/api\n\n# 是否开启压缩，可以设置为 none, brotli, gzip\nVITE_COMPRESS=gzip\n\n# 是否开启 PWA\nVITE_PWA=false\n\n# vue-router 的模式\nVITE_ROUTER_HISTORY=hash\n\n# 是否注入全局loading\nVITE_INJECT_APP_LOADING=true\n\n# 打包后是否生成dist.zip\nVITE_ARCHIVER=true\n\n```\n\n:::\n\n## 生产环境动态配置\n\n当在大仓根目录下，执行 `pnpm build`构建项目之后，会自动在对应的应用下生成 `dist/_app.config.js`文件并插入 `index.html`。\n\n`_app.config.js` 是一个动态配置文件，可以在项目构建之后，根据不同的环境动态修改配置。内容如下：\n\n```ts\nwindow._VBEN_ADMIN_PRO_APP_CONF_ = {\n  VITE_GLOB_API_URL: 'https://mock-napi.vben.pro/api',\n};\nObject.freeze(window._VBEN_ADMIN_PRO_APP_CONF_);\nObject.defineProperty(window, '_VBEN_ADMIN_PRO_APP_CONF_', {\n  configurable: false,\n  writable: false,\n});\n```\n\n### 作用\n\n`_app.config.js` 用于项目在打包后，需要动态修改配置的需求，如接口地址。不用重新进行打包，可在打包后修改 /`dist/_app.config.js` 内的变量，刷新即可更新代码内的局部变量。这里使用`js`文件，是为了确保配置文件加载顺序保持在前面。\n\n### 使用\n\n想要获取 `_app.config.js` 内的变量，需要使用`@vben/hooks`提供的 `useAppConfig`方法。\n\n```ts\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n```\n\n### 新增\n\n新增一个可动态修改的配置项，只需要按照如下步骤即可：\n\n- 首先在 `.env` 或者对应的开发环境配置文件内，新增需要可动态配置的变量，需要以 `VITE_GLOB_*` 开头的变量，如：\n\n  ```bash\n  VITE_GLOB_OTHER_API_URL=https://mock-napi.vben.pro/other-api\n  ```\n\n- 在 `packages/types/global.d.ts`,新增对应的类型定义，如：\n\n  ```ts\n  export interface VbenAdminProAppConfigRaw {\n    VITE_GLOB_API_URL: string;\n    VITE_GLOB_OTHER_API_URL: string; // [!code ++]\n  }\n\n  export interface ApplicationConfig {\n    apiURL: string;\n    otherApiURL: string; // [!code ++]\n  }\n  ```\n\n- 在 `packages/effects/hooks/src/use-app-config.ts` 中，新增对应的配置项，如：\n\n  ```ts\n  export function useAppConfig(\n    env: Record<string, any>,\n    isProduction: boolean,\n  ): ApplicationConfig {\n    // 生产环境下，直接使用 window._VBEN_ADMIN_PRO_APP_CONF_ 全局变量\n    const config = isProduction\n      ? window._VBEN_ADMIN_PRO_APP_CONF_\n      : (env as VbenAdminProAppConfigRaw);\n\n    const { VITE_GLOB_API_URL, VITE_GLOB_OTHER_API_URL } = config; // [!code ++]\n\n    return {\n      apiURL: VITE_GLOB_API_URL,\n      otherApiURL: VITE_GLOB_OTHER_API_URL, // [!code ++]\n    };\n  }\n  ```\n\n到这里，就可以在项目内使用 `useAppConfig`方法获取到新增的配置项了。\n\n```ts\nconst { otherApiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n```\n\n::: warning 注意\n\n`useAppConfig`方法只能在应用内使用，不要耦合到包内部去使用。这里传入 `import.meta.env`和`import.meta.env.PROD`是为了避免这种情况，一个纯粹的包，应避免使用特定构建工具的变量。\n\n:::\n\n## 偏好设置\n\n项目提供了非常丰富的偏好设置，用于动态配置项目的各种功能：\n\n![](/guide/preferences.png)\n\n如果你找不到文档说明，可以尝试自己配置好以后，点击`复制偏好设置`，覆盖项目默认即可。配置文件位于应用目录下的`preferences.ts`，在这里，你可以覆盖框架默认的配置，实现自定义配置。\n\n```ts\nimport { useAppConfig } from '@vben/hooks';\nimport { defineOverridesPreferences } from '@vben/preferences';\n\n/**\n * @description 项目配置文件\n * 只需要覆盖项目中的一部分配置，不需要的配置不用覆盖，会自动使用默认配置\n * !!! 更改配置后请清空缓存，否则可能不生效\n */\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n});\n```\n\n### 框架默认配置\n\n::: details 查看框架默认配置\n\n```ts\nconst defaultPreferences: Preferences = {\n  app: {\n    accessMode: 'frontend',\n    authPageLayout: 'panel-right',\n    checkUpdatesInterval: 1,\n    colorGrayMode: false,\n    colorWeakMode: false,\n    compact: false,\n    contentCompact: 'wide',\n    contentCompactWidth: 1200,\n    contentPadding: 0,\n    contentPaddingBottom: 0,\n    contentPaddingLeft: 0,\n    contentPaddingRight: 0,\n    contentPaddingTop: 0,\n    defaultAvatar:\n      'https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp',\n    defaultHomePath: '/analytics',\n    dynamicTitle: true,\n    enableCheckUpdates: true,\n    enablePreferences: true,\n    enableRefreshToken: false,\n    isMobile: false,\n    layout: 'sidebar-nav',\n    locale: 'zh-CN',\n    loginExpiredMode: 'page',\n    name: 'Vben Admin',\n    preferencesButtonPosition: 'auto',\n    watermark: false,\n    zIndex: 200,\n  },\n  breadcrumb: {\n    enable: true,\n    hideOnlyOne: false,\n    showHome: false,\n    showIcon: true,\n    styleType: 'normal',\n  },\n  copyright: {\n    companyName: 'Vben',\n    companySiteLink: 'https://www.vben.pro',\n    date: '2024',\n    enable: true,\n    icp: '',\n    icpLink: '',\n    settingShow: true,\n  },\n  footer: {\n    enable: false,\n    fixed: false,\n    height: 32,\n  },\n  header: {\n    enable: true,\n    height: 50,\n    hidden: false,\n    menuAlign: 'start',\n    mode: 'fixed',\n  },\n  logo: {\n    enable: true,\n    fit: 'contain',\n    source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n  },\n  navigation: {\n    accordion: true,\n    split: true,\n    styleType: 'rounded',\n  },\n  shortcutKeys: {\n    enable: true,\n    globalLockScreen: true,\n    globalLogout: true,\n    globalPreferences: true,\n    globalSearch: true,\n  },\n  sidebar: {\n    autoActivateChild: false,\n    collapsed: false,\n    collapsedButton: true,\n    collapsedShowTitle: false,\n    collapseWidth: 60,\n    enable: true,\n    expandOnHover: true,\n    extraCollapse: false,\n    extraCollapsedWidth: 60,\n    fixedButton: true,\n    hidden: false,\n    mixedWidth: 80,\n    width: 224,\n  },\n  tabbar: {\n    draggable: true,\n    enable: true,\n    height: 38,\n    keepAlive: true,\n    maxCount: 0,\n    middleClickToClose: false,\n    persist: true,\n    showIcon: true,\n    showMaximize: true,\n    showMore: true,\n    styleType: 'chrome',\n    wheelable: true,\n  },\n  theme: {\n    builtinType: 'default',\n    colorDestructive: 'hsl(348 100% 61%)',\n    colorPrimary: 'hsl(212 100% 45%)',\n    colorSuccess: 'hsl(144 57% 58%)',\n    colorWarning: 'hsl(42 84% 61%)',\n    mode: 'dark',\n    radius: '0.5',\n    semiDarkHeader: false,\n    semiDarkSidebar: false,\n  },\n  transition: {\n    enable: true,\n    loading: true,\n    name: 'fade-slide',\n    progress: true,\n  },\n  widget: {\n    fullscreen: true,\n    globalSearch: true,\n    languageToggle: true,\n    lockScreen: true,\n    notification: true,\n    refresh: true,\n    sidebarToggle: true,\n    themeToggle: true,\n  },\n};\n```\n\n:::\n\n::: details 查看框架默认配置类型\n\n```ts\ninterface AppPreferences {\n  /** 权限模式 */\n  accessMode: AccessModeType;\n  /** 登录注册页面布局 */\n  authPageLayout: AuthPageLayoutType;\n  /** 检查更新轮询时间 */\n  checkUpdatesInterval: number;\n  /** 是否开启灰色模式 */\n  colorGrayMode: boolean;\n  /** 是否开启色弱模式 */\n  colorWeakMode: boolean;\n  /** 是否开启紧凑模式 */\n  compact: boolean;\n  /** 是否开启内容紧凑模式 */\n  contentCompact: ContentCompactType;\n  /** 内容紧凑宽度 */\n  contentCompactWidth: number;\n  /** 内容内边距 */\n  contentPadding: number;\n  /** 内容底部内边距 */\n  contentPaddingBottom: number;\n  /** 内容左侧内边距 */\n  contentPaddingLeft: number;\n  /** 内容右侧内边距 */\n  contentPaddingRight: number;\n  /** 内容顶部内边距 */\n  contentPaddingTop: number;\n  // /** 应用默认头像 */\n  defaultAvatar: string;\n  /** 默认首页地址 */\n  defaultHomePath: string;\n  // /** 开启动态标题 */\n  dynamicTitle: boolean;\n  /** 是否开启检查更新 */\n  enableCheckUpdates: boolean;\n  /** 是否显示偏好设置 */\n  enablePreferences: boolean;\n  /**\n   * @zh_CN 是否开启refreshToken\n   */\n  enableRefreshToken: boolean;\n  /** 是否移动端 */\n  isMobile: boolean;\n  /** 布局方式 */\n  layout: LayoutType;\n  /** 支持的语言 */\n  locale: SupportedLanguagesType;\n  /** 登录过期模式 */\n  loginExpiredMode: LoginExpiredModeType;\n  /** 应用名 */\n  name: string;\n  /** 偏好设置按钮位置 */\n  preferencesButtonPosition: PreferencesButtonPositionType;\n  /**\n   * @zh_CN 是否开启水印\n   */\n  watermark: boolean;\n  /** z-index */\n  zIndex: number;\n}\n\ninterface BreadcrumbPreferences {\n  /** 面包屑是否启用 */\n  enable: boolean;\n  /** 面包屑是否只有一个时隐藏 */\n  hideOnlyOne: boolean;\n  /** 面包屑首页图标是否可见 */\n  showHome: boolean;\n  /** 面包屑图标是否可见 */\n  showIcon: boolean;\n  /** 面包屑风格 */\n  styleType: BreadcrumbStyleType;\n}\n\ninterface CopyrightPreferences {\n  /** 版权公司名 */\n  companyName: string;\n  /** 版权公司名链接 */\n  companySiteLink: string;\n  /** 版权日期 */\n  date: string;\n  /** 版权是否可见 */\n  enable: boolean;\n  /** 备案号 */\n  icp: string;\n  /** 备案号链接 */\n  icpLink: string;\n  /** 设置面板是否显示*/\n  settingShow?: boolean;\n}\n\ninterface FooterPreferences {\n  /** 底栏是否可见 */\n  enable: boolean;\n  /** 底栏是否固定 */\n  fixed: boolean;\n  /** 底栏高度 */\n  height: number;\n}\n\ninterface HeaderPreferences {\n  /** 顶栏是否启用 */\n  enable: boolean;\n  /** 顶栏高度 */\n  height: number;\n  /** 顶栏是否隐藏,css-隐藏 */\n  hidden: boolean;\n  /** 顶栏菜单位置 */\n  menuAlign: LayoutHeaderMenuAlignType;\n  /** header显示模式 */\n  mode: LayoutHeaderModeType;\n}\n\ninterface LogoPreferences {\n  /** logo是否可见 */\n  enable: boolean;\n  /** logo图片适应方式 */\n  fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\n  /** logo地址 */\n  source: string;\n}\n\ninterface NavigationPreferences {\n  /** 导航菜单手风琴模式 */\n  accordion: boolean;\n  /** 导航菜单是否切割，只在 layout=mixed-nav 生效 */\n  split: boolean;\n  /** 导航菜单风格 */\n  styleType: NavigationStyleType;\n}\n\ninterface SidebarPreferences {\n  /** 点击目录时自动激活子菜单   */\n  autoActivateChild: boolean;\n  /** 侧边栏是否折叠 */\n  collapsed: boolean;\n  /** 侧边栏折叠按钮是否可见 */\n  collapsedButton: boolean;\n  /** 侧边栏折叠时，是否显示title */\n  collapsedShowTitle: boolean;\n  /** 侧边栏折叠宽度 */\n  collapseWidth: number;\n  /** 侧边栏是否可见 */\n  enable: boolean;\n  /** 菜单自动展开状态 */\n  expandOnHover: boolean;\n  /** 侧边栏扩展区域是否折叠 */\n  extraCollapse: boolean;\n  /** 侧边栏扩展区域折叠宽度 */\n  extraCollapsedWidth: number;\n  /** 侧边栏固定按钮是否可见 */\n  fixedButton: boolean;\n  /** 侧边栏是否隐藏 - css */\n  hidden: boolean;\n  /** 混合侧边栏宽度 */\n  mixedWidth: number;\n  /** 侧边栏宽度 */\n  width: number;\n}\n\ninterface ShortcutKeyPreferences {\n  /** 是否启用快捷键-全局 */\n  enable: boolean;\n  /** 是否启用全局锁屏快捷键 */\n  globalLockScreen: boolean;\n  /** 是否启用全局注销快捷键 */\n  globalLogout: boolean;\n  /** 是否启用全局偏好设置快捷键 */\n  globalPreferences: boolean;\n  /** 是否启用全局搜索快捷键 */\n  globalSearch: boolean;\n}\n\ninterface TabbarPreferences {\n  /** 是否开启多标签页拖拽 */\n  draggable: boolean;\n  /** 是否开启多标签页 */\n  enable: boolean;\n  /** 标签页高度 */\n  height: number;\n  /** 开启标签页缓存功能 */\n  keepAlive: boolean;\n  /** 限制最大数量 */\n  maxCount: number;\n  /** 是否点击中键时关闭标签 */\n  middleClickToClose: boolean;\n  /** 是否持久化标签 */\n  persist: boolean;\n  /** 是否开启多标签页图标 */\n  showIcon: boolean;\n  /** 显示最大化按钮 */\n  showMaximize: boolean;\n  /** 显示更多按钮 */\n  showMore: boolean;\n  /** 标签页风格 */\n  styleType: TabsStyleType;\n  /** 是否开启鼠标滚轮响应 */\n  wheelable: boolean;\n}\n\ninterface ThemePreferences {\n  /** 内置主题名 */\n  builtinType: BuiltinThemeType;\n  /** 错误色 */\n  colorDestructive: string;\n  /** 主题色 */\n  colorPrimary: string;\n  /** 成功色 */\n  colorSuccess: string;\n  /** 警告色 */\n  colorWarning: string;\n  /** 当前主题 */\n  mode: ThemeModeType;\n  /** 圆角 */\n  radius: string;\n  /** 是否开启半深色header（只在theme='light'时生效） */\n  semiDarkHeader: boolean;\n  /** 是否开启半深色菜单（只在theme='light'时生效） */\n  semiDarkSidebar: boolean;\n}\n\ninterface TransitionPreferences {\n  /** 页面切换动画是否启用 */\n  enable: boolean;\n  // /** 是否开启页面加载loading */\n  loading: boolean;\n  /** 页面切换动画 */\n  name: PageTransitionType | string;\n  /** 是否开启页面加载进度动画 */\n  progress: boolean;\n}\n\ninterface WidgetPreferences {\n  /** 是否启用全屏部件 */\n  fullscreen: boolean;\n  /** 是否启用全局搜索部件 */\n  globalSearch: boolean;\n  /** 是否启用语言切换部件 */\n  languageToggle: boolean;\n  /** 是否开启锁屏功能 */\n  lockScreen: boolean;\n  /** 是否显示通知部件 */\n  notification: boolean;\n  /** 显示刷新按钮 */\n  refresh: boolean;\n  /** 是否显示侧边栏显示/隐藏部件 */\n  sidebarToggle: boolean;\n  /** 是否显示主题切换部件 */\n  themeToggle: boolean;\n}\n\ninterface Preferences {\n  /** 全局配置 */\n  app: AppPreferences;\n  /** 顶栏配置 */\n  breadcrumb: BreadcrumbPreferences;\n  /** 版权配置 */\n  copyright: CopyrightPreferences;\n  /** 底栏配置 */\n  footer: FooterPreferences;\n  /** 面包屑配置 */\n  header: HeaderPreferences;\n  /** logo配置 */\n  logo: LogoPreferences;\n  /** 导航配置 */\n  navigation: NavigationPreferences;\n  /** 快捷键配置 */\n  shortcutKeys: ShortcutKeyPreferences;\n  /** 侧边栏配置 */\n  sidebar: SidebarPreferences;\n  /** 标签页配置 */\n  tabbar: TabbarPreferences;\n  /** 主题配置 */\n  theme: ThemePreferences;\n  /** 动画配置 */\n  transition: TransitionPreferences;\n  /** 功能配置 */\n  widget: WidgetPreferences;\n}\n```\n\n:::\n\n::: warning 注意\n\n- `overridesPreferences`方法只需要覆盖项目中的一部分配置，不需要的配置不用覆盖，会自动使用默认配置。\n- 任何配置项都可以覆盖，只需要在`overridesPreferences`方法内覆盖即可，不要修改默认配置文件。\n- 更改配置后请清空缓存，否则可能不生效。\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/essentials/styles.md",
    "content": "# 样式\n\n::: tip 前言\n\n对于 vue 项目，[官方文档](https://vuejs.org/api/sfc-css-features.html#deep-selectors) 对语法已经有比较详细的介绍，这里主要是介绍项目中的样式文件结构和使用。\n\n:::\n\n## 项目结构\n\n项目中的样式文件存放在 `@vben/styles`，包含一些全局样式，如重置样式、全局变量等，它继承了 `@vben-core/design` 的样式和能力，可以根据项目需求进行覆盖。\n\n## Scss\n\n项目中使用 `scss` 作为样式预处理器，可以在项目中使用 `scss` 的特性，如变量、函数、混合等。\n\n```vue\n<style lang=\"scss\" scoped>\n$font-size: 30px;\n\n.box {\n  .title {\n    color: green;\n    font-size: $font-size;\n  }\n}\n</style>\n```\n\n## Postcss\n\n如果你不习惯使用 `scss`，也可以使用 `postcss`，它是一个更加强大的样式处理器，可以使用更多的插件，项目内置了 [postcss-nested](https://github.com/postcss/postcss-nested) 插件，配置 `Css Variables`，完全可以取代 `scss`。\n\n```vue\n<style scoped>\n.box {\n  --font-size: 30px;\n  .title {\n    color: green;\n    font-size: var(--font-size);\n  }\n}\n</style>\n```\n\n## Tailwind CSS\n\n项目中集成了 [Tailwind CSS](https://tailwindcss.com/)，可以在项目中使用 `tailwindcss` 的类名，快速构建页面。\n\n```vue\n<template>\n  <div class=\"bg-white p-4\">\n    <p class=\"text-green\">hello world</p>\n  </div>\n</template>\n```\n\n## BEM 规范\n\n样式冲突的另一种选择，是使用 `BEM` 规范。如果选择 `scss` ，建议使用 `BEM` 命名规范，可以更好的管理样式。项目默认提供了`useNamespace`函数，可以方便的生成命名空间。\n\n```vue\n<script lang=\"ts\" setup>\nimport { useNamespace } from '@vben/hooks';\n\nconst { b, e, is } = useNamespace('menu');\n</script>\n<template>\n  <div :class=\"[b()]\">\n    <div :class=\"[e('item'), is('active', true)]\">item1</div>\n  </div>\n</template>\n<style lang=\"scss\" scoped>\n// 如果你在应用内使用，这行代码可以省略，已经在所有的应用内全局引入了\n@use '@vben/styles/global' as *;\n@include b('menu') {\n  color: black;\n\n  @include e('item') {\n    background-color: black;\n\n    @include is('active') {\n      background-color: red;\n    }\n  }\n}\n</style>\n```\n\n## CSS Modules\n\n针对样式冲突问题，还有一种方案是使用 `CSS Modules` 模块化方案。使用方式如下。\n\n```vue\n<template>\n  <p :class=\"$style.red\">This should be red</p>\n</template>\n\n<style module>\n.red {\n  color: red;\n}\n</style>\n```\n\n更多用法可以见 [CSS Modules 官方文档](https://vuejs.org/api/sfc-css-features.html#css-modules)。\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/access.md",
    "content": "---\noutline: deep\n---\n\n# 权限\n\n框架内置了三种权限控制方式：\n\n- 通过用户角色来判断菜单或者按钮是否可以访问\n- 通过接口来判断菜单或者按钮是否可以访问\n- 混合模式：同时使用前端和后端权限控制\n\n## 前端访问控制\n\n**实现原理**: 在前端固定写死路由的权限，指定路由有哪些权限可以查看。只初始化通用的路由，需要权限才能访问的路由没有被加入路由表内。在登录后或者其他方式获取用户角色后，通过角色去遍历路由表，获取该角色可以访问的路由表，生成路由表，再通过 `router.addRoute` 添加到路由实例，实现权限的过滤。\n\n**缺点**: 权限相对不自由，如果后台改动角色，前台也需要跟着改动。适合角色较固定的系统\n\n### 步骤\n\n- 确保当前模式为前端访问控制模式\n\n调整对应应用目录下的`preferences.ts`，确保`accessMode='frontend'`。\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    // 默认值，可不填\n    accessMode: 'frontend',\n  },\n});\n```\n\n- 配置路由权限\n\n**如果不配置，默认可见**\n\n```ts {3}\n {\n    meta: {\n      authority: ['super'],\n    },\n},\n```\n\n- 确保接口返回的角色和路由表的权限匹配\n\n可查看应用下的 `src/store/auth`,找到下面代码，\n\n```ts\n// 设置登录用户信息，需要确保 userInfo.roles 是一个数组，且包含路由表中的权限\n// 例如：userInfo.roles=['super', 'admin']\nauthStore.setUserInfo(userInfo);\n```\n\n到这里，就已经配置完成，你需要确保登录后，接口返回的角色和路由表的权限匹配，否则无法访问。\n\n### 菜单可见，但禁止访问\n\n有时候，我们需要菜单可见，但是禁止访问，可以通过下面的方式实现，设置 `menuVisibleWithForbidden` 为 `true`，此时菜单可见，但是禁止访问，会跳转403页面。\n\n```ts\n{\n    meta: {\n      menuVisibleWithForbidden: true,\n    },\n},\n```\n\n## 后端访问控制\n\n**实现原理**: 是通过接口动态生成路由表，且遵循一定的数据结构返回。前端根据需要处理该数据为可识别的结构，再通过 `router.addRoute` 添加到路由实例，实现权限的动态生成。\n\n**缺点**: 后端需要提供符合规范的数据结构，前端需要处理数据结构，适合权限较为复杂的系统。\n\n### 步骤\n\n- 确保当前模式为后端访问控制模式\n\n调整对应应用目录下的`preferences.ts`，确保`accessMode='backend'`。\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    accessMode: 'backend',\n  },\n});\n```\n\n- 确保接口返回的菜单数据结构正确\n\n可查看应用下的 `src/router/access.ts`,找到下面代码，\n\n```ts {5}\nasync function generateAccess(options: GenerateMenuAndRoutesOptions) {\n  return await generateAccessible(preferences.app.accessMode, {\n    fetchMenuListAsync: async () => {\n      // 这个接口为后端返回的菜单数据\n      return await getAllMenus();\n    },\n  });\n}\n```\n\n- 接口返回菜单数据，可看注释说明\n\n::: details 接口返回菜单数据示例\n\n```ts\nconst dashboardMenus = [\n  {\n    meta: {\n      order: -1,\n      title: 'page.dashboard.title',\n    },\n    name: 'Dashboard',\n    path: '/',\n    redirect: '/analytics',\n    children: [\n      {\n        name: 'Analytics',\n        path: '/analytics',\n        // 这里为页面的路径，需要去掉 views/ 和 .vue\n        component: '/dashboard/analytics/index',\n        meta: {\n          affixTab: true,\n          title: 'page.dashboard.analytics',\n        },\n      },\n      {\n        name: 'Workspace',\n        path: '/workspace',\n        component: '/dashboard/workspace/index',\n        meta: {\n          title: 'page.dashboard.workspace',\n        },\n      },\n    ],\n  },\n  {\n    name: 'Test',\n    path: '/test',\n    component: '/test/index',\n    meta: {\n      title: 'page.test',\n      // 部分特殊页面如果不需要基础布局（页面顶部和侧边栏），可将noBasicLayout设置为true\n      noBasicLayout: true,\n    },\n  },\n];\n```\n\n:::\n\n到这里，就已经配置完成，你需要确保登录后，接口返回的菜单格式正确，否则无法访问。\n\n## 混合访问控制\n\n**实现原理**: 混合模式同时结合了前端访问控制和后端访问控制两种方式。系统会并行处理前端固定路由权限和后端动态菜单数据，最终将两部分路由合并，提供更灵活的权限控制方案。\n\n**优点**: 兼具前端控制的性能优势和后端控制的灵活性，适合复杂业务场景下的权限管理。\n\n### 步骤\n\n- 确保当前模式为混合访问控制模式\n\n调整对应应用目录下的`preferences.ts`，确保`accessMode='mixed'`。\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    accessMode: 'mixed',\n  },\n});\n```\n\n- 配置前端路由权限\n\n同[前端访问控制](#前端访问控制)模式的路由权限配置方式。\n\n- 配置后端菜单接口\n\n同[后端访问控制](#后端访问控制)模式的接口配置方式。\n\n- 确保角色和权限匹配\n\n需要同时满足前端路由权限配置和后端菜单数据返回的要求，确保用户角色与两种模式的权限配置都匹配。\n\n到这里，就已经配置完成，混合模式会自动合并前端和后端的路由，提供完整的权限控制功能。\n\n## 按钮细粒度控制\n\n在某些情况下，我们需要对按钮进行细粒度的控制，我们可以借助接口或者角色来控制按钮的显示。\n\n### 权限码\n\n权限码为接口返回的权限码，通过权限码来判断按钮是否显示，逻辑在`src/store/auth`下：\n\n```ts\nconst [fetchUserInfoResult, accessCodes] = await Promise.all([\n  fetchUserInfo(),\n  getAccessCodes(),\n]);\n\nuserInfo = fetchUserInfoResult;\nauthStore.setUserInfo(userInfo);\naccessStore.setAccessCodes(accessCodes);\n```\n\n找到 `getAccessCodes` 对应的接口，可根据业务逻辑进行调整。\n\n权限码返回的数据结构为字符串数组，例如：`['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`\n\n有了权限码，就可以使用 `@vben/access` 提供的`AccessControl`组件及API来进行按钮的显示与隐藏。\n\n#### 组件方式\n\n```vue\n<script lang=\"ts\" setup>\nimport { AccessControl, useAccess } from '@vben/access';\n\nconst { accessMode, hasAccessByCodes } = useAccess();\n</script>\n\n<template>\n  <!-- 需要指明 type=\"code\" -->\n  <AccessControl :codes=\"['AC_100100']\" type=\"code\">\n    <Button> Super 账号可见 [\"AC_1000001\"] </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['AC_100030']\" type=\"code\">\n    <Button> Admin 账号可见 [\"AC_100010\"] </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['AC_1000001']\" type=\"code\">\n    <Button> User 账号可见 [\"AC_1000001\"] </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['AC_100100', 'AC_100010']\" type=\"code\">\n    <Button> Super & Admin 账号可见 [\"AC_100100\",\"AC_1000001\"] </Button>\n  </AccessControl>\n</template>\n```\n\n#### API方式\n\n```vue\n<script lang=\"ts\" setup>\nimport { AccessControl, useAccess } from '@vben/access';\n\nconst { hasAccessByCodes } = useAccess();\n</script>\n\n<template>\n  <Button v-if=\"hasAccessByCodes(['AC_100100'])\">\n    Super 账号可见 [\"AC_1000001\"]\n  </Button>\n  <Button v-if=\"hasAccessByCodes(['AC_100030'])\">\n    Admin 账号可见 [\"AC_100010\"]\n  </Button>\n  <Button v-if=\"hasAccessByCodes(['AC_1000001'])\">\n    User 账号可见 [\"AC_1000001\"]\n  </Button>\n  <Button v-if=\"hasAccessByCodes(['AC_100100', 'AC_1000001'])\">\n    Super & Admin 账号可见 [\"AC_100100\",\"AC_1000001\"]\n  </Button>\n</template>\n```\n\n#### 指令方式\n\n> 指令支持绑定单个或多个权限码。单个时可以直接传入字符串或数组中包含一个权限码，多个权限码则传入数组。\n\n```vue\n<template>\n  <Button class=\"mr-4\" v-access:code=\"'AC_100100'\">\n    Super 账号可见 'AC_100100'\n  </Button>\n  <Button class=\"mr-4\" v-access:code=\"['AC_100030']\">\n    Admin 账号可见 [\"AC_100010\"]\n  </Button>\n  <Button class=\"mr-4\" v-access:code=\"['AC_1000001']\">\n    User 账号可见 [\"AC_1000001\"]\n  </Button>\n  <Button class=\"mr-4\" v-access:code=\"['AC_100100', 'AC_1000001']\">\n    Super & Admin 账号可见 [\"AC_100100\",\"AC_1000001\"]\n  </Button>\n</template>\n```\n\n### 角色\n\n角色判断方式不需要接口返回的权限码，直接通过角色来判断按钮是否显示。\n\n#### 组件方式\n\n```vue\n<script lang=\"ts\" setup>\nimport { AccessControl } from '@vben/access';\n</script>\n\n<template>\n  <AccessControl :codes=\"['super']\">\n    <Button> Super 角色可见 </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['admin']\">\n    <Button> Admin 角色可见 </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['user']\">\n    <Button> User 角色可见 </Button>\n  </AccessControl>\n  <AccessControl :codes=\"['super', 'admin']\">\n    <Button> Super & Admin 角色可见 </Button>\n  </AccessControl>\n</template>\n```\n\n#### API方式\n\n```vue\n<script lang=\"ts\" setup>\nimport { useAccess } from '@vben/access';\n\nconst { hasAccessByRoles } = useAccess();\n</script>\n\n<template>\n  <Button v-if=\"hasAccessByRoles(['super'])\"> Super 账号可见 </Button>\n  <Button v-if=\"hasAccessByRoles(['admin'])\"> Admin 账号可见 </Button>\n  <Button v-if=\"hasAccessByRoles(['user'])\"> User 账号可见 </Button>\n  <Button v-if=\"hasAccessByRoles(['super', 'admin'])\">\n    Super & Admin 账号可见\n  </Button>\n</template>\n```\n\n#### 指令方式\n\n> 指令支持绑定单个或多个角色。单个时可以直接传入字符串或数组中包含一个角色，多个角色均可访问则传入数组。\n\n```vue\n<template>\n  <Button class=\"mr-4\" v-access:role=\"'super'\"> Super 角色可见 </Button>\n  <Button class=\"mr-4\" v-access:role=\"['super']\"> Super 角色可见 </Button>\n  <Button class=\"mr-4\" v-access:role=\"['admin']\"> Admin 角色可见 </Button>\n  <Button class=\"mr-4\" v-access:role=\"['user']\"> User 角色可见 </Button>\n  <Button class=\"mr-4\" v-access:role=\"['super', 'admin']\">\n    Super & Admin 角色可见\n  </Button>\n</template>\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/check-updates.md",
    "content": "# 检查更新\n\n## 介绍\n\n当网站有更新时，您可能需要检查更新。框架提供了这一功能，通过定时检查更新，您可以在应用的 preferences.ts 文件中配置 `checkUpdatesInterval`和 `enableCheckUpdates` 字段，以开启和设置检查更新的时间间隔（单位：分钟）。\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    // 是否开启检查更新\n    enableCheckUpdates: true,\n    // 检查更新的时间间隔，单位为分钟\n    checkUpdatesInterval: 1,\n  },\n});\n```\n\n## 效果\n\n检测到更新时，会弹出提示框，询问用户是否刷新页面：\n\n![check-updates](/guide/update-notice.png)\n\n## 替换为其他检查更新方式\n\n如果需要通过其他方式检查更新，例如通过接口来更灵活地控制更新逻辑（如强制刷新、显示更新内容等），你可以通过修改 `@vben/layouts` 下面的 `src/widgets/check-updates/check-updates.vue`文件来实现。\n\n```ts\n// 这里可以替换为你的检查更新逻辑\nasync function getVersionTag() {\n  try {\n    const response = await fetch('/', {\n      cache: 'no-cache',\n      method: 'HEAD',\n    });\n\n    return (\n      response.headers.get('etag') || response.headers.get('last-modified')\n    );\n  } catch {\n    console.error('Failed to fetch version tag');\n    return null;\n  }\n}\n```\n\n## 替换为第三方库检查更新方式\n\n如果需要通过其他方式检查更新，例如使用其他版本控制方式（chunkHash、version.json）、使用`Web Worker`在后台轮询更新、自定义检查更新时机（不使用轮询），你可以通过JS库`version-polling`来实现。\n\n```bash\npnpm add version-polling\n```\n\n以`apps/web-antd`项目为例，在项目入口文件`main.ts`或者`app.vue`添加以下代码\n\n```ts\nimport { h } from 'vue';\n\nimport { Button, notification } from 'ant-design-vue';\nimport { createVersionPolling } from 'version-polling';\n\ncreateVersionPolling({\n  silent: import.meta.env.MODE === 'development', // 开发环境下不检测\n  onUpdate: (self) => {\n    const key = `open${Date.now()}`;\n    notification.info({\n      message: '提示',\n      description: '检测到网页有更新, 是否刷新页面加载最新版本？',\n      btn: () =>\n        h(\n          Button,\n          {\n            type: 'primary',\n            size: 'small',\n            onClick: () => {\n              notification.close(key);\n              self.onRefresh();\n            },\n          },\n          { default: () => '刷新' },\n        ),\n      key,\n      duration: null,\n      placement: 'bottomRight',\n    });\n  },\n});\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/features.md",
    "content": "# 常用功能\n\n一些常用的功能合集。\n\n## 登录认证过期\n\n当接口返回`401`状态码时，框架会认为登录认证过期，登录超时会跳转到登录页或者打开登录弹窗。在应用目录下的`preferences.ts`可以配置：\n\n### 跳转登录页面\n\n登录超时会跳转到登录页\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    loginExpiredMode: 'page',\n  },\n});\n```\n\n### 打开登录弹窗\n\n登录超时会打开登录弹窗\n\n![](/guide/login-expired.png)\n\n配置：\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    loginExpiredMode: 'modal',\n  },\n});\n```\n\n## 动态标题\n\n- 默认值：`true`\n\n开启后网页标题随着路由的`title`而变化。在应用目录下的`preferences.ts`，开启或者关闭即可。\n\n```ts\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    dynamicTitle: true,\n  },\n});\n```\n\n## 页面水印\n\n- 默认值：`false`\n\n开启后网页会显示水印，在应用目录下的`preferences.ts`，开启或者关闭即可。\n\n```ts\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    watermark: true,\n  },\n});\n```\n\n如果你想更新水印的内容，可以这么做，参数可以参考 [watermark-js-plus](https://zhensherlock.github.io/watermark-js-plus/)：\n\n```ts\nimport { useWatermark } from '@vben/hooks';\n\nconst { destroyWatermark, updateWatermark } = useWatermark();\n\nawait updateWatermark({\n  // 水印内容\n  content: 'hello my watermark',\n});\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/layout.md",
    "content": "# 布局\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/loading.md",
    "content": "# 全局loading\n\n全局 loading 指的是页面刷新时出现的加载效果，通常是一个旋转的图标：\n\n![Global loading spinner](/guide/loading.png)\n\n## 原理\n\n由 `vite-plugin-inject-app-loading` 插件实现，插件会在每个应用都注入一个全局的 `loading html`。\n\n## 关闭\n\n如果你不需要全局 loading，可以在 `.env` 文件中关闭：\n\n```bash\nVITE_INJECT_APP_LOADING=false\n```\n\n## 自定义\n\n如果你想要自定义全局 loading，可以在应用目录下，与`index.html`同级，创建一个`loading.html`文件，插件会自动读取并注入。这个html可以自行定义样式和动画。\n\n::: tip\n\n- 你可以使用跟`index.html`一样的语法，比如`VITE_APP_TITLE`变量，来获取应用的标题。\n- 必须保证有一个`id=\"__app-loading__\"`的元素。\n- 给`id=\"__app-loading__\"`的元素，加一个 `hidden` class。\n- 必须保证有一个`style[data-app-loading=\"inject-css\"]`的元素。\n\n```html{1,4}\n<style data-app-loading=\"inject-css\">\n  #__app-loading__.hidden {\n    pointer-events: none;\n    visibility: hidden;\n    opacity: 0;\n    transition: all 1s ease-out;\n  }\n  /* ... */\n</style>\n<div id=\"__app-loading__\">\n  <!-- ... -->\n  <div class=\"title\"><%= VITE_APP_TITLE %></div>\n</div>\n```\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/locale.md",
    "content": "# 国际化\n\n项目已经集成了 [Vue i18n](https://kazupon.github.io/vue-i18n/)，并且已经配置好了中文和英文的语言包。\n\n## IDE 插件\n\n如果你使用的 vscode 开发工具，则推荐安装 [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) 这个插件。它可以帮助你更方便的管理国际化的文案，安装了该插件后，你的代码内可以实时看到对应的语言内容：\n\n![](/public/guide/locale.png)\n\n## 配置默认语言\n\n只需要覆盖默认的偏好设置即可，在对应的应用内，找到 `src/preferences.ts` 文件，修改 `locale` 的值即可：\n\n```ts {3}\nexport const overridesPreferences = defineOverridesPreferences({\n  app: {\n    locale: 'en-US',\n  },\n});\n```\n\n## 动态切换语言\n\n切换语言有两部分组成:\n\n- 更新偏好设置\n- 加载对应的语言包\n\n```ts\nimport type { SupportedLanguagesType } from '@vben/locales';\nimport { loadLocaleMessages } from '@vben/locales';\nimport { updatePreferences } from '@vben/preferences';\n\nasync function updateLocale(value: string) {\n  // 1. 更新偏好设置\n  const locale = value as SupportedLanguagesType;\n  updatePreferences({\n    app: {\n      locale,\n    },\n  });\n  // 2. 加载对应的语言包\n  await loadLocaleMessages(locale);\n}\n\nupdateLocale('en-US');\n```\n\n## 新增翻译文本\n\n::: warning 注意\n\n- 请不要将业务翻译文本放到 `@vben/locales` 内，这样可以更好的管理业务和通用的翻译文本。\n- 有多个语言包的情况下，新增翻译文本时，需要在所有语言包内新增对应的文本。\n\n:::\n\n新增翻译文本，只需要在对应的应用内，找到 `src/locales/langs/`，新增对应的文本即可，例:\n\n**src/locales/langs/zh-CN/\\*.json**\n\n````ts\n```json\n{\n  \"about\": {\n    \"desc\": \"Vben Admin 是一个现代的管理模版。\"\n  }\n}\n````\n\n**src/locales/langs/en-US.ts**\n\n````ts\n```json\n{\n  \"about\": {\n    \"desc\": \"Vben Admin is a modern management template.\"\n  }\n}\n````\n\n## 使用翻译文本\n\n通过 `@vben/locales`，你可以很方便的使用翻译文本：\n\n### 在代码中使用\n\n```vue\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { $t } from '@vben/locales';\n\nconst items = computed(() => [{ title: $t('about.desc') }]);\n</script>\n<template>\n  <div>{{ $t('about.desc') }}</div>\n  <template v-for=\"item in items.value\">\n    <div>{{ item.title }}</div>\n  </template>\n</template>\n```\n\n## 新增语言包\n\n如果你需要新增语言包，需要按照以下步骤进行：\n\n- 在 `packages/locales/langs` 目录下新增对应的语言包文件，例：`zh-TW.json`，并翻译对应的文本。\n- 在对应的应用内，找到 `src/locales/langs` 文件，新增对应的语言包 `zh-TW.json`\n- 在 `packages/constants/src/core.ts`内，新增对应的语言：\n\n  ```ts\n  export interface LanguageOption {\n    label: string;\n    value: 'en-US' | 'zh-CN'; // [!code --]\n    value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]\n  }\n  export const SUPPORT_LANGUAGES: LanguageOption[] = [\n    {\n      label: '简体中文',\n      value: 'zh-CN',\n    },\n    {\n      label: 'English',\n      value: 'en-US',\n    },\n    {\n      label: '繁体中文', // [!code ++]\n      value: 'zh-TW', // [!code ++]\n    },\n  ];\n  ```\n\n- 在 `packages/locales/typing.ts`内，新增 Typescript 类型：\n\n  ```ts\n  export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --]\n  export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]\n  ```\n\n到这里，你就可以在项目内使用新增的语言包了。\n\n## 界面切换语言功能\n\n如果你想关闭界面上的语言切换显示按钮，在对应的应用内，找到 `src/preferences.ts` 文件，修改 `locale` 的值即可：\n\n```ts {3}\nexport const overridesPreferences = defineOverridesPreferences({\n  widget: {\n    languageToggle: false,\n  },\n});\n```\n\n## 远程加载语言包\n\n::: tip 提示\n\n通过项目自带的`request`工具进行接口请求时，默认请求头里会带上 [Accept-Language](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept-Language) ，服务端可根据请求头进行动态数据国际化处理。\n\n:::\n\n每个应用都有一个独立的语言包，它可以覆盖通用的语言配置，你可以通过远程加载的方式来获取对应的语言包，只需要在对应的应用内，找到 `src/locales/index.ts` 文件，修改 `loadMessages` 方法即可：\n\n```ts {3-4}\nasync function loadMessages(lang: SupportedLanguagesType) {\n  const [appLocaleMessages] = await Promise.all([\n    // 这里修改为远程接口加载数据即可\n    localesMap[lang](),\n    loadThirdPartyMessage(lang),\n  ]);\n  return appLocaleMessages.default;\n}\n```\n\n## 第三方语言包\n\n不同应用内使用的第三方组件库或者插件国际化方式可能不一致，所以需要差别处理。 如果你需要引入第三方的语言包，你可以在对应的应用内，找到 `src/locales/index.ts` 文件，修改 `loadThirdPartyMessage` 方法即可：\n\n```ts\n/**\n * 加载dayjs的语言包\n * @param lang\n */\nasync function loadDayjsLocale(lang: SupportedLanguagesType) {\n  let locale;\n  switch (lang) {\n    case 'zh-CN': {\n      locale = await import('dayjs/locale/zh-cn');\n      break;\n    }\n    case 'en-US': {\n      locale = await import('dayjs/locale/en');\n      break;\n    }\n    // 默认使用英语\n    default: {\n      locale = await import('dayjs/locale/en');\n    }\n  }\n  if (locale) {\n    dayjs.locale(locale);\n  } else {\n    console.error(`Failed to load dayjs locale for ${lang}`);\n  }\n}\n```\n\n## 移除国际化\n\n首先，不是很建议移除国际化，因为国际化是一个很好的开发习惯，但是如果你真的需要移除国际化，你可以直接使用中文文案，然后保留项目自带的语言包即可，整体开发体验不会影响。移除国际化的步骤如下：\n\n- 隐藏界面上的语言切换按钮，见：[界面切换语言功能](#界面切换语言功能)\n- 修改默认语言，见：[配置默认语言](#配置默认语言)\n- 关闭 `vue-i18n`的警告提示，在`src/locales/index.ts`文件内，修改`missingWarn`为`false`即可：\n\n  ```ts\n  async function setupI18n(app: App, options: LocaleSetupOptions = {}) {\n    await coreSetup(app, {\n      defaultLocale: preferences.app.locale,\n      loadMessages,\n      missingWarn: !import.meta.env.PROD, // [!code --]\n      missingWarn: false, // [!code ++]\n      ...options,\n    });\n  }\n  ```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/login.md",
    "content": "---\noutline: deep\n---\n\n# 登录\n\n本文介绍如何去改造自己的应用程序登录页以及如何快速的对接登录页面接口。\n\n## 登录页面调整\n\n如果你想调整登录页面的标题、描述和图标以及工具栏，你可以通过配置 `AuthPageLayout` 组件的参数来实现。\n\n![login](/guide/login.png)\n\n只需要在应用下的 `src/layouts/auth.vue` 内，配置`AuthPageLayout`的 `props`参数即可：\n\n```vue {2-7}\n<AuthPageLayout\n  :copyright=\"true\"\n  :toolbar=\"true\"\n  :toolbarList=\"['color', 'language', 'layout', 'theme']\"\n  :app-name=\"appName\"\n  :logo=\"logo\"\n  :page-description=\"$t('authentication.pageDesc')\"\n  :page-title=\"$t('authentication.pageTitle')\"\n>\n</AuthPageLayout>\n```\n\n## 登录表单调整\n\n如果你想调整登录表单的相关内容，你可以在应用下的 `src/views/_core/authentication/login.vue` 内，配置`AuthenticationLogin` 组件参数即可：\n\n```vue\n<AuthenticationLogin\n  :loading=\"authStore.loginLoading\"\n  @submit=\"authStore.authLogin\"\n/>\n```\n\n::: details AuthenticationLogin 组件参数\n\n```ts\n{\n  /**\n   * @zh_CN 验证码登录路径\n   */\n  codeLoginPath?: string;\n  /**\n   * @zh_CN 忘记密码路径\n   */\n  forgetPasswordPath?: string;\n\n  /**\n   * @zh_CN 是否处于加载处理状态\n   */\n  loading?: boolean;\n\n  /**\n   * @zh_CN 二维码登录路径\n   */\n  qrCodeLoginPath?: string;\n\n  /**\n   * @zh_CN 注册路径\n   */\n  registerPath?: string;\n\n  /**\n   * @zh_CN 是否显示验证码登录\n   */\n  showCodeLogin?: boolean;\n  /**\n   * @zh_CN 是否显示忘记密码\n   */\n  showForgetPassword?: boolean;\n\n  /**\n   * @zh_CN 是否显示二维码登录\n   */\n  showQrcodeLogin?: boolean;\n\n  /**\n   * @zh_CN 是否显示注册按钮\n   */\n  showRegister?: boolean;\n\n  /**\n   * @zh_CN 是否显示记住账号\n   */\n  showRememberMe?: boolean;\n\n  /**\n   * @zh_CN 是否显示第三方登录\n   */\n  showThirdPartyLogin?: boolean;\n\n  /**\n   * @zh_CN 登录框子标题\n   */\n  subTitle?: string;\n\n  /**\n   * @zh_CN 登录框标题\n   */\n  title?: string;\n\n}\n```\n\n:::\n\n::: tip Note\n\n如果这些配置不能满足你的需求，你可以自行实现登录表单及相关登录逻辑或者给我们提交 `PR`。\n\n:::\n\n## 接口对接流程\n\n这里将会快速的介绍如何快速对接自己的后端。\n\n### 前置条件\n\n- 首先文档用的后端服务，接口返回的格式统一如下：\n\n```ts\ninterface HttpResponse<T = any> {\n  /**\n   * 0 表示成功 其他表示失败\n   * 0 means success, others means fail\n   */\n  code: number;\n  data: T;\n  message: string;\n}\n```\n\n如果你不符合这个格式，你需要先阅读 [服务端交互](../essentials/server.md) 文档，改造你的`request.ts`配置。\n\n- 其次你需要在先将本地代理地址改为你的真实后端地址，你可以在应用下的 `vite.config.mts` 内配置：\n\n```ts\nimport { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    vite: {\n      server: {\n        proxy: {\n          '/api': {\n            changeOrigin: true,\n            rewrite: (path) => path.replace(/^\\/api/, ''),\n            // 这里改为你的真实接口地址\n            target: 'http://localhost:5320/api',\n            ws: true,\n          },\n        },\n      },\n    },\n  };\n});\n```\n\n### 登录接口\n\n为了能正常登录，你的后端最少需要提供 `2-3` 个接口：\n\n- 登录接口\n\n接口地址可在应用下的 `src/api/core/auth` 内修改，以下为默认接口地址：\n\n```ts\n/**\n * 登录\n */\nexport async function loginApi(data: AuthApi.LoginParams) {\n  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);\n}\n\n/** 只需要保证登录接口返回值有 `accessToken` 字段即可 */\nexport interface LoginResult {\n  accessToken: string;\n}\n```\n\n- 获取用户信息接口\n\n接口地址可在应用下的 `src/api/core/user` 内修改，以下为默认接口地址：\n\n```ts\nexport async function getUserInfoApi() {\n  return requestClient.get<UserInfo>('/user/info');\n}\n\n/** 只需要保证登录接口返回值有以下字段即可，多的字段可以自行使用 */\nexport interface UserInfo {\n  roles: string[];\n  realName: string;\n}\n```\n\n- 获取权限码 (可选)\n\n这个接口用于获取用户的权限码，权限码是用于控制用户的权限的，接口地址可在应用下的 `src/api/core/auth` 内修改，以下为默认接口地址：\n\n```ts\nexport async function getAccessCodesApi() {\n  return requestClient.get<string[]>('/auth/codes');\n}\n```\n\n如果你不需要这个权限，你只需要把代码改为返回一个空数组即可。\n\n```ts {2}\nexport async function getAccessCodesApi() {\n  // 这里返回一个空数组即可\n  return [];\n}\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/theme.md",
    "content": "# 主题\n\n框架基于 [shadcn-vue](https://www.shadcn-vue.com/themes.html) 和 [tailwindcss](https://tailwindcss.com/) 构建，提供了丰富的主题配置，可以通过简单的配置实现各种主题切换，满足个性化需求。您可以选择使用 CSS 变量或 Tailwind CSS 实用程序类进行主题设置。\n\n## Css 变量\n\n项目遵循 [shadcn-vue](https://www.shadcn-vue.com/themes.html) 的主题配置，示例：\n\n```html\n<div class=\"bg-background text-foreground\" />\n```\n\n我们对颜色使用一个简单的约定。`background`变量用于组件的背景颜色，`foreground`变量用于文本颜色。\n\n以下组件的`background`将为`hsl(var(--primary))`，`foreground`将为`hsl(var(--primary-foreground))`。\n\n## 详细的CSS变量列表\n\n::: warning 注意\n\ncss 变量内的颜色，必须使用 `hsl` 格式，如 `0 0% 100%`，不需要加 `hsl()`和 `，`。\n\n:::\n\n你可以查看下面的CSS变量列表，以了解所有可用的变量。\n\n::: details 默认主题 css 变量\n\n```css\n:root {\n  --font-family:\n    -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, 'Helvetica Neue',\n    arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',\n    'Segoe UI Symbol', 'Noto Color Emoji';\n\n  /* Default background color of <body />...etc */\n  --background: 0 0% 100%;\n\n  /* 主体区域背景色 */\n  --background-deep: 216 20.11% 95.47%;\n  --foreground: 210 6% 21%;\n\n  /* Background color for <Card /> */\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n\n  /* 主题颜色 */\n\n  --primary: 212 100% 45%;\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 0 78% 68%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* Secondary colors for <Button /> */\n\n  --secondary: 240 5% 96%;\n  --secondary-foreground: 240 6% 10%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 240 5% 96%;\n  --accent-hover: 200deg 10% 90%;\n  --accent-foreground: 240 6% 10%;\n\n  /* Darker color */\n  --heavy: 192deg 9.43% 89.61%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 5.9% 90%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 240deg 5.88% 90%;\n  --input-placeholder: 217 10.6% 65%;\n  --input-background: 0 0% 100%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* Border radius for card, input and buttons */\n  --radius: 0.5rem;\n\n  /* ============= custom ============= */\n\n  /* 遮罩颜色 */\n  --overlay: 0deg 0% 0% / 30%;\n\n  /* 基本文字大小 */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  /* menu */\n  --sidebar: 0 0% 100%;\n  --sidebar-deep: 216 20.11% 95.47%;\n  --menu: var(--sidebar);\n\n  /* header */\n  --header: 0 0% 100%;\n\n  accent-color: var(--primary);\n  color-scheme: light;\n}\n```\n\n:::\n\n::: details 默认主题黑暗模式 css 变量\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  /* Default background color of <body />...etc */\n  --background: 222.34deg 10.43% 12.27%;\n\n  /* 主体区域背景色 */\n  --background-deep: 220deg 13.06% 9%;\n  --foreground: 0 0% 95%;\n\n  /* Background color for <Card /> */\n  --card: 222.34deg 10.43% 12.27%;\n\n  /* --card: 222.2 84% 4.9%; */\n  --card-foreground: 210 40% 98%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 222.82deg 8.43% 12.27%;\n  --popover-foreground: 210 40% 98%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n  --muted: 220deg 6.82% 17.25%;\n  --muted-foreground: 215 20.2% 65.1%;\n\n  /* 主题颜色 */\n\n  /* --primary: 245 82% 67%; */\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 0 78% 68%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* 颜色次要 */\n  --secondary: 240 5% 17%;\n  --secondary-foreground: 0 0% 98%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 0deg 0% 100% / 8%;\n  --accent-hover: 0deg 0% 100% / 12%;\n  --accent-foreground: 0 0% 98%;\n\n  /* Darker color */\n  --heavy: 0deg 0% 100% / 12%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 3.7% 15.9%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 0deg 0% 100% / 10%;\n  --input-placeholder: 218deg 11% 65%;\n  --input-background: 0deg 0% 100% / 5%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* 基本圆角大小 */\n  --radius: 0.5rem;\n\n  /* ============= Custom ============= */\n\n  /* 遮罩颜色 */\n  --overlay: 0deg 0% 0% / 40%;\n\n  /* 基本文字大小 */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  --sidebar: 222.34deg 10.43% 12.27%;\n  --sidebar-deep: 220deg 13.06% 9%;\n  --menu: var(--sidebar);\n  --header: 222.34deg 10.43% 12.27%;\n\n  color-scheme: dark;\n}\n```\n\n:::\n\n## 覆盖默认的 CSS 变量\n\n你只需要在你的项目中覆盖你想要修改的 CSS 变量即可。例如，要更改默认卡片背景色，你可以在你的 CSS 文件中添加以下内容进行覆盖：\n\n### 默认主题下\n\n```css\n:root {\n  /* Background color for <Card /> */\n  --card: 0 0% 30%;\n}\n```\n\n### 黑暗模式下\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  /* Background color for <Card /> */\n  --card: 222.34deg 10.43% 12.27%;\n}\n```\n\n## 更改品牌主色\n\n::: tip\n\n- 需要使用 `hsl` 格式颜色格式。\n- 修改后需要清空缓存才可生效。\n- 你可以借助 [第三方工具](https://www.w3schools.com/colors/colors_hsl.asp)来转换颜色。\n\n:::\n\n只需要在应用目录下的`preferences.ts`，自定义配置主色即可：\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  theme: {\n    // 错误色\n    colorDestructive: 'hsl(348 100% 61%)',\n    // 主题色\n    colorPrimary: 'hsl(212 100% 45%)',\n    // 成功色\n    colorSuccess: 'hsl(144 57% 58%)',\n    // 警告色\n    colorWarning: 'hsl(42 84% 61%)',\n  },\n});\n```\n\n## 内置主题\n\n框架中内置了多种主题，你可以在`preferences.ts`中进行配置：\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  theme: {\n    builtinType: 'default',\n  },\n});\n```\n\n### 内置主题列表\n\n框架内置了 16种主题，且还支持自定义主题。理论上，你可以无限制的扩展主题。\n\n::: details 内置主题类型列表\n\n```ts\ntype BuiltinThemeType =\n  | 'custom'\n  | 'deep-blue'\n  | 'deep-green'\n  | 'default'\n  | 'gray'\n  | 'green'\n  | 'neutral'\n  | 'orange'\n  | 'pink'\n  | 'red'\n  | 'rose'\n  | 'sky-blue'\n  | 'slate'\n  | 'stone'\n  | 'violet'\n  | 'yellow'\n  | 'zinc'\n  | (Record<never, never> & string);\n```\n\n:::\n\n::: details 内置主题css变量 - light\n\n```css\n:root {\n  --font-family:\n    -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, 'Helvetica Neue',\n    arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',\n    'Segoe UI Symbol', 'Noto Color Emoji';\n\n  /* Default background color of <body />...etc */\n  --background: 0 0% 100%;\n\n  /* 主体区域背景色 */\n  --background-deep: 216 20.11% 95.47%;\n  --foreground: 222 84% 5%;\n\n  /* Background color for <Card /> */\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n\n  /* --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%; */\n\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n\n  /* 主题颜色 */\n\n  --primary: 212 100% 45%;\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 0 78% 68%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* Secondary colors for <Button /> */\n\n  --secondary: 240 5% 96%;\n  --secondary-foreground: 240 6% 10%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 240 5% 96%;\n  --accent-hover: 200deg 10% 90%;\n  --accent-foreground: 240 6% 10%;\n\n  /* Darker color */\n  --heavy: 192deg 9.43% 89.61%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 5.9% 90%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 240deg 5.88% 90%;\n  --input-placeholder: 217 10.6% 65%;\n  --input-background: 0 0% 100%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* Border radius for card, input and buttons */\n  --radius: 0.5rem;\n\n  /* ============= custom ============= */\n\n  /* 遮罩颜色 */\n  --overlay: 0deg 0% 0% / 30%;\n\n  /* 基本文字大小 */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  /* menu */\n  --sidebar: 0 0% 100%;\n  --sidebar-deep: 0 0% 100%;\n  --menu: var(--sidebar);\n\n  /* header */\n  --header: 0 0% 100%;\n\n  accent-color: var(--primary);\n  color-scheme: light;\n}\n\n[data-theme='violet'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 224 71.4% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 224 71.4% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 224 71.4% 4.1%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 220 14.3% 95.9%;\n  --secondary-foreground: 220.9 39.3% 11%;\n  --muted: 220 14.3% 95.9%;\n  --muted-foreground: 220 8.9% 46.1%;\n  --accent: 220 14.3% 95.9%;\n  --accent-foreground: 220.9 39.3% 11%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 220 13% 91%;\n  --input: 220 13% 91%;\n  --ring: 262.1 83.3% 57.8%;\n}\n\n[data-theme='pink'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 346.8 77.2% 49.8%;\n}\n\n[data-theme='rose'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 346.8 77.2% 49.8%;\n}\n\n[data-theme='sky-blue'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 221.2 83.2% 53.3%;\n}\n\n[data-theme='deep-blue'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 221.2 83.2% 53.3%;\n}\n\n[data-theme='green'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 142.1 76.2% 36.3%;\n}\n\n[data-theme='deep-green'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 142.1 76.2% 36.3%;\n}\n\n[data-theme='orange'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 20 14.3% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 20 14.3% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 20 14.3% 4.1%;\n  --primary-foreground: 60 9.1% 97.8%;\n  --secondary: 60 4.8% 95.9%;\n  --secondary-foreground: 24 9.8% 10%;\n  --muted: 60 4.8% 95.9%;\n  --muted-foreground: 25 5.3% 44.7%;\n  --accent: 60 4.8% 95.9%;\n  --accent-foreground: 24 9.8% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 20 5.9% 90%;\n  --input: 20 5.9% 90%;\n  --ring: 24.6 95% 53.1%;\n}\n\n[data-theme='yellow'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 20 14.3% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 20 14.3% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 20 14.3% 4.1%;\n  --primary-foreground: 26 83.3% 14.1%;\n  --secondary: 60 4.8% 95.9%;\n  --secondary-foreground: 24 9.8% 10%;\n  --muted: 60 4.8% 95.9%;\n  --muted-foreground: 25 5.3% 44.7%;\n  --accent: 60 4.8% 95.9%;\n  --accent-foreground: 24 9.8% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 20 5.9% 90%;\n  --input: 20 5.9% 90%;\n  --ring: 20 14.3% 4.1%;\n}\n\n[data-theme='zinc'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 0 0% 98%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 240 5.9% 10%;\n}\n\n[data-theme='neutral'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 0 0% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 0 0% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 0 0% 3.9%;\n  --primary-foreground: 0 0% 98%;\n  --secondary: 0 0% 96.1%;\n  --secondary-foreground: 0 0% 9%;\n  --muted: 0 0% 96.1%;\n  --muted-foreground: 0 0% 45.1%;\n  --accent: 0 0% 96.1%;\n  --accent-foreground: 0 0% 9%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 89.8%;\n  --input: 0 0% 89.8%;\n  --ring: 0 0% 3.9%;\n}\n\n[data-theme='slate'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 222.2 84% 4.9%;\n}\n\n[data-theme='gray'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 224 71.4% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 224 71.4% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 224 71.4% 4.1%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 220 14.3% 95.9%;\n  --secondary-foreground: 220.9 39.3% 11%;\n  --muted: 220 14.3% 95.9%;\n  --muted-foreground: 220 8.9% 46.1%;\n  --accent: 220 14.3% 95.9%;\n  --accent-foreground: 220.9 39.3% 11%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 220 13% 91%;\n  --input: 220 13% 91%;\n  --ring: 224 71.4% 4.1%;\n}\n```\n\n:::\n\n::: details 内置主题css变量 - dark\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  /* Default background color of <body />...etc */\n  --background: 222.34deg 10.43% 12.27%;\n\n  /* 主体区域背景色 */\n  --background-deep: 220deg 13.06% 9%;\n  --foreground: 0 0% 95%;\n\n  /* Background color for <Card /> */\n  --card: 222.34deg 10.43% 12.27%;\n\n  /* --card: 222.2 84% 4.9%; */\n  --card-foreground: 210 40% 98%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 222.82deg 8.43% 12.27%;\n  --popover-foreground: 210 40% 98%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n\n  /* --muted: 220deg 6.82% 17.25%; */\n\n  /* --muted-foreground: 215 20.2% 65.1%; */\n\n  --muted: 240 3.7% 15.9%;\n  --muted-foreground: 240 5% 64.9%;\n\n  /* 主题颜色 */\n\n  /* --primary: 245 82% 67%; */\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 0 78% 68%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* 颜色次要 */\n  --secondary: 240 5% 17%;\n  --secondary-foreground: 0 0% 98%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 216 5% 19%;\n  --accent-hover: 216 5% 24%;\n  --accent-foreground: 0 0% 98%;\n\n  /* Darker color */\n  --heavy: 216 5% 24%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 3.7% 22%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 0deg 0% 100% / 10%;\n  --input-placeholder: 218deg 11% 65%;\n  --input-background: 0deg 0% 100% / 5%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* 基本圆角大小 */\n  --radius: 0.5rem;\n\n  /* ============= Custom ============= */\n\n  /* 遮罩颜色 */\n  --overlay: 0deg 0% 0% / 40%;\n\n  /* 基本文字大小 */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  --sidebar: 222.34deg 10.43% 12.27%;\n  --sidebar-deep: 220deg 13.06% 9%;\n  --menu: var(--sidebar);\n\n  /* header */\n  --header: 222.34deg 10.43% 12.27%;\n\n  color-scheme: dark;\n}\n\n.dark[data-theme='violet'],\n[data-theme='violet'] .dark {\n  --background: 224 71.4% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 210 20% 98%;\n  --card: 224 71.4% 4.1%;\n  --card-foreground: 210 20% 98%;\n  --popover: 224 71.4% 4.1%;\n  --popover-foreground: 210 20% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 215 27.9% 16.9%;\n  --secondary-foreground: 210 20% 98%;\n  --muted: 215 27.9% 16.9%;\n  --muted-foreground: 217.9 10.6% 64.9%;\n  --accent: 215 27.9% 16.9%;\n  --accent-foreground: 210 20% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 215 27.9% 16.9%;\n  --input: 215 27.9% 16.9%;\n  --ring: 263.4 70% 50.4%;\n  --sidebar: 224 71.4% 4.1%;\n  --sidebar-deep: 224 71.4% 4.1%;\n  --header: 224 71.4% 4.1%;\n}\n\n.dark[data-theme='pink'],\n[data-theme='pink'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 0 0% 9%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 346.8 77.2% 49.8%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='rose'],\n[data-theme='rose'] .dark {\n  --background: 0 0% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 0 0% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 0 0% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 0 85.7% 97.3%;\n  --secondary: 0 0% 14.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 14.9%;\n  --muted-foreground: 0 0% 63.9%;\n  --accent: 0 0% 14.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 14.9%;\n  --input: 0 0% 14.9%;\n  --ring: 0 72.2% 50.6%;\n  --sidebar: 0 0% 3.9%;\n  --sidebar-deep: 0 0% 3.9%;\n  --header: 0 0% 3.9%;\n}\n\n.dark[data-theme='sky-blue'],\n[data-theme='sky-blue'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 224.3 76.3% 48%;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='deep-blue'],\n[data-theme='deep-blue'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 224.3 76.3% 48%;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='green'],\n[data-theme='green'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 24 9.8% 6%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 142.4 71.8% 29.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='deep-green'],\n[data-theme='deep-green'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 24 9.8% 6%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 142.4 71.8% 29.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='orange'],\n[data-theme='orange'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 60 9.1% 97.8%;\n  --card: 20 14.3% 4.1%;\n  --card-foreground: 60 9.1% 97.8%;\n  --popover: 20 14.3% 4.1%;\n  --popover-foreground: 60 9.1% 97.8%;\n  --primary-foreground: 60 9.1% 97.8%;\n  --secondary: 12 6.5% 15.1%;\n  --secondary-foreground: 60 9.1% 97.8%;\n  --muted: 12 6.5% 15.1%;\n  --muted-foreground: 24 5.4% 63.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 60 9.1% 97.8%;\n  --destructive: 0 72.2% 50.6%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 12 6.5% 15.1%;\n  --input: 12 6.5% 15.1%;\n  --ring: 20.5 90.2% 48.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='yellow'],\n[data-theme='yellow'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 60 9.1% 97.8%;\n  --card: 20 14.3% 4.1%;\n  --card-foreground: 60 9.1% 97.8%;\n  --popover: 20 14.3% 4.1%;\n  --popover-foreground: 60 9.1% 97.8%;\n  --primary-foreground: 26 83.3% 14.1%;\n  --secondary: 12 6.5% 15.1%;\n  --secondary-foreground: 60 9.1% 97.8%;\n  --muted: 12 6.5% 15.1%;\n  --muted-foreground: 24 5.4% 63.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 60 9.1% 97.8%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 12 6.5% 15.1%;\n  --input: 12 6.5% 15.1%;\n  --ring: 35.5 91.7% 32.9%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='zinc'],\n[data-theme='zinc'] .dark {\n  --background: 240 10% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 240 10% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 240 10% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 240 5.9% 10%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 240 3.7% 15.9%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 240 3.7% 15.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 240 4.9% 83.9%;\n  --sidebar: 240 10% 3.9%;\n  --sidebar-deep: 240 10% 3.9%;\n  --header: 240 4.9% 83.9%;\n}\n\n.dark[data-theme='neutral'],\n[data-theme='neutral'] .dark {\n  --background: 0 0% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 0 0% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 0 0% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 0 0% 9%;\n  --secondary: 0 0% 14.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 14.9%;\n  --muted-foreground: 0 0% 63.9%;\n  --accent: 0 0% 14.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 14.9%;\n  --input: 0 0% 14.9%;\n  --ring: 0 0% 83.1%;\n  --sidebar: 0 0% 3.9%;\n  --sidebar-deep: 0 0% 3.9%;\n  --header: 0 0% 3.9%;\n}\n\n.dark[data-theme='slate'],\n[data-theme='slate'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 222.2 47.4% 11.2%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 212.7 26.8% 83.9;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='gray'],\n[data-theme='gray'] .dark {\n  --background: 224 71.4% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 210 20% 98%;\n  --card: 224 71.4% 4.1%;\n  --card-foreground: 210 20% 98%;\n  --popover: 224 71.4% 4.1%;\n  --popover-foreground: 210 20% 98%;\n  --primary-foreground: 220.9 39.3% 11%;\n  --secondary: 215 27.9% 16.9%;\n  --secondary-foreground: 210 20% 98%;\n  --muted: 215 27.9% 16.9%;\n  --muted-foreground: 217.9 10.6% 64.9%;\n  --accent: 215 27.9% 16.9%;\n  --accent-foreground: 210 20% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 215 27.9% 16.9%;\n  --input: 215 27.9% 16.9%;\n  --ring: 216 12.2% 83.9%;\n  --sidebar: 224 71.4% 4.1%;\n  --sidebar-deep: 224 71.4% 4.1%;\n  --header: 224 71.4% 4.1%;\n}\n```\n\n:::\n\n## 新增主题\n\n想要新增主题，只需按照以下步骤进行：\n\n- 在应用的 `src/preferences.ts`内新增一个主题配置。\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  theme: {\n    builtinType: 'my-theme',\n  },\n});\n```\n\n- 在你的css文件中，新增主题的css变量。\n\n```css\n/* light */\n[data-theme='my-theme'] {\n  --foreground: 224 71.4% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 224 71.4% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 224 71.4% 4.1%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 220 14.3% 95.9%;\n  --secondary-foreground: 220.9 39.3% 11%;\n  --muted: 220 14.3% 95.9%;\n  --muted-foreground: 220 8.9% 46.1%;\n  --accent: 220 14.3% 95.9%;\n  --accent-foreground: 220.9 39.3% 11%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 220 13% 91%;\n  --input: 220 13% 91%;\n  --ring: 262.1 83.3% 57.8%;\n}\n\n/* dark */\n.dark[data-theme='my-theme'],\n[data-theme='my-theme'] .dark {\n  --background: 224 71.4% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 210 20% 98%;\n  --card: 224 71.4% 4.1%;\n  --card-foreground: 210 20% 98%;\n  --popover: 224 71.4% 4.1%;\n  --popover-foreground: 210 20% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 215 27.9% 16.9%;\n  --secondary-foreground: 210 20% 98%;\n  --muted: 215 27.9% 16.9%;\n  --muted-foreground: 217.9 10.6% 64.9%;\n  --accent: 215 27.9% 16.9%;\n  --accent-foreground: 210 20% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 215 27.9% 16.9%;\n  --input: 215 27.9% 16.9%;\n  --ring: 263.4 70% 50.4%;\n  --sidebar: 224 71.4% 4.1%;\n  --sidebar-deep: 224 71.4% 4.1%;\n}\n```\n\n## 黑暗模式\n\n框架中内置了多种主题，你可以在`preferences.ts`中进行配置，黑暗主题同样会读取css变量来进行配置：\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  theme: {\n    mode: 'dark',\n  },\n});\n```\n\n## 自定义侧边栏颜色\n\n侧边栏颜色通过`--sidebar`变量来配置\n\n### 默认主题下\n\n```css\n:root {\n  --sidebar: 0 0% 100%;\n}\n```\n\n### 黑暗模式下\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  --sidebar: 222.34deg 10.43% 12.27%;\n}\n```\n\n## 自定义顶栏颜色\n\n侧边栏颜色通过`--header`变量来配置\n\n### 默认主题下\n\n```css\n:root {\n  --header: 0 0% 100%;\n}\n```\n\n### 黑暗模式下\n\n```css\n.dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  --header: 222.34deg 10.43% 12.27%;\n}\n```\n\n## 色弱模式\n\n一般用于特殊场景，将设置为色弱模式，你可以在`preferences.ts`中进行配置：\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    colorWeakMode: true,\n  },\n});\n```\n\n## 灰色模式\n\n一般用于特殊场景，将网页置灰，你可以在`preferences.ts`中进行配置：\n\n```ts\nimport { defineOverridesPreferences } from '@vben/preferences';\n\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    colorGrayMode: true,\n  },\n});\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/in-depth/ui-framework.md",
    "content": "# 组件库切换\n\n`Vue Admin` 支持你自由选择组件库，目前演示站点的默认组件库是 `Ant Design Vue`，与旧版本保持一致。同时框架还内置了 `Element Plus` 版本和 `Naive UI` 版本，你可以根据自己的喜好选择。\n\n## 新增组件库应用\n\n如果你想用其他别的组件库，你只需要按以下步骤进行操作：\n\n1. 在`apps`内创建一个新的文件夹，例如`apps/web-xxx`。\n2. 更改`apps/web-xxx/package.json`的`name`字段为`web-xxx`。\n3. 移除其他组件库依赖及代码，并用你的组件库进行替换相应逻辑，需要改动的地方不多。\n4. 调整`locales`内的语言文件。\n5. 调整 `app.vue` 内的组件。\n6. 自行适配组件库的主题，与 `Vben Admin` 契合。\n7. 调整 `.env` 内的应用名\n8. 在大仓根目录增加 `dev:xxx` 脚本\n9. 执行 `pnpm install` 安装依赖\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/introduction/changelog.md",
    "content": "# 更新日志\n\nTODO\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/introduction/quick-start.md",
    "content": "---\noutline: deep\n---\n\n# 快速开始 {#quick-start}\n\n## 前置准备\n\n::: info 环境要求\n\n在启动项目前，你需要确保你的环境满足以下要求：\n\n- [Node.js](https://nodejs.org/en) 20.15.0 及以上版本，推荐使用 [fnm](https://github.com/Schniz/fnm) 、 [nvm](https://github.com/nvm-sh/nvm) 或者直接使用[pnpm](https://pnpm.io/cli/env) 进行版本管理。\n- [Git](https://git-scm.com/) 任意版本。\n\n验证你的环境是否满足以上要求，你可以通过以下命令查看版本：\n\n```bash\n# 出现相应 node LTS版本即可\nnode -v\n# 出现相应 git 版本即可\ngit -v\n```\n\n:::\n\n## 启动项目\n\n### 获取源码\n\n::: code-group\n\n```sh [GitHub]\n# clone 代码\ngit clone https://github.com/vbenjs/vue-vben-admin.git\n```\n\n```sh [Gitee]\n# clone 代码\n# Gitee 的代码可能不是最新的\ngit clone https://gitee.com/annsion/vue-vben-admin.git\n```\n\n:::\n\n::: danger 注意\n\n注意存放代码的目录及所有父级目录不能存在中文、韩文、日文以及空格，否则安装依赖后启动会出错。\n\n:::\n\n### 安装依赖\n\n在你的代码目录内打开终端，并执行以下命令:\n\n```bash\n# 进入项目目录\ncd vue-vben-admin\n\n# 使用项目指定的pnpm版本进行依赖安装\nnpm i -g corepack\n\n# 安装依赖\npnpm install\n```\n\n::: tip 注意\n\n- 项目只支持使用 `pnpm` 进行依赖安装，默认会使用 `corepack` 来安装指定版本的 `pnpm`。:\n- 如果你的网络环境无法访问npm源，你可以设置系统的环境变量`COREPACK_NPM_REGISTRY=https://registry.npmmirror.com`，然后再执行`pnpm install`。\n- 如果你不想使用`corepack`，你需要禁用`corepack`，然后使用你自己的`pnpm`进行安装。\n\n:::\n\n### 运行项目\n\n#### 选择项目\n\n执行以下命令运行项目:\n\n```bash\n# 启动项目\npnpm dev\n```\n\n此时，你会看到类似如下的输出，选择你需要运行的项目：\n\n```bash\n│\n◆  Select the app you need to run [dev]:\n│  ○ @vben/web-antd\n│  ○ @vben/web-ele\n│  ○ @vben/web-naive\n│  ○ @vben/docs\n│  ● @vben/playground\n└\n```\n\n现在，你可以在浏览器访问 `http://localhost:5555` 查看项目。\n\n#### 运行指定项目\n\n如果你不想选择项目，可以直接运行以下命令运行你需要的应用：\n\n```bash\npnpm run dev:antd\npnpm run dev:ele\npnpm run dev:naive\npnpm run dev:docs\npnpm run dev:play\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/introduction/roadmap.md",
    "content": "# 路线图\n\nTODO:\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/introduction/thin.md",
    "content": "---\noutline: deep\n---\n\n# 精简版本\n\n从 `5.0` 版本开始，我们不再提供精简的仓库或者分支。我们的目标是提供一个更加一致的开发体验，同时减少维护成本。在这里，我们将如何介绍自己的项目，如何去精简以及移除不需要的功能。\n\n## 应用精简\n\n首先，确认你需要的 `UI` 组件库版本，然后删除对应的应用，比如你选择使用 `Ant Design Vue`，那么你可以删除其他应用， 只需要删除下面两个文件夹即可：\n\n```bash\napps/web-ele\napps/web-naive\n\n```\n\n::: tip\n\n如果项目没有内置你需要的 `UI` 组件库应用，你可以直接全部删除其他应用。然后自行新建应用即可。\n\n:::\n\n## 演示代码精简\n\n如果你不需要演示代码，你可以直接删除的`playground`文件夹。\n\n## 文档精简\n\n如果你不需要文档，你可以直接删除`docs`文件夹。\n\n## Mock 服务精简\n\n如果你不需要`Mock`服务，你可以直接删除`apps/backend-mock`文件夹。同时在你的应用下`.env.development`文件中删除`VITE_NITRO_MOCK`变量。\n\n```bash\n# 是否开启 Nitro Mock服务，true 为开启，false 为关闭\nVITE_NITRO_MOCK=false\n```\n\n## 安装依赖\n\n到这里，你已经完成了精简操作，接下来你可以安装依赖，并启动你的项目：\n\n```bash\n# 根目录下执行\npnpm install\n\n```\n\n## 命令调整\n\n在精简后，你可能需要根据你的项目调整命令，在根目录下的`package.json`文件中，你可以调整`scripts`字段，移除你不需要的命令。\n\n```json\n{\n  \"scripts\": {\n    \"build:antd\": \"pnpm run build --filter=@vben/web-antd\",\n    \"build:docs\": \"pnpm run build --filter=@vben/docs\",\n    \"build:ele\": \"pnpm run build --filter=@vben/web-ele\",\n    \"build:naive\": \"pnpm run build --filter=@vben/web-naive\",\n    \"build:play\": \"pnpm run build --filter=@vben/playground\",\n    \"dev:antd\": \"pnpm -F @vben/web-antd run dev\",\n    \"dev:docs\": \"pnpm -F @vben/docs run dev\",\n    \"dev:ele\": \"pnpm -F @vben/web-ele run dev\",\n    \"dev:play\": \"pnpm -F @vben/playground run dev\",\n    \"dev:naive\": \"pnpm -F @vben/web-naive run dev\"\n  }\n}\n```\n\n## 其他\n\n如果你想更进一步精简，你可以删除参考以下文件或者文件夹的作用，判断自己是否需要，不需要删除即可：\n\n- `.changeset` 文件夹用于管理版本变更\n- `.github` 文件夹用于存放 GitHub 的配置文件\n- `.vscode` 文件夹用于存放 VSCode 的配置文件，如果你使用其他编辑器，可以删除\n- `./scripts/deploy` 文件夹用于存放部署脚本，如果你不需要docker部署，可以删除\n\n## 应用精简\n\n当你确定了某个应用，你还可以进一步精简：\n\n### 删除不需要的路由及页面\n\n- 在应用的 `src/router/routes` 文件中，你可以删除不需要的路由。其中 `core` 文件夹内，如果只需要登录和忘记密码，你可以删除其他路由，如忘记密码、注册等。路由删除后，你可以删除对应的页面文件，在 `src/views/_core` 文件夹中。\n\n- 在应用的 `src/router/routes` 文件中，你可以按需求删除不需要的路由，如`demos`、`vben` 目录等。路由删除后，你可以删除对应的页面文件，在 `src/views` 文件夹中。\n\n### 删除不需要的组件\n\n- 在应用的 `packages/effects/common-ui/src/ui` 文件夹中，你可以删除不需要的组件，如`about`、`dashboard` 目录等。删除之前请先确保你的路由中没有引用到这些组件。\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/introduction/vben.md",
    "content": "# 关于 Vben Admin\n\n::: info 你正在阅读的是 [Vben Admin](https://github.com/vbenjs/vue-vben-admin) `5.0`版本的文档！\n\n- Vben Admin 2.x 目前已存档，仅进行重大问题修复。\n- 新版本与旧版本不兼容，如果你使用的是旧版本（v2、v3），请查看 [Vue Vben Admin 2.x 文档](https://doc.vvbin.cn)\n- 如发现文档有误，欢迎提交 [issue](https://github.com/vbenjs/vue-vben-admin/issues) 帮助我们改进。\n- 如果你只是想体验一下，你可以查看[快速开始](./quick-start.md)。\n\n:::\n\n[Vben Admin](https://github.com/vbenjs/vue-vben-admin) 是一个基于 [Vue3.0](https://github.com/vuejs/core)、[Vite](https://github.com/vitejs/vite)、 [TypeScript](https://www.typescriptlang.org/) 的中后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模板，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 `vue3`、`vite`、`ts` 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。\n\n## 特点\n\n- **最新技术栈**：使用 `Vue3`、`Vite`、`TypeScript` 等前端前沿技术开发。\n- **国际化**：内置完善的国际化方案，支持多语言切换。\n- **权限验证**：完善的权限验证方案，按钮级别权限控制。\n- **多主题**：内置多种主题配置和黑暗模式，满足个性化需求。\n- **动态菜单**：支持动态菜单，可以根据权限配置显示菜单。\n- **Mock 数据**：基于 `Nitro` 的本地高性能 Mock 数据方案。\n- **组件丰富**：提供了丰富的组件，可以满足大部分的业务需求。\n- **规范**：代码规范，使用 `ESLint`、`Prettier`、`Stylelint`、`Publint`、`CSpell` 等工具保证代码质量。\n- **工程化**：使用 `Pnpm Monorepo`、`TurboRepo`、`Changeset` 等工具，提高开发效率。\n- **多UI库支持**：支持 `Ant Design Vue`、`Element Plus`、`Naive` 等主流 UI 库，不再限制于特定框架。\n\n## 浏览器支持\n\n- **本地开发**推荐使用`Chrome 最新版`浏览器，**不支持**`Chrome 80`以下版本。\n\n- **生产环境**支持现代浏览器，不支持 IE。\n\n| [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png\" alt=\"IE\" width=\"24px\" height=\"24px\"  />](http://godban.github.io/browsers-support-badges/)IE | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\" alt=\" Edge\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)Edge | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)Firefox | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)Chrome | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)Safari |\n| :-: | :-: | :-: | :-: | :-: |\n| 不支持 | last 2 versions | last 2 versions | last 2 versions | last 2 versions |\n\n## 贡献\n\n- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) 还在持续更新中，本项目欢迎您的参与，共同维护，逐步完善，打造更好的中后台解决方案。\n- 如果你有兴趣加入我们，可以通过以下方式开始，我们会根据你的活跃度邀请你加入。\n\n::: info 加入我们\n\n- 长期提交 `PR`。\n- 提供有价值的建议。\n- 参与讨论，帮助解决 `issue`。\n- 共同维护文档。\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/introduction/why.md",
    "content": "# 为什么选择我们?\n\n::: info 写在前面\n\n我们不会去和其他框架做比较。我们认为每个框架都有自己的特点，适合不同的场景。我们的目标是提供一个简单、易用的框架，让开发者可以快速上手，专注于业务逻辑的开发。所以我们只会不断完善和优化我们的框架，提供更好的体验。\n\n:::\n\n我们致力于为开发者提供一个高效、现代、易用的前端框架。我们的解决方案基于最新的技术栈，如 Vue3、Vite 和 TypeScript，确保您在构建项目时始终走在技术的前沿。同时，我们注重代码的质量与规范，通过严格的工具链保证代码的一致性和可维护性。无论是初创项目还是企业级应用，我们的框架都能帮助您快速构建、迭代和部署。\n\n## 框架历程\n\n从 Vue Vben Admin 1.x 版本开始，框架经历了许多迭代和优化。从一开始使用 `Vite 0.x` 版本，没有现成的插件，开发了很多自定义插件来弥合 Webpack 和 Vite 之间的差异。虽然很多现在已经被代替，但是我们的初衷一直没有变，就是提供一个简单、易用的框架。\n\n虽然中间有段时间由社区维护，但我们一直密切关注 Vue Vben Admin 的发展。见证了许多开发者使用 Vben Admin，并提供了许多宝贵的建议和反馈。非常感谢大家的支持和贡献，这些都是我们持续改进 Vben Admin 的动力。新版本中，我们持续收集用户反馈，重新开始，不断优化框架，以提供更好的用户体验。我们的目标是让开发者能够快速上手，专注于业务逻辑的开发。\n\n## 单元测试\n\n单元测试是确保代码质量的基石。在开发过程中编写和执行单元测试，以捕捉潜在的错误并提升代码的可靠性。框架核心逻辑使用 `vitest` 做了单元测试，并在逐步增加覆盖率。通过单元测试，可以放心地进行代码重构，减少回归问题，从而提高整体开发效率。\n\n## 质量与规范\n\n我们始终高度重视代码的质量与规范。通过使用 ESLint、Prettier、Stylelint、Publint、CSpell 等工具来确保代码质量。我们的代码规范基于 Vue3、Vite、TypeScript 等现代前端技术制定，旨在提供一个简洁、易用的框架，使开发者能够快速上手并专注于业务逻辑的开发。\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/other/faq.md",
    "content": "# 常见问题 #{faq}\n\n::: tip 列举了一些常见的问题\n\n有问题可以先来这里寻找，如果没有可以在 [GitHub Issue](https://github.com/vbenjs/vue-vben-admin/issues) 搜索或者提交你的问题, 如果是讨论性的问题可以在 [GitHub Discussions](https://github.com/vbenjs/vue-vben-admin/discussions)\n\n:::\n\n## 说明\n\n遇到问题,可以先从以下几个方面查找\n\n1. 对应模块的 GitHub 仓库 [issue](https://github.com/vbenjs/vue-vben-admin/issues) 搜索\n2. 从[google](https://www.google.com)搜索问题\n3. 从[百度](https://www.baidu.com)搜索问题\n4. 在下面列表找不到问题可以到 issue 提问 [issues](https://github.com/vbenjs/vue-vben-admin/issues)\n5. 如果不是问题类型的，需要讨论的，请到 [discussions](https://github.com/vbenjs/vue-vben-admin/discussions) 讨论\n\n## 依赖问题\n\n在 `Monorepo` 项目下，需要养成每次 `git pull`代码都要执行`pnpm install`的习惯，因为经常会有新的依赖包加入，项目在`lefthook.yml`已经配置了自动执行`pnpm install`，但是有时候会出现问题，如果没有自动执行，建议手动执行一次。\n\n## 关于缓存更新问题\n\n项目配置默认是缓存在 `localStorage` 内，所以版本更新后可能有些配置没改变。\n\n解决方式是每次更新代码的时候修改 `package.json` 内的 `version` 版本号. 因为 localStorage 的 key 是根据版本号来的。所以更新后版本不同前面的配置会失效。重新登录即可\n\n## 关于修改配置文件的问题\n\n当修改 `.env` 等环境文件以及 `vite.config.ts` 文件时，vite 会自动重启服务。\n\n自动重启有几率出现问题，请重新运行项目即可解决.\n\n## 本地运行报错\n\n由于 vite 在本地没有转换代码，且代码中用到了可选链等比较新的语法。所以本地开发需要使用版本较高的浏览器(`Chrome 90+`)进行开发\n\n## 页面切换后页面空白\n\n这是由于开启了路由切换动画,且对应的页面组件存在多个根节点导致的，在页面最外层添加`<div></div>`即可\n\n**错误示例**\n\n```vue\n<template>\n  <!-- 注释也算一个节点 -->\n  <h1>text h1</h1>\n  <h2>text h2</h2>\n</template>\n```\n\n**正确示例**\n\n```vue\n<template>\n  <div>\n    <h1>text h1</h1>\n    <h2>text h2</h2>\n  </div>\n</template>\n```\n\n::: tip 提示\n\n- 如果想使用多个根标签，可以禁用路由切换动画\n- template 下面的根注释节点也算一个节点\n\n:::\n\n## 我的代码本地开发可以，打包就不行了\n\n目前发现这个原因可能有以下，可以从以下原因来排查，如果还有别的可能，欢迎补充\n\n- 使用了 ctx 这个变量，ctx 本身未暴露出在实例类型内，Vue官方也是说了不要用这个属性。这个属性只是用于内部使用。\n\n```ts\nimport { getCurrentInstance } from 'vue';\ngetCurrentInstance().ctx.xxxx;\n```\n\n## 依赖安装问题\n\n- 如果依赖安装不了或者启动报错可以尝试执行`pnpm run reinstall`。\n- 如果依赖安装不了或者报错，可以尝试切换手机热点来进行依赖安装。\n- 如果还是不行，可以自行配置国内镜像安装。\n- 也可以在项目根目录创建 `.npmrc` 文件，内容如下\n\n```bash\n# .npmrc\nregistry = https://registry.npmmirror.com/\n```\n\n## 打包文件过大\n\n- 首先，完整版由于引用了比较多的库文件，所以打包会比较大。可以使用精简版来进行开发\n\n- 其次建议开启 gzip，使用之后体积会只有原先 1/3 左右。gzip 可以由服务器直接开启。如果是这样，前端不需要构建 `.gz` 格式的文件，如果前端构建了 `.gz` 文件，以 nginx 为例，nginx 需要开启 `gzip_static: on` 这个选项。\n\n- 开启 gzip 的同时还可以同时开启 `brotli`，比 gzip 更好的压缩。两者可以共存\n\n**注意**\n\n- gzip_static: 这个模块需要 nginx 另外安装，默认的 nginx 没有安装这个模块。\n\n- 开启 `brotli` 也需要 nginx 另外安装模块\n\n## 运行错误\n\n如果出现类似以下错误，请检查项目全路径（包含所有父级路径）不能出现中文、日文、韩文。否则将会出现路径访问 404 导致以下问题\n\n```ts\n[vite] Failed to resolve module import \"ant-design-vue/dist/antd.css-vben-adminode_modulesant-design-vuedistantd.css\". (imported by /@/setup/ant-design-vue/index.ts)\n```\n\n## 控制台路由警告问题\n\n如果看到控制台有如下警告，且页面**能正常打开** 可以忽略该警告。\n\n后续 `vue-router` 可能会提供配置项来关闭警告\n\n```ts\n[Vue Router warn]: No match found for location with path \"xxxx\"\n```\n\n## 启动报错\n\n当出现以下错误信息时，请检查你的 nodejs 版本号是否符合要求\n\n```bash\nTypeError: str.matchAll is not a function\nat Object.extractor (vue-vben-admin-main\\node_modules@purge-icons\\core\\dist\\index.js:146:27)\nat Extract (vue-vben-admin-main\\node_modules@purge-icons\\core\\dist\\index.js:173:54)\n```\n\n## nginx 部署\n\n部署到 `nginx`后，可能会出现以下错误：\n\n```bash\nFailed to load module script: Expected a JavaScript module script but the server responded with a MIME type of \"application/octet-stream\". Strict MIME type checking is enforced for module scripts per HTML spec.\n```\n\n解决方式一：\n\n```bash\nhttp {\n    #如果有此项配置需要注释掉\n    #include       mime.types;\n\n    types {\n      application/javascript js mjs;\n    }\n}\n```\n\n解决方式二：\n\n进入 `nginx` 下的`mime.types`文件, 将`application/javascript js;` 修改为 `application/javascript js mjs;`\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/other/project-update.md",
    "content": "# 项目更新\n\n## 为什么无法像 npm 插件一样更新\n\n因为项目是一个完整的项目模版，不是一个插件或者安装包，无法像插件一样更新，你使用代码后，会根据业务需求，进行二次开发，需要自行手动合并升级。\n\n## 我需要怎么做\n\n项目采用了 `Monorepo` 的方式进行管理，并将一些比较核心的代码进行了抽离，比如 `packages/@core`、`packages/effects`，只要业务代码没有修改这部分代码，那么你可以直接拉取最新代码，然后合并到你的分支上，只需要简单的处理部分冲突即可。其余文件夹只会进行一些小的调整，不会对业务代码产生影响。\n\n::: tip 推荐\n\n建议关注仓库动态，积极去合并，不要长时间积累，否则将会导致合并冲突过多，增加合并难度。\n\n:::\n\n## 使用 Git 更新代码\n\n1. 克隆代码\n\n```bash\ngit clone https://github.com/vbenjs/vue-vben-admin.git\n```\n\n2. 添加自己的公司 git 源地址\n\n```bash\n# up 为源名称,可以随意设置\n# gitUrl为开源最新代码\ngit remote add up gitUrl;\n```\n\n3. 提交代码到自己公司 git\n\n```bash\n# 提交代码到自己公司\n# main为分支名 需要自行根据情况修改\ngit push up main\n\n# 同步公司的代码\n# main为分支名 需要自行根据情况修改\ngit pull up main\n```\n\n4. 如何同步开源最新代码\n\n```bash\ngit pull origin main\n```\n\n::: tip 提示\n\n同步代码的时候会出现冲突。只需要把冲突解决即可\n\n:::\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/other/remove-code.md",
    "content": "# 移除代码\n\n## 移除百度统计代码\n\n在对应应用的 `index.html` 文件中，找到如下代码，删除即可：\n\n```html\n<!-- apps/web-antd -->\n<script>\n  var _hmt = _hmt || [];\n  (function () {\n    var hm = document.createElement('script');\n    hm.src = 'https://hm.baidu.com/hm.js?d20a01273820422b6aa2ee41b6c9414d';\n    var s = document.getElementsByTagName('script')[0];\n    s.parentNode.insertBefore(hm, s);\n  })();\n</script>\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/project/changeset.md",
    "content": "# Changeset\n\n项目内置了 [changeset](https://github.com/changesets/changesets) 作为版本管理工具。Changeset 是一个版本管理工具，它可以帮助我们更好的管理版本，生成 changelog，以及自动发布。\n\n详细使用方式可查看官方文档，这里不再阐述。如果你不需要它，可以直接忽略。\n\n## 命令行\n\nchangeset 命令在项目中已经内置：\n\n### 交互式填写变更集\n\n```bash\npnpm run changeset\n```\n\n### 统一提升版本号\n\n```bash\npnpm run version\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/project/cli.md",
    "content": "---\noutline: deep\n---\n\n# CLI\n\n项目中，提供了一些命令行工具，用于一些常用的操作，代码位于 `scrips` 内。\n\n## vsh\n\n用于一些项目操作，如清理项目、检查项目等。\n\n### 用法\n\n```bash\npnpm vsh [command] [options]\n```\n\n### vsh check-circular\n\n检查整个项目循环引用，如果有循环引用，会在控制台输出循环引用的模块。\n\n#### 用法\n\n```bash\npnpm vsh check-circular\n```\n\n#### 选项\n\n| 选项       | 说明                                |\n| ---------- | ----------------------------------- |\n| `--staged` | 只检查git暂存区内的文件,默认`false` |\n\n### vsh check-dep\n\n检查整个项目依赖情况，并在控制台输出`未使用的依赖`、`未安装的依赖`信息\n\n#### 用法\n\n```bash\npnpm vsh check-dep\n```\n\n#### 选项\n\n| 选项             | 说明                                    |\n| ---------------- | --------------------------------------- |\n| `-r,--recursive` | 递归删除整个项目,默认`true`             |\n| `--del-lock`     | 是否删除`pnpm-lock.yaml`文件,默认`true` |\n\n### vsh lint\n\n对项目进行lint检查，检查项目中的代码是否符合规范。\n\n#### 用法\n\n```bash\npnpm vsh lint\n```\n\n#### 选项\n\n| 选项       | 说明                           |\n| ---------- | ------------------------------ |\n| `--format` | 检查并尝试修复错误,默认`false` |\n\n### vsh publint\n\n对 `Monorepo` 项目进行包规范检查，检查项目中的包是否符合规范。\n\n#### 用法\n\n```bash\npnpm vsh publint\n```\n\n#### 选项\n\n| 选项      | 说明                   |\n| --------- | ---------------------- |\n| `--check` | 仅执行检查,默认`false` |\n\n### vsh code-workspace\n\n生成 `vben-admin.code-workspace` 文件，目前不需要手动执行，会在代码提交时自动执行。\n\n#### 用法\n\n```bash\npnpm vsh code-workspace\n```\n\n#### 选项\n\n| 选项            | 说明                                   |\n| --------------- | -------------------------------------- |\n| `--auto-commit` | `git commit`时候，自动提交,默认`false` |\n| `--spaces`      | 缩进格式,默认 `2`个缩进                |\n\n## turbo-run\n\n用于快速执行大仓中脚本，并提供选项式交互选择。\n\n### 用法\n\n```bash\npnpm turbo-run [command]\n```\n\n### turbo-run dev\n\n快速执行`dev`命令，并提供选项式交互选择。\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/project/dir.md",
    "content": "# 目录说明\n\n目录使用 Monorepo 管理，项目结构如下：\n\n```bash\n.\n├── Dockerfile # Docker 镜像构建文件\n├── README.md # 项目说明文档\n├── apps # 项目应用目录\n│   ├── backend-mock # 后端模拟服务应用\n│   ├── web-antd # 基于 Ant Design Vue 的前端应用\n│   ├── web-ele # 基于 Element Plus 的前端应用\n│   └── web-naive # 基于 Naive UI 的前端应用\n├── build-local-docker-image.sh # 本地构建 Docker 镜像脚本\n├── cspell.json # CSpell 配置文件\n├── docs # 项目文档目录\n├── eslint.config.mjs # ESLint 配置文件\n├── internal # 内部工具目录\n│   ├── lint-configs # 代码检查配置\n│   │   ├── commitlint-config # Commitlint 配置\n│   │   ├── eslint-config # ESLint 配置\n│   │   ├── prettier-config # Prettier 配置\n│   │   └── stylelint-config # Stylelint 配置\n│   ├── node-utils # Node.js 工具\n│   ├── tailwind-config # Tailwind 配置\n│   ├── tsconfig # 通用 tsconfig 配置\n│   └── vite-config # 通用Vite 配置\n├── package.json # 项目依赖配置\n├── packages # 项目包目录\n│   ├── @core # 核心包\n│   │   ├── base # 基础包\n│   │   │   ├── design # 设计相关\n│   │   │   ├── icons # 图标\n│   │   │   ├── shared # 共享\n│   │   │   └── typings # 类型定义\n│   │   ├── composables # 组合式 API\n│   │   ├── preferences # 偏好设置\n│   │   └── ui-kit # UI 组件集合\n│   │       ├── layout-ui # 布局 UI\n│   │       ├── menu-ui  # 菜单 UI\n│   │       ├── shadcn-ui # shadcn UI\n│   │       └── tabs-ui # 标签页 UI\n│   ├── constants # 常量\n│   ├── effects # 副作用相关包\n│   │   ├── access # 访问控制\n│   │   ├── plugins # 第三方大型依赖插件\n│   │   ├── common-ui # 通用 UI\n│   │   ├── hooks # 组合式 API\n│   │   ├── layouts # 布局\n│   │   └── request # 请求\n│   ├── icons # 图标\n│   ├── locales # 国际化\n│   ├── preferences  # 偏好设置\n│   ├── stores # 状态管理\n│   ├── styles # 样式\n│   ├── types # 类型定义\n│   └── utils # 工具\n├── playground # 演示目录\n├── pnpm-lock.yaml # pnpm 锁定文件\n├── pnpm-workspace.yaml # pnpm 工作区配置文件\n├── scripts # 脚本目录\n│   ├── turbo-run # Turbo 运行脚本\n│   └── vsh # VSH 脚本\n├── stylelint.config.mjs # Stylelint 配置文件\n├── turbo.json # Turbo 配置文件\n├── vben-admin.code-workspace # VS Code 工作区配置文件\n└── vitest.config.ts # Vite 配置文件\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/project/standard.md",
    "content": "# 规范\n\n::: tip 贡献代码\n\n- 如果你想向项目贡献代码，请确保你的代码符合项目的代码规范。\n- 如果你使用的是 `vscode`，需要安装以下插件：\n  - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - 脚本代码检查\n  - [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - 代码格式化\n  - [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - 单词语法检查\n  - [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - css 格式化\n\n:::\n\n## 作用\n\n具备基本工程素养的同学都会注重编码规范，而代码风格检查（Code Linting，简称 Lint）是保障代码规范一致性的重要手段。\n\n遵循相应的代码规范有以下好处：\n\n- 较少 bug 错误率\n- 高效的开发效率\n- 更高的可读性\n\n## 工具\n\n项目的配置文件位于 `internal/lint-configs` 下，你可以在这里修改各种lint的配置。\n\n项目内集成了以下几种代码校验工具：\n\n- [ESLint](https://eslint.org/) 用于 JavaScript 代码检查\n- [Stylelint](https://stylelint.io/) 用于 CSS 样式检查\n- [Prettier](https://prettier.io/) 用于代码格式化\n- [Commitlint](https://commitlint.js.org/) 用于检查 git 提交信息的规范\n- [Publint](https://publint.dev/) 用于检查 npm 包的规范\n- [Cspell](https://cspell.org/) 用于检查拼写错误\n- [lefthook](https://github.com/evilmartians/lefthook) 用于管理 Git hooks，在提交前自动运行代码校验和格式化\n\n## ESLint\n\nESLint 是一个代码规范和错误检查工具，用于识别和报告 TypeScript 代码中的语法错误。\n\n### 命令\n\n```bash\npnpm eslint .\n```\n\n### 配置\n\neslint 配置文件为 `eslint.config.mjs`，其核心配置放在`internal/lint-configs/eslint-config`目录下，可以根据项目需求进行修改。\n\n## Stylelint\n\nStylelint 用于校验项目内部 css 的风格,加上编辑器的自动修复，可以很好的统一项目内部 css 风格\n\n### 命令\n\n```bash\npnpm stylelint \"**/*.{vue,css,less.scss}\"\n```\n\n### 配置\n\nStylelint 配置文件为 `stylelint.config.mjs`，其核心配置放在`internal/lint-configs/stylelint-config`目录下，可以根据项目需求进行修改。\n\n## Prettier\n\nPrettier 可以用于统一项目代码风格，统一的缩进，单双引号，尾逗号等等风格\n\n### 命令\n\n```bash\npnpm prettier .\n```\n\n### 配置\n\nPrettier 配置文件为 `.prettier.mjs`，其核心配置放在`internal/lint-configs/prettier-config`目录下，可以根据项目需求进行修改。\n\n## CommitLint\n\n在一个团队中，每个人的 git 的 commit 信息都不一样，五花八门，没有一个机制很难保证规范化，如何才能规范化呢？可能你想到的是 git 的 hook 机制，去写 shell 脚本去实现。这当然可以，其实 JavaScript 有一个很好的工具可以实现这个模板，它就是 commitlint（用于校验 git 提交信息规范）。\n\n### 配置\n\nCommitLint 配置文件为 `.commitlintrc.mjs`，其核心配置放在`internal/lint-configs/commitlint-config`目录下，可以根据项目需求进行修改。\n\n### Git 提交规范\n\n参考 [Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)\n\n- `feat` 增加新功能\n- `fix` 修复问题/BUG\n- `style` 代码风格相关无影响运行结果的\n- `perf` 优化/性能提升\n- `refactor` 重构\n- `revert` 撤销修改\n- `test` 测试相关\n- `docs` 文档/注释\n- `chore` 依赖更新/脚手架配置修改等\n- `workflow` 工作流改进\n- `ci` 持续集成\n- `types` 类型修改\n\n### 关闭Git提交规范检查\n\n如果你想关闭 Git 提交规范检查，有两种方式：\n\n::: code-group\n\n```bash [临时关闭]\ngit commit -m 'feat: add home page' --no-verify\n```\n\n```bash [永久关闭]\n# 在 .husky/commit-msg 内注释以下代码即可\npnpm exec commitlint --edit \"$1\" # [!code --]\n```\n\n:::\n\n## Publint\n\nPublint 是一个用于检查 npm 包的规范的工具，可以检查包的版本号是否符合规范，是否符合标准的 ESM 规范包等等。\n\n### 命令\n\n```bash\npnpm vsh publint\n```\n\n## Cspell\n\nCspell 是一个用于检查拼写错误的工具，可以检查代码中的拼写错误，避免因为拼写错误导致的 bug。\n\n### 命令\n\n```bash\npnpm cspell lint \\\"**/*.ts\\\"  \\\"**/README.md\\\" \\\".changeset/*.md\\\" --no-progress\n```\n\n### 配置\n\ncspell 配置文件为 `cspell.json`，可以根据项目需求进行修改。\n\n## Git Hook\n\ngit hook 一般结合各种 lint，在 git 提交代码的时候进行代码风格校验，如果校验没通过，则不会进行提交。需要开发者自行修改后再次进行提交\n\n### lefthook\n\n有一个问题就是校验会校验全部代码，但是我们只想校验我们自己提交的代码，这个时候就可以使用 lefthook。\n\n最有效的解决方案就是将 Lint 校验放到本地，常见做法是使用 lefthook 在本地提交之前先做一次 Lint 校验。\n\n项目在 `lefthook.yml` 内部定义了相应的 hooks：\n\n- `pre-commit`: 在提交前运行，用于代码格式化和检查\n  - `code-workspace`: 更新 VSCode 工作区配置\n  - `lint-md`: 格式化 Markdown 文件\n  - `lint-vue`: 格式化并检查 Vue 文件\n  - `lint-js`: 格式化并检查 JavaScript/TypeScript 文件\n  - `lint-style`: 格式化并检查样式文件\n  - `lint-package`: 格式化 package.json\n  - `lint-json`: 格式化其他 JSON 文件\n\n- `post-merge`: 在合并后运行，用于自动安装依赖\n  - `install`: 运行 `pnpm install` 安装新依赖\n\n- `commit-msg`: 在提交时运行，用于检查提交信息格式\n  - `commitlint`: 使用 commitlint 检查提交信息\n\n#### 如何关闭 lefthook\n\n如果你想关闭 lefthook，有两种方式：\n\n::: code-group\n\n```bash [临时关闭]\ngit commit -m 'feat: add home page' --no-verify\n```\n\n```bash [永久关闭]\n# 删除 lefthook.yml 文件即可\nrm lefthook.yml\n```\n\n:::\n\n#### 如何修改 lefthook 配置\n\n如果你想修改 lefthook 的配置，可以编辑 `lefthook.yml` 文件。例如：\n\n```yaml\npre-commit:\n  parallel: true # 并行执行任务\n  jobs:\n    - name: lint-js\n      run: pnpm prettier --cache --ignore-unknown --write {staged_files}\n      glob: '*.{js,jsx,ts,tsx}'\n```\n\n其中：\n\n- `parallel`: 是否并行执行任务\n- `jobs`: 定义要执行的任务列表\n- `name`: 任务名称\n- `run`: 要执行的命令\n- `glob`: 匹配的文件模式\n- `{staged_files}`: 表示暂存的文件列表\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/project/tailwindcss.md",
    "content": "# Tailwind CSS\n\n[Tailwind CSS](https://tailwindcss.com/) 是一个实用性优先的CSS框架，用于快速构建自定义设计。\n\n## 配置\n\n项目的配置文件位于 `internal/tailwind-config` 下，你可以在这里修改 Tailwind CSS 的配置。\n\n::: tip 包使用 tailwindcss 的限制\n\n当前只有对应的包下面存在 `tailwind.config.mjs` 文件才会启用 tailwindcss 的编译，否则不会启用 tailwindcss。如果你是纯粹的 SDK 包，不需要使用 tailwindcss，可以不用创建 `tailwind.config.mjs` 文件。\n\n:::\n\n## 提示\n\n现`tailwindcss`已至v4.x版本，使用方法与`tailwindcss: ^3.4.17`有差异，v4.0无法与v3.x版本兼容，在开发前请确认`package.json`中的`tailwindcss`版本。\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/project/test.md",
    "content": "# 单元测试\n\n项目内置了 [Vitest](https://vitest.dev/) 作为单元测试工具。Vitest 是一个基于 Vite 的测试运行器，它提供了一套简单的 API 来编写测试用例。\n\n## 编写测试用例\n\n在项目中，我们约定将测试文件名以 `.test.ts` 结尾，或者存放到`__tests__`目录内。例如，创建一个 `utils.ts` 文件，然后同级目录`utils.test.ts` 文件，\n\n```ts\n// utils.test.ts\nimport { expect, test } from 'vitest';\nimport { sum } from './sum';\n\ntest('adds 1 + 2 to equal 3', () => {\n  expect(sum(1, 2)).toBe(3);\n});\n```\n\n## 运行测试\n\n在大仓根目录下运行以下命令即可：\n\n```bash\npnpm test:unit\n```\n\n## 现有单元测试\n\n项目中已经有一些单元测试用例，可以搜索以`.test.ts`结尾的文件查看，在你更改到相关代码时，可以运行单元测试来保证代码的正确性，建议在开发过程中，保持单元测试的覆盖率，且同时在 CI/CD 流程中运行单元测试，保证测试通过在进行项目部署。\n\n现有单元测试情况：\n\n![](/guide/test.png)\n"
  },
  {
    "path": "hiauth-front/docs/src/guide/project/vite.md",
    "content": "# Vite Config\n\n项目封装了一层vite配置，并集成了一些插件，方便在多个包以及应用内复用，使用方式如下：\n\n## 应用\n\n```ts\n// vite.config.mts\nimport { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    application: {},\n    // vite配置，参考vite官方文档进行覆盖\n    vite: {},\n  };\n});\n```\n\n## 包\n\n```ts\n// vite.config.mts\nimport { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    library: {},\n    // vite配置，参考vite官方文档进行覆盖\n    vite: {},\n  };\n});\n```\n"
  },
  {
    "path": "hiauth-front/docs/src/index.md",
    "content": "---\n# https://vitepress.dev/reference/default-theme-home-page\nlayout: home\nsidebar: false\n\nhero:\n  name: Vben Admin\n  text: 企业级管理系统框架\n  tagline: 全新升级，开箱即用，简单高效\n  image:\n    src: https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp\n    alt: Vben Admin\n  actions:\n    - theme: brand\n      text: 快速开始 ->\n      link: /guide/introduction/vben\n    - theme: alt\n      text: 在线预览\n      link: https://www.vben.pro\n    - theme: alt\n      text: 在 GitHub 查看\n      link: https://github.com/vbenjs/vue-vben-admin\n    - theme: alt\n      text: DeepWiki 文档\n      link: https://deepwiki.com/vbenjs/vue-vben-admin\n\nfeatures:\n  - icon: 🚀\n    title: 最新技术栈\n    details: 基于 Vue3、Pinia、Vue Router、TypeScript、等最新技术栈。\n    link: /guide/introduction/quick-start\n    linkText: 快速开始\n  - icon: 🦄\n    title: 丰富的配置\n    details: 企业级中后台前端解决方案，提供丰富的组件和模板以及 N 种偏好设置组合方案。\n    link: /guide/essentials/settings\n    linkText: 配置文档\n  - icon: 🎨\n    title: 主题定制\n    details: 通过简单的配置，即可实现各种主题切换，满足个性化需求。\n    link: /guide/in-depth/theme\n    linkText: 主题文档\n  - icon: 🌐\n    title: 国际化\n    details: 内置国际化方案，支持多语言切换，满足国际化需求。\n    link: /guide/in-depth/locale\n    linkText: 国际化文档\n  - icon: 🔐\n    title: 权限管理\n    details: 内置权限管理方案，支持多种权限控制方式，满足各种权限需求。\n    link: /guide/in-depth/access\n    linkText: 权限文档\n  - title: Vite\n    icon:\n      src: /logos/vite.svg\n    details: 现代化的前端构建工具，快速冷启动，瞬间热更新。\n    link: https://vitejs.dev/\n    linkText: 官方站点\n  - title: Shadcn UI\n    icon:\n      src: /logos/shadcn-ui.svg\n    details: 核心基于 Shadcn UI + Tailwindcss，业务可支持任意的 UI 框架。\n    link: https://www.shadcn-vue.com/\n    linkText: 官方站点\n  - title: Turbo Repo\n    icon:\n      src: /logos/turborepo.svg\n    details: 规范且标准的大仓架构，使用 pnpm + monorepo + turbo 工程管理模式，提供企业级开发规范。\n    link: https://turbo.build/\n    linkText: 官方站点\n  - title: Nitro Mock Server\n    icon:\n      src: /logos/nitro.svg\n    details: 内置 Nitro Mock 服务，让你的 mock 服务更加强大。\n    link: https://nitro.unjs.io/\n    linkText: 官方站点\n---\n\n<!-- <script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers,\n  VPTeamPageSection\n} from 'vitepress/theme';\n\nconst members = [\n  {\n    avatar: 'https://avatars.githubusercontent.com/u/28132598?v=4',\n    name: 'Vben',\n    title: '创建者',\n    desc: 'Vben Admin以及相关生态的作者，负责项目的整体开发。',\n    links: [\n      { icon: 'github', link: 'https://github.com/anncwb' },\n    ]\n  },\n]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      核心成员介绍\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers\n    :members=\"members\"\n  />\n</VPTeamPage> -->\n\n<VbenContributors />\n"
  },
  {
    "path": "hiauth-front/docs/src/sponsor/personal.md",
    "content": "# 赞助\n\n如果你觉得这个项目对你有帮助，你可以帮作者买一杯咖啡表示支持!\n\n![](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png)\n\n您的赞助将帮助我们：\n\n- 维持项目的基础设施，如服务器、域名、社群费用。\n- 支持开发者的贡献和加快新功能的开发。\n\n感谢所有现有的和未来的赞助者，您的支持对我们来说至关重要，让我们一起推动项目继续前行。\n"
  },
  {
    "path": "hiauth-front/docs/tailwind.config.mjs",
    "content": "import tailwindcssConfig from '@vben/tailwind-config';\n\nexport default {\n  ...tailwindcssConfig,\n  content: [\n    ...tailwindcssConfig.content,\n    '.vitepress/**/*.{js,mts,ts,vue}',\n    'src/demos/**/*.{js,mts,ts,vue}',\n    'src/**/*.md',\n  ],\n};\n"
  },
  {
    "path": "hiauth-front/docs/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"#/*\": [\"./src/_env/*\"]\n    }\n  },\n  \"include\": [\n    \".vitepress/*.mts\",\n    \".vitepress/**/*.ts\",\n    \".vitepress/**/*.vue\",\n    \"src/*.mts\",\n    \"src/**/*.ts\",\n    \"src/**/*.vue\"\n  ],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/eslint.config.mjs",
    "content": "// @ts-check\n\nimport { defineConfig } from '@vben/eslint-config';\n\nexport default defineConfig();\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/commitlint-config/index.mjs",
    "content": "import { execSync } from 'node:child_process';\n\nimport { getPackagesSync } from '@vben/node-utils';\n\nconst { packages } = getPackagesSync();\n\nconst allowedScopes = [\n  ...packages.map((pkg) => pkg.packageJson.name),\n  'project',\n  'style',\n  'lint',\n  'ci',\n  'dev',\n  'deploy',\n  'other',\n];\n\n// precomputed scope\nconst scopeComplete = execSync('git status --porcelain || true')\n  .toString()\n  .trim()\n  .split('\\n')\n  .find((r) => ~r.indexOf('M  src'))\n  ?.replace(/(\\/)/g, '%%')\n  ?.match(/src%%((\\w|-)*)/)?.[1]\n  ?.replace(/s$/, '');\n\n/**\n * @type {import('cz-git').UserConfig}\n */\nconst userConfig = {\n  extends: ['@commitlint/config-conventional'],\n  plugins: ['commitlint-plugin-function-rules'],\n  prompt: {\n    /** @use `pnpm commit :f` */\n    alias: {\n      b: 'build: bump dependencies',\n      c: 'chore: update config',\n      f: 'docs: fix typos',\n      r: 'docs: update README',\n      s: 'style: update code format',\n    },\n    allowCustomIssuePrefixs: false,\n    // scopes: [...scopes, 'mock'],\n    allowEmptyIssuePrefixs: false,\n    customScopesAlign: scopeComplete ? 'bottom' : 'top',\n    defaultScope: scopeComplete,\n    // English\n    typesAppend: [\n      { name: 'workflow: workflow improvements', value: 'workflow' },\n      { name: 'types:    type definition file changes', value: 'types' },\n    ],\n\n    // 中英文对照版\n    // messages: {\n    //   type: '选择你要提交的类型 :',\n    //   scope: '选择一个提交范围 (可选):',\n    //   customScope: '请输入自定义的提交范围 :',\n    //   subject: '填写简短精炼的变更描述 :\\n',\n    //   body: '填写更加详细的变更描述 (可选)。使用 \"|\" 换行 :\\n',\n    //   breaking: '列举非兼容性重大的变更 (可选)。使用 \"|\" 换行 :\\n',\n    //   footerPrefixsSelect: '选择关联issue前缀 (可选):',\n    //   customFooterPrefixs: '输入自定义issue前缀 :',\n    //   footer: '列举关联issue (可选) 例如: #31, #I3244 :\\n',\n    //   confirmCommit: '是否提交或修改commit ?',\n    // },\n    // types: [\n    //   { value: 'feat', name: 'feat:     新增功能' },\n    //   { value: 'fix', name: 'fix:      修复缺陷' },\n    //   { value: 'docs', name: 'docs:     文档变更' },\n    //   { value: 'style', name: 'style:    代码格式' },\n    //   { value: 'refactor', name: 'refactor: 代码重构' },\n    //   { value: 'perf', name: 'perf:     性能优化' },\n    //   { value: 'test', name: 'test:     添加疏漏测试或已有测试改动' },\n    //   { value: 'build', name: 'build:    构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },\n    //   { value: 'ci', name: 'ci:       修改 CI 配置、脚本' },\n    //   { value: 'revert', name: 'revert:   回滚 commit' },\n    //   { value: 'chore', name: 'chore:    对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },\n    //   { value: 'wip', name: 'wip:      正在开发中' },\n    //   { value: 'workflow', name: 'workflow: 工作流程改进' },\n    //   { value: 'types', name: 'types:    类型定义文件修改' },\n    // ],\n    // emptyScopesAlias: 'empty:      不填写',\n    // customScopesAlias: 'custom:     自定义',\n  },\n  rules: {\n    /**\n     * type[scope]: [function] description\n     *\n     * ^^^^^^^^^^^^^^ empty line.\n     * - Something here\n     */\n    'body-leading-blank': [2, 'always'],\n    /**\n     * type[scope]: [function] description\n     *\n     * - something here\n     *\n     * ^^^^^^^^^^^^^^\n     */\n    'footer-leading-blank': [1, 'always'],\n    /**\n     * type[scope]: [function] description\n     *      ^^^^^\n     */\n    'function-rules/scope-enum': [\n      2, // level: error\n      'always',\n      (parsed) => {\n        if (!parsed.scope || allowedScopes.includes(parsed.scope)) {\n          return [true];\n        }\n\n        return [false, `scope must be one of ${allowedScopes.join(', ')}`];\n      },\n    ],\n    /**\n     * type[scope]: [function] description [No more than 108 characters]\n     *      ^^^^^\n     */\n    'header-max-length': [2, 'always', 108],\n\n    'scope-enum': [0],\n    'subject-case': [0],\n    'subject-empty': [2, 'never'],\n    'type-empty': [2, 'never'],\n    /**\n     * type[scope]: [function] description\n     * ^^^^\n     */\n    'type-enum': [\n      2,\n      'always',\n      [\n        'feat',\n        'fix',\n        'perf',\n        'style',\n        'docs',\n        'test',\n        'refactor',\n        'build',\n        'ci',\n        'chore',\n        'revert',\n        'types',\n        'release',\n      ],\n    ],\n  },\n};\n\nexport default userConfig;\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/commitlint-config/package.json",
    "content": "{\n  \"name\": \"@vben/commitlint-config\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"internal/lint-configs/commitlint-config\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./index.mjs\",\n  \"module\": \"./index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./index.mjs\",\n      \"default\": \"./index.mjs\"\n    }\n  },\n  \"dependencies\": {\n    \"@commitlint/cli\": \"catalog:\",\n    \"@commitlint/config-conventional\": \"catalog:\",\n    \"@vben/node-utils\": \"workspace:*\",\n    \"commitlint-plugin-function-rules\": \"catalog:\",\n    \"cz-git\": \"catalog:\",\n    \"czg\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/package.json",
    "content": "{\n  \"name\": \"@vben/eslint-config\",\n  \"version\": \"5.0.0\",\n  \"private\": true,\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"internal/lint-configs/eslint-config\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"stub\": \"pnpm unbuild --stub\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.mjs\"\n    }\n  },\n  \"dependencies\": {\n    \"eslint-config-turbo\": \"catalog:\",\n    \"eslint-plugin-command\": \"catalog:\",\n    \"eslint-plugin-import-x\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"catalog:\",\n    \"@types/eslint\": \"catalog:\",\n    \"@typescript-eslint/eslint-plugin\": \"catalog:\",\n    \"@typescript-eslint/parser\": \"catalog:\",\n    \"eslint\": \"catalog:\",\n    \"eslint-plugin-eslint-comments\": \"catalog:\",\n    \"eslint-plugin-jsdoc\": \"catalog:\",\n    \"eslint-plugin-jsonc\": \"catalog:\",\n    \"eslint-plugin-n\": \"catalog:\",\n    \"eslint-plugin-no-only-tests\": \"catalog:\",\n    \"eslint-plugin-perfectionist\": \"catalog:\",\n    \"eslint-plugin-prettier\": \"catalog:\",\n    \"eslint-plugin-regexp\": \"catalog:\",\n    \"eslint-plugin-unicorn\": \"catalog:\",\n    \"eslint-plugin-unused-imports\": \"catalog:\",\n    \"eslint-plugin-vitest\": \"catalog:\",\n    \"eslint-plugin-vue\": \"catalog:\",\n    \"globals\": \"catalog:\",\n    \"jsonc-eslint-parser\": \"catalog:\",\n    \"vue-eslint-parser\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/command.ts",
    "content": "import createCommand from 'eslint-plugin-command/config';\n\nexport async function command() {\n  return [\n    {\n      // @ts-expect-error - no types\n      ...createCommand(),\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/comments.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function comments(): Promise<Linter.Config[]> {\n  const [pluginComments] = await Promise.all([\n    // @ts-expect-error - no types\n    interopDefault(import('eslint-plugin-eslint-comments')),\n  ] as const);\n\n  return [\n    {\n      plugins: {\n        'eslint-comments': pluginComments,\n      },\n      rules: {\n        'eslint-comments/no-aggregating-enable': 'error',\n        'eslint-comments/no-duplicate-disable': 'error',\n        'eslint-comments/no-unlimited-disable': 'error',\n        'eslint-comments/no-unused-enable': 'error',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/disableds.ts",
    "content": "import type { Linter } from 'eslint';\n\nexport async function disableds(): Promise<Linter.Config[]> {\n  return [\n    {\n      files: ['**/__tests__/**/*.?([cm])[jt]s?(x)'],\n      name: 'disables/test',\n      rules: {\n        '@typescript-eslint/ban-ts-comment': 'off',\n        'no-console': 'off',\n      },\n    },\n    {\n      files: ['**/*.d.ts'],\n      name: 'disables/dts',\n      rules: {\n        '@typescript-eslint/triple-slash-reference': 'off',\n      },\n    },\n    {\n      files: ['**/*.js', '**/*.mjs', '**/*.cjs'],\n      name: 'disables/js',\n      rules: {\n        '@typescript-eslint/explicit-module-boundary-types': 'off',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/ignores.ts",
    "content": "import type { Linter } from 'eslint';\n\nexport async function ignores(): Promise<Linter.Config[]> {\n  return [\n    {\n      ignores: [\n        '**/node_modules',\n        '**/dist',\n        '**/dist-*',\n        '**/*-dist',\n        '**/.husky',\n        '**/.nitro',\n        '**/.output',\n        '**/Dockerfile',\n        '**/package-lock.json',\n        '**/yarn.lock',\n        '**/pnpm-lock.yaml',\n        '**/bun.lockb',\n        '**/output',\n        '**/coverage',\n        '**/temp',\n        '**/.temp',\n        '**/tmp',\n        '**/.tmp',\n        '**/.history',\n        '**/.turbo',\n        '**/.nuxt',\n        '**/.next',\n        '**/.vercel',\n        '**/.changeset',\n        '**/.idea',\n        '**/.cache',\n        '**/.output',\n        '**/.vite-inspect',\n\n        '**/CHANGELOG*.md',\n        '**/*.min.*',\n        '**/LICENSE*',\n        '**/__snapshots__',\n        '**/*.snap',\n        '**/fixtures/**',\n        '**/.vitepress/cache/**',\n        '**/auto-import?(s).d.ts',\n        '**/components.d.ts',\n        '**/vite.config.mts.*',\n        '**/*.sh',\n        '**/*.ttf',\n        '**/*.woff',\n      ],\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/import.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport * as pluginImport from 'eslint-plugin-import-x';\n\nexport async function importPluginConfig(): Promise<Linter.Config[]> {\n  return [\n    {\n      plugins: {\n        // @ts-expect-error - This is a dynamic import\n        import: pluginImport,\n      },\n      rules: {\n        'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],\n        'import/first': 'error',\n        'import/newline-after-import': 'error',\n        'import/no-duplicates': 'error',\n        'import/no-mutable-exports': 'error',\n        'import/no-named-default': 'error',\n        'import/no-self-import': 'error',\n        'import/no-unresolved': 'off',\n        'import/no-webpack-loader-syntax': 'error',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/index.ts",
    "content": "export * from './command';\nexport * from './comments';\nexport * from './disableds';\nexport * from './ignores';\nexport * from './import';\nexport * from './javascript';\nexport * from './jsdoc';\nexport * from './jsonc';\nexport * from './node';\nexport * from './perfectionist';\nexport * from './prettier';\nexport * from './regexp';\nexport * from './test';\nexport * from './turbo';\nexport * from './typescript';\nexport * from './unicorn';\nexport * from './vue';\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/javascript.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport js from '@eslint/js';\nimport pluginUnusedImports from 'eslint-plugin-unused-imports';\nimport globals from 'globals';\n\nexport async function javascript(): Promise<Linter.Config[]> {\n  return [\n    {\n      languageOptions: {\n        ecmaVersion: 'latest',\n        globals: {\n          ...globals.browser,\n          ...globals.es2021,\n          ...globals.node,\n          document: 'readonly',\n          navigator: 'readonly',\n          window: 'readonly',\n        },\n        parserOptions: {\n          ecmaFeatures: {\n            jsx: true,\n          },\n          ecmaVersion: 'latest',\n          sourceType: 'module',\n        },\n        sourceType: 'module',\n      },\n      linterOptions: {\n        reportUnusedDisableDirectives: true,\n      },\n      plugins: {\n        'unused-imports': pluginUnusedImports,\n      },\n      rules: {\n        ...js.configs.recommended.rules,\n        'accessor-pairs': [\n          'error',\n          { enforceForClassMembers: true, setWithoutGet: true },\n        ],\n        'array-callback-return': 'error',\n        'block-scoped-var': 'error',\n        'constructor-super': 'error',\n        'default-case-last': 'error',\n        'dot-notation': ['error', { allowKeywords: true }],\n        eqeqeq: ['error', 'always'],\n        'keyword-spacing': 'off',\n\n        'new-cap': [\n          'error',\n          { capIsNew: false, newIsCap: true, properties: true },\n        ],\n        'no-alert': 'error',\n        'no-array-constructor': 'error',\n        'no-async-promise-executor': 'error',\n        'no-caller': 'error',\n        'no-case-declarations': 'error',\n        'no-class-assign': 'error',\n        'no-compare-neg-zero': 'error',\n        'no-cond-assign': ['error', 'always'],\n        'no-console': ['error', { allow: ['warn', 'error'] }],\n        'no-const-assign': 'error',\n        'no-control-regex': 'error',\n        'no-debugger': 'error',\n        'no-delete-var': 'error',\n        'no-dupe-args': 'error',\n        'no-dupe-class-members': 'error',\n        'no-dupe-keys': 'error',\n        'no-duplicate-case': 'error',\n        'no-empty': ['error', { allowEmptyCatch: true }],\n        'no-empty-character-class': 'error',\n        'no-empty-function': 'off',\n        'no-empty-pattern': 'error',\n        'no-eval': 'error',\n        'no-ex-assign': 'error',\n        'no-extend-native': 'error',\n        'no-extra-bind': 'error',\n        'no-extra-boolean-cast': 'error',\n        'no-fallthrough': 'error',\n        'no-func-assign': 'error',\n        'no-global-assign': 'error',\n        'no-implied-eval': 'error',\n        'no-import-assign': 'error',\n        'no-invalid-regexp': 'error',\n        'no-irregular-whitespace': 'error',\n        'no-iterator': 'error',\n        'no-labels': ['error', { allowLoop: false, allowSwitch: false }],\n        'no-lone-blocks': 'error',\n        'no-loss-of-precision': 'error',\n        'no-misleading-character-class': 'error',\n        'no-multi-str': 'error',\n        'no-new': 'error',\n        'no-new-func': 'error',\n        'no-new-object': 'error',\n        'no-new-symbol': 'error',\n        'no-new-wrappers': 'error',\n        'no-obj-calls': 'error',\n        'no-octal': 'error',\n        'no-octal-escape': 'error',\n        'no-proto': 'error',\n        'no-prototype-builtins': 'error',\n        'no-redeclare': ['error', { builtinGlobals: false }],\n        'no-regex-spaces': 'error',\n        'no-restricted-globals': [\n          'error',\n          { message: 'Use `globalThis` instead.', name: 'global' },\n          { message: 'Use `globalThis` instead.', name: 'self' },\n        ],\n        'no-restricted-properties': [\n          'error',\n          {\n            message:\n              'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.',\n            property: '__proto__',\n          },\n          {\n            message: 'Use `Object.defineProperty` instead.',\n            property: '__defineGetter__',\n          },\n          {\n            message: 'Use `Object.defineProperty` instead.',\n            property: '__defineSetter__',\n          },\n          {\n            message: 'Use `Object.getOwnPropertyDescriptor` instead.',\n            property: '__lookupGetter__',\n          },\n          {\n            message: 'Use `Object.getOwnPropertyDescriptor` instead.',\n            property: '__lookupSetter__',\n          },\n        ],\n        'no-restricted-syntax': [\n          'error',\n          'DebuggerStatement',\n          'LabeledStatement',\n          'WithStatement',\n          'TSEnumDeclaration[const=true]',\n          'TSExportAssignment',\n        ],\n        'no-self-assign': ['error', { props: true }],\n        'no-self-compare': 'error',\n        'no-sequences': 'error',\n        'no-shadow-restricted-names': 'error',\n        'no-sparse-arrays': 'error',\n        'no-template-curly-in-string': 'error',\n        'no-this-before-super': 'error',\n        'no-throw-literal': 'error',\n        'no-undef': 'off',\n        'no-undef-init': 'error',\n        'no-unexpected-multiline': 'error',\n        'no-unmodified-loop-condition': 'error',\n        'no-unneeded-ternary': ['error', { defaultAssignment: false }],\n        'no-unreachable': 'error',\n        'no-unreachable-loop': 'error',\n        'no-unsafe-finally': 'error',\n        'no-unsafe-negation': 'error',\n        'no-unused-expressions': [\n          'error',\n          {\n            allowShortCircuit: true,\n            allowTaggedTemplates: true,\n            allowTernary: true,\n          },\n        ],\n        'no-unused-vars': [\n          'error',\n          {\n            args: 'none',\n            caughtErrors: 'none',\n            ignoreRestSiblings: true,\n            vars: 'all',\n          },\n        ],\n        'no-use-before-define': [\n          'error',\n          { classes: false, functions: false, variables: false },\n        ],\n        'no-useless-backreference': 'error',\n        'no-useless-call': 'error',\n        'no-useless-catch': 'error',\n        'no-useless-computed-key': 'error',\n        'no-useless-constructor': 'error',\n        'no-useless-rename': 'error',\n        'no-useless-return': 'error',\n        'no-var': 'error',\n        'no-with': 'error',\n        'object-shorthand': [\n          'error',\n          'always',\n          { avoidQuotes: true, ignoreConstructors: false },\n        ],\n        'one-var': ['error', { initialized: 'never' }],\n        'prefer-arrow-callback': [\n          'error',\n          {\n            allowNamedFunctions: false,\n            allowUnboundThis: true,\n          },\n        ],\n        'prefer-const': [\n          'error',\n          {\n            destructuring: 'all',\n            ignoreReadBeforeAssign: true,\n          },\n        ],\n        'prefer-exponentiation-operator': 'error',\n\n        'prefer-promise-reject-errors': 'error',\n        'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],\n        'prefer-rest-params': 'error',\n        'prefer-spread': 'error',\n        'prefer-template': 'error',\n        'space-before-function-paren': 'off',\n        'spaced-comment': 'error',\n        'symbol-description': 'error',\n        'unicode-bom': ['error', 'never'],\n\n        'unused-imports/no-unused-imports': 'error',\n        'unused-imports/no-unused-vars': [\n          'error',\n          {\n            args: 'after-used',\n            argsIgnorePattern: '^_',\n            vars: 'all',\n            varsIgnorePattern: '^_',\n          },\n        ],\n        'use-isnan': [\n          'error',\n          { enforceForIndexOf: true, enforceForSwitchCase: true },\n        ],\n        'valid-typeof': ['error', { requireStringLiterals: true }],\n\n        'vars-on-top': 'error',\n        yoda: ['error', 'never'],\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/jsdoc.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function jsdoc(): Promise<Linter.Config[]> {\n  const [pluginJsdoc] = await Promise.all([\n    interopDefault(import('eslint-plugin-jsdoc')),\n  ] as const);\n\n  return [\n    {\n      plugins: {\n        jsdoc: pluginJsdoc,\n      },\n      rules: {\n        'jsdoc/check-access': 'warn',\n        'jsdoc/check-param-names': 'warn',\n        'jsdoc/check-property-names': 'warn',\n        'jsdoc/check-types': 'warn',\n        'jsdoc/empty-tags': 'warn',\n        'jsdoc/implements-on-classes': 'warn',\n        'jsdoc/no-defaults': 'warn',\n        'jsdoc/no-multi-asterisks': 'warn',\n        'jsdoc/require-param-name': 'warn',\n        'jsdoc/require-property': 'warn',\n        'jsdoc/require-property-description': 'warn',\n        'jsdoc/require-property-name': 'warn',\n        'jsdoc/require-returns-check': 'warn',\n        'jsdoc/require-returns-description': 'warn',\n        'jsdoc/require-yields-check': 'warn',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/jsonc.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function jsonc(): Promise<Linter.Config[]> {\n  const [pluginJsonc, parserJsonc] = await Promise.all([\n    interopDefault(import('eslint-plugin-jsonc')),\n    interopDefault(import('jsonc-eslint-parser')),\n  ] as const);\n\n  return [\n    {\n      files: ['**/*.json', '**/*.json5', '**/*.jsonc', '*.code-workspace'],\n      languageOptions: {\n        parser: parserJsonc as any,\n      },\n      plugins: {\n        jsonc: pluginJsonc as any,\n      },\n      rules: {\n        'jsonc/no-bigint-literals': 'error',\n        'jsonc/no-binary-expression': 'error',\n        'jsonc/no-binary-numeric-literals': 'error',\n        'jsonc/no-dupe-keys': 'error',\n        'jsonc/no-escape-sequence-in-identifier': 'error',\n        'jsonc/no-floating-decimal': 'error',\n        'jsonc/no-hexadecimal-numeric-literals': 'error',\n        'jsonc/no-infinity': 'error',\n        'jsonc/no-multi-str': 'error',\n        'jsonc/no-nan': 'error',\n        'jsonc/no-number-props': 'error',\n        'jsonc/no-numeric-separators': 'error',\n        'jsonc/no-octal': 'error',\n        'jsonc/no-octal-escape': 'error',\n        'jsonc/no-octal-numeric-literals': 'error',\n        'jsonc/no-parenthesized': 'error',\n        'jsonc/no-plus-sign': 'error',\n        'jsonc/no-regexp-literals': 'error',\n        'jsonc/no-sparse-arrays': 'error',\n        'jsonc/no-template-literals': 'error',\n        'jsonc/no-undefined-value': 'error',\n        'jsonc/no-unicode-codepoint-escapes': 'error',\n        'jsonc/no-useless-escape': 'error',\n        'jsonc/space-unary-ops': 'error',\n        'jsonc/valid-json-number': 'error',\n        'jsonc/vue-custom-block/no-parsing-error': 'error',\n      },\n    },\n    sortTsconfig(),\n    sortPackageJson(),\n  ];\n}\n\nfunction sortPackageJson(): Linter.Config {\n  return {\n    files: ['**/package.json'],\n    rules: {\n      'jsonc/sort-array-values': [\n        'error',\n        {\n          order: { type: 'asc' },\n          pathPattern: '^files$|^pnpm.neverBuiltDependencies$',\n        },\n      ],\n      'jsonc/sort-keys': [\n        'error',\n        {\n          order: [\n            'name',\n            'version',\n            'description',\n            'private',\n            'keywords',\n            'homepage',\n            'bugs',\n            'repository',\n            'license',\n            'author',\n            'contributors',\n            'categories',\n            'funding',\n            'type',\n            'scripts',\n            'files',\n            'sideEffects',\n            'bin',\n            'main',\n            'module',\n            'unpkg',\n            'jsdelivr',\n            'types',\n            'typesVersions',\n            'imports',\n            'exports',\n            'publishConfig',\n            'icon',\n            'activationEvents',\n            'contributes',\n            'peerDependencies',\n            'peerDependenciesMeta',\n            'dependencies',\n            'optionalDependencies',\n            'devDependencies',\n            'engines',\n            'packageManager',\n            'pnpm',\n            'overrides',\n            'resolutions',\n            'husky',\n            'simple-git-hooks',\n            'lint-staged',\n            'eslintConfig',\n          ],\n          pathPattern: '^$',\n        },\n        {\n          order: { type: 'asc' },\n          pathPattern: '^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$',\n        },\n        {\n          order: { type: 'asc' },\n          pathPattern: '^(?:resolutions|overrides|pnpm.overrides)$',\n        },\n        {\n          order: ['types', 'import', 'require', 'default'],\n          pathPattern: '^exports.*$',\n        },\n      ],\n    },\n  };\n}\n\nfunction sortTsconfig(): Linter.Config {\n  return {\n    files: [\n      '**/tsconfig.json',\n      '**/tsconfig.*.json',\n      'internal/tsconfig/*.json',\n    ],\n    rules: {\n      'jsonc/sort-keys': [\n        'error',\n        {\n          order: [\n            'extends',\n            'compilerOptions',\n            'references',\n            'files',\n            'include',\n            'exclude',\n          ],\n          pathPattern: '^$',\n        },\n        {\n          order: [\n            /* Projects */\n            'incremental',\n            'composite',\n            'tsBuildInfoFile',\n            'disableSourceOfProjectReferenceRedirect',\n            'disableSolutionSearching',\n            'disableReferencedProjectLoad',\n            /* Language and Environment */\n            'target',\n            'jsx',\n            'jsxFactory',\n            'jsxFragmentFactory',\n            'jsxImportSource',\n            'lib',\n            'moduleDetection',\n            'noLib',\n            'reactNamespace',\n            'useDefineForClassFields',\n            'emitDecoratorMetadata',\n            'experimentalDecorators',\n            /* Modules */\n            'baseUrl',\n            'rootDir',\n            'rootDirs',\n            'customConditions',\n            'module',\n            'moduleResolution',\n            'moduleSuffixes',\n            'noResolve',\n            'paths',\n            'resolveJsonModule',\n            'resolvePackageJsonExports',\n            'resolvePackageJsonImports',\n            'typeRoots',\n            'types',\n            'allowArbitraryExtensions',\n            'allowImportingTsExtensions',\n            'allowUmdGlobalAccess',\n            /* JavaScript Support */\n            'allowJs',\n            'checkJs',\n            'maxNodeModuleJsDepth',\n            /* Type Checking */\n            'strict',\n            'strictBindCallApply',\n            'strictFunctionTypes',\n            'strictNullChecks',\n            'strictPropertyInitialization',\n            'allowUnreachableCode',\n            'allowUnusedLabels',\n            'alwaysStrict',\n            'exactOptionalPropertyTypes',\n            'noFallthroughCasesInSwitch',\n            'noImplicitAny',\n            'noImplicitOverride',\n            'noImplicitReturns',\n            'noImplicitThis',\n            'noPropertyAccessFromIndexSignature',\n            'noUncheckedIndexedAccess',\n            'noUnusedLocals',\n            'noUnusedParameters',\n            'useUnknownInCatchVariables',\n            /* Emit */\n            'declaration',\n            'declarationDir',\n            'declarationMap',\n            'downlevelIteration',\n            'emitBOM',\n            'emitDeclarationOnly',\n            'importHelpers',\n            'importsNotUsedAsValues',\n            'inlineSourceMap',\n            'inlineSources',\n            'mapRoot',\n            'newLine',\n            'noEmit',\n            'noEmitHelpers',\n            'noEmitOnError',\n            'outDir',\n            'outFile',\n            'preserveConstEnums',\n            'preserveValueImports',\n            'removeComments',\n            'sourceMap',\n            'sourceRoot',\n            'stripInternal',\n            /* Interop Constraints */\n            'allowSyntheticDefaultImports',\n            'esModuleInterop',\n            'forceConsistentCasingInFileNames',\n            'isolatedModules',\n            'preserveSymlinks',\n            'verbatimModuleSyntax',\n            /* Completeness */\n            'skipDefaultLibCheck',\n            'skipLibCheck',\n          ],\n          pathPattern: '^compilerOptions$',\n        },\n      ],\n    },\n  };\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/node.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function node(): Promise<Linter.Config[]> {\n  const pluginNode = await interopDefault(import('eslint-plugin-n'));\n\n  return [\n    {\n      plugins: {\n        n: pluginNode,\n      },\n      rules: {\n        'n/handle-callback-err': ['error', '^(err|error)$'],\n        'n/no-deprecated-api': 'error',\n        'n/no-exports-assign': 'error',\n        'n/no-extraneous-import': [\n          'error',\n          {\n            allowModules: [\n              'unbuild',\n              '@vben/vite-config',\n              'vitest',\n              'vite',\n              '@vue/test-utils',\n              '@vben/tailwind-config',\n              '@playwright/test',\n            ],\n          },\n        ],\n        'n/no-new-require': 'error',\n        'n/no-path-concat': 'error',\n        // 'n/no-unpublished-import': 'off',\n        'n/no-unsupported-features/es-syntax': [\n          'error',\n          {\n            ignores: [],\n            version: '>=18.0.0',\n          },\n        ],\n        'n/prefer-global/buffer': ['error', 'never'],\n        // 'n/no-missing-import': 'off',\n        'n/prefer-global/process': ['error', 'never'],\n        'n/process-exit-as-throw': 'error',\n      },\n    },\n    {\n      files: [\n        'scripts/**/*.?([cm])[jt]s?(x)',\n        'internal/**/*.?([cm])[jt]s?(x)',\n      ],\n      rules: {\n        'n/prefer-global/process': 'off',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/perfectionist.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function perfectionist(): Promise<Linter.Config[]> {\n  const perfectionistPlugin = await interopDefault(\n    // @ts-expect-error - no types\n    import('eslint-plugin-perfectionist'),\n  );\n\n  return [\n    perfectionistPlugin.configs['recommended-natural'],\n    {\n      rules: {\n        'perfectionist/sort-exports': [\n          'error',\n          {\n            order: 'asc',\n            type: 'natural',\n          },\n        ],\n        'perfectionist/sort-imports': [\n          'error',\n          {\n            customGroups: {\n              type: {\n                'vben-core-type': ['^@vben-core/.+'],\n                'vben-type': ['^@vben/.+'],\n                'vue-type': ['^vue$', '^vue-.+', '^@vue/.+'],\n              },\n              value: {\n                vben: ['^@vben/.+'],\n                'vben-core': ['^@vben-core/.+'],\n                vue: ['^vue$', '^vue-.+', '^@vue/.+'],\n              },\n            },\n            environment: 'node',\n            groups: [\n              ['external-type', 'builtin-type', 'type'],\n              'vue-type',\n              'vben-type',\n              'vben-core-type',\n              ['parent-type', 'sibling-type', 'index-type'],\n              ['internal-type'],\n              'builtin',\n              'vue',\n              'vben',\n              'vben-core',\n              'external',\n              'internal',\n              ['parent', 'sibling', 'index'],\n              'side-effect',\n              'side-effect-style',\n              'style',\n              'object',\n              'unknown',\n            ],\n            internalPattern: ['^#/.+'],\n            newlinesBetween: 'always',\n            order: 'asc',\n            type: 'natural',\n          },\n        ],\n        'perfectionist/sort-modules': 'off',\n        'perfectionist/sort-named-exports': [\n          'error',\n          {\n            order: 'asc',\n            type: 'natural',\n          },\n        ],\n        'perfectionist/sort-objects': [\n          'off',\n          {\n            customGroups: {\n              items: 'items',\n              list: 'list',\n              children: 'children',\n            },\n            groups: ['unknown', 'items', 'list', 'children'],\n            ignorePattern: ['children'],\n            order: 'asc',\n            type: 'natural',\n          },\n        ],\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/prettier.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function prettier(): Promise<Linter.Config[]> {\n  const [pluginPrettier] = await Promise.all([\n    interopDefault(import('eslint-plugin-prettier')),\n  ] as const);\n  return [\n    {\n      plugins: {\n        prettier: pluginPrettier,\n      },\n      rules: {\n        'prettier/prettier': 'error',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/regexp.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function regexp(): Promise<Linter.Config[]> {\n  const [pluginRegexp] = await Promise.all([\n    interopDefault(import('eslint-plugin-regexp')),\n  ] as const);\n\n  return [\n    {\n      plugins: {\n        regexp: pluginRegexp,\n      },\n      rules: {\n        ...pluginRegexp.configs.recommended.rules,\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/test.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function test(): Promise<Linter.Config[]> {\n  const [pluginTest, pluginNoOnlyTests] = await Promise.all([\n    interopDefault(import('eslint-plugin-vitest')),\n    // @ts-expect-error - no types\n    interopDefault(import('eslint-plugin-no-only-tests')),\n  ] as const);\n\n  return [\n    {\n      files: [\n        `**/__tests__/**/*.?([cm])[jt]s?(x)`,\n        `**/*.spec.?([cm])[jt]s?(x)`,\n        `**/*.test.?([cm])[jt]s?(x)`,\n        `**/*.bench.?([cm])[jt]s?(x)`,\n        `**/*.benchmark.?([cm])[jt]s?(x)`,\n      ],\n      plugins: {\n        test: {\n          ...pluginTest,\n          rules: {\n            ...pluginTest.rules,\n            ...pluginNoOnlyTests.rules,\n          },\n        },\n      },\n      rules: {\n        'no-console': 'off',\n        'node/prefer-global/process': 'off',\n        'test/consistent-test-it': [\n          'error',\n          { fn: 'it', withinDescribe: 'it' },\n        ],\n        'test/no-identical-title': 'error',\n        'test/no-import-node-test': 'error',\n        'test/no-only-tests': 'error',\n        'test/prefer-hooks-in-order': 'error',\n        'test/prefer-lowercase-title': 'error',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/turbo.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function turbo(): Promise<Linter.Config[]> {\n  const [pluginTurbo] = await Promise.all([\n    // @ts-expect-error - no types\n    interopDefault(import('eslint-config-turbo')),\n  ] as const);\n\n  return [\n    {\n      plugins: {\n        turbo: pluginTurbo,\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/typescript.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function typescript(): Promise<Linter.Config[]> {\n  const [pluginTs, parserTs] = await Promise.all([\n    interopDefault(import('@typescript-eslint/eslint-plugin')),\n    // @ts-expect-error missing types\n    interopDefault(import('@typescript-eslint/parser')),\n  ] as const);\n\n  return [\n    {\n      files: ['**/*.?([cm])[jt]s?(x)'],\n      languageOptions: {\n        parser: parserTs,\n        parserOptions: {\n          createDefaultProgram: false,\n          ecmaFeatures: {\n            jsx: true,\n          },\n          ecmaVersion: 'latest',\n          extraFileExtensions: ['.vue'],\n          jsxPragma: 'React',\n          project: './tsconfig.*.json',\n          sourceType: 'module',\n        },\n      },\n      plugins: {\n        '@typescript-eslint': pluginTs,\n      },\n      rules: {\n        ...pluginTs.configs['eslint-recommended'].overrides?.[0].rules,\n        ...pluginTs.configs.strict.rules,\n        '@typescript-eslint/ban-ts-comment': [\n          'error',\n          {\n            'ts-check': false,\n            'ts-expect-error': 'allow-with-description',\n            'ts-ignore': 'allow-with-description',\n            'ts-nocheck': 'allow-with-description',\n          },\n        ],\n\n        // '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],\n        '@typescript-eslint/consistent-type-definitions': 'off',\n        '@typescript-eslint/explicit-function-return-type': 'off',\n        '@typescript-eslint/explicit-module-boundary-types': 'off',\n        '@typescript-eslint/no-empty-function': [\n          'error',\n          {\n            allow: ['arrowFunctions', 'functions', 'methods'],\n          },\n        ],\n        '@typescript-eslint/no-explicit-any': 'off',\n        '@typescript-eslint/no-namespace': 'off',\n        '@typescript-eslint/no-non-null-assertion': 'error',\n        '@typescript-eslint/no-unused-expressions': 'off',\n        '@typescript-eslint/no-unused-vars': [\n          'error',\n          {\n            argsIgnorePattern: '^_',\n            varsIgnorePattern: '^_',\n          },\n        ],\n        '@typescript-eslint/no-use-before-define': 'off',\n        '@typescript-eslint/no-var-requires': 'error',\n        'unused-imports/no-unused-vars': 'off',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/unicorn.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function unicorn(): Promise<Linter.Config[]> {\n  const [pluginUnicorn] = await Promise.all([\n    interopDefault(import('eslint-plugin-unicorn')),\n  ] as const);\n\n  return [\n    {\n      plugins: {\n        unicorn: pluginUnicorn,\n      },\n      rules: {\n        ...pluginUnicorn.configs.recommended.rules,\n\n        'unicorn/better-regex': 'off',\n        'unicorn/consistent-destructuring': 'off',\n        'unicorn/consistent-function-scoping': 'off',\n        'unicorn/expiring-todo-comments': 'off',\n        'unicorn/filename-case': 'off',\n        'unicorn/import-style': 'off',\n        'unicorn/no-array-for-each': 'off',\n        'unicorn/no-null': 'off',\n        'unicorn/no-useless-undefined': 'off',\n        'unicorn/prefer-at': 'off',\n        'unicorn/prefer-dom-node-text-content': 'off',\n        'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],\n        'unicorn/prefer-global-this': 'off',\n        'unicorn/prefer-top-level-await': 'off',\n        'unicorn/prevent-abbreviations': 'off',\n      },\n    },\n    {\n      files: [\n        'scripts/**/*.?([cm])[jt]s?(x)',\n        'internal/**/*.?([cm])[jt]s?(x)',\n      ],\n      rules: {\n        'unicorn/no-process-exit': 'off',\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/configs/vue.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport { interopDefault } from '../util';\n\nexport async function vue(): Promise<Linter.Config[]> {\n  const [pluginVue, parserVue, parserTs] = await Promise.all([\n    interopDefault(import('eslint-plugin-vue')),\n    interopDefault(import('vue-eslint-parser')),\n    // @ts-expect-error missing types\n    interopDefault(import('@typescript-eslint/parser')),\n  ] as const);\n\n  const flatEssential = pluginVue.configs?.['flat/essential'] || [];\n  const flatStronglyRecommended =\n    pluginVue.configs?.['flat/strongly-recommended'] || [];\n  const flatRecommended = pluginVue.configs?.['flat/recommended'] || [];\n\n  return [\n    ...flatEssential,\n    ...flatStronglyRecommended,\n    ...flatRecommended,\n    {\n      files: ['**/*.vue'],\n      languageOptions: {\n        // globals: {\n        //   computed: 'readonly',\n        //   defineEmits: 'readonly',\n        //   defineExpose: 'readonly',\n        //   defineProps: 'readonly',\n        //   onMounted: 'readonly',\n        //   onUnmounted: 'readonly',\n        //   reactive: 'readonly',\n        //   ref: 'readonly',\n        //   shallowReactive: 'readonly',\n        //   shallowRef: 'readonly',\n        //   toRef: 'readonly',\n        //   toRefs: 'readonly',\n        //   watch: 'readonly',\n        //   watchEffect: 'readonly',\n        // },\n        parser: parserVue,\n        parserOptions: {\n          ecmaFeatures: {\n            jsx: true,\n          },\n          extraFileExtensions: ['.vue'],\n          parser: parserTs,\n          sourceType: 'module',\n        },\n      },\n      plugins: {\n        vue: pluginVue,\n      },\n      processor: pluginVue.processors?.['.vue'],\n      rules: {\n        ...pluginVue.configs?.base?.rules,\n\n        'vue/attribute-hyphenation': [\n          'error',\n          'always',\n          {\n            ignore: [],\n          },\n        ],\n        'vue/attributes-order': 'off',\n        'vue/block-order': [\n          'error',\n          {\n            order: ['script', 'template', 'style'],\n          },\n        ],\n        'vue/component-name-in-template-casing': ['error', 'PascalCase'],\n        'vue/component-options-name-casing': ['error', 'PascalCase'],\n        'vue/custom-event-name-casing': ['error', 'camelCase'],\n        'vue/define-macros-order': [\n          'error',\n          {\n            order: [\n              'defineOptions',\n              'defineProps',\n              'defineEmits',\n              'defineSlots',\n            ],\n          },\n        ],\n        'vue/dot-location': ['error', 'property'],\n        'vue/dot-notation': ['error', { allowKeywords: true }],\n        'vue/eqeqeq': ['error', 'smart'],\n        'vue/html-closing-bracket-newline': 'error',\n        'vue/html-indent': 'off',\n        // 'vue/html-indent': ['error', 2],\n        'vue/html-quotes': ['error', 'double'],\n        'vue/html-self-closing': [\n          'error',\n          {\n            html: {\n              component: 'always',\n              normal: 'never',\n              void: 'always',\n            },\n            math: 'always',\n            svg: 'always',\n          },\n        ],\n        'vue/max-attributes-per-line': 'off',\n        'vue/multi-word-component-names': 'off',\n        'vue/multiline-html-element-content-newline': 'error',\n        'vue/no-empty-pattern': 'error',\n        'vue/no-extra-parens': ['error', 'functions'],\n        'vue/no-irregular-whitespace': 'error',\n        'vue/no-loss-of-precision': 'error',\n        'vue/no-reserved-component-names': 'off',\n        'vue/no-restricted-syntax': [\n          'error',\n          'DebuggerStatement',\n          'LabeledStatement',\n          'WithStatement',\n        ],\n        'vue/no-restricted-v-bind': ['error', '/^v-/'],\n        'vue/no-sparse-arrays': 'error',\n        'vue/no-unused-refs': 'error',\n        'vue/no-useless-v-bind': 'error',\n        'vue/object-shorthand': [\n          'error',\n          'always',\n          {\n            avoidQuotes: true,\n            ignoreConstructors: false,\n          },\n        ],\n        'vue/one-component-per-file': 'error',\n        'vue/prefer-import-from-vue': 'error',\n        'vue/prefer-separate-static-class': 'error',\n        'vue/prefer-template': 'error',\n        'vue/prop-name-casing': ['error', 'camelCase'],\n        'vue/require-default-prop': 'error',\n        'vue/require-explicit-emits': 'error',\n        'vue/require-prop-types': 'off',\n        'vue/singleline-html-element-content-newline': 'off',\n        'vue/space-infix-ops': 'error',\n        'vue/space-unary-ops': ['error', { nonwords: false, words: true }],\n        'vue/v-on-event-hyphenation': [\n          'error',\n          'always',\n          {\n            autofix: true,\n            ignore: [],\n          },\n        ],\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/custom-config.ts",
    "content": "import type { Linter } from 'eslint';\n\nconst restrictedImportIgnores = [\n  '**/vite.config.mts',\n  '**/tailwind.config.mjs',\n  '**/postcss.config.mjs',\n];\n\nconst customConfig: Linter.Config[] = [\n  // shadcn-ui 内部组件是自动生成的，不做太多限制\n  {\n    files: ['packages/@core/ui-kit/shadcn-ui/**/**'],\n    rules: {\n      'vue/require-default-prop': 'off',\n    },\n  },\n  {\n    files: [\n      'apps/**/**',\n      'packages/effects/**/**',\n      'packages/utils/**/**',\n      'packages/types/**/**',\n      'packages/locales/**/**',\n    ],\n    ignores: restrictedImportIgnores,\n    rules: {\n      'perfectionist/sort-interfaces': 'off',\n      'perfectionist/sort-objects': 'off',\n    },\n  },\n  {\n    files: ['**/**.vue'],\n    ignores: restrictedImportIgnores,\n    rules: {\n      'perfectionist/sort-objects': 'off',\n    },\n  },\n  {\n    // apps内部的一些基础规则\n    files: ['apps/**/**'],\n    ignores: restrictedImportIgnores,\n    rules: {\n      'no-restricted-imports': [\n        'error',\n        {\n          patterns: [\n            {\n              group: ['#/api/*'],\n              message:\n                'The #/api package cannot be imported, please use the @core package itself',\n            },\n            {\n              group: ['#/layouts/*'],\n              message:\n                'The #/layouts package cannot be imported, please use the @core package itself',\n            },\n            {\n              group: ['#/locales/*'],\n              message:\n                'The #/locales package cannot be imported, please use the @core package itself',\n            },\n            {\n              group: ['#/stores/*'],\n              message:\n                'The #/stores package cannot be imported, please use the @core package itself',\n            },\n          ],\n        },\n      ],\n      'perfectionist/sort-interfaces': 'off',\n    },\n  },\n  {\n    // @core内部组件，不能引入@vben/* 里面的包\n    files: ['packages/@core/**/**'],\n    ignores: restrictedImportIgnores,\n    rules: {\n      'no-restricted-imports': [\n        'error',\n        {\n          patterns: [\n            {\n              group: ['@vben/*'],\n              message:\n                'The @core package cannot import the @vben package, please use the @core package itself',\n            },\n          ],\n        },\n      ],\n    },\n  },\n  {\n    // @core/shared内部组件，不能引入@vben/* 或者 @vben-core/* 里面的包\n    files: ['packages/@core/base/**/**'],\n    ignores: restrictedImportIgnores,\n    rules: {\n      'no-restricted-imports': [\n        'error',\n        {\n          patterns: [\n            {\n              group: ['@vben/*', '@vben-core/*'],\n              message:\n                'The @vben-core/shared package cannot import the @vben package, please use the @core/shared package itself',\n            },\n          ],\n        },\n      ],\n    },\n  },\n\n  {\n    // 不能引入@vben/*里面的包\n    files: [\n      'packages/types/**/**',\n      'packages/utils/**/**',\n      'packages/icons/**/**',\n      'packages/constants/**/**',\n      'packages/styles/**/**',\n      'packages/stores/**/**',\n      'packages/preferences/**/**',\n      'packages/locales/**/**',\n    ],\n    ignores: restrictedImportIgnores,\n    rules: {\n      'no-restricted-imports': [\n        'error',\n        {\n          patterns: [\n            {\n              group: ['@vben/*'],\n              message:\n                'The @vben package cannot be imported, please use the @core package itself',\n            },\n          ],\n        },\n      ],\n    },\n  },\n  // 后端模拟代码，不需要太多规则\n  {\n    files: ['apps/backend-mock/**/**', 'docs/**/**'],\n    rules: {\n      '@typescript-eslint/no-extraneous-class': 'off',\n      'n/no-extraneous-import': 'off',\n      'n/prefer-global/buffer': 'off',\n      'n/prefer-global/process': 'off',\n      'no-console': 'off',\n      'unicorn/prefer-module': 'off',\n    },\n  },\n  {\n    files: ['**/**/playwright.config.ts'],\n    rules: {\n      'n/prefer-global/buffer': 'off',\n      'n/prefer-global/process': 'off',\n      'no-console': 'off',\n    },\n  },\n  {\n    files: ['internal/**/**', 'scripts/**/**'],\n    rules: {\n      'no-console': 'off',\n    },\n  },\n];\n\nexport { customConfig };\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/index.ts",
    "content": "import type { Linter } from 'eslint';\n\nimport {\n  command,\n  comments,\n  disableds,\n  ignores,\n  importPluginConfig,\n  javascript,\n  jsdoc,\n  jsonc,\n  node,\n  perfectionist,\n  prettier,\n  regexp,\n  test,\n  turbo,\n  typescript,\n  unicorn,\n  vue,\n} from './configs';\nimport { customConfig } from './custom-config';\n\ntype FlatConfig = Linter.Config;\n\ntype FlatConfigPromise =\n  | FlatConfig\n  | FlatConfig[]\n  | Promise<FlatConfig>\n  | Promise<FlatConfig[]>;\n\nasync function defineConfig(config: FlatConfig[] = []) {\n  const configs: FlatConfigPromise[] = [\n    vue(),\n    javascript(),\n    ignores(),\n    prettier(),\n    typescript(),\n    jsonc(),\n    disableds(),\n    importPluginConfig(),\n    node(),\n    perfectionist(),\n    comments(),\n    jsdoc(),\n    unicorn(),\n    test(),\n    regexp(),\n    command(),\n    turbo(),\n    ...customConfig,\n    ...config,\n  ];\n\n  const resolved = await Promise.all(configs);\n\n  return resolved.flat();\n}\n\nexport { defineConfig };\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/src/util.ts",
    "content": "export type Awaitable<T> = Promise<T> | T;\n\nexport async function interopDefault<T>(\n  m: Awaitable<T>,\n): Promise<T extends { default: infer U } ? U : T> {\n  const resolved = await m;\n  return (resolved as any).default || resolved;\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/eslint-config/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/prettier-config/index.mjs",
    "content": "export default {\n  endOfLine: 'auto',\n  overrides: [\n    {\n      files: ['*.json5'],\n      options: {\n        quoteProps: 'preserve',\n        singleQuote: false,\n      },\n    },\n  ],\n  plugins: ['prettier-plugin-tailwindcss'],\n  printWidth: 80,\n  proseWrap: 'never',\n  semi: true,\n  singleQuote: true,\n  trailingComma: 'all',\n};\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/prettier-config/package.json",
    "content": "{\n  \"name\": \"@vben/prettier-config\",\n  \"version\": \"5.0.0\",\n  \"private\": true,\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"internal/lint-configs/prettier-config\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./index.mjs\",\n  \"module\": \"./index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"default\": \"./index.mjs\"\n    }\n  },\n  \"dependencies\": {\n    \"prettier\": \"catalog:\",\n    \"prettier-plugin-tailwindcss\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/stylelint-config/index.mjs",
    "content": "export default {\n  extends: ['stylelint-config-standard', 'stylelint-config-recess-order'],\n  ignoreFiles: [\n    '**/*.js',\n    '**/*.jsx',\n    '**/*.tsx',\n    '**/*.ts',\n    '**/*.json',\n    '**/*.md',\n  ],\n  overrides: [\n    {\n      customSyntax: 'postcss-html',\n      files: ['*.(html|vue)', '**/*.(html|vue)'],\n      rules: {\n        'selector-pseudo-class-no-unknown': [\n          true,\n          {\n            ignorePseudoClasses: ['global', 'deep'],\n          },\n        ],\n        'selector-pseudo-element-no-unknown': [\n          true,\n          {\n            ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'],\n          },\n        ],\n      },\n    },\n    {\n      customSyntax: 'postcss-scss',\n      extends: [\n        'stylelint-config-recommended-scss',\n        'stylelint-config-recommended-vue/scss',\n      ],\n      files: ['*.scss', '**/*.scss'],\n    },\n  ],\n  plugins: [\n    'stylelint-order',\n    '@stylistic/stylelint-plugin',\n    'stylelint-prettier',\n    'stylelint-scss',\n  ],\n  rules: {\n    'at-rule-no-deprecated': null,\n    'at-rule-no-unknown': [\n      true,\n      {\n        ignoreAtRules: [\n          'extends',\n          'ignores',\n          'include',\n          'mixin',\n          'if',\n          'else',\n          'media',\n          'for',\n          'at-root',\n          'tailwind',\n          'apply',\n          'variants',\n          'responsive',\n          'screen',\n          'function',\n          'each',\n          'use',\n          'forward',\n          'return',\n        ],\n      },\n    ],\n    'font-family-no-missing-generic-family-keyword': null,\n    'function-no-unknown': null,\n    'import-notation': null,\n    'media-feature-range-notation': null,\n    'named-grid-areas-no-invalid': null,\n    'no-descending-specificity': null,\n    'no-empty-source': null,\n    'order/order': [\n      [\n        'dollar-variables',\n        'custom-properties',\n        'at-rules',\n        'declarations',\n        {\n          name: 'supports',\n          type: 'at-rule',\n        },\n        {\n          name: 'media',\n          type: 'at-rule',\n        },\n        {\n          name: 'include',\n          type: 'at-rule',\n        },\n        'rules',\n      ],\n      { severity: 'error' },\n    ],\n    'prettier/prettier': true,\n    'rule-empty-line-before': [\n      'always',\n      {\n        ignore: ['after-comment', 'first-nested'],\n      },\n    ],\n    'scss/at-rule-no-unknown': [\n      true,\n      {\n        ignoreAtRules: [\n          'extends',\n          'ignores',\n          'include',\n          'mixin',\n          'if',\n          'else',\n          'media',\n          'for',\n          'at-root',\n          'tailwind',\n          'apply',\n          'variants',\n          'responsive',\n          'screen',\n          'function',\n          'each',\n          'use',\n          'forward',\n          'return',\n        ],\n      },\n    ],\n    'scss/operator-no-newline-after': null,\n    'selector-class-pattern':\n      '^(?:(?:o|c|u|t|s|is|has|_|js|qa)-)?[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*(?:__[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:--[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:[.+])?$',\n\n    'selector-not-notation': null,\n  },\n};\n"
  },
  {
    "path": "hiauth-front/internal/lint-configs/stylelint-config/package.json",
    "content": "{\n  \"name\": \"@vben/stylelint-config\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"internal/lint-configs/stylelint-config\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./index.mjs\",\n  \"module\": \"./index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./index.mjs\",\n      \"default\": \"./index.mjs\"\n    }\n  },\n  \"dependencies\": {\n    \"@stylistic/stylelint-plugin\": \"catalog:\",\n    \"stylelint-config-recess-order\": \"catalog:\",\n    \"stylelint-scss\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"postcss\": \"catalog:\",\n    \"postcss-html\": \"catalog:\",\n    \"postcss-scss\": \"catalog:\",\n    \"prettier\": \"catalog:\",\n    \"stylelint\": \"catalog:\",\n    \"stylelint-config-recommended\": \"catalog:\",\n    \"stylelint-config-recommended-scss\": \"catalog:\",\n    \"stylelint-config-recommended-vue\": \"catalog:\",\n    \"stylelint-config-standard\": \"catalog:\",\n    \"stylelint-order\": \"catalog:\",\n    \"stylelint-prettier\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/package.json",
    "content": "{\n  \"name\": \"@vben/node-utils\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"internal/node-utils\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"stub\": \"pnpm unbuild --stub\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"import\": \"./dist/index.mjs\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"dependencies\": {\n    \"@changesets/git\": \"catalog:\",\n    \"@manypkg/get-packages\": \"catalog:\",\n    \"chalk\": \"catalog:\",\n    \"consola\": \"catalog:\",\n    \"dayjs\": \"catalog:\",\n    \"execa\": \"catalog:\",\n    \"find-up\": \"catalog:\",\n    \"ora\": \"catalog:\",\n    \"pkg-types\": \"catalog:\",\n    \"prettier\": \"catalog:\",\n    \"rimraf\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/__tests__/hash.test.ts",
    "content": "import { createHash } from 'node:crypto';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { generatorContentHash } from '../hash';\n\ndescribe('generatorContentHash', () => {\n  it('should generate an MD5 hash for the content', () => {\n    const content = 'example content';\n    const expectedHash = createHash('md5')\n      .update(content, 'utf8')\n      .digest('hex');\n    const actualHash = generatorContentHash(content);\n    expect(actualHash).toBe(expectedHash);\n  });\n\n  it('should generate an MD5 hash with specified length', () => {\n    const content = 'example content';\n    const hashLength = 10;\n    const generatedHash = generatorContentHash(content, hashLength);\n    expect(generatedHash).toHaveLength(hashLength);\n  });\n\n  it('should correctly generate the hash with specified length', () => {\n    const content = 'example content';\n    const hashLength = 8;\n    const expectedHash = createHash('md5')\n      .update(content, 'utf8')\n      .digest('hex')\n      .slice(0, hashLength);\n    const generatedHash = generatorContentHash(content, hashLength);\n    expect(generatedHash).toBe(expectedHash);\n  });\n\n  it('should return full hash if hash length parameter is not provided', () => {\n    const content = 'example content';\n    const expectedHash = createHash('md5')\n      .update(content, 'utf8')\n      .digest('hex');\n    const actualHash = generatorContentHash(content);\n    expect(actualHash).toBe(expectedHash);\n  });\n\n  it('should handle empty content', () => {\n    const content = '';\n    const expectedHash = createHash('md5')\n      .update(content, 'utf8')\n      .digest('hex');\n    const actualHash = generatorContentHash(content);\n    expect(actualHash).toBe(expectedHash);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/__tests__/path.test.ts",
    "content": "// pathUtils.test.ts\n\nimport { describe, expect, it } from 'vitest';\n\nimport { toPosixPath } from '../path';\n\ndescribe('toPosixPath', () => {\n  // 测试 Windows 风格路径到 POSIX 风格路径的转换\n  it('converts Windows-style paths to POSIX paths', () => {\n    const windowsPath = String.raw`C:\\Users\\Example\\file.txt`;\n    const expectedPosixPath = 'C:/Users/Example/file.txt';\n    expect(toPosixPath(windowsPath)).toBe(expectedPosixPath);\n  });\n\n  // 确认 POSIX 风格路径不会被改变\n  it('leaves POSIX-style paths unchanged', () => {\n    const posixPath = '/home/user/file.txt';\n    expect(toPosixPath(posixPath)).toBe(posixPath);\n  });\n\n  // 测试带有多个分隔符的路径\n  it('converts paths with mixed separators', () => {\n    const mixedPath = String.raw`C:/Users\\Example\\file.txt`;\n    const expectedPosixPath = 'C:/Users/Example/file.txt';\n    expect(toPosixPath(mixedPath)).toBe(expectedPosixPath);\n  });\n\n  // 测试空字符串\n  it('handles empty strings', () => {\n    const emptyPath = '';\n    expect(toPosixPath(emptyPath)).toBe('');\n  });\n\n  // 测试仅包含分隔符的路径\n  it('handles path with only separators', () => {\n    const separatorsPath = '\\\\\\\\\\\\';\n    const expectedPosixPath = '///';\n    expect(toPosixPath(separatorsPath)).toBe(expectedPosixPath);\n  });\n\n  // 测试不包含任何分隔符的路径\n  it('handles path without separators', () => {\n    const noSeparatorPath = 'file.txt';\n    expect(toPosixPath(noSeparatorPath)).toBe('file.txt');\n  });\n\n  // 测试以分隔符结尾的路径\n  it('handles path ending with a separator', () => {\n    const endingSeparatorPath = 'C:\\\\Users\\\\Example\\\\';\n    const expectedPosixPath = 'C:/Users/Example/';\n    expect(toPosixPath(endingSeparatorPath)).toBe(expectedPosixPath);\n  });\n\n  // 测试以分隔符开头的路径\n  it('handles path starting with a separator', () => {\n    const startingSeparatorPath = String.raw`\\Users\\Example`;\n    const expectedPosixPath = '/Users/Example';\n    expect(toPosixPath(startingSeparatorPath)).toBe(expectedPosixPath);\n  });\n\n  // 测试包含非法字符的路径\n  it('handles path with invalid characters', () => {\n    const invalidCharsPath = String.raw`C:\\Us*?ers\\Ex<ample>|file.txt`;\n    const expectedPosixPath = 'C:/Us*?ers/Ex<ample>|file.txt';\n    expect(toPosixPath(invalidCharsPath)).toBe(expectedPosixPath);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/constants.ts",
    "content": "enum UNICODE {\n  FAILURE = '\\u2716', // ✖\n  SUCCESS = '\\u2714', // ✔\n}\n\nexport { UNICODE };\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/date.ts",
    "content": "import dayjs from 'dayjs';\nimport timezone from 'dayjs/plugin/timezone';\nimport utc from 'dayjs/plugin/utc';\n\ndayjs.extend(utc);\ndayjs.extend(timezone);\n\ndayjs.tz.setDefault('Asia/Shanghai');\n\nconst dateUtil = dayjs;\n\nexport { dateUtil };\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/fs.ts",
    "content": "import { promises as fs } from 'node:fs';\nimport { dirname } from 'node:path';\n\nexport async function outputJSON(\n  filePath: string,\n  data: any,\n  spaces: number = 2,\n) {\n  try {\n    const dir = dirname(filePath);\n    await fs.mkdir(dir, { recursive: true });\n    const jsonData = JSON.stringify(data, null, spaces);\n    await fs.writeFile(filePath, jsonData, 'utf8');\n  } catch (error) {\n    console.error('Error writing JSON file:', error);\n    throw error;\n  }\n}\n\nexport async function ensureFile(filePath: string) {\n  try {\n    const dir = dirname(filePath);\n    await fs.mkdir(dir, { recursive: true });\n    await fs.writeFile(filePath, '', { flag: 'a' });\n  } catch (error) {\n    console.error('Error ensuring file:', error);\n    throw error;\n  }\n}\n\nexport async function readJSON(filePath: string) {\n  try {\n    const data = await fs.readFile(filePath, 'utf8');\n    return JSON.parse(data);\n  } catch (error) {\n    console.error('Error reading JSON file:', error);\n    throw error;\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/git.ts",
    "content": "import path from 'node:path';\n\nimport { execa } from 'execa';\n\nexport * from '@changesets/git';\n\n/**\n * 获取暂存区文件\n */\nasync function getStagedFiles(): Promise<string[]> {\n  try {\n    const { stdout } = await execa('git', [\n      '-c',\n      'submodule.recurse=false',\n      'diff',\n      '--staged',\n      '--diff-filter=ACMR',\n      '--name-only',\n      '--ignore-submodules',\n      '-z',\n    ]);\n\n    let changedList = stdout ? stdout.replace(/\\0$/, '').split('\\0') : [];\n    changedList = changedList.map((item) => path.resolve(process.cwd(), item));\n    const changedSet = new Set(changedList);\n    changedSet.delete('');\n    return [...changedSet];\n  } catch (error) {\n    console.error('Failed to get staged files:', error);\n    return [];\n  }\n}\n\nexport { getStagedFiles };\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/hash.ts",
    "content": "import { createHash } from 'node:crypto';\n\n/**\n * 生产基于内容的 hash，可自定义长度\n * @param content\n * @param hashLSize\n */\nfunction generatorContentHash(content: string, hashLSize?: number) {\n  const hash = createHash('md5').update(content, 'utf8').digest('hex');\n\n  if (hashLSize) {\n    return hash.slice(0, hashLSize);\n  }\n\n  return hash;\n}\n\nexport { generatorContentHash };\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/index.ts",
    "content": "export * from './constants';\nexport * from './date';\nexport * from './fs';\nexport * from './git';\nexport { getStagedFiles, add as gitAdd } from './git';\nexport { generatorContentHash } from './hash';\nexport * from './monorepo';\nexport { toPosixPath } from './path';\nexport { prettierFormat } from './prettier';\nexport * from './spinner';\nexport type { Package } from '@manypkg/get-packages';\nexport { default as colors } from 'chalk';\nexport { consola } from 'consola';\nexport * from 'execa';\n\nexport { default as fs } from 'node:fs/promises';\n\nexport { type PackageJson, readPackageJSON } from 'pkg-types';\nexport { rimraf } from 'rimraf';\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/monorepo.ts",
    "content": "import { dirname } from 'node:path';\n\nimport {\n  getPackages as getPackagesFunc,\n  getPackagesSync as getPackagesSyncFunc,\n} from '@manypkg/get-packages';\nimport { findUpSync } from 'find-up';\n\n/**\n * 查找大仓的根目录\n * @param cwd\n */\nfunction findMonorepoRoot(cwd: string = process.cwd()) {\n  const lockFile = findUpSync('pnpm-lock.yaml', {\n    cwd,\n    type: 'file',\n  });\n  return dirname(lockFile || '');\n}\n\n/**\n * 获取大仓的所有包\n */\nfunction getPackagesSync() {\n  const root = findMonorepoRoot();\n  return getPackagesSyncFunc(root);\n}\n\n/**\n * 获取大仓的所有包\n */\nasync function getPackages() {\n  const root = findMonorepoRoot();\n\n  return await getPackagesFunc(root);\n}\n\n/**\n * 获取大仓指定的包\n */\nasync function getPackage(pkgName: string) {\n  const { packages } = await getPackages();\n  return packages.find((pkg) => pkg.packageJson.name === pkgName);\n}\n\nexport { findMonorepoRoot, getPackage, getPackages, getPackagesSync };\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/path.ts",
    "content": "import { posix } from 'node:path';\n\n/**\n * 将给定的文件路径转换为 POSIX 风格。\n * @param {string} pathname - 原始文件路径。\n */\nfunction toPosixPath(pathname: string) {\n  return pathname.split(`\\\\`).join(posix.sep);\n}\n\nexport { toPosixPath };\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/prettier.ts",
    "content": "import fs from 'node:fs/promises';\n\nimport { format, getFileInfo, resolveConfig } from 'prettier';\n\nasync function prettierFormat(filepath: string) {\n  const prettierOptions = await resolveConfig(filepath, {});\n\n  const fileInfo = await getFileInfo(filepath);\n\n  const input = await fs.readFile(filepath, 'utf8');\n  const output = await format(input, {\n    ...prettierOptions,\n    parser: fileInfo.inferredParser as any,\n  });\n  if (output !== input) {\n    await fs.writeFile(filepath, output, 'utf8');\n  }\n  return output;\n}\n\nexport { prettierFormat };\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/src/spinner.ts",
    "content": "import type { Ora } from 'ora';\n\nimport ora from 'ora';\n\ninterface SpinnerOptions {\n  failedText?: string;\n  successText?: string;\n  title: string;\n}\nexport async function spinner<T>(\n  { failedText, successText, title }: SpinnerOptions,\n  callback: () => Promise<T>,\n): Promise<T> {\n  const loading: Ora = ora(title).start();\n\n  try {\n    const result = await callback();\n    loading.succeed(successText || 'Success!');\n    return result;\n  } catch (error) {\n    loading.fail(failedText || 'Failed!');\n    throw error;\n  } finally {\n    loading.stop();\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/node-utils/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/internal/tailwind-config/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index', './src/postcss.config'],\n  rollup: {\n    emitCJS: true,\n  },\n});\n"
  },
  {
    "path": "hiauth-front/internal/tailwind-config/package.json",
    "content": "{\n  \"name\": \"@vben/tailwind-config\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"internal/tailwind-config\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"stub\": \"pnpm unbuild --stub\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"typesVersions\": {\n    \"*\": {\n      \"*\": [\n        \"./dist/*\",\n        \"./*\"\n      ]\n    }\n  },\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"import\": \"./dist/index.mjs\",\n      \"require\": \"./dist/index.cjs\"\n    },\n    \"./postcss\": {\n      \"types\": \"./src/postcss.config.ts\",\n      \"import\": \"./dist/postcss.config.mjs\",\n      \"require\": \"./dist/postcss.config.cjs\",\n      \"default\": \"./dist/postcss.config.mjs\"\n    },\n    \"./*\": \"./*\"\n  },\n  \"peerDependencies\": {\n    \"tailwindcss\": \"^3.4.3\"\n  },\n  \"dependencies\": {\n    \"@iconify/json\": \"catalog:\",\n    \"@iconify/tailwind\": \"catalog:\",\n    \"@manypkg/get-packages\": \"catalog:\",\n    \"@tailwindcss/nesting\": \"catalog:\",\n    \"@tailwindcss/typography\": \"catalog:\",\n    \"autoprefixer\": \"catalog:\",\n    \"cssnano\": \"catalog:\",\n    \"postcss\": \"catalog:\",\n    \"postcss-antd-fixes\": \"catalog:\",\n    \"postcss-import\": \"catalog:\",\n    \"postcss-preset-env\": \"catalog:\",\n    \"tailwindcss\": \"catalog:\",\n    \"tailwindcss-animate\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/postcss-import\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/tailwind-config/src/index.ts",
    "content": "import type { Config } from 'tailwindcss';\n\nimport path from 'node:path';\n\nimport { addDynamicIconSelectors } from '@iconify/tailwind';\nimport { getPackagesSync } from '@manypkg/get-packages';\nimport typographyPlugin from '@tailwindcss/typography';\nimport animate from 'tailwindcss-animate';\n\nimport { enterAnimationPlugin } from './plugins/entry';\n\n// import defaultTheme from 'tailwindcss/defaultTheme';\n\nconst { packages } = getPackagesSync(process.cwd());\n\nconst tailwindPackages: string[] = [];\n\npackages.forEach((pkg) => {\n  // apps目录下和 @vben-core/tailwind-ui 包需要使用到 tailwindcss ui\n  // if (fs.existsSync(path.join(pkg.dir, 'tailwind.config.mjs'))) {\n  tailwindPackages.push(pkg.dir);\n  // }\n});\n\nconst shadcnUiColors = {\n  accent: {\n    DEFAULT: 'hsl(var(--accent))',\n    foreground: 'hsl(var(--accent-foreground))',\n    hover: 'hsl(var(--accent-hover))',\n    lighter: 'has(val(--accent-lighter))',\n  },\n  background: {\n    deep: 'hsl(var(--background-deep))',\n    DEFAULT: 'hsl(var(--background))',\n  },\n  border: {\n    DEFAULT: 'hsl(var(--border))',\n  },\n  card: {\n    DEFAULT: 'hsl(var(--card))',\n    foreground: 'hsl(var(--card-foreground))',\n  },\n  destructive: {\n    ...createColorsPalette('destructive'),\n    DEFAULT: 'hsl(var(--destructive))',\n  },\n\n  foreground: {\n    DEFAULT: 'hsl(var(--foreground))',\n  },\n\n  input: {\n    background: 'hsl(var(--input-background))',\n    DEFAULT: 'hsl(var(--input))',\n  },\n  muted: {\n    DEFAULT: 'hsl(var(--muted))',\n    foreground: 'hsl(var(--muted-foreground))',\n  },\n  popover: {\n    DEFAULT: 'hsl(var(--popover))',\n    foreground: 'hsl(var(--popover-foreground))',\n  },\n  primary: {\n    ...createColorsPalette('primary'),\n    DEFAULT: 'hsl(var(--primary))',\n  },\n\n  ring: 'hsl(var(--ring))',\n  secondary: {\n    DEFAULT: 'hsl(var(--secondary))',\n    desc: 'hsl(var(--secondary-desc))',\n    foreground: 'hsl(var(--secondary-foreground))',\n  },\n};\n\nconst customColors = {\n  green: {\n    ...createColorsPalette('green'),\n    foreground: 'hsl(var(--success-foreground))',\n  },\n  header: {\n    DEFAULT: 'hsl(var(--header))',\n  },\n  heavy: {\n    DEFAULT: 'hsl(var(--heavy))',\n    foreground: 'hsl(var(--heavy-foreground))',\n  },\n  main: {\n    DEFAULT: 'hsl(var(--main))',\n  },\n  overlay: {\n    content: 'hsl(var(--overlay-content))',\n    DEFAULT: 'hsl(var(--overlay))',\n  },\n  red: {\n    ...createColorsPalette('red'),\n    foreground: 'hsl(var(--destructive-foreground))',\n  },\n  sidebar: {\n    deep: 'hsl(var(--sidebar-deep))',\n    DEFAULT: 'hsl(var(--sidebar))',\n  },\n  success: {\n    ...createColorsPalette('success'),\n    DEFAULT: 'hsl(var(--success))',\n  },\n  warning: {\n    ...createColorsPalette('warning'),\n    DEFAULT: 'hsl(var(--warning))',\n  },\n  yellow: {\n    ...createColorsPalette('yellow'),\n    foreground: 'hsl(var(--warning-foreground))',\n  },\n};\n\nexport default {\n  content: [\n    './index.html',\n    ...tailwindPackages.map((item) =>\n      path.join(item, 'src/**/*.{vue,js,ts,jsx,tsx,svelte,astro,html}'),\n    ),\n  ],\n  darkMode: 'selector',\n  plugins: [\n    animate,\n    typographyPlugin,\n    addDynamicIconSelectors(),\n    enterAnimationPlugin,\n  ],\n  prefix: '',\n  theme: {\n    container: {\n      center: true,\n      padding: '2rem',\n      screens: {\n        '2xl': '1400px',\n      },\n    },\n    extend: {\n      animation: {\n        'accordion-down': 'accordion-down 0.2s ease-out',\n        'accordion-up': 'accordion-up 0.2s ease-out',\n        'collapsible-down': 'collapsible-down 0.2s ease-in-out',\n        'collapsible-up': 'collapsible-up 0.2s ease-in-out',\n        float: 'float 5s linear 0ms infinite',\n      },\n\n      animationDuration: {\n        '2000': '2000ms',\n        '3000': '3000ms',\n      },\n      borderRadius: {\n        lg: 'var(--radius)',\n        md: 'calc(var(--radius) - 2px)',\n        sm: 'calc(var(--radius) - 4px)',\n        xl: 'calc(var(--radius) + 4px)',\n      },\n      boxShadow: {\n        float: `0 6px 16px 0 rgb(0 0 0 / 8%),\n          0 3px 6px -4px rgb(0 0 0 / 12%),\n          0 9px 28px 8px rgb(0 0 0 / 5%)`,\n      },\n      colors: {\n        ...customColors,\n        ...shadcnUiColors,\n      },\n      fontFamily: {\n        sans: [\n          'var(--font-family)',\n          //  ...defaultTheme.fontFamily.sans\n        ],\n      },\n      keyframes: {\n        'accordion-down': {\n          from: { height: '0' },\n          to: { height: 'var(--radix-accordion-content-height)' },\n        },\n        'accordion-up': {\n          from: { height: 'var(--radix-accordion-content-height)' },\n          to: { height: '0' },\n        },\n        'collapsible-down': {\n          from: { height: '0' },\n          to: { height: 'var(--radix-collapsible-content-height)' },\n        },\n        'collapsible-up': {\n          from: { height: 'var(--radix-collapsible-content-height)' },\n          to: { height: '0' },\n        },\n        float: {\n          '0%': { transform: 'translateY(0)' },\n          '50%': { transform: 'translateY(-20px)' },\n          '100%': { transform: 'translateY(0)' },\n        },\n      },\n      zIndex: {\n        '100': '100',\n        '1000': '1000',\n      },\n    },\n  },\n  safelist: ['dark'],\n} as Config;\n\nfunction createColorsPalette(name: string) {\n  // backgroundLightest: '#EFF6FF', // Tailwind CSS 默认的 `blue-50`\n  //         backgroundLighter: '#DBEAFE',  // Tailwind CSS 默认的 `blue-100`\n  //         backgroundLight: '#BFDBFE',    // Tailwind CSS 默认的 `blue-200`\n  //         borderLight: '#93C5FD',        // Tailwind CSS 默认的 `blue-300`\n  //         border: '#60A5FA',             // Tailwind CSS 默认的 `blue-400`\n  //         main: '#3B82F6',               // Tailwind CSS 默认的 `blue-500`\n  //         hover: '#2563EB',              // Tailwind CSS 默认的 `blue-600`\n  //         active: '#1D4ED8',             // Tailwind CSS 默认的 `blue-700`\n  //         backgroundDark: '#1E40AF',     // Tailwind CSS 默认的 `blue-800`\n  //         backgroundDarker: '#1E3A8A',   // Tailwind CSS 默认的 `blue-900`\n  //         backgroundDarkest: '#172554',  // Tailwind CSS 默认的 `blue-950`\n\n  // •\tbackgroundLightest (#EFF6FF): 适用于最浅的背景色，可能用于非常轻微的阴影或卡片的背景。\n  // •\tbackgroundLighter (#DBEAFE): 适用于略浅的背景色，通常用于次要背景或略浅的区域。\n  // •\tbackgroundLight (#BFDBFE): 适用于浅色背景，可能用于输入框或表单区域的背景。\n  // •\tborderLight (#93C5FD): 适用于浅色边框，可能用于输入框或卡片的边框。\n  // •\tborder (#60A5FA): 适用于普通边框，可能用于按钮或卡片的边框。\n  // •\tmain (#3B82F6): 适用于主要的主题色，通常用于按钮、链接或主要的强调色。\n  // •\thover (#2563EB): 适用于鼠标悬停状态下的颜色，例如按钮悬停时的背景色或边框色。\n  // •\tactive (#1D4ED8): 适用于激活状态下的颜色，例如按钮按下时的背景色或边框色。\n  // •\tbackgroundDark (#1E40AF): 适用于深色背景，可能用于主要按钮或深色卡片背景。\n  // •\tbackgroundDarker (#1E3A8A): 适用于更深的背景，通常用于头部导航栏或页脚。\n  // •\tbackgroundDarkest (#172554): 适用于最深的背景，可能用于非常深色的区域或极端对比色。\n\n  return {\n    50: `hsl(var(--${name}-50))`,\n    100: `hsl(var(--${name}-100))`,\n    200: `hsl(var(--${name}-200))`,\n    300: `hsl(var(--${name}-300))`,\n    400: `hsl(var(--${name}-400))`,\n    500: `hsl(var(--${name}-500))`,\n    600: `hsl(var(--${name}-600))`,\n    700: `hsl(var(--${name}-700))`,\n    // 800: `hsl(var(--${name}-800))`,\n    // 900: `hsl(var(--${name}-900))`,\n    // 950: `hsl(var(--${name}-950))`,\n    // 激活状态下的颜色，适用于按钮按下时的背景色或边框色。\n    active: `hsl(var(--${name}-700))`,\n    // 浅色背景，适用于输入框或表单区域的背景。\n    'background-light': `hsl(var(--${name}-200))`,\n    // 适用于略浅的背景色，通常用于次要背景或略浅的区域。\n    'background-lighter': `hsl(var(--${name}-100))`,\n    // 最浅的背景色，适用于非常轻微的阴影或卡片的背景。\n    'background-lightest': `hsl(var(--${name}-50))`,\n    // 适用于普通边框，可能用于按钮或卡片的边框。\n    border: `hsl(var(--${name}-400))`,\n    // 浅色边框，适用于输入框或卡片的边框。\n    'border-light': `hsl(var(--${name}-300))`,\n    foreground: `hsl(var(--${name}-foreground))`,\n    // 鼠标悬停状态下的颜色，适用于按钮悬停时的背景色或边框色。\n    hover: `hsl(var(--${name}-600))`,\n    // 主色文本\n    text: `hsl(var(--${name}-500))`,\n    // 主色文本激活态\n    'text-active': `hsl(var(--${name}-700))`,\n    // 主色文本悬浮态\n    'text-hover': `hsl(var(--${name}-600))`,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/internal/tailwind-config/src/module.d.ts",
    "content": "declare module '@tailwindcss/nesting' {\n  export default any;\n}\n"
  },
  {
    "path": "hiauth-front/internal/tailwind-config/src/plugins/entry.ts",
    "content": "import plugin from 'tailwindcss/plugin.js';\n\nconst enterAnimationPlugin = plugin(({ addUtilities }) => {\n  const maxChild = 5;\n  const utilities: Record<string, any> = {};\n  for (let i = 1; i <= maxChild; i++) {\n    const baseDelay = 0.1;\n    const delay = `${baseDelay * i}s`;\n\n    utilities[`.enter-x:nth-child(${i})`] = {\n      animation: `enter-x-animation 0.3s ease-in-out ${delay} forwards`,\n      opacity: '0',\n      transform: `translateX(50px)`,\n    };\n\n    utilities[`.enter-y:nth-child(${i})`] = {\n      animation: `enter-y-animation 0.3s ease-in-out ${delay} forwards`,\n      opacity: '0',\n      transform: `translateY(50px)`,\n    };\n\n    utilities[`.-enter-x:nth-child(${i})`] = {\n      animation: `enter-x-animation 0.3s ease-in-out ${delay} forwards`,\n      opacity: '0',\n      transform: `translateX(-50px)`,\n    };\n\n    utilities[`.-enter-y:nth-child(${i})`] = {\n      animation: `enter-y-animation 0.3s ease-in-out ${delay} forwards`,\n      opacity: '0',\n      transform: `translateY(-50px)`,\n    };\n  }\n\n  // 添加动画关键帧\n  addUtilities(utilities);\n  addUtilities({\n    '@keyframes enter-x-animation': {\n      to: {\n        opacity: '1',\n        transform: 'translateX(0)',\n      },\n    },\n    '@keyframes enter-y-animation': {\n      to: {\n        opacity: '1',\n        transform: 'translateY(0)',\n      },\n    },\n  });\n});\n\nexport { enterAnimationPlugin };\n"
  },
  {
    "path": "hiauth-front/internal/tailwind-config/src/postcss.config.ts",
    "content": "import config from '.';\n\nexport default {\n  plugins: {\n    ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),\n    // Specifying the config is not necessary in most cases, but it is included\n    autoprefixer: {},\n    // 修复 element-plus 和 ant-design-vue 的样式和tailwindcss冲突问题\n    'postcss-antd-fixes': { prefixes: ['ant', 'el'] },\n    'postcss-import': {},\n    'postcss-preset-env': {},\n    tailwindcss: { config },\n    'tailwindcss/nesting': {},\n  },\n};\n"
  },
  {
    "path": "hiauth-front/internal/tailwind-config/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"compilerOptions\": {\n    \"moduleResolution\": \"bundler\"\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/internal/tsconfig/base.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Base\",\n  \"compilerOptions\": {\n    \"composite\": false,\n    \"target\": \"ESNext\",\n\n    \"moduleDetection\": \"force\",\n    \"experimentalDecorators\": true,\n\n    \"baseUrl\": \".\",\n    \"module\": \"ESNext\",\n\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n\n    \"strict\": true,\n    \"strictNullChecks\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noImplicitAny\": true,\n    \"noImplicitOverride\": true,\n    \"noImplicitThis\": true,\n    \"noUncheckedIndexedAccess\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n\n    \"inlineSources\": false,\n    \"noEmit\": true,\n    \"removeComments\": true,\n    \"sourceMap\": false,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"isolatedModules\": true,\n    \"verbatimModuleSyntax\": true,\n    \"skipLibCheck\": true,\n    \"preserveWatchOutput\": true\n  },\n  \"exclude\": [\"**/node_modules/**\", \"**/dist/**\", \"**/.turbo/**\"]\n}\n"
  },
  {
    "path": "hiauth-front/internal/tsconfig/library.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Web Application\",\n  \"extends\": \"./base.json\",\n  \"compilerOptions\": {\n    \"jsx\": \"preserve\",\n    \"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n    \"useDefineForClassFields\": true,\n    \"moduleResolution\": \"bundler\",\n    \"declaration\": true,\n    \"noEmit\": false\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/tsconfig/node.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Node Config\",\n  \"extends\": \"./base.json\",\n  \"compilerOptions\": {\n    \"composite\": false,\n    \"lib\": [\"ESNext\"],\n    \"baseUrl\": \"./\",\n    \"types\": [\"node\"],\n    \"noImplicitAny\": true\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/tsconfig/package.json",
    "content": "{\n  \"name\": \"@vben/tsconfig\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"internal/tsconfig\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"files\": [\n    \"base.json\",\n    \"library.json\",\n    \"node.json\",\n    \"web-app.json\",\n    \"web.json\"\n  ],\n  \"dependencies\": {\n    \"@vben/types\": \"workspace:*\",\n    \"vite\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/tsconfig/web-app.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Web Application\",\n  \"extends\": \"./web.json\",\n  \"compilerOptions\": {\n    \"types\": [\"vite/client\", \"@vben/types/global\"]\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/tsconfig/web.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"display\": \"Web Package\",\n  \"extends\": \"./base.json\",\n  \"compilerOptions\": {\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"vue\",\n    \"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n    \"useDefineForClassFields\": true,\n    \"moduleResolution\": \"bundler\",\n    \"types\": [\"vite/client\"],\n    \"declaration\": false\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/package.json",
    "content": "{\n  \"name\": \"@vben/vite-config\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"internal/vite-config\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"stub\": \"pnpm unbuild --stub\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"dependencies\": {\n    \"@intlify/unplugin-vue-i18n\": \"catalog:\",\n    \"@jspm/generator\": \"catalog:\",\n    \"archiver\": \"catalog:\",\n    \"cheerio\": \"catalog:\",\n    \"get-port\": \"catalog:\",\n    \"html-minifier-terser\": \"catalog:\",\n    \"nitropack\": \"catalog:\",\n    \"resolve.exports\": \"catalog:\",\n    \"vite-plugin-pwa\": \"catalog:\",\n    \"vite-plugin-vue-devtools\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@pnpm/workspace.read-manifest\": \"catalog:\",\n    \"@types/archiver\": \"catalog:\",\n    \"@types/html-minifier-terser\": \"catalog:\",\n    \"@vben/node-utils\": \"workspace:*\",\n    \"@vitejs/plugin-vue\": \"catalog:\",\n    \"@vitejs/plugin-vue-jsx\": \"catalog:\",\n    \"dayjs\": \"catalog:\",\n    \"dotenv\": \"catalog:\",\n    \"rollup\": \"catalog:\",\n    \"rollup-plugin-visualizer\": \"catalog:\",\n    \"sass\": \"catalog:\",\n    \"vite\": \"catalog:\",\n    \"vite-plugin-compression\": \"catalog:\",\n    \"vite-plugin-dts\": \"catalog:\",\n    \"vite-plugin-html\": \"catalog:\",\n    \"vite-plugin-lazy-import\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/config/application.ts",
    "content": "import type { CSSOptions, UserConfig } from 'vite';\n\nimport type { DefineApplicationOptions } from '../typing';\n\nimport path, { relative } from 'node:path';\n\nimport { findMonorepoRoot } from '@vben/node-utils';\n\nimport { NodePackageImporter } from 'sass';\nimport { defineConfig, loadEnv, mergeConfig } from 'vite';\n\nimport { defaultImportmapOptions, getDefaultPwaOptions } from '../options';\nimport { loadApplicationPlugins } from '../plugins';\nimport { loadAndConvertEnv } from '../utils/env';\nimport { getCommonConfig } from './common';\n\nfunction defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {\n  return defineConfig(async (config) => {\n    const options = await userConfigPromise?.(config);\n    const { appTitle, base, port, ...envConfig } = await loadAndConvertEnv();\n    const { command, mode } = config;\n    const { application = {}, vite = {} } = options || {};\n    const root = process.cwd();\n    const isBuild = command === 'build';\n    const env = loadEnv(mode, root);\n\n    const plugins = await loadApplicationPlugins({\n      archiver: true,\n      archiverPluginOptions: {},\n      compress: false,\n      compressTypes: ['brotli', 'gzip'],\n      devtools: true,\n      env,\n      extraAppConfig: true,\n      html: true,\n      i18n: true,\n      importmapOptions: defaultImportmapOptions,\n      injectAppLoading: true,\n      injectMetadata: true,\n      isBuild,\n      license: true,\n      mode,\n      nitroMock: !isBuild,\n      nitroMockOptions: {},\n      print: !isBuild,\n      printInfoMap: {\n        'Vben Admin Docs': 'https://doc.vben.pro',\n      },\n      pwa: true,\n      pwaOptions: getDefaultPwaOptions(appTitle),\n      vxeTableLazyImport: true,\n      ...envConfig,\n      ...application,\n    });\n\n    const { injectGlobalScss = true } = application;\n\n    const applicationConfig: UserConfig = {\n      base,\n      build: {\n        rollupOptions: {\n          output: {\n            assetFileNames: '[ext]/[name]-[hash].[ext]',\n            chunkFileNames: 'js/[name]-[hash].js',\n            entryFileNames: 'jse/index-[name]-[hash].js',\n          },\n        },\n        target: 'es2015',\n      },\n      css: createCssOptions(injectGlobalScss),\n      esbuild: {\n        drop: isBuild\n          ? [\n              // 'console',\n              'debugger',\n            ]\n          : [],\n        legalComments: 'none',\n      },\n      plugins,\n      server: {\n        host: true,\n        port,\n        warmup: {\n          // 预热文件\n          clientFiles: [\n            './index.html',\n            './src/bootstrap.ts',\n            './src/{views,layouts,router,store,api,adapter}/*',\n          ],\n        },\n      },\n    };\n\n    const mergedCommonConfig = mergeConfig(\n      await getCommonConfig(),\n      applicationConfig,\n    );\n    return mergeConfig(mergedCommonConfig, vite);\n  });\n}\n\nfunction createCssOptions(injectGlobalScss = true): CSSOptions {\n  const root = findMonorepoRoot();\n  return {\n    preprocessorOptions: injectGlobalScss\n      ? {\n          scss: {\n            additionalData: (content: string, filepath: string) => {\n              const relativePath = relative(root, filepath);\n              // apps下的包注入全局样式\n              if (relativePath.startsWith(`apps${path.sep}`)) {\n                return `@use \"@vben/styles/global\" as *;\\n${content}`;\n              }\n              return content;\n            },\n            api: 'modern',\n            importers: [new NodePackageImporter()],\n          },\n        }\n      : {},\n  };\n}\n\nexport { defineApplicationConfig };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/config/common.ts",
    "content": "import type { UserConfig } from 'vite';\n\nasync function getCommonConfig(): Promise<UserConfig> {\n  return {\n    build: {\n      chunkSizeWarningLimit: 2000,\n      reportCompressedSize: false,\n      sourcemap: false,\n    },\n  };\n}\n\nexport { getCommonConfig };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/config/index.ts",
    "content": "import type { DefineConfig } from '../typing';\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { defineApplicationConfig } from './application';\nimport { defineLibraryConfig } from './library';\n\nexport * from './application';\nexport * from './library';\n\nfunction defineConfig(\n  userConfigPromise?: DefineConfig,\n  type: 'application' | 'auto' | 'library' = 'auto',\n) {\n  let projectType = type;\n\n  // 根据包是否存在 index.html,自动判断类型\n  if (projectType === 'auto') {\n    const htmlPath = join(process.cwd(), 'index.html');\n    projectType = existsSync(htmlPath) ? 'application' : 'library';\n  }\n\n  switch (projectType) {\n    case 'application': {\n      return defineApplicationConfig(userConfigPromise);\n    }\n    case 'library': {\n      return defineLibraryConfig(userConfigPromise);\n    }\n    default: {\n      throw new Error(`Unsupported project type: ${projectType}`);\n    }\n  }\n}\n\nexport { defineConfig };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/config/library.ts",
    "content": "import type { ConfigEnv, UserConfig } from 'vite';\n\nimport type { DefineLibraryOptions } from '../typing';\n\nimport { readPackageJSON } from '@vben/node-utils';\n\nimport { defineConfig, mergeConfig } from 'vite';\n\nimport { loadLibraryPlugins } from '../plugins';\nimport { getCommonConfig } from './common';\n\nfunction defineLibraryConfig(userConfigPromise?: DefineLibraryOptions) {\n  return defineConfig(async (config: ConfigEnv) => {\n    const options = await userConfigPromise?.(config);\n    const { command, mode } = config;\n    const { library = {}, vite = {} } = options || {};\n    const root = process.cwd();\n    const isBuild = command === 'build';\n\n    const plugins = await loadLibraryPlugins({\n      dts: false,\n      injectMetadata: true,\n      isBuild,\n      mode,\n      ...library,\n    });\n\n    const { dependencies = {}, peerDependencies = {} } =\n      await readPackageJSON(root);\n\n    const externalPackages = [\n      ...Object.keys(dependencies),\n      ...Object.keys(peerDependencies),\n    ];\n\n    const packageConfig: UserConfig = {\n      build: {\n        lib: {\n          entry: 'src/index.ts',\n          fileName: () => 'index.mjs',\n          formats: ['es'],\n        },\n        rollupOptions: {\n          external: (id) => {\n            return externalPackages.some(\n              (pkg) => id === pkg || id.startsWith(`${pkg}/`),\n            );\n          },\n        },\n      },\n      plugins,\n    };\n    const commonConfig = await getCommonConfig();\n    const mergedConmonConfig = mergeConfig(commonConfig, packageConfig);\n    return mergeConfig(mergedConmonConfig, vite);\n  });\n}\n\nexport { defineLibraryConfig };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/index.ts",
    "content": "export * from './config';\nexport * from './options';\nexport * from './plugins';\nexport { loadAndConvertEnv } from './utils/env';\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/options.ts",
    "content": "import type { Options as PwaPluginOptions } from 'vite-plugin-pwa';\n\nimport type { ImportmapPluginOptions } from './typing';\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\nconst getDefaultPwaOptions = (name: string): Partial<PwaPluginOptions> => ({\n  manifest: {\n    description:\n      'Vben Admin is a modern admin dashboard template based on Vue 3. ',\n    icons: [\n      {\n        sizes: '192x192',\n        src: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/pwa-icon-192.png',\n        type: 'image/png',\n      },\n      {\n        sizes: '512x512',\n        src: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/pwa-icon-512.png',\n        type: 'image/png',\n      },\n    ],\n    name: `${name}${isDevelopment ? ' dev' : ''}`,\n    short_name: `${name}${isDevelopment ? ' dev' : ''}`,\n  },\n});\n\n/**\n * importmap CDN 暂时不开启，因为有些包不支持，且网络不稳定\n */\nconst defaultImportmapOptions: ImportmapPluginOptions = {\n  // 通过 Importmap CDN 方式引入,\n  // 目前只有esm.sh源兼容性好一点，jspm.io对于 esm 入口要求高\n  defaultProvider: 'esm.sh',\n  importmap: [\n    { name: 'vue' },\n    { name: 'pinia' },\n    { name: 'vue-router' },\n    // { name: 'vue-i18n' },\n    { name: 'dayjs' },\n    { name: 'vue-demi' },\n  ],\n};\n\nexport { defaultImportmapOptions, getDefaultPwaOptions };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/archiver.ts",
    "content": "import type { PluginOption } from 'vite';\n\nimport type { ArchiverPluginOptions } from '../typing';\n\nimport fs from 'node:fs';\nimport fsp from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport archiver from 'archiver';\n\nexport const viteArchiverPlugin = (\n  options: ArchiverPluginOptions = {},\n): PluginOption => {\n  return {\n    apply: 'build',\n    closeBundle: {\n      handler() {\n        const { name = 'dist', outputDir = '.' } = options;\n\n        setTimeout(async () => {\n          const folderToZip = 'dist';\n\n          const zipOutputDir = join(process.cwd(), outputDir);\n          const zipOutputPath = join(zipOutputDir, `${name}.zip`);\n          try {\n            await fsp.mkdir(zipOutputDir, { recursive: true });\n          } catch {\n            // ignore\n          }\n\n          try {\n            await zipFolder(folderToZip, zipOutputPath);\n            console.log(`Folder has been zipped to: ${zipOutputPath}`);\n          } catch (error) {\n            console.error('Error zipping folder:', error);\n          }\n        }, 0);\n      },\n      order: 'post',\n    },\n    enforce: 'post',\n    name: 'vite:archiver',\n  };\n};\n\nasync function zipFolder(\n  folderPath: string,\n  outputPath: string,\n): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const output = fs.createWriteStream(outputPath);\n    const archive = archiver('zip', {\n      zlib: { level: 9 }, // 设置压缩级别为 9 以实现最高压缩率\n    });\n\n    output.on('close', () => {\n      console.log(\n        `ZIP file created: ${outputPath} (${archive.pointer()} total bytes)`,\n      );\n      resolve();\n    });\n\n    archive.on('error', (err) => {\n      reject(err);\n    });\n\n    archive.pipe(output);\n\n    // 使用 directory 方法以流的方式压缩文件夹，减少内存消耗\n    archive.directory(folderPath, false);\n\n    // 流式处理完成\n    archive.finalize();\n  });\n}\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/extra-app-config.ts",
    "content": "import type { PluginOption } from 'vite';\n\nimport {\n  colors,\n  generatorContentHash,\n  readPackageJSON,\n} from '@vben/node-utils';\n\nimport { loadEnv } from '../utils/env';\n\ninterface PluginOptions {\n  isBuild: boolean;\n  root: string;\n}\n\nconst GLOBAL_CONFIG_FILE_NAME = '_app.config.js';\nconst VBEN_ADMIN_PRO_APP_CONF = '_VBEN_ADMIN_PRO_APP_CONF_';\n\n/**\n * 用于将配置文件抽离出来并注入到项目中\n * @returns\n */\n\nasync function viteExtraAppConfigPlugin({\n  isBuild,\n  root,\n}: PluginOptions): Promise<PluginOption | undefined> {\n  let publicPath: string;\n  let source: string;\n\n  if (!isBuild) {\n    return;\n  }\n\n  const { version = '' } = await readPackageJSON(root);\n\n  return {\n    async configResolved(config) {\n      publicPath = ensureTrailingSlash(config.base);\n      source = await getConfigSource();\n    },\n    async generateBundle() {\n      try {\n        this.emitFile({\n          fileName: GLOBAL_CONFIG_FILE_NAME,\n          source,\n          type: 'asset',\n        });\n\n        console.log(colors.cyan(`✨configuration file is build successfully!`));\n      } catch (error) {\n        console.log(\n          colors.red(\n            `configuration file configuration file failed to package:\\n${error}`,\n          ),\n        );\n      }\n    },\n    name: 'vite:extra-app-config',\n    async transformIndexHtml(html) {\n      const hash = `v=${version}-${generatorContentHash(source, 8)}`;\n\n      const appConfigSrc = `${publicPath}${GLOBAL_CONFIG_FILE_NAME}?${hash}`;\n\n      return {\n        html,\n        tags: [{ attrs: { src: appConfigSrc }, tag: 'script' }],\n      };\n    },\n  };\n}\n\nasync function getConfigSource() {\n  const config = await loadEnv();\n  const windowVariable = `window.${VBEN_ADMIN_PRO_APP_CONF}`;\n  // 确保变量不会被修改\n  let source = `${windowVariable}=${JSON.stringify(config)};`;\n  source += `\n    Object.freeze(${windowVariable});\n    Object.defineProperty(window, \"${VBEN_ADMIN_PRO_APP_CONF}\", {\n      configurable: false,\n      writable: false,\n    });\n  `.replaceAll(/\\s/g, '');\n  return source;\n}\n\nfunction ensureTrailingSlash(path: string) {\n  return path.endsWith('/') ? path : `${path}/`;\n}\n\nexport { viteExtraAppConfigPlugin };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/importmap.ts",
    "content": "/**\n * 参考 https://github.com/jspm/vite-plugin-jspm，调整为需要的功能\n */\nimport type { GeneratorOptions } from '@jspm/generator';\nimport type { Plugin } from 'vite';\n\nimport { Generator } from '@jspm/generator';\nimport { load } from 'cheerio';\nimport { minify } from 'html-minifier-terser';\n\nconst DEFAULT_PROVIDER = 'jspm.io';\n\ntype pluginOptions = GeneratorOptions & {\n  debug?: boolean;\n  defaultProvider?: 'esm.sh' | 'jsdelivr' | 'jspm.io';\n  importmap?: Array<{ name: string; range?: string }>;\n};\n\n// async function getLatestVersionOfShims() {\n//   const result = await fetch('https://ga.jspm.io/npm:es-module-shims');\n//   const version = result.text();\n//   return version;\n// }\n\nasync function getShimsUrl(provide: string) {\n  // const version = await getLatestVersionOfShims();\n  const version = '1.10.0';\n\n  const shimsSubpath = `dist/es-module-shims.js`;\n  const providerShimsMap: Record<string, string> = {\n    'esm.sh': `https://esm.sh/es-module-shims@${version}/${shimsSubpath}`,\n    // unpkg: `https://unpkg.com/es-module-shims@${version}/${shimsSubpath}`,\n    jsdelivr: `https://cdn.jsdelivr.net/npm/es-module-shims@${version}/${shimsSubpath}`,\n\n    // 下面两个CDN不稳定，暂时不用\n    'jspm.io': `https://ga.jspm.io/npm:es-module-shims@${version}/${shimsSubpath}`,\n  };\n\n  return providerShimsMap[provide] || providerShimsMap[DEFAULT_PROVIDER];\n}\n\nlet generator: Generator;\n\nasync function viteImportMapPlugin(\n  pluginOptions?: pluginOptions,\n): Promise<Plugin[]> {\n  const { importmap } = pluginOptions || {};\n\n  let isSSR = false;\n  let isBuild = false;\n  let installed = false;\n  let installError: Error | null = null;\n\n  const options: pluginOptions = Object.assign(\n    {},\n    {\n      debug: false,\n      defaultProvider: 'jspm.io',\n      env: ['production', 'browser', 'module'],\n      importmap: [],\n    },\n    pluginOptions,\n  );\n\n  generator = new Generator({\n    ...options,\n    baseUrl: process.cwd(),\n  });\n\n  if (options?.debug) {\n    (async () => {\n      for await (const { message, type } of generator.logStream()) {\n        console.log(`${type}: ${message}`);\n      }\n    })();\n  }\n\n  const imports = options.inputMap?.imports ?? {};\n  const scopes = options.inputMap?.scopes ?? {};\n  const firstLayerKeys = Object.keys(scopes);\n  const inputMapScopes: string[] = [];\n  firstLayerKeys.forEach((key) => {\n    inputMapScopes.push(...Object.keys(scopes[key] || {}));\n  });\n  const inputMapImports = Object.keys(imports);\n\n  const allDepNames: string[] = [\n    ...(importmap?.map((item) => item.name) || []),\n    ...inputMapImports,\n    ...inputMapScopes,\n  ];\n  const depNames = new Set<string>(allDepNames);\n\n  const installDeps = importmap?.map((item) => ({\n    range: item.range,\n    target: item.name,\n  }));\n\n  return [\n    {\n      async config(_, { command, isSsrBuild }) {\n        isBuild = command === 'build';\n        isSSR = !!isSsrBuild;\n      },\n      enforce: 'pre',\n      name: 'importmap:external',\n      resolveId(id) {\n        if (isSSR || !isBuild) {\n          return null;\n        }\n\n        if (!depNames.has(id)) {\n          return null;\n        }\n        return { external: true, id };\n      },\n    },\n    {\n      enforce: 'post',\n      name: 'importmap:install',\n      async resolveId() {\n        if (isSSR || !isBuild || installed) {\n          return null;\n        }\n        try {\n          installed = true;\n          await Promise.allSettled(\n            (installDeps || []).map((dep) => generator.install(dep)),\n          );\n        } catch (error: any) {\n          installError = error;\n          installed = false;\n        }\n        return null;\n      },\n    },\n    {\n      buildEnd() {\n        // 未生成importmap时，抛出错误，防止被turbo缓存\n        if (!installed && !isSSR) {\n          installError && console.error(installError);\n          throw new Error('Importmap installation failed.');\n        }\n      },\n      enforce: 'post',\n      name: 'importmap:html',\n      transformIndexHtml: {\n        async handler(html) {\n          if (isSSR || !isBuild) {\n            return html;\n          }\n\n          const importmapJson = generator.getMap();\n\n          if (!importmapJson) {\n            return html;\n          }\n\n          const esModuleShimsSrc = await getShimsUrl(\n            options.defaultProvider || DEFAULT_PROVIDER,\n          );\n\n          const resultHtml = await injectShimsToHtml(\n            html,\n            esModuleShimsSrc || '',\n          );\n          html = await minify(resultHtml || html, {\n            collapseWhitespace: true,\n            minifyCSS: true,\n            minifyJS: true,\n            removeComments: false,\n          });\n\n          return {\n            html,\n            tags: [\n              {\n                attrs: {\n                  type: 'importmap',\n                },\n                injectTo: 'head-prepend',\n                tag: 'script',\n                children: `${JSON.stringify(importmapJson)}`,\n              },\n            ],\n          };\n        },\n        order: 'post',\n      },\n    },\n  ];\n}\n\nasync function injectShimsToHtml(html: string, esModuleShimUrl: string) {\n  const $ = load(html);\n\n  const $script = $(`script[type='module']`);\n\n  if (!$script) {\n    return;\n  }\n\n  const entry = $script.attr('src');\n\n  $script.removeAttr('type');\n  $script.removeAttr('crossorigin');\n  $script.removeAttr('src');\n  $script.html(`\nif (!HTMLScriptElement.supports || !HTMLScriptElement.supports('importmap')) {\n  self.importShim = function () {\n      const promise = new Promise((resolve, reject) => {\n          document.head.appendChild(\n              Object.assign(document.createElement('script'), {\n                  src: '${esModuleShimUrl}',\n                  crossorigin: 'anonymous',\n                  async: true,\n                  onload() {\n                      if (!importShim.$proxy) {\n                          resolve(importShim);\n                      } else {\n                          reject(new Error('No globalThis.importShim found:' + esModuleShimUrl));\n                      }\n                  },\n                  onerror(error) {\n                      reject(error);\n                  },\n              }),\n          );\n      });\n      importShim.$proxy = true;\n      return promise.then((importShim) => importShim(...arguments));\n  };\n}\n\nvar modules = ['${entry}'];\ntypeof importShim === 'function'\n  ? modules.forEach((moduleName) => importShim(moduleName))\n  : modules.forEach((moduleName) => import(moduleName));\n `);\n  $('body').after($script);\n  $('head').remove(`script[type='module']`);\n  return $.html();\n}\n\nexport { viteImportMapPlugin };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/index.ts",
    "content": "import type { PluginOption } from 'vite';\n\nimport type {\n  ApplicationPluginOptions,\n  CommonPluginOptions,\n  ConditionPlugin,\n  LibraryPluginOptions,\n} from '../typing';\n\nimport viteVueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';\nimport viteVue from '@vitejs/plugin-vue';\nimport viteVueJsx from '@vitejs/plugin-vue-jsx';\nimport { visualizer as viteVisualizerPlugin } from 'rollup-plugin-visualizer';\nimport viteCompressPlugin from 'vite-plugin-compression';\nimport viteDtsPlugin from 'vite-plugin-dts';\nimport { createHtmlPlugin as viteHtmlPlugin } from 'vite-plugin-html';\nimport { VitePWA } from 'vite-plugin-pwa';\nimport viteVueDevTools from 'vite-plugin-vue-devtools';\n\nimport { viteArchiverPlugin } from './archiver';\nimport { viteExtraAppConfigPlugin } from './extra-app-config';\nimport { viteImportMapPlugin } from './importmap';\nimport { viteInjectAppLoadingPlugin } from './inject-app-loading';\nimport { viteMetadataPlugin } from './inject-metadata';\nimport { viteLicensePlugin } from './license';\nimport { viteNitroMockPlugin } from './nitro-mock';\nimport { vitePrintPlugin } from './print';\nimport { viteVxeTableImportsPlugin } from './vxe-table';\n\n/**\n * 获取条件成立的 vite 插件\n * @param conditionPlugins\n */\nasync function loadConditionPlugins(conditionPlugins: ConditionPlugin[]) {\n  const plugins: PluginOption[] = [];\n  for (const conditionPlugin of conditionPlugins) {\n    if (conditionPlugin.condition) {\n      const realPlugins = await conditionPlugin.plugins();\n      plugins.push(...realPlugins);\n    }\n  }\n  return plugins.flat();\n}\n\n/**\n * 根据条件获取通用的vite插件\n */\nasync function loadCommonPlugins(\n  options: CommonPluginOptions,\n): Promise<ConditionPlugin[]> {\n  const { devtools, injectMetadata, isBuild, visualizer } = options;\n  return [\n    {\n      condition: true,\n      plugins: () => [\n        viteVue({\n          script: {\n            defineModel: true,\n            // propsDestructure: true,\n          },\n        }),\n        viteVueJsx(),\n      ],\n    },\n\n    {\n      condition: !isBuild && devtools,\n      plugins: () => [viteVueDevTools()],\n    },\n    {\n      condition: injectMetadata,\n      plugins: async () => [await viteMetadataPlugin()],\n    },\n    {\n      condition: isBuild && !!visualizer,\n      plugins: () => [<PluginOption>viteVisualizerPlugin({\n          filename: './node_modules/.cache/visualizer/stats.html',\n          gzipSize: true,\n          open: true,\n        })],\n    },\n  ];\n}\n\n/**\n * 根据条件获取应用类型的vite插件\n */\nasync function loadApplicationPlugins(\n  options: ApplicationPluginOptions,\n): Promise<PluginOption[]> {\n  // 单独取，否则commonOptions拿不到\n  const isBuild = options.isBuild;\n  const env = options.env;\n\n  const {\n    archiver,\n    archiverPluginOptions,\n    compress,\n    compressTypes,\n    extraAppConfig,\n    html,\n    i18n,\n    importmap,\n    importmapOptions,\n    injectAppLoading,\n    license,\n    nitroMock,\n    nitroMockOptions,\n    print,\n    printInfoMap,\n    pwa,\n    pwaOptions,\n    vxeTableLazyImport,\n    ...commonOptions\n  } = options;\n\n  const commonPlugins = await loadCommonPlugins(commonOptions);\n\n  return await loadConditionPlugins([\n    ...commonPlugins,\n    {\n      condition: i18n,\n      plugins: async () => {\n        return [\n          viteVueI18nPlugin({\n            compositionOnly: true,\n            fullInstall: true,\n            runtimeOnly: true,\n          }),\n        ];\n      },\n    },\n    {\n      condition: print,\n      plugins: async () => {\n        return [await vitePrintPlugin({ infoMap: printInfoMap })];\n      },\n    },\n    {\n      condition: vxeTableLazyImport,\n      plugins: async () => {\n        return [await viteVxeTableImportsPlugin()];\n      },\n    },\n    {\n      condition: nitroMock,\n      plugins: async () => {\n        return [await viteNitroMockPlugin(nitroMockOptions)];\n      },\n    },\n\n    {\n      condition: injectAppLoading,\n      plugins: async () => [await viteInjectAppLoadingPlugin(!!isBuild, env)],\n    },\n    {\n      condition: license,\n      plugins: async () => [await viteLicensePlugin()],\n    },\n    {\n      condition: pwa,\n      plugins: () =>\n        VitePWA({\n          injectRegister: false,\n          workbox: {\n            globPatterns: [],\n          },\n          ...pwaOptions,\n          manifest: {\n            display: 'standalone',\n            start_url: '/',\n            theme_color: '#ffffff',\n            ...pwaOptions?.manifest,\n          },\n        }),\n    },\n    {\n      condition: isBuild && !!compress,\n      plugins: () => {\n        const compressPlugins: PluginOption[] = [];\n        if (compressTypes?.includes('brotli')) {\n          compressPlugins.push(\n            viteCompressPlugin({ deleteOriginFile: false, ext: '.br' }),\n          );\n        }\n        if (compressTypes?.includes('gzip')) {\n          compressPlugins.push(\n            viteCompressPlugin({ deleteOriginFile: false, ext: '.gz' }),\n          );\n        }\n        return compressPlugins;\n      },\n    },\n    {\n      condition: !!html,\n      plugins: () => [viteHtmlPlugin({ minify: true })],\n    },\n    {\n      condition: isBuild && importmap,\n      plugins: () => {\n        return [viteImportMapPlugin(importmapOptions)];\n      },\n    },\n    {\n      condition: isBuild && extraAppConfig,\n      plugins: async () => [\n        await viteExtraAppConfigPlugin({ isBuild: true, root: process.cwd() }),\n      ],\n    },\n    {\n      condition: archiver,\n      plugins: async () => {\n        return [await viteArchiverPlugin(archiverPluginOptions)];\n      },\n    },\n  ]);\n}\n\n/**\n * 根据条件获取库类型的vite插件\n */\nasync function loadLibraryPlugins(\n  options: LibraryPluginOptions,\n): Promise<PluginOption[]> {\n  // 单独取，否则commonOptions拿不到\n  const isBuild = options.isBuild;\n  const { dts, ...commonOptions } = options;\n  const commonPlugins = await loadCommonPlugins(commonOptions);\n  return await loadConditionPlugins([\n    ...commonPlugins,\n    {\n      condition: isBuild && !!dts,\n      plugins: () => [viteDtsPlugin({ logLevel: 'error' })],\n    },\n  ]);\n}\n\nexport {\n  loadApplicationPlugins,\n  loadLibraryPlugins,\n  viteArchiverPlugin,\n  viteCompressPlugin,\n  viteDtsPlugin,\n  viteHtmlPlugin,\n  viteVisualizerPlugin,\n  viteVxeTableImportsPlugin,\n};\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/inject-app-loading/README.md",
    "content": "# inject-app-loading\n\n用于在应用加载时显示加载动画的插件，可自行选择加载动画的样式。\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html",
    "content": "<style data-app-loading=\"inject-css\">\n  html {\n    /* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */\n    line-height: 1.15;\n  }\n\n  .dark .loading {\n    background-color: #0d0d10;\n  }\n\n  .dark .loading .title {\n    color: rgb(255 255 255 / 85%);\n  }\n\n  .loading {\n    position: fixed;\n    top: 0;\n    left: 0;\n    z-index: 9999;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    width: 100%;\n    height: 100%;\n    overflow: hidden;\n    pointer-events: none;\n    background-color: #f4f7f9;\n  }\n\n  .loading.hidden {\n    visibility: hidden;\n    opacity: 0;\n    transition: all 0.6s ease-out;\n  }\n\n  .loading .title {\n    margin-top: 36px;\n    font-size: 30px;\n    font-weight: 600;\n    color: rgb(0 0 0 / 85%);\n  }\n\n  .dot {\n    position: relative;\n    box-sizing: border-box;\n    display: inline-block;\n    width: 48px;\n    height: 48px;\n    margin-top: 30px;\n    font-size: 32px;\n    transform: rotate(45deg);\n    animation: rotate-ani 1.2s infinite linear;\n  }\n\n  .dot i {\n    position: absolute;\n    display: block;\n    width: 20px;\n    height: 20px;\n    background-color: hsl(var(--primary, 210 100% 50%));\n    border-radius: 100%;\n    opacity: 0.3;\n    transform: scale(0.75);\n    transform-origin: 50% 50%;\n    animation: spin-move-ani 1s infinite linear alternate;\n  }\n\n  .dot i:nth-child(1) {\n    top: 0;\n    left: 0;\n  }\n\n  .dot i:nth-child(2) {\n    top: 0;\n    right: 0;\n    animation-delay: 0.4s;\n  }\n\n  .dot i:nth-child(3) {\n    right: 0;\n    bottom: 0;\n    animation-delay: 0.8s;\n  }\n\n  .dot i:nth-child(4) {\n    bottom: 0;\n    left: 0;\n    animation-delay: 1.2s;\n  }\n\n  @keyframes rotate-ani {\n    to {\n      transform: rotate(405deg);\n    }\n  }\n\n  @keyframes spin-move-ani {\n    to {\n      opacity: 1;\n    }\n  }\n</style>\n<div class=\"loading\" id=\"__app-loading__\">\n  <span class=\"dot\"><i></i><i></i><i></i><i></i></span>\n  <div class=\"title\"><%= VITE_APP_TITLE %></div>\n</div>\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/inject-app-loading/default-loading.html",
    "content": "<style data-app-loading=\"inject-css\">\n  html {\n    /* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */\n    line-height: 1.15;\n  }\n\n  .loading {\n    position: fixed;\n    top: 0;\n    left: 0;\n    z-index: 9999;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    width: 100%;\n    height: 100%;\n    overflow: hidden;\n    background-color: #f4f7f9;\n\n    /* transition: all 0.8s ease-out; */\n  }\n\n  .loading.hidden {\n    pointer-events: none;\n    visibility: hidden;\n    opacity: 0;\n    transition: all 0.8s ease-out;\n  }\n\n  .dark .loading {\n    background: #0d0d10;\n  }\n\n  .title {\n    margin-top: 66px;\n    font-size: 28px;\n    font-weight: 600;\n    color: rgb(0 0 0 / 85%);\n  }\n\n  .dark .title {\n    color: #fff;\n  }\n\n  .loader {\n    position: relative;\n    width: 48px;\n    height: 48px;\n  }\n\n  .loader::before {\n    position: absolute;\n    top: 60px;\n    left: 0;\n    width: 48px;\n    height: 5px;\n    content: '';\n    background: hsl(var(--primary, 210 100% 50%) / 50%);\n    border-radius: 50%;\n    animation: shadow-ani 0.5s linear infinite;\n  }\n\n  .loader::after {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    content: '';\n    background: hsl(var(--primary, 210 100% 50%));\n    border-radius: 4px;\n    animation: jump-ani 0.5s linear infinite;\n  }\n\n  @keyframes jump-ani {\n    15% {\n      border-bottom-right-radius: 3px;\n    }\n\n    25% {\n      transform: translateY(9px) rotate(22.5deg);\n    }\n\n    50% {\n      border-bottom-right-radius: 40px;\n      transform: translateY(18px) scale(1, 0.9) rotate(45deg);\n    }\n\n    75% {\n      transform: translateY(9px) rotate(67.5deg);\n    }\n\n    100% {\n      transform: translateY(0) rotate(90deg);\n    }\n  }\n\n  @keyframes shadow-ani {\n    0%,\n    100% {\n      transform: scale(1, 1);\n    }\n\n    50% {\n      transform: scale(1.2, 1);\n    }\n  }\n</style>\n<div class=\"loading\" id=\"__app-loading__\">\n  <div class=\"loader\"></div>\n  <div class=\"title\"><%= VITE_APP_TITLE %></div>\n</div>\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/inject-app-loading/index.ts",
    "content": "import type { PluginOption } from 'vite';\n\nimport fs from 'node:fs';\nimport fsp from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { readPackageJSON } from '@vben/node-utils';\n\n/**\n * 用于生成将loading样式注入到项目中\n * 为多app提供loading样式，无需在每个 app -> index.html单独引入\n */\nasync function viteInjectAppLoadingPlugin(\n  isBuild: boolean,\n  env: Record<string, any> = {},\n  loadingTemplate = 'loading.html',\n): Promise<PluginOption | undefined> {\n  const loadingHtml = await getLoadingRawByHtmlTemplate(loadingTemplate);\n  const { version } = await readPackageJSON(process.cwd());\n  const envRaw = isBuild ? 'prod' : 'dev';\n  const cacheName = `'${env.VITE_APP_NAMESPACE}-${version}-${envRaw}-preferences-theme'`;\n\n  // 获取缓存的主题\n  // 保证黑暗主题下，刷新页面时，loading也是黑暗主题\n  const injectScript = `\n  <script data-app-loading=\"inject-js\">\n  var theme = localStorage.getItem(${cacheName});\n  document.documentElement.classList.toggle('dark', /dark/.test(theme));\n</script>\n`;\n\n  if (!loadingHtml) {\n    return;\n  }\n\n  return {\n    enforce: 'pre',\n    name: 'vite:inject-app-loading',\n    transformIndexHtml: {\n      handler(html) {\n        const re = /<body\\s*>/;\n        html = html.replace(re, `<body>${injectScript}${loadingHtml}`);\n        return html;\n      },\n      order: 'pre',\n    },\n  };\n}\n\n/**\n * 用于获取loading的html模板\n */\nasync function getLoadingRawByHtmlTemplate(loadingTemplate: string) {\n  // 支持在app内自定义loading模板，模版参考default-loading.html即可\n  let appLoadingPath = join(process.cwd(), loadingTemplate);\n\n  if (!fs.existsSync(appLoadingPath)) {\n    const __dirname = fileURLToPath(new URL('.', import.meta.url));\n    appLoadingPath = join(__dirname, './default-loading.html');\n  }\n\n  return await fsp.readFile(appLoadingPath, 'utf8');\n}\n\nexport { viteInjectAppLoadingPlugin };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/inject-metadata.ts",
    "content": "import type { PluginOption } from 'vite';\n\nimport {\n  dateUtil,\n  findMonorepoRoot,\n  getPackages,\n  readPackageJSON,\n} from '@vben/node-utils';\n\nimport { readWorkspaceManifest } from '@pnpm/workspace.read-manifest';\n\nfunction resolvePackageVersion(\n  pkgsMeta: Record<string, string>,\n  name: string,\n  value: string,\n  catalog: Record<string, string>,\n) {\n  if (value.includes('catalog:')) {\n    return catalog[name];\n  }\n\n  if (value.includes('workspace')) {\n    return pkgsMeta[name];\n  }\n\n  return value;\n}\n\nasync function resolveMonorepoDependencies() {\n  const { packages } = await getPackages();\n  const manifest = await readWorkspaceManifest(findMonorepoRoot());\n  const catalog = manifest?.catalog || {};\n\n  const resultDevDependencies: Record<string, string | undefined> = {};\n  const resultDependencies: Record<string, string | undefined> = {};\n  const pkgsMeta: Record<string, string> = {};\n\n  for (const { packageJson } of packages) {\n    pkgsMeta[packageJson.name] = packageJson.version;\n  }\n\n  for (const { packageJson } of packages) {\n    const { dependencies = {}, devDependencies = {} } = packageJson;\n    for (const [key, value] of Object.entries(dependencies)) {\n      resultDependencies[key] = resolvePackageVersion(\n        pkgsMeta,\n        key,\n        value,\n        catalog,\n      );\n    }\n    for (const [key, value] of Object.entries(devDependencies)) {\n      resultDevDependencies[key] = resolvePackageVersion(\n        pkgsMeta,\n        key,\n        value,\n        catalog,\n      );\n    }\n  }\n  return {\n    dependencies: resultDependencies,\n    devDependencies: resultDevDependencies,\n  };\n}\n\n/**\n * 用于注入项目信息\n */\nasync function viteMetadataPlugin(\n  root = process.cwd(),\n): Promise<PluginOption | undefined> {\n  const { author, description, homepage, license, version } =\n    await readPackageJSON(root);\n\n  const buildTime = dateUtil().format('YYYY-MM-DD HH:mm:ss');\n\n  return {\n    async config() {\n      const { dependencies, devDependencies } =\n        await resolveMonorepoDependencies();\n\n      const isAuthorObject = typeof author === 'object';\n      const authorName = isAuthorObject ? author.name : author;\n      const authorEmail = isAuthorObject ? author.email : null;\n      const authorUrl = isAuthorObject ? author.url : null;\n\n      return {\n        define: {\n          __VBEN_ADMIN_METADATA__: JSON.stringify({\n            authorEmail,\n            authorName,\n            authorUrl,\n            buildTime,\n            dependencies,\n            description,\n            devDependencies,\n            homepage,\n            license,\n            version,\n          }),\n          'import.meta.env.VITE_APP_VERSION': JSON.stringify(version),\n        },\n      };\n    },\n    enforce: 'post',\n    name: 'vite:inject-metadata',\n  };\n}\n\nexport { viteMetadataPlugin };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/license.ts",
    "content": "import type {\n  NormalizedOutputOptions,\n  OutputBundle,\n  OutputChunk,\n} from 'rollup';\nimport type { PluginOption } from 'vite';\n\nimport { EOL } from 'node:os';\n\nimport { dateUtil, readPackageJSON } from '@vben/node-utils';\n\n/**\n * 用于注入版权信息\n * @returns\n */\n\nasync function viteLicensePlugin(\n  root = process.cwd(),\n): Promise<PluginOption | undefined> {\n  const {\n    description = '',\n    homepage = '',\n    version = '',\n  } = await readPackageJSON(root);\n\n  return {\n    apply: 'build',\n    enforce: 'post',\n    generateBundle: {\n      handler: (_options: NormalizedOutputOptions, bundle: OutputBundle) => {\n        const date = dateUtil().format('YYYY-MM-DD ');\n        const copyrightText = `/*!\n  * Vben Admin\n  * Version: ${version}\n  * Author: vben\n  * Copyright (C) 2024 Vben\n  * License: MIT License\n  * Description: ${description}\n  * Date Created: ${date}\n  * Homepage: ${homepage}\n  * Contact: ann.vben@gmail.com\n*/\n              `.trim();\n\n        for (const [, fileContent] of Object.entries(bundle)) {\n          if (fileContent.type === 'chunk' && fileContent.isEntry) {\n            const chunkContent = fileContent as OutputChunk;\n            // 插入版权信息\n            const content = chunkContent.code;\n            const updatedContent = `${copyrightText}${EOL}${content}`;\n\n            // 更新bundle\n            (fileContent as OutputChunk).code = updatedContent;\n          }\n        }\n      },\n      order: 'post',\n    },\n    name: 'vite:license',\n  };\n}\n\nexport { viteLicensePlugin };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/nitro-mock.ts",
    "content": "import type { PluginOption } from 'vite';\n\nimport type { NitroMockPluginOptions } from '../typing';\n\nimport { colors, consola, getPackage } from '@vben/node-utils';\n\nimport getPort from 'get-port';\nimport { build, createDevServer, createNitro, prepare } from 'nitropack';\n\nconst hmrKeyRe = /^runtimeConfig\\.|routeRules\\./;\n\nexport const viteNitroMockPlugin = ({\n  mockServerPackage = '@vben/backend-mock',\n  port = 5320,\n  verbose = true,\n}: NitroMockPluginOptions = {}): PluginOption => {\n  return {\n    async configureServer(server) {\n      const availablePort = await getPort({ port });\n      if (availablePort !== port) {\n        return;\n      }\n\n      const pkg = await getPackage(mockServerPackage);\n      if (!pkg) {\n        consola.log(\n          `Package ${mockServerPackage} not found. Skip mock server.`,\n        );\n        return;\n      }\n\n      runNitroServer(pkg.dir, port, verbose);\n\n      const _printUrls = server.printUrls;\n      server.printUrls = () => {\n        _printUrls();\n\n        consola.log(\n          `  ${colors.green('➜')}  ${colors.bold('Nitro Mock Server')}: ${colors.cyan(`http://localhost:${port}/api`)}`,\n        );\n      };\n    },\n    enforce: 'pre',\n    name: 'vite:mock-server',\n  };\n};\n\nasync function runNitroServer(rootDir: string, port: number, verbose: boolean) {\n  let nitro: any;\n  const reload = async () => {\n    if (nitro) {\n      consola.info('Restarting dev server...');\n      if ('unwatch' in nitro.options._c12) {\n        await nitro.options._c12.unwatch();\n      }\n      await nitro.close();\n    }\n    nitro = await createNitro(\n      {\n        dev: true,\n        preset: 'nitro-dev',\n        rootDir,\n      },\n      {\n        c12: {\n          async onUpdate({ getDiff, newConfig }) {\n            const diff = getDiff();\n            if (diff.length === 0) {\n              return;\n            }\n            verbose &&\n              consola.info(\n                `Nitro config updated:\\n${diff\n                  .map((entry) => `  ${entry.toString()}`)\n                  .join('\\n')}`,\n              );\n            await (diff.every((e) => hmrKeyRe.test(e.key))\n              ? nitro.updateConfig(newConfig.config)\n              : reload());\n          },\n        },\n        watch: true,\n      },\n    );\n    nitro.hooks.hookOnce('restart', reload);\n\n    const server = createDevServer(nitro);\n    await server.listen(port, { showURL: false });\n    await prepare(nitro);\n    await build(nitro);\n\n    if (verbose) {\n      console.log('');\n      consola.success(colors.bold(colors.green('Nitro Mock Server started.')));\n    }\n  };\n  return await reload();\n}\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/print.ts",
    "content": "import type { PluginOption } from 'vite';\n\nimport type { PrintPluginOptions } from '../typing';\n\nimport { colors } from '@vben/node-utils';\n\nexport const vitePrintPlugin = (\n  options: PrintPluginOptions = {},\n): PluginOption => {\n  const { infoMap = {} } = options;\n\n  return {\n    configureServer(server) {\n      const _printUrls = server.printUrls;\n      server.printUrls = () => {\n        _printUrls();\n\n        for (const [key, value] of Object.entries(infoMap)) {\n          console.log(\n            `  ${colors.green('➜')}  ${colors.bold(key)}: ${colors.cyan(value)}`,\n          );\n        }\n      };\n    },\n    enforce: 'pre',\n    name: 'vite:print-info',\n  };\n};\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/plugins/vxe-table.ts",
    "content": "import type { PluginOption } from 'vite';\n\nimport { lazyImport, VxeResolver } from 'vite-plugin-lazy-import';\n\nasync function viteVxeTableImportsPlugin(): Promise<PluginOption> {\n  return [\n    lazyImport({\n      resolvers: [\n        VxeResolver({\n          libraryName: 'vxe-table',\n        }),\n        VxeResolver({\n          libraryName: 'vxe-pc-ui',\n        }),\n      ],\n    }),\n  ];\n}\n\nexport { viteVxeTableImportsPlugin };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/typing.ts",
    "content": "import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer';\nimport type { ConfigEnv, PluginOption, UserConfig } from 'vite';\nimport type { PluginOptions } from 'vite-plugin-dts';\nimport type { Options as PwaPluginOptions } from 'vite-plugin-pwa';\n\n/**\n * ImportMap 配置接口\n * @description 用于配置模块导入映射，支持自定义导入路径和范围\n * @example\n * ```typescript\n * {\n *   imports: {\n *     'vue': 'https://unpkg.com/vue@3.2.47/dist/vue.esm-browser.js'\n *   },\n *   scopes: {\n *     'https://site.com/': {\n *       'vue': 'https://unpkg.com/vue@3.2.47/dist/vue.esm-browser.js'\n *     }\n *   }\n * }\n * ```\n */\ninterface IImportMap {\n  /** 模块导入映射 */\n  imports?: Record<string, string>;\n  /** 作用域特定的导入映射 */\n  scopes?: {\n    [scope: string]: Record<string, string>;\n  };\n}\n\n/**\n * 打印插件配置选项\n * @description 用于配置控制台打印信息\n */\ninterface PrintPluginOptions {\n  /**\n   * 打印的数据映射\n   * @description 键值对形式的数据，将在控制台打印\n   * @example\n   * ```typescript\n   * {\n   *   'App Version': '1.0.0',\n   *   'Build Time': '2024-01-01'\n   * }\n   * ```\n   */\n  infoMap?: Record<string, string | undefined>;\n}\n\n/**\n * Nitro Mock 插件配置选项\n * @description 用于配置 Nitro Mock 服务器的行为\n */\ninterface NitroMockPluginOptions {\n  /**\n   * Mock 服务器包名\n   * @default '@vbenjs/nitro-mock'\n   */\n  mockServerPackage?: string;\n\n  /**\n   * Mock 服务端口\n   * @default 3000\n   */\n  port?: number;\n\n  /**\n   * 是否打印 Mock 日志\n   * @default false\n   */\n  verbose?: boolean;\n}\n\n/**\n * 归档插件配置选项\n * @description 用于配置构建产物的压缩归档\n */\ninterface ArchiverPluginOptions {\n  /**\n   * 输出文件名\n   * @default 'dist'\n   */\n  name?: string;\n  /**\n   * 输出目录\n   * @default '.'\n   */\n  outputDir?: string;\n}\n\n/**\n * ImportMap 插件配置\n * @description 用于配置模块的 CDN 导入\n */\ninterface ImportmapPluginOptions {\n  /**\n   * CDN 供应商\n   * @default 'jspm.io'\n   * @description 支持 esm.sh 和 jspm.io 两种 CDN 供应商\n   */\n  defaultProvider?: 'esm.sh' | 'jspm.io';\n  /**\n   * ImportMap 配置数组\n   * @description 配置需要从 CDN 导入的包\n   * @example\n   * ```typescript\n   * [\n   *   { name: 'vue' },\n   *   { name: 'pinia', range: '^2.0.0' }\n   * ]\n   * ```\n   */\n  importmap?: Array<{ name: string; range?: string }>;\n  /**\n   * 手动配置 ImportMap\n   * @description 自定义 ImportMap 配置\n   */\n  inputMap?: IImportMap;\n}\n\n/**\n * 条件插件配置\n * @description 用于根据条件动态加载插件\n */\ninterface ConditionPlugin {\n  /**\n   * 判断条件\n   * @description 当条件为 true 时加载插件\n   */\n  condition?: boolean;\n  /**\n   * 插件对象\n   * @description 返回插件数组或 Promise\n   */\n  plugins: () => PluginOption[] | PromiseLike<PluginOption[]>;\n}\n\n/**\n * 通用插件配置选项\n * @description 所有插件共用的基础配置\n */\ninterface CommonPluginOptions {\n  /**\n   * 是否开启开发工具\n   * @default false\n   */\n  devtools?: boolean;\n  /**\n   * 环境变量\n   * @description 自定义环境变量\n   */\n  env?: Record<string, any>;\n  /**\n   * 是否注入元数据\n   * @default true\n   */\n  injectMetadata?: boolean;\n  /**\n   * 是否为构建模式\n   * @default false\n   */\n  isBuild?: boolean;\n  /**\n   * 构建模式\n   * @default 'development'\n   */\n  mode?: string;\n  /**\n   * 是否开启依赖分析\n   * @default false\n   * @description 使用 rollup-plugin-visualizer 分析依赖\n   */\n  visualizer?: boolean | PluginVisualizerOptions;\n}\n\n/**\n * 应用插件配置选项\n * @description 用于配置应用构建时的插件选项\n */\ninterface ApplicationPluginOptions extends CommonPluginOptions {\n  /**\n   * 是否开启压缩归档\n   * @default false\n   * @description 开启后会在打包目录生成 zip 文件\n   */\n  archiver?: boolean;\n  /**\n   * 压缩归档插件配置\n   * @description 配置压缩归档的行为\n   */\n  archiverPluginOptions?: ArchiverPluginOptions;\n  /**\n   * 是否开启压缩\n   * @default false\n   * @description 支持 gzip 和 brotli 压缩\n   */\n  compress?: boolean;\n  /**\n   * 压缩类型\n   * @default ['gzip']\n   * @description 可选的压缩类型\n   */\n  compressTypes?: ('brotli' | 'gzip')[];\n  /**\n   * 是否抽离配置文件\n   * @default false\n   * @description 在构建时抽离配置文件\n   */\n  extraAppConfig?: boolean;\n  /**\n   * 是否开启 HTML 插件\n   * @default true\n   */\n  html?: boolean;\n  /**\n   * 是否开启国际化\n   * @default false\n   */\n  i18n?: boolean;\n  /**\n   * 是否开启 ImportMap CDN\n   * @default false\n   */\n  importmap?: boolean;\n  /**\n   * ImportMap 插件配置\n   */\n  importmapOptions?: ImportmapPluginOptions;\n  /**\n   * 是否注入应用加载动画\n   * @default true\n   */\n  injectAppLoading?: boolean;\n  /**\n   * 是否注入全局 SCSS\n   * @default true\n   */\n  injectGlobalScss?: boolean;\n  /**\n   * 是否注入版权信息\n   * @default true\n   */\n  license?: boolean;\n  /**\n   * 是否开启 Nitro Mock\n   * @default false\n   */\n  nitroMock?: boolean;\n  /**\n   * Nitro Mock 插件配置\n   */\n  nitroMockOptions?: NitroMockPluginOptions;\n  /**\n   * 是否开启控制台打印\n   * @default false\n   */\n  print?: boolean;\n  /**\n   * 打印插件配置\n   */\n  printInfoMap?: PrintPluginOptions['infoMap'];\n  /**\n   * 是否开启 PWA\n   * @default false\n   */\n  pwa?: boolean;\n  /**\n   * PWA 插件配置\n   */\n  pwaOptions?: Partial<PwaPluginOptions>;\n  /**\n   * 是否开启 VXE Table 懒加载\n   * @default false\n   */\n  vxeTableLazyImport?: boolean;\n}\n\n/**\n * 库插件配置选项\n * @description 用于配置库构建时的插件选项\n */\ninterface LibraryPluginOptions extends CommonPluginOptions {\n  /**\n   * 是否开启 DTS 输出\n   * @default true\n   * @description 生成 TypeScript 类型声明文件\n   */\n  dts?: boolean | PluginOptions;\n}\n\n/**\n * 应用配置选项类型\n */\ntype ApplicationOptions = ApplicationPluginOptions;\n\n/**\n * 库配置选项类型\n */\ntype LibraryOptions = LibraryPluginOptions;\n\n/**\n * 应用配置定义函数类型\n * @description 用于定义应用构建配置\n */\ntype DefineApplicationOptions = (config?: ConfigEnv) => Promise<{\n  /** 应用插件配置 */\n  application?: ApplicationOptions;\n  /** Vite 配置 */\n  vite?: UserConfig;\n}>;\n\n/**\n * 库配置定义函数类型\n * @description 用于定义库构建配置\n */\ntype DefineLibraryOptions = (config?: ConfigEnv) => Promise<{\n  /** 库插件配置 */\n  library?: LibraryOptions;\n  /** Vite 配置 */\n  vite?: UserConfig;\n}>;\n\n/**\n * 配置定义类型\n * @description 应用或库的配置定义\n */\ntype DefineConfig = DefineApplicationOptions | DefineLibraryOptions;\n\nexport type {\n  ApplicationPluginOptions,\n  ArchiverPluginOptions,\n  CommonPluginOptions,\n  ConditionPlugin,\n  DefineApplicationOptions,\n  DefineConfig,\n  DefineLibraryOptions,\n  IImportMap,\n  ImportmapPluginOptions,\n  LibraryPluginOptions,\n  NitroMockPluginOptions,\n  PrintPluginOptions,\n};\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/src/utils/env.ts",
    "content": "import type { ApplicationPluginOptions } from '../typing';\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { fs } from '@vben/node-utils';\n\nimport dotenv from 'dotenv';\n\nconst getBoolean = (value: string | undefined) => value === 'true';\n\nconst getString = (value: string | undefined, fallback: string) =>\n  value ?? fallback;\n\nconst getNumber = (value: string | undefined, fallback: number) =>\n  Number(value) || fallback;\n\n/**\n * 获取当前环境下生效的配置文件名\n */\nfunction getConfFiles() {\n  const script = process.env.npm_lifecycle_script as string;\n  const reg = /--mode ([\\d_a-z]+)/;\n  const result = reg.exec(script);\n  let mode = 'production';\n  if (result) {\n    mode = result[1] as string;\n  }\n  return ['.env', '.env.local', `.env.${mode}`, `.env.${mode}.local`];\n}\n\n/**\n * Get the environment variables starting with the specified prefix\n * @param match prefix\n * @param confFiles ext\n */\nasync function loadEnv<T = Record<string, string>>(\n  match = 'VITE_GLOB_',\n  confFiles = getConfFiles(),\n) {\n  let envConfig = {};\n\n  for (const confFile of confFiles) {\n    try {\n      const confFilePath = join(process.cwd(), confFile);\n      if (existsSync(confFilePath)) {\n        const envPath = await fs.readFile(confFilePath, {\n          encoding: 'utf8',\n        });\n        const env = dotenv.parse(envPath);\n        envConfig = { ...envConfig, ...env };\n      }\n    } catch (error) {\n      console.error(`Error while parsing ${confFile}`, error);\n    }\n  }\n  const reg = new RegExp(`^(${match})`);\n  Object.keys(envConfig).forEach((key) => {\n    if (!reg.test(key)) {\n      Reflect.deleteProperty(envConfig, key);\n    }\n  });\n  return envConfig as T;\n}\n\nasync function loadAndConvertEnv(\n  match = 'VITE_',\n  confFiles = getConfFiles(),\n): Promise<\n  Partial<ApplicationPluginOptions> & {\n    appTitle: string;\n    base: string;\n    port: number;\n  }\n> {\n  const envConfig = await loadEnv(match, confFiles);\n\n  const {\n    VITE_APP_TITLE,\n    VITE_ARCHIVER,\n    VITE_BASE,\n    VITE_COMPRESS,\n    VITE_DEVTOOLS,\n    VITE_INJECT_APP_LOADING,\n    VITE_NITRO_MOCK,\n    VITE_PORT,\n    VITE_PWA,\n    VITE_VISUALIZER,\n  } = envConfig;\n\n  const compressTypes = (VITE_COMPRESS ?? '')\n    .split(',')\n    .filter((item) => item === 'brotli' || item === 'gzip');\n\n  return {\n    appTitle: getString(VITE_APP_TITLE, 'Vben Admin'),\n    archiver: getBoolean(VITE_ARCHIVER),\n    base: getString(VITE_BASE, '/'),\n    compress: compressTypes.length > 0,\n    compressTypes,\n    devtools: getBoolean(VITE_DEVTOOLS),\n    injectAppLoading: getBoolean(VITE_INJECT_APP_LOADING),\n    nitroMock: getBoolean(VITE_NITRO_MOCK),\n    port: getNumber(VITE_PORT, 5173),\n    pwa: getBoolean(VITE_PWA),\n    visualizer: getBoolean(VITE_VISUALIZER),\n  };\n}\n\nexport { loadAndConvertEnv, loadEnv };\n"
  },
  {
    "path": "hiauth-front/internal/vite-config/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/package.json",
    "content": "{\n  \"name\": \"vben-admin-monorepo\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"keywords\": [\n    \"monorepo\",\n    \"turbo\",\n    \"vben\",\n    \"vben admin\",\n    \"vben pro\",\n    \"vue\",\n    \"vue admin\",\n    \"vue vben admin\",\n    \"vue vben admin pro\",\n    \"vue3\"\n  ],\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": \"vbenjs/vue-vben-admin.git\",\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"vben\",\n    \"email\": \"ann.vben@gmail.com\",\n    \"url\": \"https://github.com/anncwb\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build\",\n    \"build:analyze\": \"turbo build:analyze\",\n    \"build:antd\": \"pnpm run build --filter=@vben/web-antd\",\n    \"build:docker\": \"./scripts/deploy/build-local-docker-image.sh\",\n    \"build:docs\": \"pnpm run build --filter=@vben/docs\",\n    \"build:ele\": \"pnpm run build --filter=@vben/web-ele\",\n    \"build:naive\": \"pnpm run build --filter=@vben/web-naive\",\n    \"build:play\": \"pnpm run build --filter=@vben/playground\",\n    \"build:auth\": \"pnpm run build --filter=@vben/web-auth\",\n    \"changeset\": \"pnpm exec changeset\",\n    \"check\": \"pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell\",\n    \"check:circular\": \"vsh check-circular\",\n    \"check:cspell\": \"cspell lint **/*.ts **/README.md .changeset/*.md --no-progress\",\n    \"check:dep\": \"vsh check-dep\",\n    \"check:type\": \"turbo run typecheck\",\n    \"clean\": \"node ./scripts/clean.mjs\",\n    \"commit\": \"czg\",\n    \"dev\": \"turbo-run dev\",\n    \"dev:antd\": \"pnpm -F @vben/web-antd run dev\",\n    \"dev:docs\": \"pnpm -F @vben/docs run dev\",\n    \"dev:ele\": \"pnpm -F @vben/web-ele run dev\",\n    \"dev:naive\": \"pnpm -F @vben/web-naive run dev\",\n    \"dev:play\": \"pnpm -F @vben/playground run dev\",\n    \"dev:auth\": \"pnpm -F @vben/web-auth run dev\",\n    \"format\": \"vsh lint --format\",\n    \"lint\": \"vsh lint\",\n    \"postinstall\": \"pnpm -r run stub --if-present\",\n    \"preinstall\": \"npx only-allow pnpm\",\n    \"preview\": \"turbo-run preview\",\n    \"publint\": \"vsh publint\",\n    \"reinstall\": \"pnpm clean --del-lock && pnpm install\",\n    \"test:unit\": \"vitest run --dom\",\n    \"test:e2e\": \"turbo run test:e2e\",\n    \"update:deps\": \"npx taze -r -w\",\n    \"version\": \"pnpm exec changeset version && pnpm install --no-frozen-lockfile\",\n    \"catalog\": \"pnpx codemod pnpm/catalog\"\n  },\n  \"devDependencies\": {\n    \"@changesets/changelog-github\": \"catalog:\",\n    \"@changesets/cli\": \"catalog:\",\n    \"@playwright/test\": \"catalog:\",\n    \"@types/node\": \"catalog:\",\n    \"@vben/commitlint-config\": \"workspace:*\",\n    \"@vben/eslint-config\": \"workspace:*\",\n    \"@vben/prettier-config\": \"workspace:*\",\n    \"@vben/stylelint-config\": \"workspace:*\",\n    \"@vben/tailwind-config\": \"workspace:*\",\n    \"@vben/tsconfig\": \"workspace:*\",\n    \"@vben/turbo-run\": \"workspace:*\",\n    \"@vben/vite-config\": \"workspace:*\",\n    \"@vben/vsh\": \"workspace:*\",\n    \"@vitejs/plugin-vue\": \"catalog:\",\n    \"@vitejs/plugin-vue-jsx\": \"catalog:\",\n    \"@vue/test-utils\": \"catalog:\",\n    \"autoprefixer\": \"catalog:\",\n    \"cross-env\": \"catalog:\",\n    \"cspell\": \"catalog:\",\n    \"happy-dom\": \"catalog:\",\n    \"is-ci\": \"catalog:\",\n    \"lefthook\": \"catalog:\",\n    \"playwright\": \"catalog:\",\n    \"rimraf\": \"catalog:\",\n    \"tailwindcss\": \"catalog:\",\n    \"turbo\": \"catalog:\",\n    \"typescript\": \"catalog:\",\n    \"unbuild\": \"catalog:\",\n    \"vite\": \"catalog:\",\n    \"vitest\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-tsc\": \"catalog:\"\n  },\n  \"engines\": {\n    \"node\": \">=20.10.0\",\n    \"pnpm\": \">=9.12.0\"\n  },\n  \"packageManager\": \"pnpm@10.14.0\",\n  \"pnpm\": {\n    \"peerDependencyRules\": {\n      \"allowedVersions\": {\n        \"eslint\": \"*\"\n      }\n    },\n    \"overrides\": {\n      \"@ast-grep/napi\": \"catalog:\",\n      \"@ctrl/tinycolor\": \"catalog:\",\n      \"clsx\": \"catalog:\",\n      \"esbuild\": \"0.25.3\",\n      \"pinia\": \"catalog:\",\n      \"vue\": \"catalog:\"\n    },\n    \"neverBuiltDependencies\": [\n      \"canvas\",\n      \"node-gyp\"\n    ]\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/README.md",
    "content": "# @vben-core\n\n系统一些比较基础的SDK和UI组件库，该目录后续完善后，可能会迁移出去或者发布到npm，请勿将任何业务逻辑和业务包放在该目录。\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/README.md",
    "content": "# base\n\n基础共享包，请勿引入 workspace 依赖\n\n-\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/package.json",
    "content": "{\n  \"name\": \"@vben-core/design\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/base/design\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm vite build\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\",\n    \"src\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \"./bem\": {\n      \"development\": \"./src/scss-bem/bem.scss\",\n      \"default\": \"./dist/bem.scss\"\n    },\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/design.css\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/css/global.css",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n  *,\n  ::after,\n  ::before {\n    @apply border-border;\n\n    box-sizing: border-box;\n    border-style: solid;\n    border-width: 0;\n  }\n\n  html {\n    @apply text-foreground bg-background font-sans text-[100%];\n\n    font-variation-settings: normal;\n    line-height: 1.15;\n    text-size-adjust: 100%;\n    font-synthesis-weight: none;\n    scroll-behavior: smooth;\n    text-rendering: optimizelegibility;\n    -webkit-tap-highlight-color: transparent;\n\n    /* -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale; */\n  }\n\n  #app,\n  body,\n  html {\n    @apply size-full;\n\n    /* scrollbar-gutter: stable; */\n  }\n\n  body {\n    min-height: 100vh;\n\n    /* pointer-events: auto !important; */\n\n    /* overflow: overlay; */\n\n    /* -webkit-font-smoothing: antialiased; */\n\n    /* -moz-osx-font-smoothing: grayscale; */\n  }\n\n  a,\n  a:active,\n  a:hover,\n  a:link,\n  a:visited {\n    @apply no-underline;\n  }\n\n  ::view-transition-new(root),\n  ::view-transition-old(root) {\n    @apply animate-none mix-blend-normal;\n  }\n\n  ::view-transition-old(root) {\n    @apply z-[1];\n  }\n\n  ::view-transition-new(root) {\n    @apply z-[2147483646];\n  }\n\n  html.dark::view-transition-old(root) {\n    @apply z-[2147483646];\n  }\n\n  html.dark::view-transition-new(root) {\n    @apply z-[1];\n  }\n\n  input::placeholder,\n  textarea::placeholder {\n    @apply opacity-100;\n  }\n\n  /* input:-webkit-autofill {\n    @apply border-none;\n\n    box-shadow: 0 0 0 1000px transparent inset;\n  } */\n\n  input[type='number']::-webkit-inner-spin-button,\n  input[type='number']::-webkit-outer-spin-button {\n    @apply m-0 appearance-none;\n  }\n\n  /* 只有非mac下才进行调整，mac下使用默认滚动条 */\n  html:not([data-platform='macOs']) {\n    ::-webkit-scrollbar {\n      @apply h-[10px] w-[10px];\n    }\n\n    ::-webkit-scrollbar-thumb {\n      @apply bg-border rounded-sm border-none;\n    }\n\n    ::-webkit-scrollbar-track {\n      @apply rounded-sm border-none bg-transparent shadow-none;\n    }\n\n    ::-webkit-scrollbar-button {\n      @apply hidden;\n    }\n  }\n}\n\n@layer components {\n  .flex-center {\n    @apply flex items-center justify-center;\n  }\n\n  .flex-col-center {\n    @apply flex flex-col items-center justify-center;\n  }\n\n  .outline-box {\n    @apply outline-border relative cursor-pointer rounded-md p-1 outline outline-1;\n  }\n\n  .outline-box::after {\n    @apply absolute left-1/2 top-1/2 z-20 h-0 w-[1px] rounded-sm opacity-0 outline outline-2 outline-transparent transition-all duration-300 content-[\"\"];\n  }\n\n  .outline-box.outline-box-active {\n    @apply outline-primary outline outline-2;\n  }\n\n  .outline-box.outline-box-active::after {\n    display: none;\n  }\n\n  .outline-box:not(.outline-box-active):hover::after {\n    @apply outline-primary left-0 top-0 h-full w-full p-1 opacity-100;\n  }\n\n  .vben-link {\n    @apply text-primary hover:text-primary-hover active:text-primary-active cursor-pointer;\n  }\n\n  .card-box {\n    @apply bg-card text-card-foreground border-border rounded-xl border;\n  }\n}\n\nhtml.invert-mode {\n  @apply invert;\n}\n\nhtml.grayscale-mode {\n  @apply grayscale;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/css/nprogress.css",
    "content": "/* Make clicks pass-through */\n#nprogress {\n  @apply pointer-events-none;\n}\n\n#nprogress .bar {\n  @apply bg-primary fixed left-0 top-0 z-[1031] h-[2px] w-full;\n}\n\n/* Fancy blur effect */\n#nprogress .peg {\n  @apply absolute right-0 block h-full w-[100px];\n\n  box-shadow:\n    0 0 10px hsl(var(--primary)),\n    0 0 5px hsl(var(--primary));\n  opacity: 1;\n  transform: rotate(3deg) translate(0, -4px);\n}\n\n/* Remove these to get rid of the spinner */\n#nprogress .spinner {\n  @apply fixed right-4 top-4 z-[1031] block;\n}\n\n#nprogress .spinner-icon {\n  @apply border-t-primary border-l-primary size-4 rounded-full border-[2px] border-solid border-transparent;\n\n  animation: nprogress-spinner 400ms linear infinite;\n}\n\n.nprogress-custom-parent {\n  @apply relative overflow-hidden;\n}\n\n.nprogress-custom-parent #nprogress .spinner,\n.nprogress-custom-parent #nprogress .bar {\n  @apply absolute;\n}\n\n@keyframes nprogress-spinner {\n  0% {\n    transform: rotate(0deg);\n  }\n\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes nprogress-spinner {\n  0% {\n    transform: rotate(0deg);\n  }\n\n  100% {\n    transform: rotate(360deg);\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/css/transition.css",
    "content": ".slide-up-enter-active,\n.slide-up-leave-active {\n  transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1);\n}\n\n.slide-up-move {\n  transition: transform 0.3s;\n}\n\n.slide-up-enter-from,\n.slide-up-leave-to {\n  opacity: 0;\n  transform: translateY(-15px);\n}\n\n.slide-down-enter-active,\n.slide-down-leave-active {\n  transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1);\n}\n\n.slide-down-move {\n  transition: transform 0.3s;\n}\n\n.slide-down-enter-from,\n.slide-down-leave-to {\n  opacity: 0;\n  transform: translateY(15px);\n}\n\n.slide-left-enter-active,\n.slide-left-leave-active {\n  transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1);\n}\n\n.slide-left-move {\n  transition: transform 0.3s;\n}\n\n.slide-left-enter-from,\n.slide-left-leave-to {\n  opacity: 0;\n  transform: translate(-15px);\n}\n\n.slide-right-enter-active,\n.slide-right-leave-active {\n  transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1);\n}\n\n.slide-right-move {\n  transition: transform 0.3s;\n}\n\n.slide-right-enter-from,\n.slide-right-leave-to {\n  opacity: 0;\n  transform: translate(15px);\n}\n\n.fade-transition-enter-active,\n.fade-transition-leave-active {\n  transition: opacity 0.2s ease-in-out;\n}\n\n.fade-transition-enter-from,\n.fade-transition-leave-to {\n  opacity: 0;\n}\n\n.fade-enter-active,\n.fade-leave-active {\n  transition: opacity 0.2s ease-in-out;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n  opacity: 0;\n}\n\n.fade-slide-leave-active,\n.fade-slide-enter-active {\n  transition: all 0.3s;\n}\n\n.fade-slide-enter-from {\n  opacity: 0;\n  transform: translate(-30px);\n}\n\n.fade-slide-leave-to {\n  opacity: 0;\n  transform: translate(30px);\n}\n\n.fade-down-enter-active,\n.fade-down-leave-active {\n  transition:\n    opacity 0.25s,\n    transform 0.3s;\n}\n\n.fade-down-enter-from {\n  opacity: 0;\n  transform: translateY(-10%);\n}\n\n.fade-down-leave-to {\n  opacity: 0;\n  transform: translateY(10%);\n}\n\n.fade-scale-leave-active,\n.fade-scale-enter-active {\n  transition: all 0.28s;\n}\n\n.fade-scale-enter-from {\n  opacity: 0;\n  transform: scale(1.2);\n}\n\n.fade-scale-leave-to {\n  opacity: 0;\n  transform: scale(0.8);\n}\n\n.fade-up-enter-active,\n.fade-up-leave-active {\n  transition:\n    opacity 0.2s,\n    transform 0.25s;\n}\n\n.fade-up-enter-from {\n  opacity: 0;\n  transform: translateY(10%);\n}\n\n.fade-up-leave-to {\n  opacity: 0;\n  transform: translateY(-10%);\n}\n\n@keyframes fade-slide {\n  0% {\n    opacity: 0;\n    transform: translate(-30px);\n  }\n\n  50% {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    transform: translate(30px);\n  }\n}\n\n@keyframes fade {\n  0% {\n    opacity: 0;\n  }\n\n  50% {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n  }\n}\n\n@keyframes fade-up {\n  0% {\n    opacity: 0;\n    transform: translateY(10%);\n  }\n\n  50% {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    transform: translateY(-10%);\n  }\n}\n\n@keyframes fade-down {\n  0% {\n    opacity: 0;\n    transform: translateY(-10%);\n  }\n\n  50% {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    transform: translateY(10%);\n  }\n}\n\n.fade-slow {\n  animation: fade 3s infinite;\n}\n\n.fade-slide-slow {\n  animation: fade-slide 3s infinite;\n}\n\n.fade-up-slow {\n  animation: fade-up 3s infinite;\n}\n\n.fade-down-slow {\n  animation: fade-down 3s infinite;\n}\n\n.collapse-transition {\n  transition:\n    0.2s height ease-in-out,\n    0.2s padding-top ease-in-out,\n    0.2s padding-bottom ease-in-out;\n}\n\n.collapse-transition-leave-active,\n.collapse-transition-enter-active {\n  transition:\n    0.2s max-height ease-in-out,\n    0.2s padding-top ease-in-out,\n    0.2s margin-top ease-in-out;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/css/ui.css",
    "content": ".side-content {\n  animation-duration: 0.2s;\n  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.side-content[data-side='top'] {\n  animation-name: slide-up;\n}\n\n.side-content[data-side='bottom'] {\n  animation-name: slide-down;\n}\n\n.side-content[data-side='left'] {\n  animation-name: slide-left;\n}\n\n.side-content[data-side='right'] {\n  animation-name: slide-right;\n}\n\n.breadcrumb-transition-enter-active {\n  transition:\n    transform 0.4s cubic-bezier(0.76, 0, 0.24, 1),\n    opacity 0.4s cubic-bezier(0.76, 0, 0.24, 1);\n}\n\n.breadcrumb-transition-leave-active {\n  display: none;\n}\n\n.breadcrumb-transition-enter-from {\n  opacity: 0;\n  transform: translateX(30px) skewX(-30deg);\n}\n\n@keyframes slide-down {\n  from {\n    opacity: 0;\n    transform: translateY(-10px);\n  }\n\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n\n@keyframes slide-left {\n  from {\n    opacity: 0;\n    transform: translateX(-10px);\n  }\n\n  to {\n    opacity: 1;\n    transform: translateX(0);\n  }\n}\n\n@keyframes slide-right {\n  from {\n    opacity: 0;\n    transform: translateX(-10px);\n  }\n\n  to {\n    opacity: 1;\n    transform: translateX(0);\n  }\n}\n\n@keyframes slide-up {\n  from {\n    opacity: 0;\n    transform: translateY(10px);\n  }\n\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n\n.z-popup {\n  z-index: var(--popup-z-index);\n}\n\n@keyframes shrink {\n  0% {\n    transform: scale(1);\n  }\n\n  50% {\n    transform: scale(0.9);\n  }\n\n  100% {\n    transform: scale(1);\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/design-tokens/dark.css",
    "content": ".dark,\n.dark[data-theme='custom'],\n.dark[data-theme='default'] {\n  /* Default background color of <body />...etc */\n  --background: 222.34deg 10.43% 12.27%;\n\n  /* 主体区域背景色 */\n  --background-deep: 220deg 13.06% 9%;\n  --foreground: 0 0% 95%;\n\n  /* Background color for <Card /> */\n  --card: 222.34deg 10.43% 12.27%;\n\n  /* --card: 222.2 84% 4.9%; */\n  --card-foreground: 210 40% 98%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n\n  /* --popover: 222.82deg 8.43% 12.27%; */\n\n  /* 弹出层的背景色与主题区域背景色太过接近  */\n  --popover: 0 0% 14.2%;\n  --popover-foreground: 210 40% 98%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n\n  /* --muted: 220deg 6.82% 17.25%; */\n\n  /* --muted-foreground: 215 20.2% 65.1%; */\n\n  --muted: 240 3.7% 15.9%;\n  --muted-foreground: 240 5% 64.9%;\n\n  /* 主题颜色 */\n\n  /* --primary: 245 82% 67%; */\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --info: 180, 1.54%, 12.75%;\n  --info-foreground: 220, 4%, 58%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* 颜色次要 */\n  --secondary: 240 5% 17%;\n  --secondary-foreground: 0 0% 98%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 216 5% 19%;\n  --accent-dark: 240 0% 22%;\n  --accent-darker: 240 0% 26%;\n  --accent-lighter: 216 5% 12%;\n  --accent-hover: 216 5% 24%;\n  --accent-foreground: 0 0% 98%;\n\n  /* Darker color */\n  --heavy: 216 5% 24%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 3.7% 22%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 0deg 0% 100% / 10%;\n  --input-placeholder: 218deg 11% 65%;\n  --input-background: 0deg 0% 100% / 5%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* 基本圆角大小 */\n  --radius: 0.5rem;\n\n  /* ============= Custom ============= */\n\n  /* 遮罩颜色 */\n  --overlay: 0deg 0% 0% / 40%;\n  --overlay-content: 0deg 0% 0% / 40%;\n\n  /* 基本文字大小 */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  --sidebar: 222.34deg 10.43% 12.27%;\n  --sidebar-deep: 220deg 13.06% 9%;\n  --menu: var(--sidebar);\n\n  /* header */\n  --header: 222.34deg 10.43% 12.27%;\n\n  color-scheme: dark;\n}\n\n.dark[data-theme='violet'],\n[data-theme='violet'] .dark {\n  --background: 224 71.4% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 210 20% 98%;\n  --card: 224 71.4% 4.1%;\n  --card-foreground: 210 20% 98%;\n  --popover: 224 71.4% 4.1%;\n  --popover-foreground: 210 20% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 215 27.9% 16.9%;\n  --secondary-foreground: 210 20% 98%;\n  --muted: 215 27.9% 16.9%;\n  --muted-foreground: 217.9 10.6% 64.9%;\n  --accent: 215 27.9% 16.9%;\n  --accent-foreground: 210 20% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 215 27.9% 16.9%;\n  --input: 215 27.9% 16.9%;\n  --ring: 263.4 70% 50.4%;\n  --sidebar: 224 71.4% 4.1%;\n  --sidebar-deep: 224 71.4% 4.1%;\n  --header: 224 71.4% 4.1%;\n}\n\n.dark[data-theme='pink'],\n[data-theme='pink'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 0 0% 9%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 346.8 77.2% 49.8%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='rose'],\n[data-theme='rose'] .dark {\n  --background: 0 0% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 0 0% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 0 0% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 0 85.7% 97.3%;\n  --secondary: 0 0% 14.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 14.9%;\n  --muted-foreground: 0 0% 63.9%;\n  --accent: 0 0% 14.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 14.9%;\n  --input: 0 0% 14.9%;\n  --ring: 0 72.2% 50.6%;\n  --sidebar: 0 0% 3.9%;\n  --sidebar-deep: 0 0% 3.9%;\n  --header: 0 0% 3.9%;\n}\n\n.dark[data-theme='sky-blue'],\n[data-theme='sky-blue'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 224.3 76.3% 48%;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='deep-blue'],\n[data-theme='deep-blue'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 224.3 76.3% 48%;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='green'],\n[data-theme='green'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 24 9.8% 6%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 142.4 71.8% 29.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='deep-green'],\n[data-theme='deep-green'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 95%;\n  --card: 24 9.8% 6%;\n  --card-foreground: 0 0% 95%;\n  --popover: 0 0% 9%;\n  --popover-foreground: 0 0% 95%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 15%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 0 85.7% 97.3%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 142.4 71.8% 29.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='orange'],\n[data-theme='orange'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 60 9.1% 97.8%;\n  --card: 20 14.3% 4.1%;\n  --card-foreground: 60 9.1% 97.8%;\n  --popover: 20 14.3% 4.1%;\n  --popover-foreground: 60 9.1% 97.8%;\n  --primary-foreground: 60 9.1% 97.8%;\n  --secondary: 12 6.5% 15.1%;\n  --secondary-foreground: 60 9.1% 97.8%;\n  --muted: 12 6.5% 15.1%;\n  --muted-foreground: 24 5.4% 63.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 60 9.1% 97.8%;\n  --destructive: 0 72.2% 50.6%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 12 6.5% 15.1%;\n  --input: 12 6.5% 15.1%;\n  --ring: 20.5 90.2% 48.2%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='yellow'],\n[data-theme='yellow'] .dark {\n  --background: 20 14.3% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 60 9.1% 97.8%;\n  --card: 20 14.3% 4.1%;\n  --card-foreground: 60 9.1% 97.8%;\n  --popover: 20 14.3% 4.1%;\n  --popover-foreground: 60 9.1% 97.8%;\n  --primary-foreground: 26 83.3% 14.1%;\n  --secondary: 12 6.5% 15.1%;\n  --secondary-foreground: 60 9.1% 97.8%;\n  --muted: 12 6.5% 15.1%;\n  --muted-foreground: 24 5.4% 63.9%;\n  --accent: 12 6.5% 15.1%;\n  --accent-foreground: 60 9.1% 97.8%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 12 6.5% 15.1%;\n  --input: 12 6.5% 15.1%;\n  --ring: 35.5 91.7% 32.9%;\n  --sidebar: 20 14.3% 4.1%;\n  --sidebar-deep: 20 14.3% 4.1%;\n  --header: 20 14.3% 4.1%;\n}\n\n.dark[data-theme='zinc'],\n[data-theme='zinc'] .dark {\n  --background: 240 10% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 240 10% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 240 10% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 240 5.9% 10%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 240 3.7% 15.9%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 240 3.7% 15.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 3.7% 15.9%;\n  --input: 240 3.7% 15.9%;\n  --ring: 240 4.9% 83.9%;\n  --sidebar: 240 10% 3.9%;\n  --sidebar-deep: 240 10% 3.9%;\n  --header: 240 10% 3.9%;\n}\n\n.dark[data-theme='neutral'],\n[data-theme='neutral'] .dark {\n  --background: 0 0% 3.9%;\n  --background-deep: var(--background);\n  --foreground: 0 0% 98%;\n  --card: 0 0% 3.9%;\n  --card-foreground: 0 0% 98%;\n  --popover: 0 0% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary-foreground: 0 0% 9%;\n  --secondary: 0 0% 14.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 0 0% 14.9%;\n  --muted-foreground: 0 0% 63.9%;\n  --accent: 0 0% 14.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 14.9%;\n  --input: 0 0% 14.9%;\n  --ring: 0 0% 83.1%;\n  --sidebar: 0 0% 3.9%;\n  --sidebar-deep: 0 0% 3.9%;\n  --header: 0 0% 3.9%;\n}\n\n.dark[data-theme='slate'],\n[data-theme='slate'] .dark {\n  --background: 222.2 84% 4.9%;\n  --background-deep: var(--background);\n  --foreground: 210 40% 98%;\n  --card: 222.2 84% 4.9%;\n  --card-foreground: 210 40% 98%;\n  --popover: 222.2 84% 4.9%;\n  --popover-foreground: 210 40% 98%;\n  --primary-foreground: 222.2 47.4% 11.2%;\n  --secondary: 217.2 32.6% 17.5%;\n  --secondary-foreground: 210 40% 98%;\n  --muted: 217.2 32.6% 17.5%;\n  --muted-foreground: 215 20.2% 65.1%;\n  --accent: 217.2 32.6% 17.5%;\n  --accent-foreground: 210 40% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 217.2 32.6% 17.5%;\n  --input: 217.2 32.6% 17.5%;\n  --ring: 212.7 26.8% 83.9;\n  --sidebar: 222.2 84% 4.9%;\n  --sidebar-deep: 222.2 84% 4.9%;\n  --header: 222.2 84% 4.9%;\n}\n\n.dark[data-theme='gray'],\n[data-theme='gray'] .dark {\n  --background: 224 71.4% 4.1%;\n  --background-deep: var(--background);\n  --foreground: 210 20% 98%;\n  --card: 224 71.4% 4.1%;\n  --card-foreground: 210 20% 98%;\n  --popover: 224 71.4% 4.1%;\n  --popover-foreground: 210 20% 98%;\n  --primary-foreground: 220.9 39.3% 11%;\n  --secondary: 215 27.9% 16.9%;\n  --secondary-foreground: 210 20% 98%;\n  --muted: 215 27.9% 16.9%;\n  --muted-foreground: 217.9 10.6% 64.9%;\n  --accent: 215 27.9% 16.9%;\n  --accent-foreground: 210 20% 98%;\n  --destructive: 359.21 68.47% 56.47%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 215 27.9% 16.9%;\n  --input: 215 27.9% 16.9%;\n  --ring: 216 12.2% 83.9%;\n  --sidebar: 224 71.4% 4.1%;\n  --sidebar-deep: 224 71.4% 4.1%;\n  --header: 224 71.4% 4.1%;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/design-tokens/default.css",
    "content": ":root {\n  /** 弹出层的基础层级 **/\n  --popup-z-index: 2000;\n  --font-family:\n    -apple-system, blinkmacsystemfont, 'Segoe UI', roboto, 'Helvetica Neue',\n    arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',\n    'Segoe UI Symbol', 'Noto Color Emoji';\n\n  /* Default background color of <body />...etc */\n  --background: 0 0% 100%;\n\n  /* 主体区域背景色 */\n  --background-deep: 216 20.11% 95.47%;\n  --foreground: 210 6% 21%;\n\n  /* Background color for <Card /> */\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n\n  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n\n  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */\n\n  /* --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%; */\n\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n\n  /* 主题颜色 */\n\n  --primary: 212 100% 45%;\n  --primary-foreground: 0 0% 98%;\n\n  /* Used for destructive actions such as <Button variant=\"destructive\"> */\n\n  --destructive: 359.33 100% 65.1%;\n  --destructive-foreground: 0 0% 98%;\n\n  /* Used for success actions such as <message> */\n\n  --info: 240, 5%, 96%;\n  --info-foreground: 220, 4%, 58%;\n\n  /* Used for success actions such as <message> */\n\n  --success: 144 57% 58%;\n  --success-foreground: 0 0% 98%;\n\n  /* Used for warning actions such as <message> */\n\n  --warning: 42 84% 61%;\n  --warning-foreground: 0 0% 98%;\n\n  /* Secondary colors for <Button /> */\n\n  --secondary: 240 5% 96%;\n  --secondary-foreground: 240 6% 10%;\n\n  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */\n  --accent: 240 5% 96%;\n  --accent-dark: 216 14% 93%;\n  --accent-darker: 216 11% 91%;\n  --accent-lighter: 240 0% 98%;\n  --accent-hover: 200deg 10% 90%;\n  --accent-foreground: 240 6% 10%;\n\n  /* Darker color */\n  --heavy: 192deg 9.43% 89.61%;\n  --heavy-foreground: var(--accent-foreground);\n\n  /* Default border color */\n  --border: 240 5.9% 90%;\n\n  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */\n  --input: 240deg 5.88% 90%;\n  --input-placeholder: 217 10.6% 65%;\n  --input-background: 0 0% 100%;\n\n  /* Used for focus ring */\n  --ring: 222.2 84% 4.9%;\n\n  /* Border radius for card, input and buttons */\n  --radius: 0.5rem;\n\n  /* ============= custom ============= */\n\n  /* 遮罩颜色 */\n  --overlay: 0 0% 0% / 45%;\n  --overlay-content: 0 0% 95% / 45%;\n\n  /* 基本文字大小 */\n  --font-size-base: 16px;\n\n  /* =============component & UI============= */\n\n  /* menu */\n  --sidebar: 0 0% 100%;\n  --sidebar-deep: 0 0% 100%;\n  --menu: var(--sidebar);\n\n  /* header */\n  --header: 0 0% 100%;\n\n  accent-color: var(--primary);\n  color-scheme: light;\n}\n\n[data-theme='violet'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 224 71.4% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 224 71.4% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 224 71.4% 4.1%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 220 14.3% 95.9%;\n  --secondary-foreground: 220.9 39.3% 11%;\n  --muted: 220 14.3% 95.9%;\n  --muted-foreground: 220 8.9% 46.1%;\n  --accent: 220 14.3% 95.9%;\n  --accent-foreground: 220.9 39.3% 11%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 220 13% 91%;\n  --input: 220 13% 91%;\n  --ring: 262.1 83.3% 57.8%;\n}\n\n[data-theme='pink'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 346.8 77.2% 49.8%;\n}\n\n[data-theme='rose'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 346.8 77.2% 49.8%;\n}\n\n[data-theme='sky-blue'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 221.2 83.2% 53.3%;\n}\n\n[data-theme='deep-blue'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 221.2 83.2% 53.3%;\n}\n\n[data-theme='green'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 142.1 76.2% 36.3%;\n}\n\n[data-theme='deep-green'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 355.7 100% 97.3%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 142.1 76.2% 36.3%;\n}\n\n[data-theme='orange'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 20 14.3% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 20 14.3% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 20 14.3% 4.1%;\n  --primary-foreground: 60 9.1% 97.8%;\n  --secondary: 60 4.8% 95.9%;\n  --secondary-foreground: 24 9.8% 10%;\n  --muted: 60 4.8% 95.9%;\n  --muted-foreground: 25 5.3% 44.7%;\n  --accent: 60 4.8% 95.9%;\n  --accent-foreground: 24 9.8% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 20 5.9% 90%;\n  --input: 20 5.9% 90%;\n  --ring: 24.6 95% 53.1%;\n}\n\n[data-theme='yellow'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 20 14.3% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 20 14.3% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 20 14.3% 4.1%;\n  --primary-foreground: 26 83.3% 14.1%;\n  --secondary: 60 4.8% 95.9%;\n  --secondary-foreground: 24 9.8% 10%;\n  --muted: 60 4.8% 95.9%;\n  --muted-foreground: 25 5.3% 44.7%;\n  --accent: 60 4.8% 95.9%;\n  --accent-foreground: 24 9.8% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 60 9.1% 97.8%;\n  --border: 20 5.9% 90%;\n  --input: 20 5.9% 90%;\n  --ring: 20 14.3% 4.1%;\n}\n\n[data-theme='zinc'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary-foreground: 0 0% 98%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 95.9%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 240 5.9% 10%;\n}\n\n[data-theme='neutral'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 0 0% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 0 0% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 0 0% 3.9%;\n  --primary-foreground: 0 0% 98%;\n  --secondary: 0 0% 96.1%;\n  --secondary-foreground: 0 0% 9%;\n  --muted: 0 0% 96.1%;\n  --muted-foreground: 0 0% 45.1%;\n  --accent: 0 0% 96.1%;\n  --accent-foreground: 0 0% 9%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 0 0% 89.8%;\n  --input: 0 0% 89.8%;\n  --ring: 0 0% 3.9%;\n}\n\n[data-theme='slate'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 222.2 84% 4.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 222.2 84% 4.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 222.2 84% 4.9%;\n  --primary-foreground: 210 40% 98%;\n  --secondary: 210 40% 96.1%;\n  --secondary-foreground: 222.2 47.4% 11.2%;\n  --muted: 210 40% 96.1%;\n  --muted-foreground: 215.4 16.3% 46.9%;\n  --accent: 210 40% 96.1%;\n  --accent-foreground: 222.2 47.4% 11.2%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 40% 98%;\n  --border: 214.3 31.8% 91.4%;\n  --input: 214.3 31.8% 91.4%;\n  --ring: 222.2 84% 4.9%;\n}\n\n[data-theme='gray'] {\n  /* --background: 0 0% 100%; */\n  --foreground: 224 71.4% 4.1%;\n  --card: 0 0% 100%;\n  --card-foreground: 224 71.4% 4.1%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 224 71.4% 4.1%;\n  --primary-foreground: 210 20% 98%;\n  --secondary: 220 14.3% 95.9%;\n  --secondary-foreground: 220.9 39.3% 11%;\n  --muted: 220 14.3% 95.9%;\n  --muted-foreground: 220 8.9% 46.1%;\n  --accent: 220 14.3% 95.9%;\n  --accent-foreground: 220.9 39.3% 11%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 210 20% 98%;\n  --border: 220 13% 91%;\n  --input: 220 13% 91%;\n  --ring: 224 71.4% 4.1%;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/design-tokens/index.ts",
    "content": "import './default.css';\nimport './dark.css';\n\nexport {};\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/index.ts",
    "content": "import './design-tokens';\n\nimport './css/global.css';\nimport './css/transition.css';\nimport './css/nprogress.css';\nimport './css/ui.css';\n\nexport {};\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/scss-bem/bem.scss",
    "content": "@forward './constants';\n\n@mixin b($block) {\n  $B: $namespace + '-' + $block !global;\n\n  .#{$B} {\n    @content;\n  }\n}\n\n@mixin e($name) {\n  @at-root {\n    &#{$element-separator}#{$name} {\n      @content;\n    }\n  }\n}\n\n@mixin m($name) {\n  @at-root {\n    &#{$modifier-separator}#{$name} {\n      @content;\n    }\n  }\n}\n\n// block__element.is-active {}\n@mixin is($state, $prefix: $state-prefix) {\n  @at-root {\n    &.#{$prefix}-#{$state} {\n      @content;\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/src/scss-bem/constants.scss",
    "content": "$namespace: 'vben' !default;\n$common-separator: '-' !default;\n$element-separator: '__' !default;\n$modifier-separator: '--' !default;\n$state-prefix: 'is' !default;\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/design/vite.config.mts",
    "content": "import { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    vite: {\n      publicDir: 'src/scss-bem',\n    },\n  };\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/icons/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/icons/package.json",
    "content": "{\n  \"name\": \"@vben-core/icons\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/base/icons\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"types\": \"./dist/index.d.ts\",\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@iconify/vue\": \"catalog:\",\n    \"lucide-vue-next\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/icons/src/create-icon.ts",
    "content": "import { defineComponent, h } from 'vue';\n\nimport { Icon } from '@iconify/vue';\n\nfunction createIconifyIcon(icon: string) {\n  return defineComponent({\n    name: `Icon-${icon}`,\n    setup(props, { attrs }) {\n      return () => h(Icon, { icon, ...props, ...attrs });\n    },\n  });\n}\n\nexport { createIconifyIcon };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/icons/src/index.ts",
    "content": "export * from './create-icon';\n\nexport * from './lucide';\n\nexport type { IconifyIcon as IconifyIconStructure } from '@iconify/vue';\nexport {\n  addCollection,\n  addIcon,\n  Icon as IconifyIcon,\n  listIcons,\n} from '@iconify/vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/icons/src/lucide.ts",
    "content": "export {\n  ArrowDown,\n  ArrowLeft,\n  ArrowLeftToLine,\n  ArrowRightLeft,\n  ArrowRightToLine,\n  ArrowUp,\n  ArrowUpToLine,\n  Bell,\n  BookOpenText,\n  Check,\n  ChevronDown,\n  ChevronLeft,\n  ChevronRight,\n  ChevronsLeft,\n  ChevronsRight,\n  Circle,\n  CircleAlert,\n  CircleCheckBig,\n  CircleHelp,\n  CircleX,\n  Copy,\n  CornerDownLeft,\n  Ellipsis,\n  Expand,\n  ExternalLink,\n  Eye,\n  EyeOff,\n  FoldHorizontal,\n  Fullscreen,\n  Github,\n  Grip,\n  GripVertical,\n  Menu as IconDefault,\n  Inbox,\n  Info,\n  InspectionPanel,\n  Languages,\n  LoaderCircle,\n  LockKeyhole,\n  LogOut,\n  MailCheck,\n  Maximize,\n  ArrowRightFromLine as MdiMenuClose,\n  ArrowLeftFromLine as MdiMenuOpen,\n  Menu,\n  Minimize,\n  Minimize2,\n  MoonStar,\n  Palette,\n  PanelLeft,\n  PanelRight,\n  Pin,\n  PinOff,\n  Plus,\n  RotateCw,\n  Search,\n  SearchX,\n  Settings,\n  Shrink,\n  Square,\n  SquareCheckBig,\n  SquareMinus,\n  Sun,\n  SunMoon,\n  SwatchBook,\n  UserRoundPen,\n  X,\n} from 'lucide-vue-next';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/icons/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: [\n    'src/store',\n    'src/constants/index',\n    'src/utils/index',\n    'src/color/index',\n    'src/cache/index',\n    'src/global-state',\n  ],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/package.json",
    "content": "{\n  \"name\": \"@vben-core/shared\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/base/shared\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\",\n    \"stub\": \"pnpm unbuild --stub\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"sideEffects\": false,\n  \"exports\": {\n    \"./constants\": {\n      \"types\": \"./src/constants/index.ts\",\n      \"development\": \"./src/constants/index.ts\",\n      \"default\": \"./dist/constants/index.mjs\"\n    },\n    \"./utils\": {\n      \"types\": \"./src/utils/index.ts\",\n      \"development\": \"./src/utils/index.ts\",\n      \"default\": \"./dist/utils/index.mjs\"\n    },\n    \"./color\": {\n      \"types\": \"./src/color/index.ts\",\n      \"development\": \"./src/color/index.ts\",\n      \"default\": \"./dist/color/index.mjs\"\n    },\n    \"./cache\": {\n      \"types\": \"./src/cache/index.ts\",\n      \"development\": \"./src/cache/index.ts\",\n      \"default\": \"./dist/cache/index.mjs\"\n    },\n    \"./store\": {\n      \"types\": \"./src/store.ts\",\n      \"development\": \"./src/store.ts\",\n      \"default\": \"./dist/store.mjs\"\n    },\n    \"./global-state\": {\n      \"types\": \"./src/global-state.ts\",\n      \"development\": \"./src/global-state.ts\",\n      \"default\": \"./dist/global-state.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \"./constants\": {\n        \"types\": \"./dist/constants/index.d.ts\",\n        \"default\": \"./dist/constants/index.mjs\"\n      },\n      \"./utils\": {\n        \"types\": \"./dist/utils/index.d.ts\",\n        \"default\": \"./dist/utils/index.mjs\"\n      },\n      \"./color\": {\n        \"types\": \"./dist/color/index.d.ts\",\n        \"default\": \"./dist/color/index.mjs\"\n      },\n      \"./cache\": {\n        \"types\": \"./dist/cache/index.d.ts\",\n        \"default\": \"./dist/cache/index.mjs\"\n      },\n      \"./store\": {\n        \"types\": \"./dist/store.d.ts\",\n        \"default\": \"./dist/store.mjs\"\n      },\n      \"./global-state\": {\n        \"types\": \"./dist/global-state.d.ts\",\n        \"default\": \"./dist/global-state.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@ctrl/tinycolor\": \"catalog:\",\n    \"@tanstack/vue-store\": \"catalog:\",\n    \"@vue/shared\": \"catalog:\",\n    \"clsx\": \"catalog:\",\n    \"dayjs\": \"catalog:\",\n    \"defu\": \"catalog:\",\n    \"lodash.clonedeep\": \"catalog:\",\n    \"lodash.get\": \"catalog:\",\n    \"lodash.isequal\": \"catalog:\",\n    \"lodash.set\": \"catalog:\",\n    \"nprogress\": \"catalog:\",\n    \"tailwind-merge\": \"catalog:\",\n    \"theme-colors\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/lodash.clonedeep\": \"catalog:\",\n    \"@types/lodash.get\": \"catalog:\",\n    \"@types/lodash.isequal\": \"catalog:\",\n    \"@types/lodash.set\": \"catalog:\",\n    \"@types/nprogress\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { StorageManager } from '../storage-manager';\n\ndescribe('storageManager', () => {\n  let storageManager: StorageManager;\n\n  beforeEach(() => {\n    vi.useFakeTimers();\n    localStorage.clear();\n    storageManager = new StorageManager({\n      prefix: 'test_',\n    });\n  });\n\n  it('should set and get an item', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' });\n    const user = storageManager.getItem('user');\n    expect(user).toEqual({ age: 30, name: 'John Doe' });\n  });\n\n  it('should return default value if item does not exist', () => {\n    const user = storageManager.getItem('nonexistent', {\n      age: 0,\n      name: 'Default User',\n    });\n    expect(user).toEqual({ age: 0, name: 'Default User' });\n  });\n\n  it('should remove an item', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' });\n    storageManager.removeItem('user');\n    const user = storageManager.getItem('user');\n    expect(user).toBeNull();\n  });\n\n  it('should clear all items with the prefix', () => {\n    storageManager.setItem('user1', { age: 30, name: 'John Doe' });\n    storageManager.setItem('user2', { age: 25, name: 'Jane Doe' });\n    storageManager.clear();\n    expect(storageManager.getItem('user1')).toBeNull();\n    expect(storageManager.getItem('user2')).toBeNull();\n  });\n\n  it('should clear expired items', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' }, 1000); // 1秒过期\n    vi.advanceTimersByTime(1001); // 快进时间\n    storageManager.clearExpiredItems();\n    const user = storageManager.getItem('user');\n    expect(user).toBeNull();\n  });\n\n  it('should not clear non-expired items', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' }, 10_000); // 10秒过期\n    vi.advanceTimersByTime(5000); // 快进时间\n    storageManager.clearExpiredItems();\n    const user = storageManager.getItem('user');\n    expect(user).toEqual({ age: 30, name: 'John Doe' });\n  });\n\n  it('should handle JSON parse errors gracefully', () => {\n    localStorage.setItem('test_user', '{ invalid JSON }');\n    const user = storageManager.getItem('user', {\n      age: 0,\n      name: 'Default User',\n    });\n    expect(user).toEqual({ age: 0, name: 'Default User' });\n  });\n  it('should return null for non-existent items without default value', () => {\n    const user = storageManager.getItem('nonexistent');\n    expect(user).toBeNull();\n  });\n\n  it('should overwrite existing items', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' });\n    storageManager.setItem('user', { age: 25, name: 'Jane Doe' });\n    const user = storageManager.getItem('user');\n    expect(user).toEqual({ age: 25, name: 'Jane Doe' });\n  });\n\n  it('should handle items without expiry correctly', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' });\n    vi.advanceTimersByTime(5000);\n    const user = storageManager.getItem('user');\n    expect(user).toEqual({ age: 30, name: 'John Doe' });\n  });\n\n  it('should remove expired items when accessed', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' }, 1000); // 1秒过期\n    vi.advanceTimersByTime(1001); // 快进时间\n    const user = storageManager.getItem('user');\n    expect(user).toBeNull();\n  });\n\n  it('should not remove non-expired items when accessed', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' }, 10_000); // 10秒过期\n    vi.advanceTimersByTime(5000); // 快进时间\n    const user = storageManager.getItem('user');\n    expect(user).toEqual({ age: 30, name: 'John Doe' });\n  });\n\n  it('should handle multiple items with different expiry times', () => {\n    storageManager.setItem('user1', { age: 30, name: 'John Doe' }, 1000); // 1秒过期\n    storageManager.setItem('user2', { age: 25, name: 'Jane Doe' }, 2000); // 2秒过期\n    vi.advanceTimersByTime(1500); // 快进时间\n    storageManager.clearExpiredItems();\n    const user1 = storageManager.getItem('user1');\n    const user2 = storageManager.getItem('user2');\n    expect(user1).toBeNull();\n    expect(user2).toEqual({ age: 25, name: 'Jane Doe' });\n  });\n\n  it('should handle items with no expiry', () => {\n    storageManager.setItem('user', { age: 30, name: 'John Doe' });\n    vi.advanceTimersByTime(10_000); // 快进时间\n    storageManager.clearExpiredItems();\n    const user = storageManager.getItem('user');\n    expect(user).toEqual({ age: 30, name: 'John Doe' });\n  });\n\n  it('should clear all items correctly', () => {\n    storageManager.setItem('user1', { age: 30, name: 'John Doe' });\n    storageManager.setItem('user2', { age: 25, name: 'Jane Doe' });\n    storageManager.clear();\n    const user1 = storageManager.getItem('user1');\n    const user2 = storageManager.getItem('user2');\n    expect(user1).toBeNull();\n    expect(user2).toBeNull();\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/cache/index.ts",
    "content": "export * from './storage-manager';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/cache/storage-manager.ts",
    "content": "type StorageType = 'localStorage' | 'sessionStorage';\n\ninterface StorageManagerOptions {\n  prefix?: string;\n  storageType?: StorageType;\n}\n\ninterface StorageItem<T> {\n  expiry?: number;\n  value: T;\n}\n\nclass StorageManager {\n  private prefix: string;\n  private storage: Storage;\n\n  constructor({\n    prefix = '',\n    storageType = 'localStorage',\n  }: StorageManagerOptions = {}) {\n    this.prefix = prefix;\n    this.storage =\n      storageType === 'localStorage'\n        ? window.localStorage\n        : window.sessionStorage;\n  }\n\n  /**\n   * 清除所有带前缀的存储项\n   */\n  clear(): void {\n    const keysToRemove: string[] = [];\n    for (let i = 0; i < this.storage.length; i++) {\n      const key = this.storage.key(i);\n      if (key && key.startsWith(this.prefix)) {\n        keysToRemove.push(key);\n      }\n    }\n    keysToRemove.forEach((key) => this.storage.removeItem(key));\n  }\n\n  /**\n   * 清除所有过期的存储项\n   */\n  clearExpiredItems(): void {\n    for (let i = 0; i < this.storage.length; i++) {\n      const key = this.storage.key(i);\n      if (key && key.startsWith(this.prefix)) {\n        const shortKey = key.replace(this.prefix, '');\n        this.getItem(shortKey); // 调用 getItem 方法检查并移除过期项\n      }\n    }\n  }\n\n  /**\n   * 获取存储项\n   * @param key 键\n   * @param defaultValue 当项不存在或已过期时返回的默认值\n   * @returns 值，如果项已过期或解析错误则返回默认值\n   */\n  getItem<T>(key: string, defaultValue: null | T = null): null | T {\n    const fullKey = this.getFullKey(key);\n    const itemStr = this.storage.getItem(fullKey);\n    if (!itemStr) {\n      return defaultValue;\n    }\n\n    try {\n      const item: StorageItem<T> = JSON.parse(itemStr);\n      if (item.expiry && Date.now() > item.expiry) {\n        this.storage.removeItem(fullKey);\n        return defaultValue;\n      }\n      return item.value;\n    } catch (error) {\n      console.error(`Error parsing item with key \"${fullKey}\":`, error);\n      this.storage.removeItem(fullKey); // 如果解析失败，删除该项\n      return defaultValue;\n    }\n  }\n\n  /**\n   * 移除存储项\n   * @param key 键\n   */\n  removeItem(key: string): void {\n    const fullKey = this.getFullKey(key);\n    this.storage.removeItem(fullKey);\n  }\n\n  /**\n   * 设置存储项\n   * @param key 键\n   * @param value 值\n   * @param ttl 存活时间（毫秒）\n   */\n  setItem<T>(key: string, value: T, ttl?: number): void {\n    const fullKey = this.getFullKey(key);\n    const expiry = ttl ? Date.now() + ttl : undefined;\n    const item: StorageItem<T> = { expiry, value };\n    try {\n      this.storage.setItem(fullKey, JSON.stringify(item));\n    } catch (error) {\n      console.error(`Error setting item with key \"${fullKey}\":`, error);\n    }\n  }\n\n  /**\n   * 获取完整的存储键\n   * @param key 原始键\n   * @returns 带前缀的完整键\n   */\n  private getFullKey(key: string): string {\n    return `${this.prefix}-${key}`;\n  }\n}\n\nexport { StorageManager };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/cache/types.ts",
    "content": "type StorageType = 'localStorage' | 'sessionStorage';\n\ninterface StorageValue<T> {\n  data: T;\n  expiry: null | number;\n}\n\ninterface IStorageCache {\n  clear(): void;\n  getItem<T>(key: string): null | T;\n  key(index: number): null | string;\n  length(): number;\n  removeItem(key: string): void;\n  setItem<T>(key: string, value: T, expiryInMinutes?: number): void;\n}\n\nexport type { IStorageCache, StorageType, StorageValue };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/color/__tests__/convert.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport {\n  convertToHsl,\n  convertToHslCssVar,\n  convertToRgb,\n  isValidColor,\n} from '../convert';\n\ndescribe('color conversion functions', () => {\n  it('should correctly convert color to HSL format', () => {\n    const color = '#ff0000';\n    const expectedHsl = 'hsl(0 100% 50%)';\n    expect(convertToHsl(color)).toEqual(expectedHsl);\n  });\n\n  it('should correctly convert color with alpha to HSL format', () => {\n    const color = 'rgba(255, 0, 0, 0.5)';\n    const expectedHsl = 'hsl(0 100% 50%) 0.5';\n    expect(convertToHsl(color)).toEqual(expectedHsl);\n  });\n\n  it('should correctly convert color to HSL CSS variable format', () => {\n    const color = '#ff0000';\n    const expectedHsl = '0 100% 50%';\n    expect(convertToHslCssVar(color)).toEqual(expectedHsl);\n  });\n\n  it('should correctly convert color with alpha to HSL CSS variable format', () => {\n    const color = 'rgba(255, 0, 0, 0.5)';\n    const expectedHsl = '0 100% 50% / 0.5';\n    expect(convertToHslCssVar(color)).toEqual(expectedHsl);\n  });\n\n  it('should correctly convert color to RGB CSS variable format', () => {\n    const color = 'hsl(284, 100%, 50%)';\n    const expectedRgb = 'rgb(187, 0, 255)';\n    expect(convertToRgb(color)).toEqual(expectedRgb);\n  });\n\n  it('should correctly convert color with alpha to RGBA CSS variable format', () => {\n    const color = 'hsla(284, 100%, 50%, 0.92)';\n    const expectedRgba = 'rgba(187, 0, 255, 0.92)';\n    expect(convertToRgb(color)).toEqual(expectedRgba);\n  });\n});\n\ndescribe('isValidColor', () => {\n  it('isValidColor function', () => {\n    // 测试有效颜色\n    expect(isValidColor('blue')).toBe(true);\n    expect(isValidColor('#000000')).toBe(true);\n\n    // 测试无效颜色\n    expect(isValidColor('invalid color')).toBe(false);\n    expect(isValidColor()).toBe(false);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/color/color.ts",
    "content": "import { TinyColor } from '@ctrl/tinycolor';\n\nexport function isDarkColor(color: string) {\n  return new TinyColor(color).isDark();\n}\n\nexport function isLightColor(color: string) {\n  return new TinyColor(color).isLight();\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/color/convert.ts",
    "content": "import { TinyColor } from '@ctrl/tinycolor';\n\n/**\n * 将颜色转换为HSL格式。\n *\n * HSL是一种颜色模型，包括色相(Hue)、饱和度(Saturation)和亮度(Lightness)三个部分。\n *\n * @param {string} color 输入的颜色。\n * @returns {string} HSL格式的颜色字符串。\n */\nfunction convertToHsl(color: string): string {\n  const { a, h, l, s } = new TinyColor(color).toHsl();\n  const hsl = `hsl(${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%)`;\n  return a < 1 ? `${hsl} ${a}` : hsl;\n}\n\n/**\n * 将颜色转换为HSL CSS变量。\n *\n * 这个函数与convertToHsl函数类似，但是返回的字符串格式稍有不同，\n * 以便可以作为CSS变量使用。\n *\n * @param {string} color 输入的颜色。\n * @returns {string} 可以作为CSS变量使用的HSL格式的颜色字符串。\n */\nfunction convertToHslCssVar(color: string): string {\n  const { a, h, l, s } = new TinyColor(color).toHsl();\n  const hsl = `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;\n  return a < 1 ? `${hsl} / ${a}` : hsl;\n}\n\n/**\n * 将颜色转换为RGB颜色字符串\n * TinyColor无法处理hsl内包含'deg'、'grad'、'rad'或'turn'的字符串\n * 比如 hsl(231deg 98% 65%)将被解析为rgb(0, 0, 0)\n * 这里在转换之前先将这些单位去掉\n * @param str 表示HLS颜色值的字符串\n * @returns 如果颜色值有效，则返回对应的RGB颜色字符串；如果无效，则返回rgb(0, 0, 0)\n */\nfunction convertToRgb(str: string): string {\n  return new TinyColor(str.replaceAll(/deg|grad|rad|turn/g, '')).toRgbString();\n}\n\n/**\n * 检查颜色是否有效\n * @param {string} color - 待检查的颜色\n * 如果颜色有效返回true，否则返回false\n */\nfunction isValidColor(color?: string) {\n  if (!color) {\n    return false;\n  }\n  return new TinyColor(color).isValid;\n}\n\nexport {\n  convertToHsl,\n  convertToHslCssVar,\n  convertToRgb,\n  isValidColor,\n  TinyColor,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/color/generator.ts",
    "content": "import { getColors } from 'theme-colors';\n\nimport { convertToHslCssVar, TinyColor } from './convert';\n\ninterface ColorItem {\n  alias?: string;\n  color: string;\n  name: string;\n}\n\nfunction generatorColorVariables(colorItems: ColorItem[]) {\n  const colorVariables: Record<string, string> = {};\n\n  colorItems.forEach(({ alias, color, name }) => {\n    if (color) {\n      const colorsMap = getColors(new TinyColor(color).toHexString());\n\n      let mainColor = colorsMap['500'];\n\n      const colorKeys = Object.keys(colorsMap);\n\n      colorKeys.forEach((key) => {\n        const colorValue = colorsMap[key];\n\n        if (colorValue) {\n          const hslColor = convertToHslCssVar(colorValue);\n          colorVariables[`--${name}-${key}`] = hslColor;\n          if (alias) {\n            colorVariables[`--${alias}-${key}`] = hslColor;\n          }\n\n          if (key === '500') {\n            mainColor = hslColor;\n          }\n        }\n      });\n      if (alias && mainColor) {\n        colorVariables[`--${alias}`] = mainColor;\n      }\n    }\n  });\n  return colorVariables;\n}\n\nexport { generatorColorVariables };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/color/index.ts",
    "content": "export * from './color';\nexport * from './convert';\nexport * from './generator';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/constants/globals.ts",
    "content": "/** layout content 组件的高度 */\nexport const CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT = `--vben-content-height`;\n/** layout content 组件的宽度 */\nexport const CSS_VARIABLE_LAYOUT_CONTENT_WIDTH = `--vben-content-width`;\n/** layout header 组件的高度 */\nexport const CSS_VARIABLE_LAYOUT_HEADER_HEIGHT = `--vben-header-height`;\n/** layout footer 组件的高度 */\nexport const CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT = `--vben-footer-height`;\n\n/** 内容区域的组件ID */\nexport const ELEMENT_ID_MAIN_CONTENT = `__vben_main_content`;\n\n/**\n * @zh_CN 默认命名空间\n */\nexport const DEFAULT_NAMESPACE = 'vben';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/constants/index.ts",
    "content": "export * from './globals';\nexport * from './vben';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/constants/vben.ts",
    "content": "/**\n * @zh_CN GITHUB 仓库地址\n */\nexport const VBEN_GITHUB_URL = 'https://github.com/vbenjs/vue-vben-admin';\n\n/**\n * @zh_CN 文档地址\n */\nexport const VBEN_DOC_URL = 'https://doc.vben.pro';\n\n/**\n * @zh_CN Vben Logo\n */\nexport const VBEN_LOGO_URL =\n  'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp';\n\n/**\n * @zh_CN Vben Admin 首页地址\n */\nexport const VBEN_PREVIEW_URL = 'https://www.vben.pro';\n\nexport const VBEN_ELE_PREVIEW_URL = 'https://ele.vben.pro';\n\nexport const VBEN_NAIVE_PREVIEW_URL = 'https://naive.vben.pro';\n\nexport const VBEN_ANT_PREVIEW_URL = 'https://ant.vben.pro';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/global-state.ts",
    "content": "/**\n * 全局复用的变量、组件、配置，各个模块之间共享\n * 通过单例模式实现,单例必须注意不受请求影响，例如用户信息这些需要根据请求获取的。后续如果有ssr需求，也不会影响\n */\n\ninterface ComponentsState {\n  [key: string]: any;\n}\n\ninterface MessageState {\n  copyPreferencesSuccess?: (title: string, content?: string) => void;\n}\n\nexport interface IGlobalSharedState {\n  components: ComponentsState;\n  message: MessageState;\n}\n\nclass GlobalShareState {\n  #components: ComponentsState = {};\n  #message: MessageState = {};\n\n  /**\n   * 定义框架内部各个场景的消息提示\n   */\n  public defineMessage({ copyPreferencesSuccess }: MessageState) {\n    this.#message = {\n      copyPreferencesSuccess,\n    };\n  }\n\n  public getComponents(): ComponentsState {\n    return this.#components;\n  }\n\n  public getMessage(): MessageState {\n    return this.#message;\n  }\n\n  public setComponents(value: ComponentsState) {\n    this.#components = value;\n  }\n}\n\nexport const globalShareState = new GlobalShareState();\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/store.ts",
    "content": "export * from '@tanstack/vue-store';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/diff.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { diff } from '../diff';\n\ndescribe('diff function', () => {\n  it('should return an empty object when comparing identical objects', () => {\n    const obj1 = { a: 1, b: { c: 2 } };\n    const obj2 = { a: 1, b: { c: 2 } };\n    expect(diff(obj1, obj2)).toEqual(undefined);\n  });\n\n  it('should detect simple changes in primitive values', () => {\n    const obj1 = { a: 1, b: 2 };\n    const obj2 = { a: 1, b: 3 };\n    expect(diff(obj1, obj2)).toEqual({ b: 3 });\n  });\n\n  it('should detect nested object changes', () => {\n    const obj1 = { a: 1, b: { c: 2, d: 4 } };\n    const obj2 = { a: 1, b: { c: 3, d: 4 } };\n    expect(diff(obj1, obj2)).toEqual({ b: { c: 3 } });\n  });\n\n  it('should handle array changes', () => {\n    const obj1 = { a: [1, 2, 3], b: 2 };\n    const obj2 = { a: [1, 2, 4], b: 2 };\n    expect(diff(obj1, obj2)).toEqual({ a: [1, 2, 4] });\n  });\n\n  it('should handle added keys', () => {\n    const obj1 = { a: 1 };\n    const obj2 = { a: 1, b: 2 };\n    expect(diff(obj1, obj2)).toEqual({ b: 2 });\n  });\n\n  it('should handle removed keys', () => {\n    const obj1 = { a: 1, b: 2 };\n    const obj2 = { a: 1 };\n    expect(diff(obj1, obj2)).toEqual(undefined);\n  });\n\n  it('should handle boolean value changes', () => {\n    const obj1 = { a: true, b: false };\n    const obj2 = { a: true, b: true };\n    expect(diff(obj1, obj2)).toEqual({ b: true });\n  });\n\n  it('should handle null and undefined values', () => {\n    const obj1 = { a: null, b: undefined };\n    const obj2: any = { a: 1, b: undefined };\n    expect(diff(obj1, obj2)).toEqual({ a: 1 });\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/dom.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getElementVisibleRect } from '../dom';\n\ndescribe('getElementVisibleRect', () => {\n  // 设置浏览器视口尺寸的 mock\n  beforeEach(() => {\n    vi.spyOn(document.documentElement, 'clientHeight', 'get').mockReturnValue(\n      800,\n    );\n    vi.spyOn(window, 'innerHeight', 'get').mockReturnValue(800);\n    vi.spyOn(document.documentElement, 'clientWidth', 'get').mockReturnValue(\n      1000,\n    );\n    vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(1000);\n  });\n\n  it('should return default rect if element is undefined', () => {\n    expect(getElementVisibleRect()).toEqual({\n      bottom: 0,\n      height: 0,\n      left: 0,\n      right: 0,\n      top: 0,\n      width: 0,\n    });\n  });\n\n  it('should return default rect if element is null', () => {\n    expect(getElementVisibleRect(null)).toEqual({\n      bottom: 0,\n      height: 0,\n      left: 0,\n      right: 0,\n      top: 0,\n      width: 0,\n    });\n  });\n\n  it('should return correct visible rect when element is fully visible', () => {\n    const element = {\n      getBoundingClientRect: () => ({\n        bottom: 400,\n        height: 300,\n        left: 200,\n        right: 600,\n        top: 100,\n        width: 400,\n      }),\n    } as HTMLElement;\n\n    expect(getElementVisibleRect(element)).toEqual({\n      bottom: 400,\n      height: 300,\n      left: 200,\n      right: 600,\n      top: 100,\n      width: 400,\n    });\n  });\n\n  it('should return correct visible rect when element is partially off-screen at the top', () => {\n    const element = {\n      getBoundingClientRect: () => ({\n        bottom: 200,\n        height: 250,\n        left: 100,\n        right: 500,\n        top: -50,\n        width: 400,\n      }),\n    } as HTMLElement;\n\n    expect(getElementVisibleRect(element)).toEqual({\n      bottom: 200,\n      height: 200,\n      left: 100,\n      right: 500,\n      top: 0,\n      width: 400,\n    });\n  });\n\n  it('should return correct visible rect when element is partially off-screen at the right', () => {\n    const element = {\n      getBoundingClientRect: () => ({\n        bottom: 400,\n        height: 300,\n        left: 800,\n        right: 1200,\n        top: 100,\n        width: 400,\n      }),\n    } as HTMLElement;\n\n    expect(getElementVisibleRect(element)).toEqual({\n      bottom: 400,\n      height: 300,\n      left: 800,\n      right: 1000,\n      top: 100,\n      width: 200,\n    });\n  });\n\n  it('should return all zeros when element is completely off-screen', () => {\n    const element = {\n      getBoundingClientRect: () => ({\n        bottom: 1200,\n        height: 300,\n        left: 1100,\n        right: 1400,\n        top: 900,\n        width: 300,\n      }),\n    } as HTMLElement;\n\n    expect(getElementVisibleRect(element)).toEqual({\n      bottom: 800,\n      height: 0,\n      left: 1100,\n      right: 1000,\n      top: 900,\n      width: 0,\n    });\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/inference.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport {\n  getFirstNonNullOrUndefined,\n  isBoolean,\n  isEmpty,\n  isHttpUrl,\n  isObject,\n  isUndefined,\n  isWindow,\n} from '../inference';\n\ndescribe('isHttpUrl', () => {\n  it(\"should return true when given 'http://example.com'\", () => {\n    expect(isHttpUrl('http://example.com')).toBe(true);\n  });\n\n  it(\"should return true when given 'https://example.com'\", () => {\n    expect(isHttpUrl('https://example.com')).toBe(true);\n  });\n\n  it(\"should return false when given 'ftp://example.com'\", () => {\n    expect(isHttpUrl('ftp://example.com')).toBe(false);\n  });\n\n  it(\"should return false when given 'example.com'\", () => {\n    expect(isHttpUrl('example.com')).toBe(false);\n  });\n});\n\ndescribe('isUndefined', () => {\n  it('isUndefined should return true for undefined values', () => {\n    expect(isUndefined()).toBe(true);\n  });\n\n  it('isUndefined should return false for null values', () => {\n    expect(isUndefined(null)).toBe(false);\n  });\n\n  it('isUndefined should return false for defined values', () => {\n    expect(isUndefined(0)).toBe(false);\n    expect(isUndefined('')).toBe(false);\n    expect(isUndefined(false)).toBe(false);\n  });\n\n  it('isUndefined should return false for objects and arrays', () => {\n    expect(isUndefined({})).toBe(false);\n    expect(isUndefined([])).toBe(false);\n  });\n});\n\ndescribe('isEmpty', () => {\n  it('should return true for empty string', () => {\n    expect(isEmpty('')).toBe(true);\n  });\n\n  it('should return true for empty array', () => {\n    expect(isEmpty([])).toBe(true);\n  });\n\n  it('should return true for empty object', () => {\n    expect(isEmpty({})).toBe(true);\n  });\n\n  it('should return false for non-empty string', () => {\n    expect(isEmpty('hello')).toBe(false);\n  });\n\n  it('should return false for non-empty array', () => {\n    expect(isEmpty([1, 2, 3])).toBe(false);\n  });\n\n  it('should return false for non-empty object', () => {\n    expect(isEmpty({ a: 1 })).toBe(false);\n  });\n\n  it('should return true for null or undefined', () => {\n    expect(isEmpty(null)).toBe(true);\n    expect(isEmpty()).toBe(true);\n  });\n\n  it('should return false for number or boolean', () => {\n    expect(isEmpty(0)).toBe(false);\n    expect(isEmpty(true)).toBe(false);\n  });\n});\n\ndescribe('isWindow', () => {\n  it('should return true for the window object', () => {\n    expect(isWindow(window)).toBe(true);\n  });\n\n  it('should return false for other objects', () => {\n    expect(isWindow({})).toBe(false);\n    expect(isWindow([])).toBe(false);\n    expect(isWindow(null)).toBe(false);\n  });\n});\n\ndescribe('isBoolean', () => {\n  it('should return true for boolean values', () => {\n    expect(isBoolean(true)).toBe(true);\n    expect(isBoolean(false)).toBe(true);\n  });\n\n  it('should return false for non-boolean values', () => {\n    expect(isBoolean(null)).toBe(false);\n    expect(isBoolean(42)).toBe(false);\n    expect(isBoolean('string')).toBe(false);\n    expect(isBoolean({})).toBe(false);\n    expect(isBoolean([])).toBe(false);\n  });\n});\n\ndescribe('isObject', () => {\n  it('should return true for objects', () => {\n    expect(isObject({})).toBe(true);\n    expect(isObject({ a: 1 })).toBe(true);\n  });\n\n  it('should return false for non-objects', () => {\n    expect(isObject(null)).toBe(false);\n    expect(isObject(42)).toBe(false);\n    expect(isObject('string')).toBe(false);\n    expect(isObject(true)).toBe(false);\n    expect(isObject([1, 2, 3])).toBe(true);\n    expect(isObject(new Date())).toBe(true);\n    expect(isObject(/regex/)).toBe(true);\n  });\n});\n\ndescribe('getFirstNonNullOrUndefined', () => {\n  describe('getFirstNonNullOrUndefined', () => {\n    it('should return the first non-null and non-undefined value for a number array', () => {\n      expect(getFirstNonNullOrUndefined<number>(undefined, null, 0, 42)).toBe(\n        0,\n      );\n      expect(getFirstNonNullOrUndefined<number>(null, undefined, 42, 123)).toBe(\n        42,\n      );\n    });\n\n    it('should return the first non-null and non-undefined value for a string array', () => {\n      expect(\n        getFirstNonNullOrUndefined<string>(undefined, null, '', 'hello'),\n      ).toBe('');\n      expect(\n        getFirstNonNullOrUndefined<string>(null, undefined, 'test', 'world'),\n      ).toBe('test');\n    });\n\n    it('should return undefined if all values are null or undefined', () => {\n      expect(getFirstNonNullOrUndefined(undefined, null)).toBeUndefined();\n      expect(getFirstNonNullOrUndefined(null)).toBeUndefined();\n    });\n\n    it('should work with a single value', () => {\n      expect(getFirstNonNullOrUndefined(42)).toBe(42);\n      expect(getFirstNonNullOrUndefined()).toBeUndefined();\n      expect(getFirstNonNullOrUndefined(null)).toBeUndefined();\n    });\n\n    it('should handle mixed types correctly', () => {\n      expect(\n        getFirstNonNullOrUndefined<number | object | string>(\n          undefined,\n          null,\n          'test',\n          123,\n          { key: 'value' },\n        ),\n      ).toBe('test');\n      expect(\n        getFirstNonNullOrUndefined<number | object | string>(\n          null,\n          undefined,\n          [1, 2, 3],\n          'string',\n        ),\n      ).toEqual([1, 2, 3]);\n    });\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/letter.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport {\n  capitalizeFirstLetter,\n  kebabToCamelCase,\n  toCamelCase,\n  toLowerCaseFirstLetter,\n} from '../letter';\n\ndescribe('capitalizeFirstLetter', () => {\n  it('should capitalize the first letter of a string', () => {\n    expect(capitalizeFirstLetter('hello')).toBe('Hello');\n    expect(capitalizeFirstLetter('world')).toBe('World');\n  });\n\n  it('should handle empty strings', () => {\n    expect(capitalizeFirstLetter('')).toBe('');\n  });\n\n  it('should handle single character strings', () => {\n    expect(capitalizeFirstLetter('a')).toBe('A');\n    expect(capitalizeFirstLetter('b')).toBe('B');\n  });\n\n  it('should not change the case of other characters', () => {\n    expect(capitalizeFirstLetter('hElLo')).toBe('HElLo');\n  });\n});\n\ndescribe('toLowerCaseFirstLetter', () => {\n  it('should convert the first letter to lowercase', () => {\n    expect(toLowerCaseFirstLetter('CommonAppName')).toBe('commonAppName');\n    expect(toLowerCaseFirstLetter('AnotherKeyExample')).toBe(\n      'anotherKeyExample',\n    );\n  });\n\n  it('should return the same string if the first letter is already lowercase', () => {\n    expect(toLowerCaseFirstLetter('alreadyLowerCase')).toBe('alreadyLowerCase');\n  });\n\n  it('should handle empty strings', () => {\n    expect(toLowerCaseFirstLetter('')).toBe('');\n  });\n\n  it('should handle single character strings', () => {\n    expect(toLowerCaseFirstLetter('A')).toBe('a');\n    expect(toLowerCaseFirstLetter('a')).toBe('a');\n  });\n\n  it('should handle strings with only one uppercase letter', () => {\n    expect(toLowerCaseFirstLetter('A')).toBe('a');\n  });\n\n  it('should handle strings with special characters', () => {\n    expect(toLowerCaseFirstLetter('!Special')).toBe('!Special');\n    expect(toLowerCaseFirstLetter('123Number')).toBe('123Number');\n  });\n});\n\ndescribe('toCamelCase', () => {\n  it('should return the key if parentKey is empty', () => {\n    expect(toCamelCase('child', '')).toBe('child');\n  });\n\n  it('should combine parentKey and key in camel case', () => {\n    expect(toCamelCase('child', 'parent')).toBe('parentChild');\n  });\n\n  it('should handle empty key and parentKey', () => {\n    expect(toCamelCase('', '')).toBe('');\n  });\n\n  it('should handle key with capital letters', () => {\n    expect(toCamelCase('Child', 'parent')).toBe('parentChild');\n    expect(toCamelCase('Child', 'Parent')).toBe('ParentChild');\n  });\n});\n\ndescribe('kebabToCamelCase', () => {\n  it('should convert kebab-case to camelCase correctly', () => {\n    expect(kebabToCamelCase('my-component-name')).toBe('myComponentName');\n  });\n\n  it('should handle multiple consecutive hyphens', () => {\n    expect(kebabToCamelCase('my--component--name')).toBe('myComponentName');\n  });\n\n  it('should trim leading and trailing hyphens', () => {\n    expect(kebabToCamelCase('-my-component-name-')).toBe('myComponentName');\n  });\n\n  it('should preserve the case of the first word', () => {\n    expect(kebabToCamelCase('My-component-name')).toBe('MyComponentName');\n  });\n\n  it('should convert a single word correctly', () => {\n    expect(kebabToCamelCase('component')).toBe('component');\n  });\n\n  it('should return an empty string if input is empty', () => {\n    expect(kebabToCamelCase('')).toBe('');\n  });\n\n  it('should handle strings with no hyphens', () => {\n    expect(kebabToCamelCase('mycomponentname')).toBe('mycomponentname');\n  });\n\n  it('should handle strings with only hyphens', () => {\n    expect(kebabToCamelCase('---')).toBe('');\n  });\n\n  it('should handle mixed case inputs', () => {\n    expect(kebabToCamelCase('my-Component-Name')).toBe('myComponentName');\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/resources.test.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\n\nimport { loadScript } from '../resources';\n\nconst testJsPath =\n  'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js';\n\ndescribe('loadScript', () => {\n  beforeEach(() => {\n    // 每个测试前清空 head，保证环境干净\n    document.head.innerHTML = '';\n  });\n\n  it('should resolve when the script loads successfully', async () => {\n    const promise = loadScript(testJsPath);\n\n    // 此时脚本元素已被创建并插入\n    const script = document.querySelector(\n      `script[src=\"${testJsPath}\"]`,\n    ) as HTMLScriptElement;\n    expect(script).toBeTruthy();\n\n    // 模拟加载成功\n    script.dispatchEvent(new Event('load'));\n\n    // 等待 promise resolve\n    await expect(promise).resolves.toBeUndefined();\n  });\n\n  it('should not insert duplicate script and resolve immediately if already loaded', async () => {\n    // 先手动插入一个相同 src 的 script\n    const existing = document.createElement('script');\n    existing.src = 'bar.js';\n    document.head.append(existing);\n\n    // 再次调用\n    const promise = loadScript('bar.js');\n\n    // 立即 resolve\n    await expect(promise).resolves.toBeUndefined();\n\n    // head 中只保留一个\n    const scripts = document.head.querySelectorAll('script[src=\"bar.js\"]');\n    expect(scripts).toHaveLength(1);\n  });\n\n  it('should reject when the script fails to load', async () => {\n    const promise = loadScript('error.js');\n\n    const script = document.querySelector(\n      'script[src=\"error.js\"]',\n    ) as HTMLScriptElement;\n    expect(script).toBeTruthy();\n\n    // 模拟加载失败\n    script.dispatchEvent(new Event('error'));\n\n    await expect(promise).rejects.toThrow('Failed to load script: error.js');\n  });\n\n  it('should handle multiple concurrent calls and only insert one script tag', async () => {\n    const p1 = loadScript(testJsPath);\n    const p2 = loadScript(testJsPath);\n\n    const script = document.querySelector(\n      `script[src=\"${testJsPath}\"]`,\n    ) as HTMLScriptElement;\n    expect(script).toBeTruthy();\n\n    // 触发一次 load，两个 promise 都应该 resolve\n    script.dispatchEvent(new Event('load'));\n\n    await expect(p1).resolves.toBeUndefined();\n    await expect(p2).resolves.toBeUndefined();\n\n    // 只插入一次\n    const scripts = document.head.querySelectorAll(\n      `script[src=\"${testJsPath}\"]`,\n    );\n    expect(scripts).toHaveLength(1);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/state-handler.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { StateHandler } from '../state-handler';\n\ndescribe('stateHandler', () => {\n  it('should resolve when condition is set to true', async () => {\n    const handler = new StateHandler();\n\n    // 模拟异步设置 condition 为 true\n    setTimeout(() => {\n      handler.setConditionTrue(); // 明确触发 condition 为 true\n    }, 10);\n\n    // 等待条件被设置为 true\n    await handler.waitForCondition();\n    expect(handler.isConditionTrue()).toBe(true);\n  });\n\n  it('should resolve immediately if condition is already true', async () => {\n    const handler = new StateHandler();\n    handler.setConditionTrue(); // 提前设置为 true\n\n    // 立即 resolve，因为 condition 已经是 true\n    await handler.waitForCondition();\n    expect(handler.isConditionTrue()).toBe(true);\n  });\n\n  it('should reject when condition is set to false after waiting', async () => {\n    const handler = new StateHandler();\n\n    // 模拟异步设置 condition 为 false\n    setTimeout(() => {\n      handler.setConditionFalse(); // 明确触发 condition 为 false\n    }, 10);\n\n    // 等待过程中，期望 Promise 被 reject\n    await expect(handler.waitForCondition()).rejects.toThrow();\n    expect(handler.isConditionTrue()).toBe(false);\n  });\n\n  it('should reset condition to false', () => {\n    const handler = new StateHandler();\n    handler.setConditionTrue(); // 设置为 true\n    handler.reset(); // 重置为 false\n\n    expect(handler.isConditionTrue()).toBe(false);\n  });\n\n  it('should resolve when condition is set to true after reset', async () => {\n    const handler = new StateHandler();\n    handler.reset(); // 确保初始为 false\n\n    setTimeout(() => {\n      handler.setConditionTrue(); // 重置后设置为 true\n    }, 10);\n\n    await handler.waitForCondition();\n    expect(handler.isConditionTrue()).toBe(true);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/tree.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { filterTree, mapTree, traverseTreeValues } from '../tree';\n\ndescribe('traverseTreeValues', () => {\n  interface Node {\n    children?: Node[];\n    name: string;\n  }\n\n  type NodeValue = string;\n\n  const sampleTree: Node[] = [\n    {\n      name: 'A',\n      children: [\n        { name: 'B' },\n        {\n          name: 'C',\n          children: [{ name: 'D' }, { name: 'E' }],\n        },\n      ],\n    },\n    {\n      name: 'F',\n      children: [\n        { name: 'G' },\n        {\n          name: 'H',\n          children: [{ name: 'I' }],\n        },\n      ],\n    },\n  ];\n\n  it('traverses tree and returns all node values', () => {\n    const values = traverseTreeValues<Node, NodeValue>(\n      sampleTree,\n      (node) => node.name,\n      {\n        childProps: 'children',\n      },\n    );\n    expect(values).toEqual(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']);\n  });\n\n  it('handles empty tree', () => {\n    const values = traverseTreeValues<Node, NodeValue>([], (node) => node.name);\n    expect(values).toEqual([]);\n  });\n\n  it('handles tree with only root node', () => {\n    const rootNode = { name: 'A' };\n    const values = traverseTreeValues<Node, NodeValue>(\n      [rootNode],\n      (node) => node.name,\n    );\n    expect(values).toEqual(['A']);\n  });\n\n  it('handles tree with only leaf nodes', () => {\n    const leafNodes = [{ name: 'A' }, { name: 'B' }, { name: 'C' }];\n    const values = traverseTreeValues<Node, NodeValue>(\n      leafNodes,\n      (node) => node.name,\n    );\n    expect(values).toEqual(['A', 'B', 'C']);\n  });\n});\n\ndescribe('filterTree', () => {\n  const tree = [\n    {\n      id: 1,\n      children: [\n        { id: 2 },\n        { id: 3, children: [{ id: 4 }, { id: 5 }, { id: 6 }] },\n        { id: 7 },\n      ],\n    },\n    { id: 8, children: [{ id: 9 }, { id: 10 }] },\n    { id: 11 },\n  ];\n\n  it('should return all nodes when condition is always true', () => {\n    const result = filterTree(tree, () => true, { childProps: 'children' });\n    expect(result).toEqual(tree);\n  });\n\n  it('should return only root nodes when condition is always false', () => {\n    const result = filterTree(tree, () => false);\n    expect(result).toEqual([]);\n  });\n\n  it('should return nodes with even id values', () => {\n    const result = filterTree(tree, (node) => node.id % 2 === 0);\n    expect(result).toEqual([{ id: 8, children: [{ id: 10 }] }]);\n  });\n\n  it('should return nodes with odd id values and their ancestors', () => {\n    const result = filterTree(tree, (node) => node.id % 2 === 1);\n    expect(result).toEqual([\n      {\n        id: 1,\n        children: [{ id: 3, children: [{ id: 5 }] }, { id: 7 }],\n      },\n      { id: 11 },\n    ]);\n  });\n\n  it('should return nodes with \"leaf\" in their name', () => {\n    const tree = [\n      {\n        name: 'root',\n        children: [\n          { name: 'leaf 1' },\n          {\n            name: 'branch',\n            children: [{ name: 'leaf 2' }, { name: 'leaf 3' }],\n          },\n          { name: 'leaf 4' },\n        ],\n      },\n    ];\n    const result = filterTree(\n      tree,\n      (node) => node.name.includes('leaf') || node.name === 'root',\n    );\n    expect(result).toEqual([\n      {\n        name: 'root',\n        children: [{ name: 'leaf 1' }, { name: 'leaf 4' }],\n      },\n    ]);\n  });\n});\n\ndescribe('mapTree', () => {\n  it('map infinite depth tree using mapTree', () => {\n    const tree = [\n      {\n        id: 1,\n        name: 'node1',\n        children: [\n          { id: 2, name: 'node2' },\n          { id: 3, name: 'node3' },\n          {\n            id: 4,\n            name: 'node4',\n            children: [\n              {\n                id: 5,\n                name: 'node5',\n                children: [\n                  { id: 6, name: 'node6' },\n                  { id: 7, name: 'node7' },\n                ],\n              },\n              { id: 8, name: 'node8' },\n            ],\n          },\n        ],\n      },\n    ];\n    const newTree = mapTree(tree, (node) => ({\n      ...node,\n      name: `${node.name}-new`,\n    }));\n\n    expect(newTree).toEqual([\n      {\n        id: 1,\n        name: 'node1-new',\n        children: [\n          { id: 2, name: 'node2-new' },\n          { id: 3, name: 'node3-new' },\n          {\n            id: 4,\n            name: 'node4-new',\n            children: [\n              {\n                id: 5,\n                name: 'node5-new',\n                children: [\n                  { id: 6, name: 'node6-new' },\n                  { id: 7, name: 'node7-new' },\n                ],\n              },\n              { id: 8, name: 'node8-new' },\n            ],\n          },\n        ],\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/unique.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { uniqueByField } from '../unique';\n\ndescribe('uniqueByField', () => {\n  it('should return an array with unique items based on id field', () => {\n    const items = [\n      { id: 1, name: 'Item 1' },\n      { id: 2, name: 'Item 2' },\n      { id: 3, name: 'Item 3' },\n      { id: 1, name: 'Duplicate Item' },\n    ];\n\n    const uniqueItems = uniqueByField(items, 'id');\n\n    expect(uniqueItems).toHaveLength(3);\n    expect(uniqueItems).toEqual([\n      { id: 1, name: 'Item 1' },\n      { id: 2, name: 'Item 2' },\n      { id: 3, name: 'Item 3' },\n    ]);\n  });\n\n  it('should return an empty array when input array is empty', () => {\n    const items: any[] = []; // Empty array\n\n    const uniqueItems = uniqueByField(items, 'id');\n\n    // Assert expected results\n    expect(uniqueItems).toEqual([]);\n  });\n\n  it('should handle arrays with only one item correctly', () => {\n    const items = [{ id: 1, name: 'Item 1' }];\n\n    const uniqueItems = uniqueByField(items, 'id');\n\n    // Assert expected results\n    expect(uniqueItems).toHaveLength(1);\n    expect(uniqueItems).toEqual([{ id: 1, name: 'Item 1' }]);\n  });\n\n  it('should preserve the order of the first occurrence of each item', () => {\n    const items = [\n      { id: 2, name: 'Item 2' },\n      { id: 1, name: 'Item 1' },\n      { id: 3, name: 'Item 3' },\n      { id: 1, name: 'Duplicate Item' },\n    ];\n\n    const uniqueItems = uniqueByField(items, 'id');\n\n    // Assert expected results (order of first occurrences preserved)\n    expect(uniqueItems).toEqual([\n      { id: 2, name: 'Item 2' },\n      { id: 1, name: 'Item 1' },\n      { id: 3, name: 'Item 3' },\n    ]);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/update-css-variables.test.ts",
    "content": "import { expect, it } from 'vitest';\n\nimport { updateCSSVariables } from '../update-css-variables';\n\nit('updateCSSVariables should update CSS variables in :root selector', () => {\n  // 模拟初始的内联样式表内容\n  const initialStyleContent = ':root { --primaryColor: red; }';\n  document.head.innerHTML = `<style id=\"custom-styles\">${initialStyleContent}</style>`;\n\n  // 要更新的CSS变量和它们的新值\n  const updatedVariables = {\n    fontSize: '16px',\n    primaryColor: 'blue',\n    secondaryColor: 'green',\n  };\n\n  // 调用函数来更新CSS变量\n  updateCSSVariables(updatedVariables, 'custom-styles');\n\n  // 获取更新后的样式内容\n  const styleElement = document.querySelector('#custom-styles');\n  const updatedStyleContent = styleElement ? styleElement.textContent : '';\n\n  // 检查更新后的样式内容是否包含正确的更新值\n  expect(\n    updatedStyleContent?.includes('primaryColor: blue;') &&\n      updatedStyleContent?.includes('secondaryColor: green;') &&\n      updatedStyleContent?.includes('fontSize: 16px;'),\n  ).toBe(true);\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/util.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { bindMethods, getNestedValue } from '../util';\n\nclass TestClass {\n  public value: string;\n\n  constructor(value: string) {\n    this.value = value;\n    bindMethods(this); // 调用通用方法\n  }\n\n  getValue() {\n    return this.value;\n  }\n\n  setValue(newValue: string) {\n    this.value = newValue;\n  }\n}\n\ndescribe('bindMethods', () => {\n  it('should bind methods to the instance correctly', () => {\n    const instance = new TestClass('initial');\n\n    // 解构方法\n    const { getValue } = instance;\n\n    // 检查 getValue 是否能正确调用，并且 this 绑定了 instance\n    expect(getValue()).toBe('initial');\n  });\n\n  it('should bind multiple methods', () => {\n    const instance = new TestClass('initial');\n\n    const { getValue, setValue } = instance;\n\n    // 检查 getValue 和 setValue 方法是否正确绑定了 this\n    setValue('newValue');\n    expect(getValue()).toBe('newValue');\n  });\n\n  it('should not bind non-function properties', () => {\n    const instance = new TestClass('initial');\n\n    // 检查普通属性是否保持原样\n    expect(instance.value).toBe('initial');\n  });\n\n  it('should not bind constructor method', () => {\n    const instance = new TestClass('test');\n\n    // 检查 constructor 是否没有被绑定\n    expect(instance.constructor.name).toBe('TestClass');\n  });\n\n  it('should not bind getter/setter properties', () => {\n    class TestWithGetterSetter {\n      get value() {\n        return this._value;\n      }\n\n      set value(newValue: string) {\n        this._value = newValue;\n      }\n\n      private _value: string = 'test';\n\n      constructor() {\n        bindMethods(this);\n      }\n    }\n\n    const instance = new TestWithGetterSetter();\n    const { value } = instance;\n\n    // Getter 和 setter 不应被绑定\n    expect(value).toBe('test');\n  });\n});\n\ndescribe('getNestedValue', () => {\n  interface UserProfile {\n    age: number;\n    name: string;\n  }\n\n  interface UserSettings {\n    theme: string;\n  }\n\n  interface Data {\n    user: {\n      profile: UserProfile;\n      settings: UserSettings;\n    };\n  }\n\n  const data: Data = {\n    user: {\n      profile: {\n        age: 25,\n        name: 'Alice',\n      },\n      settings: {\n        theme: 'dark',\n      },\n    },\n  };\n\n  it('should get a nested value when the path is valid', () => {\n    const result = getNestedValue(data, 'user.profile.name');\n    expect(result).toBe('Alice');\n  });\n\n  it('should return undefined for non-existent property', () => {\n    const result = getNestedValue(data, 'user.profile.gender');\n    expect(result).toBeUndefined();\n  });\n\n  it('should return undefined when accessing a non-existent deep path', () => {\n    const result = getNestedValue(data, 'user.nonexistent.field');\n    expect(result).toBeUndefined();\n  });\n\n  it('should return undefined if a middle level is undefined', () => {\n    const result = getNestedValue({ user: undefined }, 'user.profile.name');\n    expect(result).toBeUndefined();\n  });\n\n  it('should return the correct value for a nested setting', () => {\n    const result = getNestedValue(data, 'user.settings.theme');\n    expect(result).toBe('dark');\n  });\n\n  it('should work for a single-level path', () => {\n    const result = getNestedValue({ a: 1, b: 2 }, 'b');\n    expect(result).toBe(2);\n  });\n\n  it('should return the entire object if path is empty', () => {\n    expect(() => getNestedValue(data, '')()).toThrow();\n  });\n\n  it('should handle paths with array indexes', () => {\n    const complexData = { list: [{ name: 'Item1' }, { name: 'Item2' }] };\n    const result = getNestedValue(complexData, 'list.1.name');\n    expect(result).toBe('Item2');\n  });\n\n  it('should return undefined when accessing an out-of-bounds array index', () => {\n    const complexData = { list: [{ name: 'Item1' }] };\n    const result = getNestedValue(complexData, 'list.2.name');\n    expect(result).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/__tests__/window.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { openWindow } from '../window';\n\ndescribe('openWindow', () => {\n  // 保存原始的 window.open 函数\n  let originalOpen: typeof window.open;\n\n  beforeEach(() => {\n    originalOpen = window.open;\n  });\n\n  afterEach(() => {\n    window.open = originalOpen;\n  });\n\n  it('should call window.open with correct arguments', () => {\n    const url = 'https://example.com';\n    const options = { noopener: true, noreferrer: true, target: '_blank' };\n\n    window.open = vi.fn();\n\n    // 调用函数\n    openWindow(url, options);\n\n    // 验证 window.open 是否被正确地调用\n    expect(window.open).toHaveBeenCalledWith(\n      url,\n      options.target,\n      'noopener=yes,noreferrer=yes',\n    );\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/cn.ts",
    "content": "import type { ClassValue } from 'clsx';\n\nimport { clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nfunction cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport { cn };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/date.ts",
    "content": "import dayjs from 'dayjs';\n\nexport function formatDate(time: number | string, format = 'YYYY-MM-DD') {\n  try {\n    const date = dayjs(time);\n    if (!date.isValid()) {\n      throw new Error('Invalid date');\n    }\n    return date.format(format);\n  } catch (error) {\n    console.error(`Error formatting date: ${error}`);\n    return time;\n  }\n}\n\nexport function formatDateTime(time: number | string) {\n  return formatDate(time, 'YYYY-MM-DD HH:mm:ss');\n}\n\nexport function isDate(value: any): value is Date {\n  return value instanceof Date;\n}\n\nexport function isDayjsObject(value: any): value is dayjs.Dayjs {\n  return dayjs.isDayjs(value);\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/diff.ts",
    "content": "// type Diff<T = any> = T;\n\n// 比较两个数组是否相等\n\nfunction arraysEqual<T>(a: T[], b: T[]): boolean {\n  if (a.length !== b.length) return false;\n  const counter = new Map<T, number>();\n  for (const value of a) {\n    counter.set(value, (counter.get(value) || 0) + 1);\n  }\n  for (const value of b) {\n    const count = counter.get(value);\n    if (count === undefined || count === 0) {\n      return false;\n    }\n    counter.set(value, count - 1);\n  }\n  return true;\n}\n\n// 深度对比两个值\n// function deepEqual<T>(oldVal: T, newVal: T): boolean {\n//   if (\n//     typeof oldVal === 'object' &&\n//     oldVal !== null &&\n//     typeof newVal === 'object' &&\n//     newVal !== null\n//   ) {\n//     return Array.isArray(oldVal) && Array.isArray(newVal)\n//       ? arraysEqual(oldVal, newVal)\n//       : diff(oldVal as any, newVal as any) === null;\n//   } else {\n//     return oldVal === newVal;\n//   }\n// }\n\n// // diff 函数\n// function diff<T extends object>(\n//   oldObj: T,\n//   newObj: T,\n//   ignoreFields: (keyof T)[] = [],\n// ): { [K in keyof T]?: Diff<T[K]> } | null {\n//   const difference: { [K in keyof T]?: Diff<T[K]> } = {};\n\n//   for (const key in oldObj) {\n//     if (ignoreFields.includes(key)) continue;\n//     const oldValue = oldObj[key];\n//     const newValue = newObj[key];\n\n//     if (!deepEqual(oldValue, newValue)) {\n//       difference[key] = newValue;\n//     }\n//   }\n\n//   return Object.keys(difference).length === 0 ? null : difference;\n// }\n\ntype DiffResult<T> = Partial<{\n  [K in keyof T]: T[K] extends object ? DiffResult<T[K]> : T[K];\n}>;\n\nfunction diff<T extends Record<string, any>>(obj1: T, obj2: T): DiffResult<T> {\n  function findDifferences(o1: any, o2: any): any {\n    if (Array.isArray(o1) && Array.isArray(o2)) {\n      if (!arraysEqual(o1, o2)) {\n        return o2;\n      }\n      return undefined;\n    }\n\n    if (\n      typeof o1 === 'object' &&\n      typeof o2 === 'object' &&\n      o1 !== null &&\n      o2 !== null\n    ) {\n      const diffResult: any = {};\n\n      const keys = new Set([...Object.keys(o1), ...Object.keys(o2)]);\n      keys.forEach((key) => {\n        const valueDiff = findDifferences(o1[key], o2[key]);\n        if (valueDiff !== undefined) {\n          diffResult[key] = valueDiff;\n        }\n      });\n\n      return Object.keys(diffResult).length > 0 ? diffResult : undefined;\n    }\n\n    return o1 === o2 ? undefined : o2;\n  }\n\n  return findDifferences(obj1, obj2);\n}\n\nexport { arraysEqual, diff };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/dom.ts",
    "content": "export interface VisibleDomRect {\n  bottom: number;\n  height: number;\n  left: number;\n  right: number;\n  top: number;\n  width: number;\n}\n\n/**\n * 获取元素可见信息\n * @param element\n */\nexport function getElementVisibleRect(\n  element?: HTMLElement | null | undefined,\n): VisibleDomRect {\n  if (!element) {\n    return {\n      bottom: 0,\n      height: 0,\n      left: 0,\n      right: 0,\n      top: 0,\n      width: 0,\n    };\n  }\n  const rect = element.getBoundingClientRect();\n  const viewHeight = Math.max(\n    document.documentElement.clientHeight,\n    window.innerHeight,\n  );\n\n  const top = Math.max(rect.top, 0);\n  const bottom = Math.min(rect.bottom, viewHeight);\n\n  const viewWidth = Math.max(\n    document.documentElement.clientWidth,\n    window.innerWidth,\n  );\n\n  const left = Math.max(rect.left, 0);\n  const right = Math.min(rect.right, viewWidth);\n\n  return {\n    bottom,\n    height: Math.max(0, bottom - top),\n    left,\n    right,\n    top,\n    width: Math.max(0, right - left),\n  };\n}\n\nexport function getScrollbarWidth() {\n  const scrollDiv = document.createElement('div');\n\n  scrollDiv.style.visibility = 'hidden';\n  scrollDiv.style.overflow = 'scroll';\n  scrollDiv.style.position = 'absolute';\n  scrollDiv.style.top = '-9999px';\n\n  document.body.append(scrollDiv);\n\n  const innerDiv = document.createElement('div');\n  scrollDiv.append(innerDiv);\n\n  const scrollbarWidth = scrollDiv.offsetWidth - innerDiv.offsetWidth;\n\n  scrollDiv.remove();\n  return scrollbarWidth;\n}\n\nexport function needsScrollbar() {\n  const doc = document.documentElement;\n  const body = document.body;\n\n  // 检查 body 的 overflow-y 样式\n  const overflowY = window.getComputedStyle(body).overflowY;\n\n  // 如果明确设置了需要滚动条的样式\n  if (overflowY === 'scroll' || overflowY === 'auto') {\n    return doc.scrollHeight > window.innerHeight;\n  }\n\n  // 在其他情况下，根据 scrollHeight 和 innerHeight 比较判断\n  return doc.scrollHeight > window.innerHeight;\n}\n\nexport function triggerWindowResize(): void {\n  // 创建一个新的 resize 事件\n  const resizeEvent = new Event('resize');\n\n  // 触发 window 的 resize 事件\n  window.dispatchEvent(resizeEvent);\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/download.ts",
    "content": "import { openWindow } from './window';\n\ninterface DownloadOptions<T = string> {\n  fileName?: string;\n  source: T;\n  target?: string;\n}\n\nconst DEFAULT_FILENAME = 'downloaded_file';\n\n/**\n * 通过 URL 下载文件，支持跨域\n * @throws {Error} - 当下载失败时抛出错误\n */\nexport async function downloadFileFromUrl({\n  fileName,\n  source,\n  target = '_blank',\n}: DownloadOptions): Promise<void> {\n  if (!source || typeof source !== 'string') {\n    throw new Error('Invalid URL.');\n  }\n\n  const isChrome = window.navigator.userAgent.toLowerCase().includes('chrome');\n  const isSafari = window.navigator.userAgent.toLowerCase().includes('safari');\n\n  if (/iP/.test(window.navigator.userAgent)) {\n    console.error('Your browser does not support download!');\n    return;\n  }\n\n  if (isChrome || isSafari) {\n    triggerDownload(source, resolveFileName(source, fileName));\n    return;\n  }\n  if (!source.includes('?')) {\n    source += '?download';\n  }\n\n  openWindow(source, { target });\n}\n\n/**\n * 通过 Base64 下载文件\n */\nexport function downloadFileFromBase64({ fileName, source }: DownloadOptions) {\n  if (!source || typeof source !== 'string') {\n    throw new Error('Invalid Base64 data.');\n  }\n\n  const resolvedFileName = fileName || DEFAULT_FILENAME;\n  triggerDownload(source, resolvedFileName);\n}\n\n/**\n * 通过图片 URL 下载图片文件\n */\nexport async function downloadFileFromImageUrl({\n  fileName,\n  source,\n}: DownloadOptions) {\n  const base64 = await urlToBase64(source);\n  downloadFileFromBase64({ fileName, source: base64 });\n}\n\n/**\n * 通过 Blob 下载文件\n */\nexport function downloadFileFromBlob({\n  fileName = DEFAULT_FILENAME,\n  source,\n}: DownloadOptions<Blob>): void {\n  if (!(source instanceof Blob)) {\n    throw new TypeError('Invalid Blob data.');\n  }\n\n  const url = URL.createObjectURL(source);\n  triggerDownload(url, fileName);\n}\n\n/**\n * 下载文件，支持 Blob、字符串和其他 BlobPart 类型\n */\nexport function downloadFileFromBlobPart({\n  fileName = DEFAULT_FILENAME,\n  source,\n}: DownloadOptions<BlobPart>): void {\n  // 如果 data 不是 Blob，则转换为 Blob\n  const blob =\n    source instanceof Blob\n      ? source\n      : new Blob([source], { type: 'application/octet-stream' });\n\n  // 创建对象 URL 并触发下载\n  const url = URL.createObjectURL(blob);\n  triggerDownload(url, fileName);\n}\n\n/**\n * img url to base64\n * @param url\n */\nexport function urlToBase64(url: string, mineType?: string): Promise<string> {\n  return new Promise((resolve, reject) => {\n    let canvas = document.createElement('CANVAS') as HTMLCanvasElement | null;\n    const ctx = canvas?.getContext('2d');\n    const img = new Image();\n    img.crossOrigin = '';\n    img.addEventListener('load', () => {\n      if (!canvas || !ctx) {\n        return reject(new Error('Failed to create canvas.'));\n      }\n      canvas.height = img.height;\n      canvas.width = img.width;\n      ctx.drawImage(img, 0, 0);\n      const dataURL = canvas.toDataURL(mineType || 'image/png');\n      canvas = null;\n      resolve(dataURL);\n    });\n    img.src = url;\n  });\n}\n\n/**\n * 通用下载触发函数\n * @param href - 文件下载的 URL\n * @param fileName - 下载文件的名称，如果未提供则自动识别\n * @param revokeDelay - 清理 URL 的延迟时间 (毫秒)\n */\nexport function triggerDownload(\n  href: string,\n  fileName: string | undefined,\n  revokeDelay: number = 100,\n): void {\n  const defaultFileName = 'downloaded_file';\n  const finalFileName = fileName || defaultFileName;\n\n  const link = document.createElement('a');\n  link.href = href;\n  link.download = finalFileName;\n  link.style.display = 'none';\n\n  if (link.download === undefined) {\n    link.setAttribute('target', '_blank');\n  }\n\n  document.body.append(link);\n  link.click();\n  link.remove();\n\n  // 清理临时 URL 以释放内存\n  setTimeout(() => URL.revokeObjectURL(href), revokeDelay);\n}\n\nfunction resolveFileName(url: string, fileName?: string): string {\n  return fileName || url.slice(url.lastIndexOf('/') + 1) || DEFAULT_FILENAME;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/index.ts",
    "content": "export * from './cn';\nexport * from './date';\nexport * from './diff';\nexport * from './dom';\nexport * from './download';\nexport * from './inference';\nexport * from './letter';\nexport * from './merge';\nexport * from './nprogress';\nexport * from './resources';\nexport * from './state-handler';\nexport * from './to';\nexport * from './tree';\nexport * from './unique';\nexport * from './update-css-variables';\nexport * from './util';\nexport * from './window';\nexport { default as cloneDeep } from 'lodash.clonedeep';\nexport { default as get } from 'lodash.get';\nexport { default as isEqual } from 'lodash.isequal';\nexport { default as set } from 'lodash.set';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/inference.ts",
    "content": "// eslint-disable-next-line vue/prefer-import-from-vue\nimport { isFunction, isObject, isString } from '@vue/shared';\n\n/**\n * 检查传入的值是否为undefined。\n *\n * @param {unknown} value 要检查的值。\n * @returns {boolean} 如果值是undefined，返回true，否则返回false。\n */\nfunction isUndefined(value?: unknown): value is undefined {\n  return value === undefined;\n}\n\n/**\n * 检查传入的值是否为boolean\n * @param value\n * @returns 如果值是布尔值，返回true，否则返回false。\n */\nfunction isBoolean(value: unknown): value is boolean {\n  return typeof value === 'boolean';\n}\n\n/**\n * 检查传入的值是否为空。\n *\n * 以下情况将被认为是空：\n * - 值为null。\n * - 值为undefined。\n * - 值为一个空字符串。\n * - 值为一个长度为0的数组。\n * - 值为一个没有元素的Map或Set。\n * - 值为一个没有属性的对象。\n *\n * @param {T} value 要检查的值。\n * @returns {boolean} 如果值为空，返回true，否则返回false。\n */\nfunction isEmpty<T = unknown>(value?: T): value is T {\n  if (value === null || value === undefined) {\n    return true;\n  }\n\n  if (Array.isArray(value) || isString(value)) {\n    return value.length === 0;\n  }\n\n  if (value instanceof Map || value instanceof Set) {\n    return value.size === 0;\n  }\n\n  if (isObject(value)) {\n    return Object.keys(value).length === 0;\n  }\n\n  return false;\n}\n\n/**\n * 检查传入的字符串是否为有效的HTTP或HTTPS URL。\n *\n * @param {string} url 要检查的字符串。\n * @return {boolean} 如果字符串是有效的HTTP或HTTPS URL，返回true，否则返回false。\n */\nfunction isHttpUrl(url?: string): boolean {\n  if (!url) {\n    return false;\n  }\n  // 使用正则表达式测试URL是否以http:// 或 https:// 开头\n  const httpRegex = /^https?:\\/\\/.*$/;\n  return httpRegex.test(url);\n}\n\n/**\n * 检查传入的值是否为window对象。\n *\n * @param {any} value 要检查的值。\n * @returns {boolean} 如果值是window对象，返回true，否则返回false。\n */\nfunction isWindow(value: any): value is Window {\n  return (\n    typeof window !== 'undefined' && value !== null && value === value.window\n  );\n}\n\n/**\n * 检查当前运行环境是否为Mac OS。\n *\n * 这个函数通过检查navigator.userAgent字符串来判断当前运行环境。\n * 如果userAgent字符串中包含\"macintosh\"或\"mac os x\"（不区分大小写），则认为当前环境是Mac OS。\n *\n * @returns {boolean} 如果当前环境是Mac OS，返回true，否则返回false。\n */\nfunction isMacOs(): boolean {\n  const macRegex = /macintosh|mac os x/i;\n  return macRegex.test(navigator.userAgent);\n}\n\n/**\n * 检查当前运行环境是否为Windows OS。\n *\n * 这个函数通过检查navigator.userAgent字符串来判断当前运行环境。\n * 如果userAgent字符串中包含\"windows\"或\"win32\"（不区分大小写），则认为当前环境是Windows OS。\n *\n * @returns {boolean} 如果当前环境是Windows OS，返回true，否则返回false。\n */\nfunction isWindowsOs(): boolean {\n  const windowsRegex = /windows|win32/i;\n  return windowsRegex.test(navigator.userAgent);\n}\n\n/**\n * 检查传入的值是否为数字\n * @param value\n */\nfunction isNumber(value: any): value is number {\n  return typeof value === 'number' && Number.isFinite(value);\n}\n\n/**\n * Returns the first value in the provided list that is neither `null` nor `undefined`.\n *\n * This function iterates over the input values and returns the first one that is\n * not strictly equal to `null` or `undefined`. If all values are either `null` or\n * `undefined`, it returns `undefined`.\n *\n * @template T - The type of the input values.\n * @param {...(T | null | undefined)[]} values - A list of values to evaluate.\n * @returns {T | undefined} - The first value that is not `null` or `undefined`, or `undefined` if none are found.\n *\n * @example\n * // Returns 42 because it is the first non-null, non-undefined value.\n * getFirstNonNullOrUndefined(undefined, null, 42, 'hello'); // 42\n *\n * @example\n * // Returns 'hello' because it is the first non-null, non-undefined value.\n * getFirstNonNullOrUndefined(null, undefined, 'hello', 123); // 'hello'\n *\n * @example\n * // Returns undefined because all values are either null or undefined.\n * getFirstNonNullOrUndefined(undefined, null); // undefined\n */\nfunction getFirstNonNullOrUndefined<T>(\n  ...values: (null | T | undefined)[]\n): T | undefined {\n  for (const value of values) {\n    if (value !== undefined && value !== null) {\n      return value;\n    }\n  }\n  return undefined;\n}\n\nexport {\n  getFirstNonNullOrUndefined,\n  isBoolean,\n  isEmpty,\n  isFunction,\n  isHttpUrl,\n  isMacOs,\n  isNumber,\n  isObject,\n  isString,\n  isUndefined,\n  isWindow,\n  isWindowsOs,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/letter.ts",
    "content": "/**\n * 将字符串的首字母大写\n * @param string\n */\nfunction capitalizeFirstLetter(string: string): string {\n  return string.charAt(0).toUpperCase() + string.slice(1);\n}\n\n/**\n * 将字符串的首字母转换为小写。\n *\n * @param str 要转换的字符串\n * @returns 首字母小写的字符串\n */\nfunction toLowerCaseFirstLetter(str: string): string {\n  if (!str) return str; // 如果字符串为空，直接返回\n  return str.charAt(0).toLowerCase() + str.slice(1);\n}\n\n/**\n *  生成驼峰命名法的键名\n * @param key\n * @param parentKey\n */\nfunction toCamelCase(key: string, parentKey: string): string {\n  if (!parentKey) {\n    return key;\n  }\n  return parentKey + key.charAt(0).toUpperCase() + key.slice(1);\n}\n\nfunction kebabToCamelCase(str: string): string {\n  return str\n    .split('-')\n    .filter(Boolean)\n    .map((word, index) =>\n      index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1),\n    )\n    .join('');\n}\n\nexport {\n  capitalizeFirstLetter,\n  kebabToCamelCase,\n  toCamelCase,\n  toLowerCaseFirstLetter,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/merge.ts",
    "content": "import { createDefu } from 'defu';\n\nexport { createDefu as createMerge, defu as merge } from 'defu';\n\nexport const mergeWithArrayOverride = createDefu((originObj, key, updates) => {\n  if (Array.isArray(originObj[key]) && Array.isArray(updates)) {\n    originObj[key] = updates;\n    return true;\n  }\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/nprogress.ts",
    "content": "import type NProgress from 'nprogress';\n\n// 创建一个NProgress实例的变量，初始值为null\nlet nProgressInstance: null | typeof NProgress = null;\n\n/**\n * 动态加载NProgress库，并进行配置。\n * 此函数首先检查是否已经加载过NProgress库，如果已经加载过，则直接返回NProgress实例。\n * 否则，动态导入NProgress库，进行配置，然后返回NProgress实例。\n *\n * @returns  NProgress实例的Promise对象。\n */\nasync function loadNprogress() {\n  if (nProgressInstance) {\n    return nProgressInstance;\n  }\n  nProgressInstance = await import('nprogress');\n  nProgressInstance.configure({\n    showSpinner: true,\n    speed: 300,\n  });\n  return nProgressInstance;\n}\n\n/**\n * 开始显示进度条。\n * 此函数首先加载NProgress库，然后调用NProgress的start方法开始显示进度条。\n */\nasync function startProgress() {\n  const nprogress = await loadNprogress();\n  nprogress?.start();\n}\n\n/**\n * 停止显示进度条，并隐藏进度条。\n * 此函数首先加载NProgress库，然后调用NProgress的done方法停止并隐藏进度条。\n */\nasync function stopProgress() {\n  const nprogress = await loadNprogress();\n  nprogress?.done();\n}\n\nexport { startProgress, stopProgress };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/resources.ts",
    "content": "/**\n * 加载js文件\n * @param src js文件地址\n */\nfunction loadScript(src: string) {\n  return new Promise<void>((resolve, reject) => {\n    if (document.querySelector(`script[src=\"${src}\"]`)) {\n      // 如果已经加载过，直接 resolve\n      return resolve();\n    }\n    const script = document.createElement('script');\n    script.src = src;\n    script.addEventListener('load', () => resolve());\n    script.addEventListener('error', () =>\n      reject(new Error(`Failed to load script: ${src}`)),\n    );\n    document.head.append(script);\n  });\n}\n\nexport { loadScript };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/state-handler.ts",
    "content": "export class StateHandler {\n  private condition: boolean = false;\n  private rejectCondition: (() => void) | null = null;\n  private resolveCondition: (() => void) | null = null;\n\n  isConditionTrue(): boolean {\n    return this.condition;\n  }\n\n  reset() {\n    this.condition = false;\n    this.clearPromises();\n  }\n\n  // 触发状态为 false 时，reject\n  setConditionFalse() {\n    this.condition = false;\n    if (this.rejectCondition) {\n      this.rejectCondition();\n      this.clearPromises();\n    }\n  }\n\n  // 触发状态为 true 时，resolve\n  setConditionTrue() {\n    this.condition = true;\n    if (this.resolveCondition) {\n      this.resolveCondition();\n      this.clearPromises();\n    }\n  }\n\n  // 返回一个 Promise，等待 condition 变为 true\n  waitForCondition(): Promise<void> {\n    return new Promise((resolve, reject) => {\n      if (this.condition) {\n        resolve(); // 如果 condition 已经为 true，立即 resolve\n      } else {\n        this.resolveCondition = resolve;\n        this.rejectCondition = reject;\n      }\n    });\n  }\n\n  // 清理 resolve/reject 函数\n  private clearPromises() {\n    this.resolveCondition = null;\n    this.rejectCondition = null;\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/to.ts",
    "content": "/**\n * @param { Readonly<Promise> } promise\n * @param {object=} errorExt - Additional Information you can pass to the err object\n * @return { Promise }\n */\nexport async function to<T, U = Error>(\n  promise: Readonly<Promise<T>>,\n  errorExt?: object,\n): Promise<[null, T] | [U, undefined]> {\n  try {\n    const data = await promise;\n    const result: [null, T] = [null, data];\n    return result;\n  } catch (error) {\n    if (errorExt) {\n      const parsedError = Object.assign({}, error, errorExt);\n      return [parsedError as U, undefined];\n    }\n    return [error as U, undefined];\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/tree.ts",
    "content": "interface TreeConfigOptions {\n  // 子属性的名称，默认为'children'\n  childProps: string;\n}\n\n/**\n * @zh_CN 遍历树形结构，并返回所有节点中指定的值。\n * @param tree 树形结构数组\n * @param getValue 获取节点值的函数\n * @param options 作为子节点数组的可选属性名称。\n * @returns 所有节点中指定的值的数组\n */\nfunction traverseTreeValues<T, V>(\n  tree: T[],\n  getValue: (node: T) => V,\n  options?: TreeConfigOptions,\n): V[] {\n  const result: V[] = [];\n  const { childProps } = options || {\n    childProps: 'children',\n  };\n\n  const dfs = (treeNode: T) => {\n    const value = getValue(treeNode);\n    result.push(value);\n    const children = (treeNode as Record<string, any>)?.[childProps];\n    if (!children) {\n      return;\n    }\n    if (children.length > 0) {\n      for (const child of children) {\n        dfs(child);\n      }\n    }\n  };\n\n  for (const treeNode of tree) {\n    dfs(treeNode);\n  }\n  return result.filter(Boolean);\n}\n\n/**\n * 根据条件过滤给定树结构的节点，并以原有顺序返回所有匹配节点的数组。\n * @param tree 要过滤的树结构的根节点数组。\n * @param filter 用于匹配每个节点的条件。\n * @param options 作为子节点数组的可选属性名称。\n * @returns 包含所有匹配节点的数组。\n */\nfunction filterTree<T extends Record<string, any>>(\n  tree: T[],\n  filter: (node: T) => boolean,\n  options?: TreeConfigOptions,\n): T[] {\n  const { childProps } = options || {\n    childProps: 'children',\n  };\n\n  const _filterTree = (nodes: T[]): T[] => {\n    return nodes.filter((node: Record<string, any>) => {\n      if (filter(node as T)) {\n        if (node[childProps]) {\n          node[childProps] = _filterTree(node[childProps]);\n        }\n        return true;\n      }\n      return false;\n    });\n  };\n\n  return _filterTree(tree);\n}\n\n/**\n * 根据条件重新映射给定树结构的节\n * @param tree 要过滤的树结构的根节点数组。\n * @param mapper 用于map每个节点的条件。\n * @param options 作为子节点数组的可选属性名称。\n */\nfunction mapTree<T, V extends Record<string, any>>(\n  tree: T[],\n  mapper: (node: T) => V,\n  options?: TreeConfigOptions,\n): V[] {\n  const { childProps } = options || {\n    childProps: 'children',\n  };\n  return tree.map((node) => {\n    const mapperNode: Record<string, any> = mapper(node);\n    if (mapperNode[childProps]) {\n      mapperNode[childProps] = mapTree(mapperNode[childProps], mapper, options);\n    }\n    return mapperNode as V;\n  });\n}\n\nexport { filterTree, mapTree, traverseTreeValues };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/unique.ts",
    "content": "/**\n * 根据指定字段对对象数组进行去重\n * @param arr 要去重的对象数组\n * @param key 去重依据的字段名\n * @returns 去重后的对象数组\n */\nfunction uniqueByField<T>(arr: T[], key: keyof T): T[] {\n  const seen = new Map<any, T>();\n  return arr.filter((item) => {\n    const value = item[key];\n    return seen.has(value) ? false : (seen.set(value, item), true);\n  });\n}\n\nexport { uniqueByField };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/update-css-variables.ts",
    "content": "/**\n * 更新 CSS 变量的函数\n * @param variables 要更新的 CSS 变量与其新值的映射\n */\nfunction updateCSSVariables(\n  variables: { [key: string]: string },\n  id = '__vben-styles__',\n): void {\n  // 获取或创建内联样式表元素\n  const styleElement =\n    document.querySelector(`#${id}`) || document.createElement('style');\n\n  styleElement.id = id;\n\n  // 构建要更新的 CSS 变量的样式文本\n  let cssText = ':root {';\n  for (const key in variables) {\n    if (Object.prototype.hasOwnProperty.call(variables, key)) {\n      cssText += `${key}: ${variables[key]};`;\n    }\n  }\n  cssText += '}';\n\n  // 将样式文本赋值给内联样式表\n  styleElement.textContent = cssText;\n\n  // 将内联样式表添加到文档头部\n  if (!document.querySelector(`#${id}`)) {\n    setTimeout(() => {\n      document.head.append(styleElement);\n    });\n  }\n}\n\nexport { updateCSSVariables };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/util.ts",
    "content": "export function bindMethods<T extends object>(instance: T): void {\n  const prototype = Object.getPrototypeOf(instance);\n  const propertyNames = Object.getOwnPropertyNames(prototype);\n\n  propertyNames.forEach((propertyName) => {\n    const descriptor = Object.getOwnPropertyDescriptor(prototype, propertyName);\n    const propertyValue = instance[propertyName as keyof T];\n\n    if (\n      typeof propertyValue === 'function' &&\n      propertyName !== 'constructor' &&\n      descriptor &&\n      !descriptor.get &&\n      !descriptor.set\n    ) {\n      instance[propertyName as keyof T] = propertyValue.bind(instance);\n    }\n  });\n}\n\n/**\n * 获取嵌套对象的字段值\n * @param obj - 要查找的对象\n * @param path - 用于查找字段的路径，使用小数点分隔\n * @returns 字段值，或者未找到时返回 undefined\n */\nexport function getNestedValue<T>(obj: T, path: string): any {\n  if (typeof path !== 'string' || path.length === 0) {\n    throw new Error('Path must be a non-empty string');\n  }\n  // 把路径字符串按 \".\" 分割成数组\n  const keys = path.split('.') as (number | string)[];\n\n  let current: any = obj;\n\n  for (const key of keys) {\n    if (current === null || current === undefined) {\n      return undefined;\n    }\n    current = current[key as keyof typeof current];\n  }\n\n  return current;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/src/utils/window.ts",
    "content": "interface OpenWindowOptions {\n  noopener?: boolean;\n  noreferrer?: boolean;\n  target?: '_blank' | '_parent' | '_self' | '_top' | string;\n}\n\n/**\n * 新窗口打开URL。\n *\n * @param url - 需要打开的网址。\n * @param options - 打开窗口的选项。\n */\nfunction openWindow(url: string, options: OpenWindowOptions = {}): void {\n  // 解构并设置默认值\n  const { noopener = true, noreferrer = true, target = '_blank' } = options;\n\n  // 基于选项创建特性字符串\n  const features = [noopener && 'noopener=yes', noreferrer && 'noreferrer=yes']\n    .filter(Boolean)\n    .join(',');\n\n  // 打开窗口\n  window.open(url, target, features);\n}\n\n/**\n * 在新窗口中打开路由。\n * @param path\n */\nfunction openRouteInNewWindow(path: string) {\n  const { hash, origin } = location;\n  const fullPath = path.startsWith('/') ? path : `/${path}`;\n  const url = `${origin}${hash && !fullPath.startsWith('/#') ? '/#' : ''}${fullPath}`;\n  openWindow(url, { target: '_blank' });\n}\n\nexport { openRouteInNewWindow, openWindow };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/shared/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/library.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/package.json",
    "content": "{\n  \"name\": \"@vben-core/typings\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/base/typings\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    },\n    \"./vue-router\": {\n      \"types\": \"./vue-router.d.ts\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"types\": \"./dist/index.d.ts\",\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/src/app.d.ts",
    "content": "type LayoutType =\n  | 'full-content'\n  | 'header-mixed-nav'\n  | 'header-nav'\n  | 'header-sidebar-nav'\n  | 'mixed-nav'\n  | 'sidebar-mixed-nav'\n  | 'sidebar-nav';\n\ntype ThemeModeType = 'auto' | 'dark' | 'light';\n\n/**\n * 偏好设置按钮位置\n * fixed 固定在右侧\n * header 顶栏\n * auto 自动\n */\ntype PreferencesButtonPositionType = 'auto' | 'fixed' | 'header';\n\ntype BuiltinThemeType =\n  | 'custom'\n  | 'deep-blue'\n  | 'deep-green'\n  | 'default'\n  | 'gray'\n  | 'green'\n  | 'neutral'\n  | 'orange'\n  | 'pink'\n  | 'red'\n  | 'rose'\n  | 'sky-blue'\n  | 'slate'\n  | 'stone'\n  | 'violet'\n  | 'yellow'\n  | 'zinc'\n  | (Record<never, never> & string);\n\ntype ContentCompactType = 'compact' | 'wide';\n\ntype LayoutHeaderModeType = 'auto' | 'auto-scroll' | 'fixed' | 'static';\ntype LayoutHeaderMenuAlignType = 'center' | 'end' | 'start';\n\n/**\n * 登录过期模式\n * modal 弹窗模式\n * page 页面模式\n */\ntype LoginExpiredModeType = 'modal' | 'page';\n\n/**\n * 面包屑样式\n * background 背景\n * normal 默认\n */\ntype BreadcrumbStyleType = 'background' | 'normal';\n\n/**\n * 权限模式\n * backend 后端权限模式\n * frontend 前端权限模式\n * mixed 混合权限模式\n */\ntype AccessModeType = 'backend' | 'frontend' | 'mixed';\n\n/**\n * 导航风格\n * plain 朴素\n * rounded 圆润\n */\ntype NavigationStyleType = 'plain' | 'rounded';\n\n/**\n * 标签栏风格\n * brisk 轻快\n * card 卡片\n * chrome 谷歌\n * plain 朴素\n */\ntype TabsStyleType = 'brisk' | 'card' | 'chrome' | 'plain';\n\n/**\n * 页面切换动画\n */\ntype PageTransitionType = 'fade' | 'fade-down' | 'fade-slide' | 'fade-up';\n\n/**\n * 页面切换动画\n * panel-center 居中布局\n * panel-left 居左布局\n * panel-right 居右布局\n */\ntype AuthPageLayoutType = 'panel-center' | 'panel-left' | 'panel-right';\n\nexport type {\n  AccessModeType,\n  AuthPageLayoutType,\n  BreadcrumbStyleType,\n  BuiltinThemeType,\n  ContentCompactType,\n  LayoutHeaderMenuAlignType,\n  LayoutHeaderModeType,\n  LayoutType,\n  LoginExpiredModeType,\n  NavigationStyleType,\n  PageTransitionType,\n  PreferencesButtonPositionType,\n  TabsStyleType,\n  ThemeModeType,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/src/basic.d.ts",
    "content": "interface BasicOption {\n  label: string;\n  value: string;\n}\n\ntype SelectOption = BasicOption;\n\ntype TabOption = BasicOption;\n\ninterface BasicUserInfo {\n  /**\n   * 头像\n   */\n  avatar: string;\n  /**\n   * 用户昵称\n   */\n  realName: string;\n  /**\n   * 用户角色\n   */\n  roles?: string[];\n  /**\n   * 用户id\n   */\n  userId: string;\n  /**\n   * 用户名\n   */\n  username: string;\n}\n\ntype ClassType = Array<object | string> | object | string;\n\nexport type { BasicOption, BasicUserInfo, ClassType, SelectOption, TabOption };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/src/helper.d.ts",
    "content": "import type { ComputedRef, MaybeRef } from 'vue';\n\n/**\n * 深层递归所有属性为可选\n */\ntype DeepPartial<T> = T extends object\n  ? {\n      [P in keyof T]?: DeepPartial<T[P]>;\n    }\n  : T;\n\n/**\n * 深层递归所有属性为只读\n */\ntype DeepReadonly<T> = {\n  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];\n};\n\n/**\n * 任意类型的异步函数\n */\n\ntype AnyPromiseFunction<T extends any[] = any[], R = void> = (\n  ...arg: T\n) => PromiseLike<R>;\n\n/**\n * 任意类型的普通函数\n */\ntype AnyNormalFunction<T extends any[] = any[], R = void> = (...arg: T) => R;\n\n/**\n * 任意类型的函数\n */\ntype AnyFunction<T extends any[] = any[], R = void> =\n  | AnyNormalFunction<T, R>\n  | AnyPromiseFunction<T, R>;\n\n/**\n *  T | null 包装\n */\ntype Nullable<T> = null | T;\n\n/**\n * T | Not null 包装\n */\ntype NonNullable<T> = T extends null | undefined ? never : T;\n\n/**\n * 字符串类型对象\n */\ntype Recordable<T> = Record<string, T>;\n\n/**\n * 字符串类型对象（只读）\n */\ninterface ReadonlyRecordable<T = any> {\n  readonly [key: string]: T;\n}\n\n/**\n * setTimeout 返回值类型\n */\ntype TimeoutHandle = ReturnType<typeof setTimeout>;\n\n/**\n * setInterval 返回值类型\n */\ntype IntervalHandle = ReturnType<typeof setInterval>;\n\n/**\n * 也许它是一个计算的 ref，或者一个 getter 函数\n *\n */\ntype MaybeReadonlyRef<T> = (() => T) | ComputedRef<T>;\n\n/**\n * 也许它是一个 ref，或者一个普通值，或者一个 getter 函数\n *\n */\ntype MaybeComputedRef<T> = MaybeReadonlyRef<T> | MaybeRef<T>;\n\ntype Merge<O extends object, T extends object> = {\n  [K in keyof O | keyof T]: K extends keyof T\n    ? T[K]\n    : K extends keyof O\n      ? O[K]\n      : never;\n};\n\n/**\n * T = [\n *  { name: string; age: number; },\n *  { sex: 'male' | 'female'; age: string }\n * ]\n * =>\n * MergeAll<T> = {\n *  name: string;\n *  sex: 'male' | 'female';\n *  age: string\n * }\n */\ntype MergeAll<\n  T extends object[],\n  R extends object = Record<string, any>,\n> = T extends [infer F extends object, ...infer Rest extends object[]]\n  ? MergeAll<Rest, Merge<R, F>>\n  : R;\n\ntype EmitType = (name: Name, ...args: any[]) => void;\n\ntype MaybePromise<T> = Promise<T> | T;\n\nexport type {\n  AnyFunction,\n  AnyNormalFunction,\n  AnyPromiseFunction,\n  DeepPartial,\n  DeepReadonly,\n  EmitType,\n  IntervalHandle,\n  MaybeComputedRef,\n  MaybePromise,\n  MaybeReadonlyRef,\n  Merge,\n  MergeAll,\n  NonNullable,\n  Nullable,\n  ReadonlyRecordable,\n  Recordable,\n  TimeoutHandle,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/src/index.ts",
    "content": "export type * from './app';\nexport type * from './basic';\nexport type * from './helper';\nexport type * from './menu-record';\nexport type * from './tabs';\nexport type * from './vue-router';\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/src/menu-record.ts",
    "content": "import type { Component } from 'vue';\nimport type { RouteRecordRaw } from 'vue-router';\n\n/**\n * 扩展路由原始对象\n */\ntype ExRouteRecordRaw = RouteRecordRaw & {\n  parent?: string;\n  parents?: string[];\n  path?: any;\n};\n\ninterface MenuRecordBadgeRaw {\n  /**\n   * 徽标\n   */\n  badge?: string;\n  /**\n   * 徽标类型\n   */\n  badgeType?: 'dot' | 'normal';\n  /**\n   * 徽标颜色\n   */\n  badgeVariants?: 'destructive' | 'primary' | string;\n}\n\n/**\n * 菜单原始对象\n */\ninterface MenuRecordRaw extends MenuRecordBadgeRaw {\n  /**\n   * 激活时的图标名\n   */\n  activeIcon?: string;\n  /**\n   * 子菜单\n   */\n  children?: MenuRecordRaw[];\n  /**\n   * 是否禁用菜单\n   * @default false\n   */\n  disabled?: boolean;\n  /**\n   * 图标名\n   */\n  icon?: Component | string;\n  /**\n   * 菜单名\n   */\n  name: string;\n  /**\n   * 排序号\n   */\n  order?: number;\n  /**\n   * 父级路径\n   */\n  parent?: string;\n  /**\n   * 所有父级路径\n   */\n  parents?: string[];\n  /**\n   * 菜单路径，唯一，可当作key\n   */\n  path: string;\n  /**\n   * 是否显示菜单\n   * @default true\n   */\n  show?: boolean;\n}\n\nexport type { ExRouteRecordRaw, MenuRecordBadgeRaw, MenuRecordRaw };\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/src/tabs.ts",
    "content": "import type { RouteLocationNormalized } from 'vue-router';\n\nexport interface TabDefinition extends RouteLocationNormalized {\n  /**\n   * 标签页的key\n   */\n  key?: string;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/src/vue-router.d.ts",
    "content": "import type { Component } from 'vue';\nimport type { Router, RouteRecordRaw } from 'vue-router';\n\ninterface RouteMeta {\n  /**\n   * 激活图标（菜单/tab）\n   */\n  activeIcon?: string;\n  /**\n   * 当前激活的菜单，有时候不想激活现有菜单，需要激活父级菜单时使用\n   */\n  activePath?: string;\n  /**\n   * 是否固定标签页\n   * @default false\n   */\n  affixTab?: boolean;\n  /**\n   * 固定标签页的顺序\n   * @default 0\n   */\n  affixTabOrder?: number;\n  /**\n   * 需要特定的角色标识才可以访问\n   * @default []\n   */\n  authority?: string[];\n  /**\n   * 徽标\n   */\n  badge?: string;\n  /**\n   * 徽标类型\n   */\n  badgeType?: 'dot' | 'normal';\n  /**\n   * 徽标颜色\n   */\n  badgeVariants?:\n    | 'default'\n    | 'destructive'\n    | 'primary'\n    | 'success'\n    | 'warning'\n    | string;\n  /**\n   * 路由的完整路径作为key（默认true）\n   */\n  fullPathKey?: boolean;\n  /**\n   * 当前路由的子级在菜单中不展现\n   * @default false\n   */\n  hideChildrenInMenu?: boolean;\n  /**\n   * 当前路由在面包屑中不展现\n   * @default false\n   */\n  hideInBreadcrumb?: boolean;\n  /**\n   * 当前路由在菜单中不展现\n   * @default false\n   */\n  hideInMenu?: boolean;\n  /**\n   * 当前路由在标签页不展现\n   * @default false\n   */\n  hideInTab?: boolean;\n  /**\n   * 图标（菜单/tab）\n   */\n  icon?: Component | string;\n  /**\n   * iframe 地址\n   */\n  iframeSrc?: string;\n  /**\n   * 忽略权限，直接可以访问\n   * @default false\n   */\n  ignoreAccess?: boolean;\n  /**\n   * 开启KeepAlive缓存\n   */\n  keepAlive?: boolean;\n  /**\n   * 外链-跳转路径\n   */\n  link?: string;\n  /**\n   * 路由是否已经加载过\n   */\n  loaded?: boolean;\n  /**\n   * 标签页最大打开数量\n   * @default -1\n   */\n  maxNumOfOpenTab?: number;\n  /**\n   * 菜单可以看到，但是访问会被重定向到403\n   */\n  menuVisibleWithForbidden?: boolean;\n  /**\n   * 不使用基础布局（仅在顶级生效）\n   */\n  noBasicLayout?: boolean;\n  /**\n   * 在新窗口打开\n   */\n  openInNewWindow?: boolean;\n  /**\n   * 用于路由->菜单排序\n   */\n  order?: number;\n  /**\n   * 菜单所携带的参数\n   */\n  query?: Recordable;\n  /**\n   * 标题名称\n   */\n  title: string;\n}\n\n// 定义递归类型以将 RouteRecordRaw 的 component 属性更改为 string\ntype RouteRecordStringComponent<T = string> = Omit<\n  RouteRecordRaw,\n  'children' | 'component'\n> & {\n  children?: RouteRecordStringComponent<T>[];\n  component: T;\n};\n\ntype ComponentRecordType = Record<string, () => Promise<Component>>;\n\ninterface GenerateMenuAndRoutesOptions {\n  fetchMenuListAsync?: () => Promise<RouteRecordStringComponent[]>;\n  forbiddenComponent?: RouteRecordRaw['component'];\n  layoutMap?: ComponentRecordType;\n  pageMap?: ComponentRecordType;\n  roles?: string[];\n  router: Router;\n  routes: RouteRecordRaw[];\n}\n\nexport type {\n  ComponentRecordType,\n  GenerateMenuAndRoutesOptions,\n  RouteMeta,\n  RouteRecordRaw,\n  RouteRecordStringComponent,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/library.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/base/typings/vue-router.d.ts",
    "content": "/* eslint-disable no-restricted-imports */\nimport type { RouteMeta as IRouteMeta } from '@vben-core/typings';\n\nimport 'vue-router';\n\ndeclare module 'vue-router' {\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  interface RouteMeta extends IRouteMeta {}\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/package.json",
    "content": "{\n  \"name\": \"@vben-core/composables\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@core/composables\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"sideEffects\": false,\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"types\": \"./dist/index.d.ts\",\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"radix-vue\": \"catalog:\",\n    \"sortablejs\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/sortablejs\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/__tests__/use-sortable.test.ts",
    "content": "import type { SortableOptions } from 'sortablejs';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { useSortable } from '../use-sortable';\n\ndescribe('useSortable', () => {\n  beforeEach(() => {\n    vi.mock('sortablejs/modular/sortable.complete.esm.js', () => ({\n      default: {\n        create: vi.fn(),\n      },\n    }));\n  });\n  it('should call Sortable.create with the correct options', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div') as HTMLDivElement;\n\n    // Define custom options\n    const customOptions: SortableOptions = {\n      group: 'test-group',\n      sort: false,\n    };\n\n    // Use the useSortable function\n    const { initializeSortable } = useSortable(mockElement, customOptions);\n\n    // Initialize sortable\n    await initializeSortable();\n\n    // Import sortablejs to access the mocked create function\n    const Sortable = await import(\n      'sortablejs/modular/sortable.complete.esm.js'\n    );\n\n    // Verify that Sortable.create was called with the correct parameters\n    expect(Sortable.default.create).toHaveBeenCalledTimes(1);\n    expect(Sortable.default.create).toHaveBeenCalledWith(\n      mockElement,\n      expect.objectContaining({\n        animation: 300,\n        delay: 400,\n        delayOnTouchOnly: true,\n        ...customOptions,\n      }),\n    );\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/index.ts",
    "content": "export * from './use-is-mobile';\nexport * from './use-layout-style';\nexport * from './use-namespace';\nexport * from './use-priority-value';\nexport * from './use-scroll-lock';\nexport * from './use-simple-locale';\nexport * from './use-sortable';\nexport {\n  useEmitAsProps,\n  useForwardExpose,\n  useForwardProps,\n  useForwardPropsEmits,\n} from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-is-mobile.ts",
    "content": "import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';\n\nexport function useIsMobile() {\n  const breakpoints = useBreakpoints(breakpointsTailwind);\n  const isMobile = breakpoints.smaller('md');\n  return { isMobile };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-layout-style.ts",
    "content": "import type { CSSProperties } from 'vue';\n\nimport type { VisibleDomRect } from '@vben-core/shared/utils';\n\nimport { computed, onMounted, onUnmounted, ref } from 'vue';\n\nimport {\n  CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT,\n  CSS_VARIABLE_LAYOUT_CONTENT_WIDTH,\n  CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT,\n  CSS_VARIABLE_LAYOUT_HEADER_HEIGHT,\n} from '@vben-core/shared/constants';\nimport { getElementVisibleRect } from '@vben-core/shared/utils';\n\nimport { useCssVar, useDebounceFn } from '@vueuse/core';\n\n/**\n * @zh_CN content style\n */\nexport function useLayoutContentStyle() {\n  let resizeObserver: null | ResizeObserver = null;\n  const contentElement = ref<HTMLDivElement | null>(null);\n  const visibleDomRect = ref<null | VisibleDomRect>(null);\n  const contentHeight = useCssVar(CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT);\n  const contentWidth = useCssVar(CSS_VARIABLE_LAYOUT_CONTENT_WIDTH);\n\n  const overlayStyle = computed((): CSSProperties => {\n    const { height, left, top, width } = visibleDomRect.value ?? {};\n    return {\n      height: `${height}px`,\n      left: `${left}px`,\n      position: 'fixed',\n      top: `${top}px`,\n      width: `${width}px`,\n      zIndex: 150,\n    };\n  });\n\n  const debouncedCalcHeight = useDebounceFn(\n    (_entries: ResizeObserverEntry[]) => {\n      visibleDomRect.value = getElementVisibleRect(contentElement.value);\n      contentHeight.value = `${visibleDomRect.value.height}px`;\n      contentWidth.value = `${visibleDomRect.value.width}px`;\n    },\n    16,\n  );\n\n  onMounted(() => {\n    if (contentElement.value && !resizeObserver) {\n      resizeObserver = new ResizeObserver(debouncedCalcHeight);\n      resizeObserver.observe(contentElement.value);\n    }\n  });\n\n  onUnmounted(() => {\n    resizeObserver?.disconnect();\n    resizeObserver = null;\n  });\n\n  return { contentElement, overlayStyle, visibleDomRect };\n}\n\nexport function useLayoutHeaderStyle() {\n  const headerHeight = useCssVar(CSS_VARIABLE_LAYOUT_HEADER_HEIGHT);\n\n  return {\n    getLayoutHeaderHeight: () => {\n      return Number.parseInt(`${headerHeight.value}`, 10);\n    },\n    setLayoutHeaderHeight: (height: number) => {\n      headerHeight.value = `${height}px`;\n    },\n  };\n}\n\nexport function useLayoutFooterStyle() {\n  const footerHeight = useCssVar(CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT);\n\n  return {\n    getLayoutFooterHeight: () => {\n      return Number.parseInt(`${footerHeight.value}`, 10);\n    },\n    setLayoutFooterHeight: (height: number) => {\n      footerHeight.value = `${height}px`;\n    },\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-namespace.ts",
    "content": "import { DEFAULT_NAMESPACE } from '@vben-core/shared/constants';\n\n/**\n * @see copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-namespace/index.ts\n */\n\nconst statePrefix = 'is-';\n\nconst _bem = (\n  namespace: string,\n  block: string,\n  blockSuffix: string,\n  element: string,\n  modifier: string,\n) => {\n  let cls = `${namespace}-${block}`;\n  if (blockSuffix) {\n    cls += `-${blockSuffix}`;\n  }\n  if (element) {\n    cls += `__${element}`;\n  }\n  if (modifier) {\n    cls += `--${modifier}`;\n  }\n  return cls;\n};\n\nconst is: {\n  (name: string): string;\n  // eslint-disable-next-line @typescript-eslint/unified-signatures\n  (name: string, state: boolean | undefined): string;\n} = (name: string, ...args: [] | [boolean | undefined]) => {\n  const state = args.length > 0 ? args[0] : true;\n  return name && state ? `${statePrefix}${name}` : '';\n};\n\nconst useNamespace = (block: string) => {\n  const namespace = DEFAULT_NAMESPACE;\n  const b = (blockSuffix = '') => _bem(namespace, block, blockSuffix, '', '');\n  const e = (element?: string) =>\n    element ? _bem(namespace, block, '', element, '') : '';\n  const m = (modifier?: string) =>\n    modifier ? _bem(namespace, block, '', '', modifier) : '';\n  const be = (blockSuffix?: string, element?: string) =>\n    blockSuffix && element\n      ? _bem(namespace, block, blockSuffix, element, '')\n      : '';\n  const em = (element?: string, modifier?: string) =>\n    element && modifier ? _bem(namespace, block, '', element, modifier) : '';\n  const bm = (blockSuffix?: string, modifier?: string) =>\n    blockSuffix && modifier\n      ? _bem(namespace, block, blockSuffix, '', modifier)\n      : '';\n  const bem = (blockSuffix?: string, element?: string, modifier?: string) =>\n    blockSuffix && element && modifier\n      ? _bem(namespace, block, blockSuffix, element, modifier)\n      : '';\n\n  // for css var\n  // --el-xxx: value;\n  const cssVar = (object: Record<string, string>) => {\n    const styles: Record<string, string> = {};\n    for (const key in object) {\n      if (object[key]) {\n        styles[`--${namespace}-${key}`] = object[key];\n      }\n    }\n    return styles;\n  };\n  // with block\n  const cssVarBlock = (object: Record<string, string>) => {\n    const styles: Record<string, string> = {};\n    for (const key in object) {\n      if (object[key]) {\n        styles[`--${namespace}-${block}-${key}`] = object[key];\n      }\n    }\n    return styles;\n  };\n\n  const cssVarName = (name: string) => `--${namespace}-${name}`;\n  const cssVarBlockName = (name: string) => `--${namespace}-${block}-${name}`;\n\n  return {\n    b,\n    be,\n    bem,\n    bm,\n    // css\n    cssVar,\n    cssVarBlock,\n    cssVarBlockName,\n    cssVarName,\n    e,\n    em,\n    is,\n    m,\n    namespace,\n  };\n};\n\ntype UseNamespaceReturn = ReturnType<typeof useNamespace>;\n\nexport type { UseNamespaceReturn };\nexport { useNamespace };\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-priority-value.ts",
    "content": "import type { ComputedRef, Ref } from 'vue';\n\nimport { computed, getCurrentInstance, unref, useAttrs, useSlots } from 'vue';\n\nimport {\n  getFirstNonNullOrUndefined,\n  kebabToCamelCase,\n} from '@vben-core/shared/utils';\n\n/**\n * 依次从插槽、attrs、props、state 中获取值\n * @param key\n * @param props\n * @param state\n */\nexport function usePriorityValue<\n  T extends Record<string, any>,\n  S extends Record<string, any>,\n  K extends keyof T = keyof T,\n>(key: K, props: T, state: Readonly<Ref<NoInfer<S>>> | undefined) {\n  const instance = getCurrentInstance();\n  const slots = useSlots();\n  const attrs = useAttrs() as T;\n\n  const value = computed((): T[K] => {\n    // props不管有没有传，都会有默认值，会影响这里的顺序，\n    // 通过判断原始props是否有值来判断是否传入\n    const rawProps = (instance?.vnode?.props || {}) as T;\n\n    const standardRawProps = {} as T;\n\n    for (const [key, value] of Object.entries(rawProps)) {\n      standardRawProps[kebabToCamelCase(key) as K] = value;\n    }\n    const propsKey =\n      standardRawProps?.[key] === undefined ? undefined : props[key];\n\n    // slot可以关闭\n    return getFirstNonNullOrUndefined(\n      slots[key as string],\n      attrs[key],\n      propsKey,\n      state?.value?.[key as keyof S],\n    ) as T[K];\n  });\n\n  return value;\n}\n\n/**\n * 批量获取state中的值（每个值都是ref）\n * @param props\n * @param state\n */\nexport function usePriorityValues<\n  T extends Record<string, any>,\n  S extends Ref<Record<string, any>> = Readonly<Ref<NoInfer<T>, NoInfer<T>>>,\n>(props: T, state: S | undefined) {\n  const result: { [K in keyof T]: ComputedRef<T[K]> } = {} as never;\n\n  (Object.keys(props) as (keyof T)[]).forEach((key) => {\n    result[key] = usePriorityValue(key as keyof typeof props, props, state);\n  });\n\n  return result;\n}\n\n/**\n * 批量获取state中的值（集中在一个computed，用于透传）\n * @param props\n * @param state\n */\nexport function useForwardPriorityValues<\n  T extends Record<string, any>,\n  S extends Ref<Record<string, any>> = Readonly<Ref<NoInfer<T>, NoInfer<T>>>,\n>(props: T, state: S | undefined) {\n  const computedResult: { [K in keyof T]: ComputedRef<T[K]> } = {} as never;\n\n  (Object.keys(props) as (keyof T)[]).forEach((key) => {\n    computedResult[key] = usePriorityValue(\n      key as keyof typeof props,\n      props,\n      state,\n    );\n  });\n\n  return computed(() => {\n    const unwrapResult: Record<string, any> = {};\n    Object.keys(props).forEach((key) => {\n      unwrapResult[key] = unref(computedResult[key]);\n    });\n    return unwrapResult as { [K in keyof T]: T[K] };\n  });\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-scroll-lock.ts",
    "content": "import { getScrollbarWidth, needsScrollbar } from '@vben-core/shared/utils';\n\nimport {\n  useScrollLock as _useScrollLock,\n  tryOnBeforeUnmount,\n  tryOnMounted,\n} from '@vueuse/core';\n\nexport const SCROLL_FIXED_CLASS = `_scroll__fixed_`;\n\nexport function useScrollLock() {\n  const isLocked = _useScrollLock(document.body);\n  const scrollbarWidth = getScrollbarWidth();\n\n  tryOnMounted(() => {\n    if (!needsScrollbar()) {\n      return;\n    }\n    document.body.style.paddingRight = `${scrollbarWidth}px`;\n\n    const layoutFixedNodes = document.querySelectorAll<HTMLElement>(\n      `.${SCROLL_FIXED_CLASS}`,\n    );\n    const nodes = [...layoutFixedNodes];\n    if (nodes.length > 0) {\n      nodes.forEach((node) => {\n        node.dataset.transition = node.style.transition;\n        node.style.transition = 'none';\n        node.style.paddingRight = `${scrollbarWidth}px`;\n      });\n    }\n    isLocked.value = true;\n  });\n\n  tryOnBeforeUnmount(() => {\n    if (!needsScrollbar()) {\n      return;\n    }\n    isLocked.value = false;\n    const layoutFixedNodes = document.querySelectorAll<HTMLElement>(\n      `.${SCROLL_FIXED_CLASS}`,\n    );\n    const nodes = [...layoutFixedNodes];\n    if (nodes.length > 0) {\n      nodes.forEach((node) => {\n        node.style.paddingRight = '';\n        requestAnimationFrame(() => {\n          node.style.transition = node.dataset.transition || '';\n        });\n      });\n    }\n    document.body.style.paddingRight = '';\n  });\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-simple-locale/README.md",
    "content": "# Simple i18n\n\nSimple i18 implementation\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-simple-locale/index.ts",
    "content": "import type { Locale } from './messages';\n\nimport { computed, ref } from 'vue';\n\nimport { createSharedComposable } from '@vueuse/core';\n\nimport { getMessages } from './messages';\n\nexport const useSimpleLocale = createSharedComposable(() => {\n  const currentLocale = ref<Locale>('zh-CN');\n\n  const setSimpleLocale = (locale: Locale) => {\n    currentLocale.value = locale;\n  };\n\n  const $t = computed(() => {\n    const localeMessages = getMessages(currentLocale.value);\n    return (key: string) => {\n      return localeMessages[key] || key;\n    };\n  });\n  return {\n    $t,\n    currentLocale,\n    setSimpleLocale,\n  };\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-simple-locale/messages.ts",
    "content": "export type Locale = 'en-US' | 'zh-CN';\n\nexport const messages: Record<Locale, Record<string, string>> = {\n  'en-US': {\n    cancel: 'Cancel',\n    collapse: 'Collapse',\n    confirm: 'Confirm',\n    expand: 'Expand',\n    prompt: 'Prompt',\n    reset: 'Reset',\n    submit: 'Submit',\n  },\n  'zh-CN': {\n    cancel: '取消',\n    collapse: '收起',\n    confirm: '确认',\n    expand: '展开',\n    prompt: '提示',\n    reset: '重置',\n    submit: '提交',\n  },\n};\n\nexport const getMessages = (locale: Locale) => messages[locale];\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/src/use-sortable.ts",
    "content": "import type { SortableOptions } from 'sortablejs';\nimport type Sortable from 'sortablejs';\n\nfunction useSortable<T extends HTMLElement>(\n  sortableContainer: T,\n  options: SortableOptions = {},\n) {\n  const initializeSortable = async () => {\n    const Sortable = await import(\n      // @ts-expect-error - This is a dynamic import\n      'sortablejs/modular/sortable.complete.esm.js'\n    );\n    const sortable = Sortable?.default?.create?.(sortableContainer, {\n      animation: 300,\n      delay: 400,\n      delayOnTouchOnly: true,\n      ...options,\n    });\n    return sortable as Sortable;\n  };\n\n  return {\n    initializeSortable,\n  };\n}\n\nexport { useSortable };\n\nexport type { Sortable };\n"
  },
  {
    "path": "hiauth-front/packages/@core/composables/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/library.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`defaultPreferences immutability test > should not modify the config object 1`] = `\n{\n  \"app\": {\n    \"accessMode\": \"frontend\",\n    \"authPageLayout\": \"panel-right\",\n    \"checkUpdatesInterval\": 1,\n    \"colorGrayMode\": false,\n    \"colorWeakMode\": false,\n    \"compact\": false,\n    \"contentCompact\": \"wide\",\n    \"contentCompactWidth\": 1200,\n    \"contentPadding\": 0,\n    \"contentPaddingBottom\": 0,\n    \"contentPaddingLeft\": 0,\n    \"contentPaddingRight\": 0,\n    \"contentPaddingTop\": 0,\n    \"defaultAvatar\": \"https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp\",\n    \"defaultHomePath\": \"/analytics\",\n    \"dynamicTitle\": true,\n    \"enableCheckUpdates\": true,\n    \"enablePreferences\": true,\n    \"enableRefreshToken\": false,\n    \"isMobile\": false,\n    \"layout\": \"sidebar-nav\",\n    \"locale\": \"zh-CN\",\n    \"loginExpiredMode\": \"page\",\n    \"name\": \"Vben Admin\",\n    \"preferencesButtonPosition\": \"auto\",\n    \"watermark\": false,\n    \"zIndex\": 200,\n  },\n  \"breadcrumb\": {\n    \"enable\": true,\n    \"hideOnlyOne\": false,\n    \"showHome\": false,\n    \"showIcon\": true,\n    \"styleType\": \"normal\",\n  },\n  \"copyright\": {\n    \"companyName\": \"Vben\",\n    \"companySiteLink\": \"https://www.vben.pro\",\n    \"date\": \"2024\",\n    \"enable\": true,\n    \"icp\": \"\",\n    \"icpLink\": \"\",\n    \"settingShow\": true,\n  },\n  \"footer\": {\n    \"enable\": false,\n    \"fixed\": false,\n    \"height\": 32,\n  },\n  \"header\": {\n    \"enable\": true,\n    \"height\": 50,\n    \"hidden\": false,\n    \"menuAlign\": \"start\",\n    \"mode\": \"fixed\",\n  },\n  \"logo\": {\n    \"enable\": true,\n    \"fit\": \"contain\",\n    \"source\": \"https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp\",\n  },\n  \"navigation\": {\n    \"accordion\": true,\n    \"split\": true,\n    \"styleType\": \"rounded\",\n  },\n  \"shortcutKeys\": {\n    \"enable\": true,\n    \"globalLockScreen\": true,\n    \"globalLogout\": true,\n    \"globalPreferences\": true,\n    \"globalSearch\": true,\n  },\n  \"sidebar\": {\n    \"autoActivateChild\": false,\n    \"collapseWidth\": 60,\n    \"collapsed\": false,\n    \"collapsedButton\": true,\n    \"collapsedShowTitle\": false,\n    \"enable\": true,\n    \"expandOnHover\": true,\n    \"extraCollapse\": false,\n    \"extraCollapsedWidth\": 60,\n    \"fixedButton\": true,\n    \"hidden\": false,\n    \"mixedWidth\": 80,\n    \"width\": 224,\n  },\n  \"tabbar\": {\n    \"draggable\": true,\n    \"enable\": true,\n    \"height\": 38,\n    \"keepAlive\": true,\n    \"maxCount\": 0,\n    \"middleClickToClose\": false,\n    \"persist\": true,\n    \"showIcon\": true,\n    \"showMaximize\": true,\n    \"showMore\": true,\n    \"styleType\": \"chrome\",\n    \"wheelable\": true,\n  },\n  \"theme\": {\n    \"builtinType\": \"default\",\n    \"colorDestructive\": \"hsl(348 100% 61%)\",\n    \"colorPrimary\": \"hsl(212 100% 45%)\",\n    \"colorSuccess\": \"hsl(144 57% 58%)\",\n    \"colorWarning\": \"hsl(42 84% 61%)\",\n    \"mode\": \"dark\",\n    \"radius\": \"0.5\",\n    \"semiDarkHeader\": false,\n    \"semiDarkSidebar\": false,\n  },\n  \"transition\": {\n    \"enable\": true,\n    \"loading\": true,\n    \"name\": \"fade-slide\",\n    \"progress\": true,\n  },\n  \"widget\": {\n    \"fullscreen\": true,\n    \"globalSearch\": true,\n    \"languageToggle\": true,\n    \"lockScreen\": true,\n    \"notification\": true,\n    \"refresh\": true,\n    \"sidebarToggle\": true,\n    \"themeToggle\": true,\n  },\n}\n`;\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/__tests__/config.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { defaultPreferences } from '../src/config';\n\ndescribe('defaultPreferences immutability test', () => {\n  // 创建快照，确保默认配置对象不被修改\n  it('should not modify the config object', () => {\n    expect(defaultPreferences).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/__tests__/preferences.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { defaultPreferences } from '../src/config';\nimport { PreferenceManager } from '../src/preferences';\nimport { isDarkTheme } from '../src/update-css-variables';\n\ndescribe('preferences', () => {\n  let preferenceManager: PreferenceManager;\n\n  // 模拟 window.matchMedia 方法\n  vi.stubGlobal(\n    'matchMedia',\n    vi.fn().mockImplementation((query) => ({\n      addEventListener: vi.fn(),\n      addListener: vi.fn(), // Deprecated\n      dispatchEvent: vi.fn(),\n      matches: query === '(prefers-color-scheme: dark)',\n      media: query,\n      onchange: null,\n      removeEventListener: vi.fn(),\n      removeListener: vi.fn(), // Deprecated\n    })),\n  );\n  beforeEach(() => {\n    preferenceManager = new PreferenceManager();\n  });\n\n  it('loads default preferences if no saved preferences found', () => {\n    const preferences = preferenceManager.getPreferences();\n    expect(preferences).toEqual(defaultPreferences);\n  });\n\n  it('initializes preferences with overrides', async () => {\n    const overrides: any = {\n      app: {\n        locale: 'en-US',\n      },\n    };\n    await preferenceManager.initPreferences({\n      namespace: 'testNamespace',\n      overrides,\n    });\n\n    // 等待防抖动操作完成\n    // await new Promise((resolve) => setTimeout(resolve, 300)); // 等待100毫秒\n\n    const expected = {\n      ...defaultPreferences,\n      app: {\n        ...defaultPreferences.app,\n        ...overrides.app,\n      },\n    };\n\n    expect(preferenceManager.getPreferences()).toEqual(expected);\n  });\n\n  it('updates theme mode correctly', () => {\n    preferenceManager.updatePreferences({\n      theme: {\n        mode: 'light',\n      },\n    });\n\n    expect(preferenceManager.getPreferences().theme.mode).toBe('light');\n  });\n\n  it('updates color modes correctly', () => {\n    preferenceManager.updatePreferences({\n      app: { colorGrayMode: true, colorWeakMode: true },\n    });\n\n    expect(preferenceManager.getPreferences().app.colorGrayMode).toBe(true);\n    expect(preferenceManager.getPreferences().app.colorWeakMode).toBe(true);\n  });\n\n  it('resets preferences to default', () => {\n    // 先更新一些偏好设置\n    preferenceManager.updatePreferences({\n      theme: {\n        mode: 'light',\n      },\n    });\n\n    // 然后重置偏好设置\n    preferenceManager.resetPreferences();\n\n    expect(preferenceManager.getPreferences()).toEqual(defaultPreferences);\n  });\n\n  it('updates isMobile correctly', () => {\n    // 模拟移动端状态\n    vi.stubGlobal(\n      'matchMedia',\n      vi.fn().mockImplementation((query) => ({\n        addEventListener: vi.fn(),\n        addListener: vi.fn(),\n        dispatchEvent: vi.fn(),\n        matches: query === '(max-width: 768px)',\n        media: query,\n        onchange: null,\n        removeEventListener: vi.fn(),\n        removeListener: vi.fn(),\n      })),\n    );\n\n    preferenceManager.updatePreferences({\n      app: { isMobile: true },\n    });\n\n    expect(preferenceManager.getPreferences().app.isMobile).toBe(true);\n  });\n\n  it('updates the locale preference correctly', () => {\n    preferenceManager.updatePreferences({\n      app: { locale: 'en-US' },\n    });\n\n    expect(preferenceManager.getPreferences().app.locale).toBe('en-US');\n  });\n\n  it('updates the sidebar width correctly', () => {\n    preferenceManager.updatePreferences({\n      sidebar: { width: 200 },\n    });\n\n    expect(preferenceManager.getPreferences().sidebar.width).toBe(200);\n  });\n  it('updates the sidebar collapse state correctly', () => {\n    preferenceManager.updatePreferences({\n      sidebar: { collapsed: true },\n    });\n\n    expect(preferenceManager.getPreferences().sidebar.collapsed).toBe(true);\n  });\n  it('updates the navigation style type correctly', () => {\n    preferenceManager.updatePreferences({\n      navigation: { styleType: 'flat' },\n    } as any);\n\n    expect(preferenceManager.getPreferences().navigation.styleType).toBe(\n      'flat',\n    );\n  });\n\n  it('resets preferences to default correctly', () => {\n    // 先更新一些偏好设置\n    preferenceManager.updatePreferences({\n      app: { locale: 'en-US' },\n      sidebar: { collapsed: true, width: 200 },\n      theme: {\n        mode: 'light',\n      },\n    });\n\n    // 然后重置偏好设置\n    preferenceManager.resetPreferences();\n\n    expect(preferenceManager.getPreferences()).toEqual(defaultPreferences);\n  });\n\n  it('does not update undefined preferences', () => {\n    const originalPreferences = preferenceManager.getPreferences();\n\n    preferenceManager.updatePreferences({\n      app: { nonexistentField: 'value' },\n    } as any);\n\n    expect(preferenceManager.getPreferences()).toEqual(originalPreferences);\n  });\n\n  it('reverts to default when a preference field is deleted', () => {\n    preferenceManager.updatePreferences({\n      app: { locale: 'en-US' },\n    });\n\n    preferenceManager.updatePreferences({\n      app: { locale: undefined },\n    });\n\n    expect(preferenceManager.getPreferences().app.locale).toBe('en-US');\n  });\n\n  it('ignores updates with invalid preference value types', () => {\n    const originalPreferences = preferenceManager.getPreferences();\n\n    preferenceManager.updatePreferences({\n      app: { isMobile: 'true' as unknown as boolean }, // 错误类型\n    });\n\n    expect(preferenceManager.getPreferences()).toEqual(originalPreferences);\n  });\n\n  it('merges nested preference objects correctly', () => {\n    preferenceManager.updatePreferences({\n      app: { name: 'New App Name' },\n    });\n\n    const expected = {\n      ...defaultPreferences,\n      app: {\n        ...defaultPreferences.app,\n        name: 'New App Name',\n      },\n    };\n\n    expect(preferenceManager.getPreferences()).toEqual(expected);\n  });\n\n  it('applies updates immediately after initialization', async () => {\n    const overrides: any = {\n      app: {\n        locale: 'en-US',\n      },\n    };\n\n    await preferenceManager.initPreferences(overrides);\n\n    preferenceManager.updatePreferences({\n      theme: { mode: 'light' },\n    });\n\n    expect(preferenceManager.getPreferences().theme.mode).toBe('light');\n  });\n});\n\ndescribe('isDarkTheme', () => {\n  it('should return true for dark theme', () => {\n    expect(isDarkTheme('dark')).toBe(true);\n  });\n\n  it('should return false for light theme', () => {\n    expect(isDarkTheme('light')).toBe(false);\n  });\n\n  it('should return system preference for auto theme', () => {\n    vi.spyOn(window, 'matchMedia').mockImplementation((query) => ({\n      addEventListener: vi.fn(),\n      addListener: vi.fn(), // Deprecated\n      dispatchEvent: vi.fn(),\n      matches: query === '(prefers-color-scheme: dark)',\n      media: query,\n      onchange: null,\n      removeEventListener: vi.fn(),\n      removeListener: vi.fn(), // Deprecated\n    }));\n\n    expect(isDarkTheme('auto')).toBe(true);\n    expect(window.matchMedia).toHaveBeenCalledWith(\n      '(prefers-color-scheme: dark)',\n    );\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/package.json",
    "content": "{\n  \"name\": \"@vben-core/preferences\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@core/preferences\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"#build\": \"pnpm unbuild\"\n  },\n  \"files\": [\n    \"dist\",\n    \"src\"\n  ],\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\",\n      \"#default\": \"./dist/index.mjs\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/src/config.ts",
    "content": "import type { Preferences } from './types';\n\nconst defaultPreferences: Preferences = {\n  app: {\n    accessMode: 'frontend',\n    authPageLayout: 'panel-right',\n    checkUpdatesInterval: 1,\n    colorGrayMode: false,\n    colorWeakMode: false,\n    compact: false,\n    contentCompact: 'wide',\n    contentCompactWidth: 1200,\n    contentPadding: 0,\n    contentPaddingBottom: 0,\n    contentPaddingLeft: 0,\n    contentPaddingRight: 0,\n    contentPaddingTop: 0,\n    defaultAvatar:\n      'https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp',\n    defaultHomePath: '/analytics',\n    dynamicTitle: true,\n    enableCheckUpdates: true,\n    enablePreferences: true,\n    enableRefreshToken: false,\n    enableStickyPreferencesNavigationBar: true,\n    isMobile: false,\n    layout: 'sidebar-nav',\n    locale: 'zh-CN',\n    loginExpiredMode: 'page',\n    name: 'Vben Admin',\n    preferencesButtonPosition: 'auto',\n    watermark: false,\n    watermarkContent: '',\n    zIndex: 200,\n  },\n  breadcrumb: {\n    enable: true,\n    hideOnlyOne: false,\n    showHome: false,\n    showIcon: true,\n    styleType: 'normal',\n  },\n  copyright: {\n    companyName: 'Vben',\n    companySiteLink: 'https://www.vben.pro',\n    date: '2024',\n    enable: true,\n    icp: '',\n    icpLink: '',\n    settingShow: true,\n  },\n  footer: {\n    enable: false,\n    fixed: false,\n    height: 32,\n  },\n  header: {\n    enable: true,\n    height: 50,\n    hidden: false,\n    menuAlign: 'start',\n    mode: 'fixed',\n  },\n\n  logo: {\n    enable: true,\n    fit: 'contain',\n    source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n  },\n  navigation: {\n    accordion: true,\n    split: true,\n    styleType: 'rounded',\n  },\n  shortcutKeys: {\n    enable: true,\n    globalLockScreen: true,\n    globalLogout: true,\n    globalPreferences: true,\n    globalSearch: true,\n  },\n  sidebar: {\n    autoActivateChild: false,\n    collapsed: false,\n    collapsedButton: true,\n    collapsedShowTitle: false,\n    collapseWidth: 60,\n    enable: true,\n    expandOnHover: true,\n    extraCollapse: false,\n    extraCollapsedWidth: 60,\n    fixedButton: true,\n    hidden: false,\n    mixedWidth: 80,\n    width: 224,\n  },\n  tabbar: {\n    draggable: true,\n    enable: true,\n    height: 38,\n    keepAlive: true,\n    maxCount: 0,\n    middleClickToClose: false,\n    persist: true,\n    showIcon: true,\n    showMaximize: true,\n    showMore: true,\n    styleType: 'chrome',\n    wheelable: true,\n  },\n  theme: {\n    builtinType: 'default',\n    colorDestructive: 'hsl(348 100% 61%)',\n    colorPrimary: 'hsl(212 100% 45%)',\n    colorSuccess: 'hsl(144 57% 58%)',\n    colorWarning: 'hsl(42 84% 61%)',\n    mode: 'dark',\n    radius: '0.5',\n    semiDarkHeader: false,\n    semiDarkSidebar: false,\n  },\n  transition: {\n    enable: true,\n    loading: true,\n    name: 'fade-slide',\n    progress: true,\n  },\n  widget: {\n    fullscreen: true,\n    globalSearch: true,\n    languageToggle: true,\n    lockScreen: true,\n    notification: true,\n    refresh: true,\n    sidebarToggle: true,\n    themeToggle: true,\n  },\n};\n\nexport { defaultPreferences };\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/src/constants.ts",
    "content": "import type { BuiltinThemeType } from '@vben-core/typings';\n\ninterface BuiltinThemePreset {\n  color: string;\n  darkPrimaryColor?: string;\n  primaryColor?: string;\n  type: BuiltinThemeType;\n}\n\nconst BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [\n  {\n    color: 'hsl(212 100% 45%)',\n    type: 'default',\n  },\n  {\n    color: 'hsl(245 82% 67%)',\n    type: 'violet',\n  },\n  {\n    color: 'hsl(347 77% 60%)',\n    type: 'pink',\n  },\n  {\n    color: 'hsl(42 84% 61%)',\n    type: 'yellow',\n  },\n  {\n    color: 'hsl(231 98% 65%)',\n    type: 'sky-blue',\n  },\n  {\n    color: 'hsl(161 90% 43%)',\n    type: 'green',\n  },\n  {\n    color: 'hsl(240 5% 26%)',\n    darkPrimaryColor: 'hsl(0 0% 98%)',\n    primaryColor: 'hsl(240 5.9% 10%)',\n    type: 'zinc',\n  },\n\n  {\n    color: 'hsl(181 84% 32%)',\n    type: 'deep-green',\n  },\n\n  {\n    color: 'hsl(211 91% 39%)',\n    type: 'deep-blue',\n  },\n  {\n    color: 'hsl(18 89% 40%)',\n    type: 'orange',\n  },\n  {\n    color: 'hsl(0 75% 42%)',\n    type: 'rose',\n  },\n\n  {\n    color: 'hsl(0 0% 25%)',\n    darkPrimaryColor: 'hsl(0 0% 98%)',\n    primaryColor: 'hsl(240 5.9% 10%)',\n    type: 'neutral',\n  },\n  {\n    color: 'hsl(215 25% 27%)',\n    darkPrimaryColor: 'hsl(0 0% 98%)',\n    primaryColor: 'hsl(240 5.9% 10%)',\n    type: 'slate',\n  },\n  {\n    color: 'hsl(217 19% 27%)',\n    darkPrimaryColor: 'hsl(0 0% 98%)',\n    primaryColor: 'hsl(240 5.9% 10%)',\n    type: 'gray',\n  },\n  {\n    color: '',\n    type: 'custom',\n  },\n];\n\nexport const COLOR_PRESETS = [...BUILT_IN_THEME_PRESETS].slice(0, 7);\n\nexport { BUILT_IN_THEME_PRESETS };\n\nexport type { BuiltinThemePreset };\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/src/index.ts",
    "content": "import type { Preferences } from './types';\n\nimport { preferencesManager } from './preferences';\n\n// 偏好设置（带有层级关系）\nconst preferences: Preferences =\n  preferencesManager.getPreferences.apply(preferencesManager);\n\n// 更新偏好设置\nconst updatePreferences =\n  preferencesManager.updatePreferences.bind(preferencesManager);\n\n// 重置偏好设置\nconst resetPreferences =\n  preferencesManager.resetPreferences.bind(preferencesManager);\n\nconst clearPreferencesCache =\n  preferencesManager.clearCache.bind(preferencesManager);\n\n// 初始化偏好设置\nconst initPreferences =\n  preferencesManager.initPreferences.bind(preferencesManager);\n\nexport {\n  clearPreferencesCache,\n  initPreferences,\n  preferences,\n  preferencesManager,\n  resetPreferences,\n  updatePreferences,\n};\n\nexport * from './constants';\nexport type * from './types';\nexport * from './use-preferences';\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/src/preferences.ts",
    "content": "import type { DeepPartial } from '@vben-core/typings';\n\nimport type { InitialOptions, Preferences } from './types';\n\nimport { markRaw, reactive, readonly, watch } from 'vue';\n\nimport { StorageManager } from '@vben-core/shared/cache';\nimport { isMacOs, merge } from '@vben-core/shared/utils';\n\nimport {\n  breakpointsTailwind,\n  useBreakpoints,\n  useDebounceFn,\n} from '@vueuse/core';\n\nimport { defaultPreferences } from './config';\nimport { updateCSSVariables } from './update-css-variables';\n\nconst STORAGE_KEY = 'preferences';\nconst STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`;\nconst STORAGE_KEY_THEME = `${STORAGE_KEY}-theme`;\n\nclass PreferenceManager {\n  private cache: null | StorageManager = null;\n  // private flattenedState: Flatten<Preferences>;\n  private initialPreferences: Preferences = defaultPreferences;\n  private isInitialized: boolean = false;\n  private savePreferences: (preference: Preferences) => void;\n  private state: Preferences = reactive<Preferences>({\n    ...this.loadPreferences(),\n  });\n  constructor() {\n    this.cache = new StorageManager();\n\n    // 避免频繁的操作缓存\n    this.savePreferences = useDebounceFn(\n      (preference: Preferences) => this._savePreferences(preference),\n      150,\n    );\n  }\n\n  clearCache() {\n    [STORAGE_KEY, STORAGE_KEY_LOCALE, STORAGE_KEY_THEME].forEach((key) => {\n      this.cache?.removeItem(key);\n    });\n  }\n\n  public getInitialPreferences() {\n    return this.initialPreferences;\n  }\n\n  public getPreferences() {\n    return readonly(this.state);\n  }\n\n  /**\n   * 覆盖偏好设置\n   * overrides  要覆盖的偏好设置\n   * namespace  命名空间\n   */\n  public async initPreferences({ namespace, overrides }: InitialOptions) {\n    // 是否初始化过\n    if (this.isInitialized) {\n      return;\n    }\n    // 初始化存储管理器\n    this.cache = new StorageManager({ prefix: namespace });\n    // 合并初始偏好设置\n    this.initialPreferences = merge({}, overrides, defaultPreferences);\n\n    // 加载并合并当前存储的偏好设置\n    const mergedPreference = merge(\n      {},\n      // overrides,\n      this.loadCachedPreferences() || {},\n      this.initialPreferences,\n    );\n\n    // 更新偏好设置\n    this.updatePreferences(mergedPreference);\n\n    this.setupWatcher();\n\n    this.initPlatform();\n    // 标记为已初始化\n    this.isInitialized = true;\n  }\n\n  /**\n   * 重置偏好设置\n   * 偏好设置将被重置为初始值，并从 localStorage 中移除。\n   *\n   * @example\n   * 假设 initialPreferences 为 { theme: 'light', language: 'en' }\n   * 当前 state 为 { theme: 'dark', language: 'fr' }\n   * this.resetPreferences();\n   * 调用后，state 将被重置为 { theme: 'light', language: 'en' }\n   * 并且 localStorage 中的对应项将被移除\n   */\n  resetPreferences() {\n    // 将状态重置为初始偏好设置\n    Object.assign(this.state, this.initialPreferences);\n    // 保存重置后的偏好设置\n    this.savePreferences(this.state);\n    // 从存储中移除偏好设置项\n    [STORAGE_KEY, STORAGE_KEY_THEME, STORAGE_KEY_LOCALE].forEach((key) => {\n      this.cache?.removeItem(key);\n    });\n    this.updatePreferences(this.state);\n  }\n\n  /**\n   * 更新偏好设置\n   * @param updates - 要更新的偏好设置\n   */\n  public updatePreferences(updates: DeepPartial<Preferences>) {\n    const mergedState = merge({}, updates, markRaw(this.state));\n\n    Object.assign(this.state, mergedState);\n\n    // 根据更新的键值执行相应的操作\n    this.handleUpdates(updates);\n    this.savePreferences(this.state);\n  }\n\n  /**\n   * 保存偏好设置\n   * @param {Preferences} preference - 需要保存的偏好设置\n   */\n  private _savePreferences(preference: Preferences) {\n    this.cache?.setItem(STORAGE_KEY, preference);\n    this.cache?.setItem(STORAGE_KEY_LOCALE, preference.app.locale);\n    this.cache?.setItem(STORAGE_KEY_THEME, preference.theme.mode);\n  }\n\n  /**\n   * 处理更新的键值\n   * 根据更新的键值执行相应的操作。\n   * @param {DeepPartial<Preferences>} updates - 部分更新的偏好设置\n   */\n  private handleUpdates(updates: DeepPartial<Preferences>) {\n    const themeUpdates = updates.theme || {};\n    const appUpdates = updates.app || {};\n    if (themeUpdates && Object.keys(themeUpdates).length > 0) {\n      updateCSSVariables(this.state);\n    }\n\n    if (\n      Reflect.has(appUpdates, 'colorGrayMode') ||\n      Reflect.has(appUpdates, 'colorWeakMode')\n    ) {\n      this.updateColorMode(this.state);\n    }\n  }\n\n  private initPlatform() {\n    const dom = document.documentElement;\n    dom.dataset.platform = isMacOs() ? 'macOs' : 'window';\n  }\n\n  /**\n   *  从缓存中加载偏好设置。如果缓存中没有找到对应的偏好设置，则返回默认偏好设置。\n   */\n  private loadCachedPreferences() {\n    return this.cache?.getItem<Preferences>(STORAGE_KEY);\n  }\n\n  /**\n   * 加载偏好设置\n   * @returns {Preferences} 加载的偏好设置\n   */\n  private loadPreferences(): Preferences {\n    return this.loadCachedPreferences() || { ...defaultPreferences };\n  }\n\n  /**\n   * 监听状态和系统偏好设置的变化。\n   */\n  private setupWatcher() {\n    if (this.isInitialized) {\n      return;\n    }\n\n    // 监听断点，判断是否移动端\n    const breakpoints = useBreakpoints(breakpointsTailwind);\n    const isMobile = breakpoints.smaller('md');\n    watch(\n      () => isMobile.value,\n      (val) => {\n        this.updatePreferences({\n          app: { isMobile: val },\n        });\n      },\n      { immediate: true },\n    );\n\n    // 监听系统主题偏好设置变化\n    window\n      .matchMedia('(prefers-color-scheme: dark)')\n      .addEventListener('change', ({ matches: isDark }) => {\n        // 如果偏好设置中主题模式为auto，则跟随系统更新\n        if (this.state.theme.mode === 'auto') {\n          this.updatePreferences({\n            theme: { mode: isDark ? 'dark' : 'light' },\n          });\n          // 恢复为auto模式\n          this.updatePreferences({\n            theme: { mode: 'auto' },\n          });\n        }\n      });\n  }\n\n  /**\n   * 更新页面颜色模式（灰色、色弱）\n   * @param preference\n   */\n  private updateColorMode(preference: Preferences) {\n    if (preference.app) {\n      const { colorGrayMode, colorWeakMode } = preference.app;\n      const dom = document.documentElement;\n      const COLOR_WEAK = 'invert-mode';\n      const COLOR_GRAY = 'grayscale-mode';\n      colorWeakMode\n        ? dom.classList.add(COLOR_WEAK)\n        : dom.classList.remove(COLOR_WEAK);\n      colorGrayMode\n        ? dom.classList.add(COLOR_GRAY)\n        : dom.classList.remove(COLOR_GRAY);\n    }\n  }\n}\n\nconst preferencesManager = new PreferenceManager();\nexport { PreferenceManager, preferencesManager };\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/src/types.ts",
    "content": "import type {\n  AccessModeType,\n  AuthPageLayoutType,\n  BreadcrumbStyleType,\n  BuiltinThemeType,\n  ContentCompactType,\n  DeepPartial,\n  LayoutHeaderMenuAlignType,\n  LayoutHeaderModeType,\n  LayoutType,\n  LoginExpiredModeType,\n  NavigationStyleType,\n  PageTransitionType,\n  PreferencesButtonPositionType,\n  TabsStyleType,\n  ThemeModeType,\n} from '@vben-core/typings';\n\ntype SupportedLanguagesType = 'en-US' | 'zh-CN';\n\ninterface AppPreferences {\n  /** 权限模式 */\n  accessMode: AccessModeType;\n  /** 登录注册页面布局 */\n  authPageLayout: AuthPageLayoutType;\n  /** 检查更新轮询时间 */\n  checkUpdatesInterval: number;\n  /** 是否开启灰色模式 */\n  colorGrayMode: boolean;\n  /** 是否开启色弱模式 */\n  colorWeakMode: boolean;\n  /** 是否开启紧凑模式 */\n  compact: boolean;\n  /** 是否开启内容紧凑模式 */\n  contentCompact: ContentCompactType;\n  /** 内容紧凑宽度 */\n  contentCompactWidth: number;\n  /** 内容内边距 */\n  contentPadding: number;\n  /** 内容底部内边距 */\n  contentPaddingBottom: number;\n  /** 内容左侧内边距 */\n  contentPaddingLeft: number;\n  /** 内容右侧内边距 */\n  contentPaddingRight: number;\n  /** 内容顶部内边距 */\n  contentPaddingTop: number;\n  // /** 应用默认头像 */\n  defaultAvatar: string;\n  /** 默认首页地址 */\n  defaultHomePath: string;\n  // /** 开启动态标题 */\n  dynamicTitle: boolean;\n  /** 是否开启检查更新 */\n  enableCheckUpdates: boolean;\n  /** 是否显示偏好设置 */\n  enablePreferences: boolean;\n  /**\n   * @zh_CN 是否开启refreshToken\n   */\n  enableRefreshToken: boolean;\n  /**\n   * @zh_CN 是否开启首选项导航栏吸顶效果\n   */\n  enableStickyPreferencesNavigationBar: boolean;\n  /** 是否移动端 */\n  isMobile: boolean;\n  /** 布局方式 */\n  layout: LayoutType;\n  /** 支持的语言 */\n  locale: SupportedLanguagesType;\n  /** 登录过期模式 */\n  loginExpiredMode: LoginExpiredModeType;\n  /** 应用名 */\n  name: string;\n  /** 偏好设置按钮位置 */\n  preferencesButtonPosition: PreferencesButtonPositionType;\n  /**\n   * @zh_CN 是否开启水印\n   */\n  watermark: boolean;\n  /**\n   * @zh_CN 水印文案\n   */\n  watermarkContent: string;\n  /** z-index */\n  zIndex: number;\n}\n\ninterface BreadcrumbPreferences {\n  /** 面包屑是否启用 */\n  enable: boolean;\n  /** 面包屑是否只有一个时隐藏 */\n  hideOnlyOne: boolean;\n  /** 面包屑首页图标是否可见 */\n  showHome: boolean;\n  /** 面包屑图标是否可见 */\n  showIcon: boolean;\n  /** 面包屑风格 */\n  styleType: BreadcrumbStyleType;\n}\n\ninterface CopyrightPreferences {\n  /** 版权公司名 */\n  companyName: string;\n  /** 版权公司名链接 */\n  companySiteLink: string;\n  /** 版权日期 */\n  date: string;\n  /** 版权是否可见 */\n  enable: boolean;\n  /** 备案号 */\n  icp: string;\n  /** 备案号链接 */\n  icpLink: string;\n  /** 设置面板是否显示*/\n  settingShow?: boolean;\n}\n\ninterface FooterPreferences {\n  /** 底栏是否可见 */\n  enable: boolean;\n  /** 底栏是否固定 */\n  fixed: boolean;\n  /** 底栏高度 */\n  height: number;\n}\n\ninterface HeaderPreferences {\n  /** 顶栏是否启用 */\n  enable: boolean;\n  /** 顶栏高度 */\n  height: number;\n  /** 顶栏是否隐藏,css-隐藏 */\n  hidden: boolean;\n  /** 顶栏菜单位置 */\n  menuAlign: LayoutHeaderMenuAlignType;\n  /** header显示模式 */\n  mode: LayoutHeaderModeType;\n}\n\ninterface LogoPreferences {\n  /** logo是否可见 */\n  enable: boolean;\n  /** logo图片适应方式 */\n  fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\n  /** logo地址 */\n  source: string;\n}\n\ninterface NavigationPreferences {\n  /** 导航菜单手风琴模式 */\n  accordion: boolean;\n  /** 导航菜单是否切割，只在 layout=mixed-nav 生效 */\n  split: boolean;\n  /** 导航菜单风格 */\n  styleType: NavigationStyleType;\n}\n\ninterface SidebarPreferences {\n  /** 点击目录时自动激活子菜单   */\n  autoActivateChild: boolean;\n  /** 侧边栏是否折叠 */\n  collapsed: boolean;\n  /** 侧边栏折叠按钮是否可见 */\n  collapsedButton: boolean;\n  /** 侧边栏折叠时，是否显示title */\n  collapsedShowTitle: boolean;\n  /** 侧边栏折叠宽度 */\n  collapseWidth: number;\n  /** 侧边栏是否可见 */\n  enable: boolean;\n  /** 菜单自动展开状态 */\n  expandOnHover: boolean;\n  /** 侧边栏扩展区域是否折叠 */\n  extraCollapse: boolean;\n  /** 侧边栏扩展区域折叠宽度 */\n  extraCollapsedWidth: number;\n  /** 侧边栏固定按钮是否可见 */\n  fixedButton: boolean;\n  /** 侧边栏是否隐藏 - css */\n  hidden: boolean;\n  /** 混合侧边栏宽度 */\n  mixedWidth: number;\n  /** 侧边栏宽度 */\n  width: number;\n}\n\ninterface ShortcutKeyPreferences {\n  /** 是否启用快捷键-全局 */\n  enable: boolean;\n  /** 是否启用全局锁屏快捷键 */\n  globalLockScreen: boolean;\n  /** 是否启用全局注销快捷键 */\n  globalLogout: boolean;\n  /** 是否启用全局偏好设置快捷键 */\n  globalPreferences: boolean;\n  /** 是否启用全局搜索快捷键 */\n  globalSearch: boolean;\n}\n\ninterface TabbarPreferences {\n  /** 是否开启多标签页拖拽 */\n  draggable: boolean;\n  /** 是否开启多标签页 */\n  enable: boolean;\n  /** 标签页高度 */\n  height: number;\n  /** 开启标签页缓存功能 */\n  keepAlive: boolean;\n  /** 限制最大数量 */\n  maxCount: number;\n  /** 是否点击中键时关闭标签 */\n  middleClickToClose: boolean;\n  /** 是否持久化标签 */\n  persist: boolean;\n  /** 是否开启多标签页图标 */\n  showIcon: boolean;\n  /** 显示最大化按钮 */\n  showMaximize: boolean;\n  /** 显示更多按钮 */\n  showMore: boolean;\n  /** 标签页风格 */\n  styleType: TabsStyleType;\n  /** 是否开启鼠标滚轮响应 */\n  wheelable: boolean;\n}\n\ninterface ThemePreferences {\n  /** 内置主题名 */\n  builtinType: BuiltinThemeType;\n  /** 错误色 */\n  colorDestructive: string;\n  /** 主题色 */\n  colorPrimary: string;\n  /** 成功色 */\n  colorSuccess: string;\n  /** 警告色 */\n  colorWarning: string;\n  /** 当前主题 */\n  mode: ThemeModeType;\n  /** 圆角 */\n  radius: string;\n  /** 是否开启半深色header（只在theme='light'时生效） */\n  semiDarkHeader: boolean;\n  /** 是否开启半深色菜单（只在theme='light'时生效） */\n  semiDarkSidebar: boolean;\n}\n\ninterface TransitionPreferences {\n  /** 页面切换动画是否启用 */\n  enable: boolean;\n  // /** 是否开启页面加载loading */\n  loading: boolean;\n  /** 页面切换动画 */\n  name: PageTransitionType | string;\n  /** 是否开启页面加载进度动画 */\n  progress: boolean;\n}\n\ninterface WidgetPreferences {\n  /** 是否启用全屏部件 */\n  fullscreen: boolean;\n  /** 是否启用全局搜索部件 */\n  globalSearch: boolean;\n  /** 是否启用语言切换部件 */\n  languageToggle: boolean;\n  /** 是否开启锁屏功能 */\n  lockScreen: boolean;\n  /** 是否显示通知部件 */\n  notification: boolean;\n  /** 显示刷新按钮 */\n  refresh: boolean;\n  /** 是否显示侧边栏显示/隐藏部件 */\n  sidebarToggle: boolean;\n  /** 是否显示主题切换部件 */\n  themeToggle: boolean;\n}\n\ninterface Preferences {\n  /** 全局配置 */\n  app: AppPreferences;\n  /** 顶栏配置 */\n  breadcrumb: BreadcrumbPreferences;\n  /** 版权配置 */\n  copyright: CopyrightPreferences;\n  /** 底栏配置 */\n  footer: FooterPreferences;\n  /** 面包屑配置 */\n  header: HeaderPreferences;\n  /** logo配置 */\n  logo: LogoPreferences;\n  /** 导航配置 */\n  navigation: NavigationPreferences;\n  /** 快捷键配置 */\n  shortcutKeys: ShortcutKeyPreferences;\n  /** 侧边栏配置 */\n  sidebar: SidebarPreferences;\n  /** 标签页配置 */\n  tabbar: TabbarPreferences;\n  /** 主题配置 */\n  theme: ThemePreferences;\n  /** 动画配置 */\n  transition: TransitionPreferences;\n  /** 功能配置 */\n  widget: WidgetPreferences;\n}\n\ntype PreferencesKeys = keyof Preferences;\n\ninterface InitialOptions {\n  namespace: string;\n  overrides?: DeepPartial<Preferences>;\n}\nexport type {\n  AppPreferences,\n  BreadcrumbPreferences,\n  FooterPreferences,\n  HeaderPreferences,\n  InitialOptions,\n  LogoPreferences,\n  NavigationPreferences,\n  Preferences,\n  PreferencesKeys,\n  ShortcutKeyPreferences,\n  SidebarPreferences,\n  SupportedLanguagesType,\n  TabbarPreferences,\n  ThemePreferences,\n  TransitionPreferences,\n  WidgetPreferences,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/src/update-css-variables.ts",
    "content": "import type { Preferences } from './types';\n\nimport { generatorColorVariables } from '@vben-core/shared/color';\nimport { updateCSSVariables as executeUpdateCSSVariables } from '@vben-core/shared/utils';\n\nimport { BUILT_IN_THEME_PRESETS } from './constants';\n\n/**\n * 更新主题的 CSS 变量以及其他 CSS 变量\n * @param preferences - 当前偏好设置对象，它的主题值将被用来设置文档的主题。\n */\nfunction updateCSSVariables(preferences: Preferences) {\n  // 当修改到颜色变量时，更新 css 变量\n  const root = document.documentElement;\n  if (!root) {\n    return;\n  }\n\n  const theme = preferences?.theme ?? {};\n\n  const { builtinType, mode, radius } = theme;\n\n  // html 设置 dark 类\n  if (Reflect.has(theme, 'mode')) {\n    const dark = isDarkTheme(mode);\n    root.classList.toggle('dark', dark);\n  }\n\n  // html 设置 data-theme=[builtinType]\n  if (Reflect.has(theme, 'builtinType')) {\n    const rootTheme = root.dataset.theme;\n    if (rootTheme !== builtinType) {\n      root.dataset.theme = builtinType;\n    }\n  }\n\n  // 获取当前的内置主题\n  const currentBuiltType = [...BUILT_IN_THEME_PRESETS].find(\n    (item) => item.type === builtinType,\n  );\n\n  let builtinTypeColorPrimary: string | undefined = '';\n\n  if (currentBuiltType) {\n    const isDark = isDarkTheme(preferences.theme.mode);\n    // 设置不同主题的主要颜色\n    const color = isDark\n      ? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor\n      : currentBuiltType.primaryColor;\n    builtinTypeColorPrimary = color || currentBuiltType.color;\n  }\n\n  // 如果内置主题颜色和自定义颜色都不存在，则不更新主题颜色\n  if (\n    builtinTypeColorPrimary ||\n    Reflect.has(theme, 'colorPrimary') ||\n    Reflect.has(theme, 'colorDestructive') ||\n    Reflect.has(theme, 'colorSuccess') ||\n    Reflect.has(theme, 'colorWarning')\n  ) {\n    // preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;\n    updateMainColorVariables(preferences);\n  }\n\n  // 更新圆角\n  if (Reflect.has(theme, 'radius')) {\n    document.documentElement.style.setProperty('--radius', `${radius}rem`);\n  }\n}\n\n/**\n * 更新主要的 CSS 变量\n * @param  preference - 当前偏好设置对象，它的颜色值将被转换成 HSL 格式并设置为 CSS 变量。\n */\nfunction updateMainColorVariables(preference: Preferences) {\n  if (!preference.theme) {\n    return;\n  }\n  const { colorDestructive, colorPrimary, colorSuccess, colorWarning } =\n    preference.theme;\n\n  const colorVariables = generatorColorVariables([\n    { color: colorPrimary, name: 'primary' },\n    { alias: 'warning', color: colorWarning, name: 'yellow' },\n    { alias: 'success', color: colorSuccess, name: 'green' },\n    { alias: 'destructive', color: colorDestructive, name: 'red' },\n  ]);\n\n  // 要设置的 CSS 变量映射\n  const colorMappings = {\n    '--green-500': '--success',\n    '--primary-500': '--primary',\n    '--red-500': '--destructive',\n    '--yellow-500': '--warning',\n  };\n\n  // 统一处理颜色变量的更新\n  Object.entries(colorMappings).forEach(([sourceVar, targetVar]) => {\n    const colorValue = colorVariables[sourceVar];\n    if (colorValue) {\n      document.documentElement.style.setProperty(targetVar, colorValue);\n    }\n  });\n\n  executeUpdateCSSVariables(colorVariables);\n}\n\nfunction isDarkTheme(theme: string) {\n  let dark = theme === 'dark';\n  if (theme === 'auto') {\n    dark = window.matchMedia('(prefers-color-scheme: dark)').matches;\n  }\n  return dark;\n}\n\nexport { isDarkTheme, updateCSSVariables };\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/src/use-preferences.ts",
    "content": "import { computed } from 'vue';\n\nimport { diff } from '@vben-core/shared/utils';\n\nimport { preferencesManager } from './preferences';\nimport { isDarkTheme } from './update-css-variables';\n\nfunction usePreferences() {\n  const preferences = preferencesManager.getPreferences();\n  const initialPreferences = preferencesManager.getInitialPreferences();\n  /**\n   * @zh_CN 计算偏好设置的变化\n   */\n  const diffPreference = computed(() => {\n    return diff(initialPreferences, preferences);\n  });\n\n  const appPreferences = computed(() => preferences.app);\n\n  const shortcutKeysPreferences = computed(() => preferences.shortcutKeys);\n\n  /**\n   * @zh_CN 判断是否为暗黑模式\n   * @param  preferences - 当前偏好设置对象，它的主题值将被用来判断是否为暗黑模式。\n   * @returns 如果主题为暗黑模式，返回 true，否则返回 false。\n   */\n  const isDark = computed(() => {\n    return isDarkTheme(preferences.theme.mode);\n  });\n\n  const locale = computed(() => {\n    return preferences.app.locale;\n  });\n\n  const isMobile = computed(() => {\n    return appPreferences.value.isMobile;\n  });\n\n  const theme = computed(() => {\n    return isDark.value ? 'dark' : 'light';\n  });\n\n  /**\n   * @zh_CN 布局方式\n   */\n  const layout = computed(() =>\n    isMobile.value ? 'sidebar-nav' : appPreferences.value.layout,\n  );\n\n  /**\n   * @zh_CN 是否显示顶栏\n   */\n  const isShowHeaderNav = computed(() => {\n    return preferences.header.enable;\n  });\n\n  /**\n   * @zh_CN 是否全屏显示content，不需要侧边、底部、顶部、tab区域\n   */\n  const isFullContent = computed(\n    () => appPreferences.value.layout === 'full-content',\n  );\n\n  /**\n   * @zh_CN 是否侧边导航模式\n   */\n  const isSideNav = computed(\n    () => appPreferences.value.layout === 'sidebar-nav',\n  );\n\n  /**\n   * @zh_CN 是否侧边混合模式\n   */\n  const isSideMixedNav = computed(\n    () => appPreferences.value.layout === 'sidebar-mixed-nav',\n  );\n\n  /**\n   * @zh_CN 是否为头部导航模式\n   */\n  const isHeaderNav = computed(\n    () => appPreferences.value.layout === 'header-nav',\n  );\n\n  /**\n   * @zh_CN 是否为头部混合导航模式\n   */\n  const isHeaderMixedNav = computed(\n    () => appPreferences.value.layout === 'header-mixed-nav',\n  );\n\n  /**\n   * @zh_CN 是否为顶部通栏+侧边导航模式\n   */\n  const isHeaderSidebarNav = computed(\n    () => appPreferences.value.layout === 'header-sidebar-nav',\n  );\n\n  /**\n   * @zh_CN 是否为混合导航模式\n   */\n  const isMixedNav = computed(\n    () => appPreferences.value.layout === 'mixed-nav',\n  );\n\n  /**\n   * @zh_CN 是否包含侧边导航模式\n   */\n  const isSideMode = computed(() => {\n    return (\n      isMixedNav.value ||\n      isSideMixedNav.value ||\n      isSideNav.value ||\n      isHeaderMixedNav.value ||\n      isHeaderSidebarNav.value\n    );\n  });\n\n  const sidebarCollapsed = computed(() => {\n    return preferences.sidebar.collapsed;\n  });\n\n  /**\n   * @zh_CN 是否开启keep-alive\n   * 在tabs可见以及开启keep-alive的情况下才开启\n   */\n  const keepAlive = computed(\n    () => preferences.tabbar.enable && preferences.tabbar.keepAlive,\n  );\n\n  /**\n   * @zh_CN 登录注册页面布局是否为左侧\n   */\n  const authPanelLeft = computed(() => {\n    return appPreferences.value.authPageLayout === 'panel-left';\n  });\n\n  /**\n   * @zh_CN 登录注册页面布局是否为左侧\n   */\n  const authPanelRight = computed(() => {\n    return appPreferences.value.authPageLayout === 'panel-right';\n  });\n\n  /**\n   * @zh_CN 登录注册页面布局是否为中间\n   */\n  const authPanelCenter = computed(() => {\n    return appPreferences.value.authPageLayout === 'panel-center';\n  });\n\n  /**\n   * @zh_CN 内容是否已经最大化\n   * 排除 full-content模式\n   */\n  const contentIsMaximize = computed(() => {\n    const headerIsHidden = preferences.header.hidden;\n    const sidebarIsHidden = preferences.sidebar.hidden;\n    return headerIsHidden && sidebarIsHidden && !isFullContent.value;\n  });\n\n  /**\n   * @zh_CN 是否启用全局搜索快捷键\n   */\n  const globalSearchShortcutKey = computed(() => {\n    const { enable, globalSearch } = shortcutKeysPreferences.value;\n    return enable && globalSearch;\n  });\n\n  /**\n   * @zh_CN 是否启用全局注销快捷键\n   */\n  const globalLogoutShortcutKey = computed(() => {\n    const { enable, globalLogout } = shortcutKeysPreferences.value;\n    return enable && globalLogout;\n  });\n\n  const globalLockScreenShortcutKey = computed(() => {\n    const { enable, globalLockScreen } = shortcutKeysPreferences.value;\n    return enable && globalLockScreen;\n  });\n\n  /**\n   * @zh_CN 偏好设置按钮位置\n   */\n  const preferencesButtonPosition = computed(() => {\n    const { enablePreferences, preferencesButtonPosition } = preferences.app;\n\n    // 如果没有启用偏好设置按钮\n    if (!enablePreferences) {\n      return {\n        fixed: false,\n        header: false,\n      };\n    }\n\n    const { header, sidebar } = preferences;\n    const headerHidden = header.hidden;\n    const sidebarHidden = sidebar.hidden;\n\n    const contentIsMaximize = headerHidden && sidebarHidden;\n\n    const isHeaderPosition = preferencesButtonPosition === 'header';\n\n    // 如果设置了固定位置\n    if (preferencesButtonPosition !== 'auto') {\n      return {\n        fixed: preferencesButtonPosition === 'fixed',\n        header: isHeaderPosition,\n      };\n    }\n\n    // 如果是全屏模式或者没有固定在顶部，\n    const fixed =\n      contentIsMaximize ||\n      isFullContent.value ||\n      isMobile.value ||\n      !isShowHeaderNav.value;\n\n    return {\n      fixed,\n      header: !fixed,\n    };\n  });\n\n  return {\n    authPanelCenter,\n    authPanelLeft,\n    authPanelRight,\n    contentIsMaximize,\n    diffPreference,\n    globalLockScreenShortcutKey,\n    globalLogoutShortcutKey,\n    globalSearchShortcutKey,\n    isDark,\n    isFullContent,\n    isHeaderMixedNav,\n    isHeaderNav,\n    isHeaderSidebarNav,\n    isMixedNav,\n    isMobile,\n    isSideMixedNav,\n    isSideMode,\n    isSideNav,\n    keepAlive,\n    layout,\n    locale,\n    preferencesButtonPosition,\n    sidebarCollapsed,\n    theme,\n  };\n}\n\nexport { usePreferences };\n"
  },
  {
    "path": "hiauth-front/packages/@core/preferences/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\", \"__tests__\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/README.md",
    "content": "# ui-kit\n\n用于管理公共组件、不同UI组件库封装的组件\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { FormApi } from '../src/form-api';\n\ndescribe('formApi', () => {\n  let formApi: FormApi;\n\n  beforeEach(() => {\n    formApi = new FormApi();\n  });\n\n  it('should initialize with default state', () => {\n    expect(formApi.state).toEqual(\n      expect.objectContaining({\n        actionWrapperClass: '',\n        collapsed: false,\n        collapsedRows: 1,\n        commonConfig: {},\n        handleReset: undefined,\n        handleSubmit: undefined,\n        layout: 'horizontal',\n        resetButtonOptions: {},\n        schema: [],\n        showCollapseButton: false,\n        showDefaultActions: true,\n        submitButtonOptions: {},\n        wrapperClass: 'grid-cols-1',\n      }),\n    );\n    expect(formApi.isMounted).toBe(false);\n  });\n\n  it('should mount form actions', async () => {\n    const formActions: any = {\n      meta: {},\n      resetForm: vi.fn(),\n      setFieldValue: vi.fn(),\n      setValues: vi.fn(),\n      submitForm: vi.fn(),\n      validate: vi.fn(),\n      values: { name: 'test' },\n    };\n\n    await formApi.mount(formActions);\n    expect(formApi.isMounted).toBe(true);\n    expect(formApi.form).toEqual(formActions);\n  });\n\n  it('should get values from form', async () => {\n    const formActions: any = {\n      meta: {},\n      values: { name: 'test' },\n    };\n\n    await formApi.mount(formActions);\n    const values = await formApi.getValues();\n    expect(values).toEqual({ name: 'test' });\n  });\n\n  it('should set field value', async () => {\n    const setFieldValueMock = vi.fn();\n    const formActions: any = {\n      meta: {},\n      setFieldValue: setFieldValueMock,\n      values: { name: 'test' },\n    };\n\n    await formApi.mount(formActions);\n    await formApi.setFieldValue('name', 'new value');\n    expect(setFieldValueMock).toHaveBeenCalledWith(\n      'name',\n      'new value',\n      undefined,\n    );\n  });\n\n  it('should reset form', async () => {\n    const resetFormMock = vi.fn();\n    const formActions: any = {\n      meta: {},\n      resetForm: resetFormMock,\n      values: { name: 'test' },\n    };\n\n    await formApi.mount(formActions);\n    await formApi.resetForm();\n    expect(resetFormMock).toHaveBeenCalled();\n  });\n\n  it('should call handleSubmit on submit', async () => {\n    const handleSubmitMock = vi.fn();\n    const formActions: any = {\n      meta: {},\n      submitForm: vi.fn().mockResolvedValue(true),\n      values: { name: 'test' },\n    };\n\n    const state = {\n      handleSubmit: handleSubmitMock,\n    };\n\n    formApi.setState(state);\n    await formApi.mount(formActions);\n\n    const result = await formApi.submitForm();\n    expect(formActions.submitForm).toHaveBeenCalled();\n    expect(handleSubmitMock).toHaveBeenCalledWith({ name: 'test' });\n    expect(result).toEqual({ name: 'test' });\n  });\n\n  it('should unmount form and reset state', () => {\n    formApi.unmount();\n    expect(formApi.isMounted).toBe(false);\n  });\n\n  it('should validate form', async () => {\n    const validateMock = vi.fn().mockResolvedValue(true);\n    const formActions: any = {\n      meta: {},\n      validate: validateMock,\n    };\n\n    await formApi.mount(formActions);\n    const isValid = await formApi.validate();\n    expect(validateMock).toHaveBeenCalled();\n    expect(isValid).toBe(true);\n  });\n});\n\ndescribe('updateSchema', () => {\n  let instance: FormApi;\n\n  beforeEach(() => {\n    instance = new FormApi();\n    instance.state = {\n      schema: [\n        { component: 'text', fieldName: 'name' },\n        { component: 'number', fieldName: 'age', label: 'Age' },\n      ],\n    };\n  });\n\n  it('should update the schema correctly when fieldName matches', () => {\n    const newSchema = [\n      { component: 'text', fieldName: 'name' },\n      { component: 'number', fieldName: 'age', label: 'Age' },\n    ];\n\n    instance.updateSchema(newSchema);\n\n    expect(instance.state?.schema?.[0]?.component).toBe('text');\n    expect(instance.state?.schema?.[1]?.label).toBe('Age');\n  });\n\n  it('should log an error if fieldName is missing in some items', () => {\n    const newSchema: any[] = [\n      { component: 'textarea', fieldName: 'name' },\n      { component: 'number' },\n    ];\n\n    const consoleErrorSpy = vi\n      .spyOn(console, 'error')\n      .mockImplementation(() => {});\n\n    instance.updateSchema(newSchema);\n\n    expect(consoleErrorSpy).toHaveBeenCalledWith(\n      'All items in the schema array must have a valid `fieldName` property to be updated',\n    );\n  });\n\n  it('should not update schema if fieldName does not match', () => {\n    const newSchema = [{ component: 'textarea', fieldName: 'unknown' }];\n\n    instance.updateSchema(newSchema);\n\n    expect(instance.state?.schema?.[0]?.component).toBe('text');\n    expect(instance.state?.schema?.[1]?.component).toBe('number');\n  });\n\n  it('should not update schema if updatedMap is empty', () => {\n    const newSchema: any[] = [{ component: 'textarea' }];\n\n    instance.updateSchema(newSchema);\n\n    expect(instance.state?.schema?.[0]?.component).toBe('text');\n    expect(instance.state?.schema?.[1]?.component).toBe('number');\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: [\n    {\n      builder: 'mkdist',\n      input: './src',\n      loaders: ['vue'],\n      pattern: ['**/*.vue'],\n    },\n    {\n      builder: 'mkdist',\n      format: 'esm',\n      input: './src',\n      loaders: ['js'],\n      pattern: ['**/*.ts'],\n    },\n  ],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/package.json",
    "content": "{\n  \"name\": \"@vben-core/form-ui\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/uikit/form-ui\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/composables\": \"workspace:*\",\n    \"@vben-core/icons\": \"workspace:*\",\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"@vee-validate/zod\": \"catalog:\",\n    \"@vueuse/core\": \"catalog:\",\n    \"vee-validate\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"zod\": \"catalog:\",\n    \"zod-defaults\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/components/form-actions.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, toRaw, unref, watch } from 'vue';\n\nimport { useSimpleLocale } from '@vben-core/composables';\nimport { VbenExpandableArrow } from '@vben-core/shadcn-ui';\nimport { cn, isFunction, triggerWindowResize } from '@vben-core/shared/utils';\n\nimport { COMPONENT_MAP } from '../config';\nimport { injectFormProps } from '../use-form-context';\n\nconst { $t } = useSimpleLocale();\n\nconst [rootProps, form] = injectFormProps();\n\nconst collapsed = defineModel({ default: false });\n\nconst resetButtonOptions = computed(() => {\n  return {\n    content: `${$t.value('reset')}`,\n    show: true,\n    ...unref(rootProps).resetButtonOptions,\n  };\n});\n\nconst submitButtonOptions = computed(() => {\n  return {\n    content: `${$t.value('submit')}`,\n    show: true,\n    ...unref(rootProps).submitButtonOptions,\n  };\n});\n\n// const isQueryForm = computed(() => {\n//   return !!unref(rootProps).showCollapseButton;\n// });\n\nasync function handleSubmit(e: Event) {\n  e?.preventDefault();\n  e?.stopPropagation();\n  const props = unref(rootProps);\n  if (!props.formApi) {\n    return;\n  }\n\n  const { valid } = await props.formApi.validate();\n  if (!valid) {\n    return;\n  }\n\n  const values = toRaw(await props.formApi.getValues());\n  await props.handleSubmit?.(values);\n}\n\nasync function handleReset(e: Event) {\n  e?.preventDefault();\n  e?.stopPropagation();\n  const props = unref(rootProps);\n\n  const values = toRaw(await props.formApi?.getValues());\n\n  if (isFunction(props.handleReset)) {\n    await props.handleReset?.(values);\n  } else {\n    form.resetForm();\n  }\n}\n\nwatch(\n  () => collapsed.value,\n  () => {\n    const props = unref(rootProps);\n    if (props.collapseTriggerResize) {\n      triggerWindowResize();\n    }\n  },\n);\n\nconst actionWrapperClass = computed(() => {\n  const props = unref(rootProps);\n  const actionLayout = props.actionLayout || 'rowEnd';\n  const actionPosition = props.actionPosition || 'right';\n\n  const cls = [\n    'flex',\n    'items-center',\n    'gap-3',\n    props.compact ? 'pb-2' : 'pb-4',\n    props.layout === 'vertical' ? 'self-end' : 'self-center',\n    props.layout === 'inline' ? '' : 'w-full',\n    props.actionWrapperClass,\n  ];\n\n  switch (actionLayout) {\n    case 'newLine': {\n      cls.push('col-span-full');\n      break;\n    }\n    case 'rowEnd': {\n      cls.push('col-[-2/-1]');\n      break;\n    }\n    // 'inline' 不需要额外类名，保持默认\n  }\n\n  switch (actionPosition) {\n    case 'center': {\n      cls.push('justify-center');\n      break;\n    }\n    case 'left': {\n      cls.push('justify-start');\n      break;\n    }\n    default: {\n      // case 'right': 默认右对齐\n      cls.push('justify-end');\n      break;\n    }\n  }\n\n  return cls.join(' ');\n});\n\ndefineExpose({\n  handleReset,\n  handleSubmit,\n});\n</script>\n<template>\n  <div :class=\"cn(actionWrapperClass)\">\n    <template v-if=\"rootProps.actionButtonsReverse\">\n      <!-- 提交按钮前 -->\n      <slot name=\"submit-before\"></slot>\n\n      <component\n        :is=\"COMPONENT_MAP.PrimaryButton\"\n        v-if=\"submitButtonOptions.show\"\n        type=\"button\"\n        @click=\"handleSubmit\"\n        v-bind=\"submitButtonOptions\"\n      >\n        {{ submitButtonOptions.content }}\n      </component>\n    </template>\n\n    <!-- 重置按钮前 -->\n    <slot name=\"reset-before\"></slot>\n\n    <component\n      :is=\"COMPONENT_MAP.DefaultButton\"\n      v-if=\"resetButtonOptions.show\"\n      type=\"button\"\n      @click=\"handleReset\"\n      v-bind=\"resetButtonOptions\"\n    >\n      {{ resetButtonOptions.content }}\n    </component>\n\n    <template v-if=\"!rootProps.actionButtonsReverse\">\n      <!-- 提交按钮前 -->\n      <slot name=\"submit-before\"></slot>\n\n      <component\n        :is=\"COMPONENT_MAP.PrimaryButton\"\n        v-if=\"submitButtonOptions.show\"\n        type=\"button\"\n        @click=\"handleSubmit\"\n        v-bind=\"submitButtonOptions\"\n      >\n        {{ submitButtonOptions.content }}\n      </component>\n    </template>\n\n    <!-- 展开按钮前 -->\n    <slot name=\"expand-before\"></slot>\n\n    <VbenExpandableArrow\n      class=\"ml-[-0.3em]\"\n      v-if=\"rootProps.showCollapseButton\"\n      v-model:model-value=\"collapsed\"\n    >\n      <span>{{ collapsed ? $t('expand') : $t('collapse') }}</span>\n    </VbenExpandableArrow>\n\n    <!-- 展开按钮后 -->\n    <slot name=\"expand-after\"></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/config.ts",
    "content": "import type { Component } from 'vue';\n\nimport type {\n  BaseFormComponentType,\n  FormCommonConfig,\n  VbenFormAdapterOptions,\n} from './types';\n\nimport { h } from 'vue';\n\nimport {\n  VbenButton,\n  VbenCheckbox,\n  Input as VbenInput,\n  VbenInputPassword,\n  VbenPinInput,\n  VbenSelect,\n} from '@vben-core/shadcn-ui';\nimport { globalShareState } from '@vben-core/shared/global-state';\n\nimport { defineRule } from 'vee-validate';\n\nconst DEFAULT_MODEL_PROP_NAME = 'modelValue';\n\nexport const DEFAULT_FORM_COMMON_CONFIG: FormCommonConfig = {};\n\nexport const COMPONENT_MAP: Record<BaseFormComponentType, Component> = {\n  DefaultButton: h(VbenButton, { size: 'sm', variant: 'outline' }),\n  PrimaryButton: h(VbenButton, { size: 'sm', variant: 'default' }),\n  VbenCheckbox,\n  VbenInput,\n  VbenInputPassword,\n  VbenPinInput,\n  VbenSelect,\n};\n\nexport const COMPONENT_BIND_EVENT_MAP: Partial<\n  Record<BaseFormComponentType, string>\n> = {\n  VbenCheckbox: 'checked',\n};\n\nexport function setupVbenForm<\n  T extends BaseFormComponentType = BaseFormComponentType,\n>(options: VbenFormAdapterOptions<T>) {\n  const { config, defineRules } = options;\n\n  const {\n    disabledOnChangeListener = true,\n    disabledOnInputListener = true,\n    emptyStateValue = undefined,\n  } = (config || {}) as FormCommonConfig;\n\n  Object.assign(DEFAULT_FORM_COMMON_CONFIG, {\n    disabledOnChangeListener,\n    disabledOnInputListener,\n    emptyStateValue,\n  });\n\n  if (defineRules) {\n    for (const key of Object.keys(defineRules)) {\n      defineRule(key, defineRules[key as never]);\n    }\n  }\n\n  const baseModelPropName =\n    config?.baseModelPropName ?? DEFAULT_MODEL_PROP_NAME;\n  const modelPropNameMap = config?.modelPropNameMap as\n    | Record<BaseFormComponentType, string>\n    | undefined;\n\n  const components = globalShareState.getComponents();\n\n  for (const component of Object.keys(components)) {\n    const key = component as BaseFormComponentType;\n    COMPONENT_MAP[key] = components[component as never];\n\n    if (baseModelPropName !== DEFAULT_MODEL_PROP_NAME) {\n      COMPONENT_BIND_EVENT_MAP[key] = baseModelPropName;\n    }\n\n    // 覆盖特殊组件的modelPropName\n    if (modelPropNameMap && modelPropNameMap[key]) {\n      COMPONENT_BIND_EVENT_MAP[key] = modelPropNameMap[key];\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-api.ts",
    "content": "import type {\n  FormState,\n  GenericObject,\n  ResetFormOpts,\n  ValidationOptions,\n} from 'vee-validate';\n\nimport type { ComponentPublicInstance } from 'vue';\n\nimport type { Recordable } from '@vben-core/typings';\n\nimport type { FormActions, FormSchema, VbenFormProps } from './types';\n\nimport { isRef, toRaw } from 'vue';\n\nimport { Store } from '@vben-core/shared/store';\nimport {\n  bindMethods,\n  createMerge,\n  formatDate,\n  isDate,\n  isDayjsObject,\n  isFunction,\n  isObject,\n  mergeWithArrayOverride,\n  StateHandler,\n} from '@vben-core/shared/utils';\n\nfunction getDefaultState(): VbenFormProps {\n  return {\n    actionWrapperClass: '',\n    collapsed: false,\n    collapsedRows: 1,\n    collapseTriggerResize: false,\n    commonConfig: {},\n    handleReset: undefined,\n    handleSubmit: undefined,\n    handleValuesChange: undefined,\n    layout: 'horizontal',\n    resetButtonOptions: {},\n    schema: [],\n    scrollToFirstError: false,\n    showCollapseButton: false,\n    showDefaultActions: true,\n    submitButtonOptions: {},\n    submitOnChange: false,\n    submitOnEnter: false,\n    wrapperClass: 'grid-cols-1',\n  };\n}\n\nexport class FormApi {\n  // private api: Pick<VbenFormProps, 'handleReset' | 'handleSubmit'>;\n  public form = {} as FormActions;\n  isMounted = false;\n\n  public state: null | VbenFormProps = null;\n  stateHandler: StateHandler;\n\n  public store: Store<VbenFormProps>;\n\n  /**\n   * 组件实例映射\n   */\n  private componentRefMap: Map<string, unknown> = new Map();\n\n  // 最后一次点击提交时的表单值\n  private latestSubmissionValues: null | Recordable<any> = null;\n\n  private prevState: null | VbenFormProps = null;\n\n  constructor(options: VbenFormProps = {}) {\n    const { ...storeState } = options;\n\n    const defaultState = getDefaultState();\n\n    this.store = new Store<VbenFormProps>(\n      {\n        ...defaultState,\n        ...storeState,\n      },\n      {\n        onUpdate: () => {\n          this.prevState = this.state;\n          this.state = this.store.state;\n          this.updateState();\n        },\n      },\n    );\n\n    this.state = this.store.state;\n    this.stateHandler = new StateHandler();\n    bindMethods(this);\n  }\n\n  /**\n   * 获取字段组件实例\n   * @param fieldName 字段名\n   * @returns 组件实例\n   */\n  getFieldComponentRef<T = ComponentPublicInstance>(\n    fieldName: string,\n  ): T | undefined {\n    let target = this.componentRefMap.has(fieldName)\n      ? (this.componentRefMap.get(fieldName) as ComponentPublicInstance)\n      : undefined;\n    if (\n      target &&\n      target.$.type.name === 'AsyncComponentWrapper' &&\n      target.$.subTree.ref\n    ) {\n      if (Array.isArray(target.$.subTree.ref)) {\n        if (\n          target.$.subTree.ref.length > 0 &&\n          isRef(target.$.subTree.ref[0]?.r)\n        ) {\n          target = target.$.subTree.ref[0]?.r.value as ComponentPublicInstance;\n        }\n      } else if (isRef(target.$.subTree.ref.r)) {\n        target = target.$.subTree.ref.r.value as ComponentPublicInstance;\n      }\n    }\n    return target as T;\n  }\n\n  /**\n   * 获取当前聚焦的字段，如果没有聚焦的字段则返回undefined\n   */\n  getFocusedField() {\n    for (const fieldName of this.componentRefMap.keys()) {\n      const ref = this.getFieldComponentRef(fieldName);\n      if (ref) {\n        let el: HTMLElement | null = null;\n        if (ref instanceof HTMLElement) {\n          el = ref;\n        } else if (ref.$el instanceof HTMLElement) {\n          el = ref.$el;\n        }\n        if (!el) {\n          continue;\n        }\n        if (\n          el === document.activeElement ||\n          el.contains(document.activeElement)\n        ) {\n          return fieldName;\n        }\n      }\n    }\n    return undefined;\n  }\n\n  getLatestSubmissionValues() {\n    return this.latestSubmissionValues || {};\n  }\n\n  getState() {\n    return this.state;\n  }\n\n  async getValues<T = Recordable<any>>() {\n    const form = await this.getForm();\n    return (form.values ? this.handleRangeTimeValue(form.values) : {}) as T;\n  }\n\n  async isFieldValid(fieldName: string) {\n    const form = await this.getForm();\n    return form.isFieldValid(fieldName);\n  }\n\n  merge(formApi: FormApi) {\n    const chain = [this, formApi];\n    const proxy = new Proxy(formApi, {\n      get(target: any, prop: any) {\n        if (prop === 'merge') {\n          return (nextFormApi: FormApi) => {\n            chain.push(nextFormApi);\n            return proxy;\n          };\n        }\n        if (prop === 'submitAllForm') {\n          return async (needMerge: boolean = true) => {\n            try {\n              const results = await Promise.all(\n                chain.map(async (api) => {\n                  const validateResult = await api.validate();\n                  if (!validateResult.valid) {\n                    return;\n                  }\n                  const rawValues = toRaw((await api.getValues()) || {});\n                  return rawValues;\n                }),\n              );\n              if (needMerge) {\n                const mergedResults = Object.assign({}, ...results);\n                return mergedResults;\n              }\n              return results;\n            } catch (error) {\n              console.error('Validation error:', error);\n            }\n          };\n        }\n        return target[prop];\n      },\n    });\n\n    return proxy;\n  }\n\n  mount(formActions: FormActions, componentRefMap: Map<string, unknown>) {\n    if (!this.isMounted) {\n      Object.assign(this.form, formActions);\n      this.stateHandler.setConditionTrue();\n      this.setLatestSubmissionValues({\n        ...toRaw(this.handleRangeTimeValue(this.form.values)),\n      });\n      this.componentRefMap = componentRefMap;\n      this.isMounted = true;\n    }\n  }\n\n  /**\n   * 根据字段名移除表单项\n   * @param fields\n   */\n  async removeSchemaByFields(fields: string[]) {\n    const fieldSet = new Set(fields);\n    const schema = this.state?.schema ?? [];\n\n    const filterSchema = schema.filter((item) => !fieldSet.has(item.fieldName));\n\n    this.setState({\n      schema: filterSchema,\n    });\n  }\n\n  /**\n   * 重置表单\n   */\n  async resetForm(\n    state?: Partial<FormState<GenericObject>> | undefined,\n    opts?: Partial<ResetFormOpts>,\n  ) {\n    const form = await this.getForm();\n    return form.resetForm(state, opts);\n  }\n\n  async resetValidate() {\n    const form = await this.getForm();\n    const fields = Object.keys(form.errors.value);\n    fields.forEach((field) => {\n      form.setFieldError(field, undefined);\n    });\n  }\n\n  /**\n   * 滚动到第一个错误字段\n   * @param errors 验证错误对象\n   */\n  scrollToFirstError(errors: Record<string, any> | string) {\n    // https://github.com/logaretm/vee-validate/discussions/3835\n    const firstErrorFieldName =\n      typeof errors === 'string' ? errors : Object.keys(errors)[0];\n\n    if (!firstErrorFieldName) {\n      return;\n    }\n\n    let el = document.querySelector(\n      `[name=\"${firstErrorFieldName}\"]`,\n    ) as HTMLElement;\n\n    // 如果通过 name 属性找不到，尝试通过组件引用查找, 正常情况下不会走到这，怕哪天 vee-validate 改了 name 属性有个兜底的\n    if (!el) {\n      const componentRef = this.getFieldComponentRef(firstErrorFieldName);\n      if (componentRef && componentRef.$el instanceof HTMLElement) {\n        el = componentRef.$el;\n      }\n    }\n\n    if (el) {\n      // 滚动到错误字段，添加一些偏移量以确保字段完全可见\n      el.scrollIntoView({\n        behavior: 'smooth',\n        block: 'center',\n        inline: 'nearest',\n      });\n    }\n  }\n\n  async setFieldValue(field: string, value: any, shouldValidate?: boolean) {\n    const form = await this.getForm();\n    form.setFieldValue(field, value, shouldValidate);\n  }\n\n  setLatestSubmissionValues(values: null | Recordable<any>) {\n    this.latestSubmissionValues = { ...toRaw(values) };\n  }\n\n  setState(\n    stateOrFn:\n      | ((prev: VbenFormProps) => Partial<VbenFormProps>)\n      | Partial<VbenFormProps>,\n  ) {\n    if (isFunction(stateOrFn)) {\n      this.store.setState((prev) => {\n        return mergeWithArrayOverride(stateOrFn(prev), prev);\n      });\n    } else {\n      this.store.setState((prev) => mergeWithArrayOverride(stateOrFn, prev));\n    }\n  }\n\n  /**\n   * 设置表单值\n   * @param fields record\n   * @param filterFields 过滤不在schema中定义的字段 默认为true\n   * @param shouldValidate\n   */\n  async setValues(\n    fields: Record<string, any>,\n    filterFields: boolean = true,\n    shouldValidate: boolean = false,\n  ) {\n    const form = await this.getForm();\n    if (!filterFields) {\n      form.setValues(fields, shouldValidate);\n      return;\n    }\n\n    /**\n     * 合并算法有待改进，目前的算法不支持object类型的值。\n     * antd的日期时间相关组件的值类型为dayjs对象\n     * element-plus的日期时间相关组件的值类型可能为Date对象\n     * 以上两种类型需要排除深度合并\n     */\n    const fieldMergeFn = createMerge((obj, key, value) => {\n      if (key in obj) {\n        obj[key] =\n          !Array.isArray(obj[key]) &&\n          isObject(obj[key]) &&\n          !isDayjsObject(obj[key]) &&\n          !isDate(obj[key])\n            ? fieldMergeFn(value, obj[key])\n            : value;\n      }\n      return true;\n    });\n    const filteredFields = fieldMergeFn(fields, form.values);\n    form.setValues(filteredFields, shouldValidate);\n  }\n\n  async submitForm(e?: Event) {\n    e?.preventDefault();\n    e?.stopPropagation();\n    const form = await this.getForm();\n    await form.submitForm();\n    const rawValues = toRaw(await this.getValues());\n    await this.state?.handleSubmit?.(rawValues);\n\n    return rawValues;\n  }\n\n  unmount() {\n    this.form?.resetForm?.();\n    // this.state = null;\n    this.latestSubmissionValues = null;\n    this.isMounted = false;\n    this.stateHandler.reset();\n  }\n\n  updateSchema(schema: Partial<FormSchema>[]) {\n    const updated: Partial<FormSchema>[] = [...schema];\n    const hasField = updated.every(\n      (item) => Reflect.has(item, 'fieldName') && item.fieldName,\n    );\n\n    if (!hasField) {\n      console.error(\n        'All items in the schema array must have a valid `fieldName` property to be updated',\n      );\n      return;\n    }\n    const currentSchema = [...(this.state?.schema ?? [])];\n\n    const updatedMap: Record<string, any> = {};\n\n    updated.forEach((item) => {\n      if (item.fieldName) {\n        updatedMap[item.fieldName] = item;\n      }\n    });\n\n    currentSchema.forEach((schema, index) => {\n      const updatedData = updatedMap[schema.fieldName];\n      if (updatedData) {\n        currentSchema[index] = mergeWithArrayOverride(\n          updatedData,\n          schema,\n        ) as FormSchema;\n      }\n    });\n    this.setState({ schema: currentSchema });\n  }\n\n  async validate(opts?: Partial<ValidationOptions>) {\n    const form = await this.getForm();\n\n    const validateResult = await form.validate(opts);\n\n    if (Object.keys(validateResult?.errors ?? {}).length > 0) {\n      console.error('validate error', validateResult?.errors);\n\n      if (this.state?.scrollToFirstError) {\n        this.scrollToFirstError(validateResult.errors);\n      }\n    }\n    return validateResult;\n  }\n\n  async validateAndSubmitForm() {\n    const form = await this.getForm();\n    const { valid, errors } = await form.validate();\n    if (!valid) {\n      if (this.state?.scrollToFirstError) {\n        this.scrollToFirstError(errors);\n      }\n      return;\n    }\n    return await this.submitForm();\n  }\n\n  async validateField(fieldName: string, opts?: Partial<ValidationOptions>) {\n    const form = await this.getForm();\n    const validateResult = await form.validateField(fieldName, opts);\n\n    if (Object.keys(validateResult?.errors ?? {}).length > 0) {\n      console.error('validate error', validateResult?.errors);\n\n      if (this.state?.scrollToFirstError) {\n        this.scrollToFirstError(fieldName);\n      }\n    }\n    return validateResult;\n  }\n\n  private async getForm() {\n    if (!this.isMounted) {\n      // 等待form挂载\n      await this.stateHandler.waitForCondition();\n    }\n    if (!this.form?.meta) {\n      throw new Error('<VbenForm /> is not mounted');\n    }\n    return this.form;\n  }\n\n  private handleMultiFields = (originValues: Record<string, any>) => {\n    const arrayToStringFields = this.state?.arrayToStringFields;\n    if (!arrayToStringFields || !Array.isArray(arrayToStringFields)) {\n      return;\n    }\n\n    const processFields = (fields: string[], separator: string = ',') => {\n      this.processFields(fields, separator, originValues, (value, sep) => {\n        if (Array.isArray(value)) {\n          return value.join(sep);\n        } else if (typeof value === 'string') {\n          // 处理空字符串的情况\n          if (value === '') {\n            return [];\n          }\n          // 处理复杂分隔符的情况\n          const escapedSeparator = sep.replaceAll(\n            /[.*+?^${}()|[\\]\\\\]/g,\n            String.raw`\\$&`,\n          );\n          return value.split(new RegExp(escapedSeparator));\n        } else {\n          return value;\n        }\n      });\n    };\n\n    // 处理简单数组格式 ['field1', 'field2', ';'] 或 ['field1', 'field2']\n    if (arrayToStringFields.every((item) => typeof item === 'string')) {\n      const lastItem =\n        arrayToStringFields[arrayToStringFields.length - 1] || '';\n      const fields =\n        lastItem.length === 1\n          ? arrayToStringFields.slice(0, -1)\n          : arrayToStringFields;\n      const separator = lastItem.length === 1 ? lastItem : ',';\n      processFields(fields, separator);\n      return;\n    }\n\n    // 处理嵌套数组格式 [['field1'], ';']\n    arrayToStringFields.forEach((fieldConfig) => {\n      if (Array.isArray(fieldConfig)) {\n        const [fields, separator = ','] = fieldConfig;\n        // 根据类型定义，fields 应该始终是字符串数组\n        if (!Array.isArray(fields)) {\n          console.warn(\n            `Invalid field configuration: fields should be an array of strings, got ${typeof fields}`,\n          );\n          return;\n        }\n        processFields(fields, separator);\n      }\n    });\n  };\n\n  private handleRangeTimeValue = (originValues: Record<string, any>) => {\n    const values = { ...originValues };\n    const fieldMappingTime = this.state?.fieldMappingTime;\n\n    this.handleMultiFields(values);\n    if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) {\n      return values;\n    }\n\n    fieldMappingTime.forEach(\n      ([field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD']) => {\n        if (startTimeKey && endTimeKey && values[field] === null) {\n          Reflect.deleteProperty(values, startTimeKey);\n          Reflect.deleteProperty(values, endTimeKey);\n          // delete values[startTimeKey];\n          // delete values[endTimeKey];\n        }\n\n        if (!values[field]) {\n          Reflect.deleteProperty(values, field);\n          // delete values[field];\n          return;\n        }\n\n        const [startTime, endTime] = values[field];\n        if (format === null) {\n          values[startTimeKey] = startTime;\n          values[endTimeKey] = endTime;\n        } else if (isFunction(format)) {\n          values[startTimeKey] = format(startTime, startTimeKey);\n          values[endTimeKey] = format(endTime, endTimeKey);\n        } else {\n          const [startTimeFormat, endTimeFormat] = Array.isArray(format)\n            ? format\n            : [format, format];\n\n          values[startTimeKey] = startTime\n            ? formatDate(startTime, startTimeFormat)\n            : undefined;\n          values[endTimeKey] = endTime\n            ? formatDate(endTime, endTimeFormat)\n            : undefined;\n        }\n        // delete values[field];\n        Reflect.deleteProperty(values, field);\n      },\n    );\n    return values;\n  };\n\n  private processFields = (\n    fields: string[],\n    separator: string,\n    originValues: Record<string, any>,\n    transformFn: (value: any, separator: string) => any,\n  ) => {\n    fields.forEach((field) => {\n      const value = originValues[field];\n      if (value === undefined || value === null) {\n        return;\n      }\n      originValues[field] = transformFn(value, separator);\n    });\n  };\n\n  private updateState() {\n    const currentSchema = this.state?.schema ?? [];\n    const prevSchema = this.prevState?.schema ?? [];\n    // 进行了删除schema操作\n    if (currentSchema.length < prevSchema.length) {\n      const currentFields = new Set(\n        currentSchema.map((item) => item.fieldName),\n      );\n      const deletedSchema = prevSchema.filter(\n        (item) => !currentFields.has(item.fieldName),\n      );\n      for (const schema of deletedSchema) {\n        this.form?.setFieldValue?.(schema.fieldName, undefined);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-render/context.ts",
    "content": "import type { FormRenderProps } from '../types';\n\nimport { computed } from 'vue';\n\nimport { createContext } from '@vben-core/shadcn-ui';\n\nexport const [injectRenderFormProps, provideFormRenderProps] =\n  createContext<FormRenderProps>('FormRenderProps');\n\nexport const useFormContext = () => {\n  const formRenderProps = injectRenderFormProps();\n\n  const isVertical = computed(() => formRenderProps.layout === 'vertical');\n\n  const componentMap = computed(() => formRenderProps.componentMap);\n  const componentBindEventMap = computed(\n    () => formRenderProps.componentBindEventMap,\n  );\n  return {\n    componentBindEventMap,\n    componentMap,\n    isVertical,\n  };\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-render/dependencies.ts",
    "content": "import type {\n  FormItemDependencies,\n  FormSchemaRuleType,\n  MaybeComponentProps,\n} from '../types';\n\nimport { computed, ref, watch } from 'vue';\n\nimport { isBoolean, isFunction } from '@vben-core/shared/utils';\n\nimport { useFormValues } from 'vee-validate';\n\nimport { injectRenderFormProps } from './context';\n\nexport default function useDependencies(\n  getDependencies: () => FormItemDependencies | undefined,\n) {\n  const values = useFormValues();\n\n  const formRenderProps = injectRenderFormProps();\n\n  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n  const formApi = formRenderProps.form!;\n\n  if (!values) {\n    throw new Error('useDependencies should be used within <VbenForm>');\n  }\n\n  const isIf = ref(true);\n  const isDisabled = ref(false);\n  const isShow = ref(true);\n  const isRequired = ref(false);\n  const dynamicComponentProps = ref<MaybeComponentProps>({});\n  const dynamicRules = ref<FormSchemaRuleType>();\n\n  const triggerFieldValues = computed(() => {\n    // 该字段可能会被多个字段触发\n    const triggerFields = getDependencies()?.triggerFields ?? [];\n    return triggerFields.map((dep) => {\n      return values.value[dep];\n    });\n  });\n\n  const resetConditionState = () => {\n    isDisabled.value = false;\n    isIf.value = true;\n    isShow.value = true;\n    isRequired.value = false;\n    dynamicRules.value = undefined;\n    dynamicComponentProps.value = {};\n  };\n\n  watch(\n    [triggerFieldValues, getDependencies],\n    async ([_values, dependencies]) => {\n      if (!dependencies || !dependencies?.triggerFields?.length) {\n        return;\n      }\n      resetConditionState();\n      const {\n        componentProps,\n        disabled,\n        if: whenIf,\n        required,\n        rules,\n        show,\n        trigger,\n      } = dependencies;\n\n      // 1. 优先判断if，如果if为false，则不渲染dom，后续判断也不再执行\n      const formValues = values.value;\n\n      if (isFunction(whenIf)) {\n        isIf.value = !!(await whenIf(formValues, formApi));\n        // 不渲染\n        if (!isIf.value) return;\n      } else if (isBoolean(whenIf)) {\n        isIf.value = whenIf;\n        if (!isIf.value) return;\n      }\n\n      // 2. 判断show，如果show为false，则隐藏\n      if (isFunction(show)) {\n        isShow.value = !!(await show(formValues, formApi));\n        if (!isShow.value) return;\n      } else if (isBoolean(show)) {\n        isShow.value = show;\n        if (!isShow.value) return;\n      }\n\n      if (isFunction(componentProps)) {\n        dynamicComponentProps.value = await componentProps(formValues, formApi);\n      }\n\n      if (isFunction(rules)) {\n        dynamicRules.value = await rules(formValues, formApi);\n      }\n\n      if (isFunction(disabled)) {\n        isDisabled.value = !!(await disabled(formValues, formApi));\n      } else if (isBoolean(disabled)) {\n        isDisabled.value = disabled;\n      }\n\n      if (isFunction(required)) {\n        isRequired.value = !!(await required(formValues, formApi));\n      }\n\n      if (isFunction(trigger)) {\n        await trigger(formValues, formApi);\n      }\n    },\n    { deep: true, immediate: true },\n  );\n\n  return {\n    dynamicComponentProps,\n    dynamicRules,\n    isDisabled,\n    isIf,\n    isRequired,\n    isShow,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-render/expandable.ts",
    "content": "import type { FormRenderProps } from '../types';\n\nimport { computed, nextTick, onMounted, ref, useTemplateRef, watch } from 'vue';\n\nimport {\n  breakpointsTailwind,\n  useBreakpoints,\n  useElementVisibility,\n} from '@vueuse/core';\n\n/**\n * 动态计算行数\n */\nexport function useExpandable(props: FormRenderProps) {\n  const wrapperRef = useTemplateRef<HTMLElement>('wrapperRef');\n  const isVisible = useElementVisibility(wrapperRef);\n  const rowMapping = ref<Record<number, number>>({});\n  // 是否已经计算过一次\n  const isCalculated = ref(false);\n\n  const breakpoints = useBreakpoints(breakpointsTailwind);\n\n  const keepFormItemIndex = computed(() => {\n    const rows = props.collapsedRows ?? 1;\n    const mapping = rowMapping.value;\n    let maxItem = 0;\n    for (let index = 1; index <= rows; index++) {\n      maxItem += mapping?.[index] ?? 0;\n    }\n    // 保持一行\n    return maxItem - 1 || 1;\n  });\n\n  watch(\n    [\n      () => props.showCollapseButton,\n      () => breakpoints.active().value,\n      () => props.schema?.length,\n      () => isVisible.value,\n    ],\n    async ([val]) => {\n      if (val) {\n        await nextTick();\n        rowMapping.value = {};\n        isCalculated.value = false;\n        await calculateRowMapping();\n      }\n    },\n  );\n\n  async function calculateRowMapping() {\n    if (!props.showCollapseButton) {\n      return;\n    }\n\n    await nextTick();\n    if (!wrapperRef.value) {\n      return;\n    }\n    // 小屏幕不计算\n    // if (breakpoints.smaller('sm').value) {\n    //   // 保持一行\n    //   rowMapping.value = { 1: 2 };\n    //   return;\n    // }\n\n    const formItems = [...wrapperRef.value.children];\n\n    const container = wrapperRef.value;\n    const containerStyles = window.getComputedStyle(container);\n    const rowHeights = containerStyles\n      .getPropertyValue('grid-template-rows')\n      .split(' ');\n\n    const containerRect = container?.getBoundingClientRect();\n\n    formItems.forEach((el) => {\n      const itemRect = el.getBoundingClientRect();\n\n      // 计算元素在第几行\n      const itemTop = itemRect.top - containerRect.top;\n      let rowStart = 0;\n      let cumulativeHeight = 0;\n\n      for (const [i, rowHeight] of rowHeights.entries()) {\n        cumulativeHeight += Number.parseFloat(rowHeight);\n        if (itemTop < cumulativeHeight) {\n          rowStart = i + 1;\n          break;\n        }\n      }\n      if (rowStart > (props?.collapsedRows ?? 1)) {\n        return;\n      }\n      rowMapping.value[rowStart] = (rowMapping.value[rowStart] ?? 0) + 1;\n      isCalculated.value = true;\n    });\n  }\n\n  onMounted(() => {\n    calculateRowMapping();\n  });\n\n  return { isCalculated, keepFormItemIndex, wrapperRef };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ZodType } from 'zod';\n\nimport type { FormSchema, MaybeComponentProps } from '../types';\n\nimport { computed, nextTick, onUnmounted, useTemplateRef, watch } from 'vue';\n\nimport { CircleAlert } from '@vben-core/icons';\nimport {\n  FormControl,\n  FormDescription,\n  FormField,\n  FormItem,\n  FormMessage,\n  VbenRenderContent,\n  VbenTooltip,\n} from '@vben-core/shadcn-ui';\nimport { cn, isFunction, isObject, isString } from '@vben-core/shared/utils';\n\nimport { toTypedSchema } from '@vee-validate/zod';\nimport { useFieldError, useFormValues } from 'vee-validate';\n\nimport { injectComponentRefMap } from '../use-form-context';\nimport { injectRenderFormProps, useFormContext } from './context';\nimport useDependencies from './dependencies';\nimport FormLabel from './form-label.vue';\nimport { isEventObjectLike } from './helper';\n\ninterface Props extends FormSchema {}\n\nconst {\n  colon,\n  commonComponentProps,\n  component,\n  componentProps,\n  dependencies,\n  description,\n  disabled,\n  disabledOnChangeListener,\n  disabledOnInputListener,\n  emptyStateValue,\n  fieldName,\n  formFieldProps,\n  hide,\n  label,\n  labelClass,\n  labelWidth,\n  modelPropName,\n  renderComponentContent,\n  rules,\n} = defineProps<\n  Props & {\n    commonComponentProps: MaybeComponentProps;\n  }\n>();\n\nconst { componentBindEventMap, componentMap, isVertical } = useFormContext();\nconst formRenderProps = injectRenderFormProps();\nconst values = useFormValues();\nconst errors = useFieldError(fieldName);\nconst fieldComponentRef = useTemplateRef<HTMLInputElement>('fieldComponentRef');\nconst formApi = formRenderProps.form;\nconst compact = computed(() => formRenderProps.compact);\nconst isInValid = computed(() => errors.value?.length > 0);\n\nconst FieldComponent = computed(() => {\n  const finalComponent = isString(component)\n    ? componentMap.value[component]\n    : component;\n  if (!finalComponent) {\n    // 组件未注册\n    console.warn(`Component ${component} is not registered`);\n  }\n  return finalComponent;\n});\n\nconst {\n  dynamicComponentProps,\n  dynamicRules,\n  isDisabled,\n  isIf,\n  isRequired,\n  isShow,\n} = useDependencies(() => dependencies);\n\nconst labelStyle = computed(() => {\n  return labelClass?.includes('w-') || isVertical.value\n    ? {}\n    : {\n        width: `${labelWidth}px`,\n      };\n});\n\nconst currentRules = computed(() => {\n  return dynamicRules.value || rules;\n});\n\nconst visible = computed(() => {\n  return !hide && isIf.value && isShow.value;\n});\n\nconst shouldRequired = computed(() => {\n  if (!visible.value) {\n    return false;\n  }\n\n  if (!currentRules.value) {\n    return isRequired.value;\n  }\n\n  if (isRequired.value) {\n    return true;\n  }\n\n  if (isString(currentRules.value)) {\n    return ['required', 'selectRequired'].includes(currentRules.value);\n  }\n\n  let isOptional = currentRules?.value?.isOptional?.();\n\n  // 如果有设置默认值，则不是必填，需要特殊处理\n  const typeName = currentRules?.value?._def?.typeName;\n  if (typeName === 'ZodDefault') {\n    const innerType = currentRules?.value?._def.innerType;\n    if (innerType) {\n      isOptional = innerType.isOptional?.();\n    }\n  }\n\n  return !isOptional;\n});\n\nconst fieldRules = computed(() => {\n  if (!visible.value) {\n    return null;\n  }\n\n  let rules = currentRules.value;\n  if (!rules) {\n    return isRequired.value ? 'required' : null;\n  }\n\n  if (isString(rules)) {\n    return rules;\n  }\n\n  const isOptional = !shouldRequired.value;\n  if (!isOptional) {\n    const unwrappedRules = (rules as any)?.unwrap?.();\n    if (unwrappedRules) {\n      rules = unwrappedRules;\n    }\n  }\n  return toTypedSchema(rules as ZodType);\n});\n\nconst computedProps = computed(() => {\n  const finalComponentProps = isFunction(componentProps)\n    ? componentProps(values.value, formApi!)\n    : componentProps;\n\n  return {\n    ...commonComponentProps,\n    ...finalComponentProps,\n    ...dynamicComponentProps.value,\n  };\n});\n\nwatch(\n  () => computedProps.value?.autofocus,\n  (value) => {\n    if (value === true) {\n      nextTick(() => {\n        autofocus();\n      });\n    }\n  },\n  { immediate: true },\n);\n\nconst shouldDisabled = computed(() => {\n  return isDisabled.value || disabled || computedProps.value?.disabled;\n});\n\nconst customContentRender = computed(() => {\n  if (!isFunction(renderComponentContent)) {\n    return {};\n  }\n  return renderComponentContent(values.value, formApi!);\n});\n\nconst renderContentKey = computed(() => {\n  return Object.keys(customContentRender.value);\n});\n\nconst fieldProps = computed(() => {\n  const rules = fieldRules.value;\n  return {\n    keepValue: true,\n    label: isString(label) ? label : '',\n    ...(rules ? { rules } : {}),\n    ...(formFieldProps as Record<string, any>),\n  };\n});\n\nfunction fieldBindEvent(slotProps: Record<string, any>) {\n  const modelValue = slotProps.componentField.modelValue;\n  const handler = slotProps.componentField['onUpdate:modelValue'];\n\n  const bindEventField =\n    modelPropName ||\n    (isString(component) ? componentBindEventMap.value?.[component] : null);\n\n  let value = modelValue;\n  // antd design 的一些组件会传递一个 event 对象\n  if (modelValue && isObject(modelValue) && bindEventField) {\n    value = isEventObjectLike(modelValue)\n      ? modelValue?.target?.[bindEventField]\n      : (modelValue?.[bindEventField] ?? modelValue);\n  }\n\n  if (bindEventField) {\n    return {\n      [`onUpdate:${bindEventField}`]: handler,\n      [bindEventField]: value === undefined ? emptyStateValue : value,\n      onChange: disabledOnChangeListener\n        ? undefined\n        : (e: Record<string, any>) => {\n            const shouldUnwrap = isEventObjectLike(e);\n            const onChange = slotProps?.componentField?.onChange;\n            if (!shouldUnwrap) {\n              return onChange?.(e);\n            }\n\n            return onChange?.(e?.target?.[bindEventField] ?? e);\n          },\n      ...(disabledOnInputListener ? { onInput: undefined } : {}),\n    };\n  }\n  return {\n    ...(disabledOnInputListener ? { onInput: undefined } : {}),\n    ...(disabledOnChangeListener ? { onChange: undefined } : {}),\n  };\n}\n\nfunction createComponentProps(slotProps: Record<string, any>) {\n  const bindEvents = fieldBindEvent(slotProps);\n\n  const binds = {\n    ...slotProps.componentField,\n    ...computedProps.value,\n    ...bindEvents,\n    ...(Reflect.has(computedProps.value, 'onChange')\n      ? { onChange: computedProps.value.onChange }\n      : {}),\n    ...(Reflect.has(computedProps.value, 'onInput')\n      ? { onInput: computedProps.value.onInput }\n      : {}),\n  };\n\n  return binds;\n}\n\nfunction autofocus() {\n  if (\n    fieldComponentRef.value &&\n    isFunction(fieldComponentRef.value.focus) &&\n    // 检查当前是否有元素被聚焦\n    document.activeElement !== fieldComponentRef.value\n  ) {\n    fieldComponentRef.value?.focus?.();\n  }\n}\nconst componentRefMap = injectComponentRefMap();\nwatch(fieldComponentRef, (componentRef) => {\n  componentRefMap?.set(fieldName, componentRef);\n});\nonUnmounted(() => {\n  if (componentRefMap?.has(fieldName)) {\n    componentRefMap.delete(fieldName);\n  }\n});\n</script>\n\n<template>\n  <FormField\n    v-if=\"!hide && isIf\"\n    v-bind=\"fieldProps\"\n    v-slot=\"slotProps\"\n    :name=\"fieldName\"\n  >\n    <FormItem\n      v-show=\"isShow\"\n      :class=\"{\n        'form-valid-error': isInValid,\n        'form-is-required': shouldRequired,\n        'flex-col': isVertical,\n        'flex-row items-center': !isVertical,\n        'pb-4': !compact,\n        'pb-2': compact,\n      }\"\n      class=\"relative flex\"\n      v-bind=\"$attrs\"\n    >\n      <FormLabel\n        v-if=\"!hideLabel\"\n        :class=\"\n          cn(\n            'flex leading-6',\n            {\n              'mr-2 flex-shrink-0 justify-end': !isVertical,\n              'mb-1 flex-row': isVertical,\n            },\n            labelClass,\n          )\n        \"\n        :help=\"help\"\n        :colon=\"colon\"\n        :label=\"label\"\n        :required=\"shouldRequired && !hideRequiredMark\"\n        :style=\"labelStyle\"\n      >\n        <template v-if=\"label\">\n          <VbenRenderContent :content=\"label\" />\n        </template>\n      </FormLabel>\n      <div class=\"flex-auto overflow-hidden p-[1px]\">\n        <div :class=\"cn('relative flex w-full items-center', wrapperClass)\">\n          <FormControl :class=\"cn(controlClass)\">\n            <slot\n              v-bind=\"{\n                ...slotProps,\n                ...createComponentProps(slotProps),\n                disabled: shouldDisabled,\n                isInValid,\n              }\"\n            >\n              <component\n                :is=\"FieldComponent\"\n                ref=\"fieldComponentRef\"\n                :class=\"{\n                  'border-destructive focus:border-destructive hover:border-destructive/80 focus:shadow-[0_0_0_2px_rgba(255,38,5,0.06)]':\n                    isInValid,\n                }\"\n                v-bind=\"createComponentProps(slotProps)\"\n                :disabled=\"shouldDisabled\"\n              >\n                <template\n                  v-for=\"name in renderContentKey\"\n                  :key=\"name\"\n                  #[name]=\"renderSlotProps\"\n                >\n                  <VbenRenderContent\n                    :content=\"customContentRender[name]\"\n                    v-bind=\"{ ...renderSlotProps, formContext: slotProps }\"\n                  />\n                </template>\n                <!-- <slot></slot> -->\n              </component>\n              <VbenTooltip\n                v-if=\"compact && isInValid\"\n                :delay-duration=\"300\"\n                side=\"left\"\n              >\n                <template #trigger>\n                  <slot name=\"trigger\">\n                    <CircleAlert\n                      :class=\"\n                        cn(\n                          'text-foreground/80 hover:text-foreground inline-flex size-5 cursor-pointer',\n                        )\n                      \"\n                    />\n                  </slot>\n                </template>\n                <FormMessage />\n              </VbenTooltip>\n            </slot>\n          </FormControl>\n          <!-- 自定义后缀 -->\n          <div v-if=\"suffix\" class=\"ml-1\">\n            <VbenRenderContent :content=\"suffix\" />\n          </div>\n          <FormDescription v-if=\"description\" class=\"ml-1\">\n            <VbenRenderContent :content=\"description\" />\n          </FormDescription>\n        </div>\n\n        <Transition name=\"slide-up\" v-if=\"!compact\">\n          <FormMessage class=\"absolute\" />\n        </Transition>\n      </div>\n    </FormItem>\n  </FormField>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CustomRenderType } from '../types';\n\nimport {\n  FormLabel,\n  VbenHelpTooltip,\n  VbenRenderContent,\n} from '@vben-core/shadcn-ui';\nimport { cn } from '@vben-core/shared/utils';\n\ninterface Props {\n  class?: string;\n  colon?: boolean;\n  help?: CustomRenderType;\n  label?: CustomRenderType;\n  required?: boolean;\n}\n\nconst props = defineProps<Props>();\n</script>\n\n<template>\n  <FormLabel :class=\"cn('flex items-center', props.class)\">\n    <span v-if=\"required\" class=\"text-destructive mr-[2px]\">*</span>\n    <slot></slot>\n    <VbenHelpTooltip v-if=\"help\" trigger-class=\"size-3.5 ml-1\">\n      <VbenRenderContent :content=\"help\" />\n    </VbenHelpTooltip>\n    <span v-if=\"colon && label\" class=\"ml-[2px]\">:</span>\n  </FormLabel>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-render/form.vue",
    "content": "<script setup lang=\"ts\">\nimport type { GenericObject } from 'vee-validate';\nimport type { ZodTypeAny } from 'zod';\n\nimport type {\n  FormCommonConfig,\n  FormRenderProps,\n  FormSchema,\n  FormShape,\n} from '../types';\n\nimport { computed } from 'vue';\n\nimport { Form } from '@vben-core/shadcn-ui';\nimport {\n  cn,\n  isFunction,\n  isString,\n  mergeWithArrayOverride,\n} from '@vben-core/shared/utils';\n\nimport { provideFormRenderProps } from './context';\nimport { useExpandable } from './expandable';\nimport FormField from './form-field.vue';\nimport { getBaseRules, getDefaultValueInZodStack } from './helper';\n\ninterface Props extends FormRenderProps {}\n\nconst props = withDefaults(\n  defineProps<Props & { globalCommonConfig?: FormCommonConfig }>(),\n  {\n    collapsedRows: 1,\n    commonConfig: () => ({}),\n    globalCommonConfig: () => ({}),\n    showCollapseButton: false,\n    wrapperClass: 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3',\n  },\n);\n\nconst emits = defineEmits<{\n  submit: [event: any];\n}>();\n\nconst wrapperClass = computed(() => {\n  const cls = ['flex'];\n  if (props.layout === 'inline') {\n    cls.push('flex-wrap gap-x-2');\n  } else {\n    cls.push(props.compact ? 'gap-x-2' : 'gap-x-4', 'flex-col grid');\n  }\n  return cn(...cls, props.wrapperClass);\n});\n\nprovideFormRenderProps(props);\n\nconst { isCalculated, keepFormItemIndex, wrapperRef } = useExpandable(props);\n\nconst shapes = computed(() => {\n  const resultShapes: FormShape[] = [];\n  props.schema?.forEach((schema) => {\n    const { fieldName } = schema;\n    const rules = schema.rules as ZodTypeAny;\n\n    let typeName = '';\n    if (rules && !isString(rules)) {\n      typeName = rules._def.typeName;\n    }\n\n    const baseRules = getBaseRules(rules) as ZodTypeAny;\n\n    resultShapes.push({\n      default: getDefaultValueInZodStack(rules),\n      fieldName,\n      required: !['ZodNullable', 'ZodOptional'].includes(typeName),\n      rules: baseRules,\n    });\n  });\n  return resultShapes;\n});\n\nconst formComponent = computed(() => (props.form ? 'form' : Form));\n\nconst formComponentProps = computed(() => {\n  return props.form\n    ? {\n        onSubmit: props.form.handleSubmit((val) => emits('submit', val)),\n      }\n    : {\n        onSubmit: (val: GenericObject) => emits('submit', val),\n      };\n});\n\nconst formCollapsed = computed(() => {\n  return props.collapsed && isCalculated.value;\n});\n\nconst computedSchema = computed(\n  (): (Omit<FormSchema, 'formFieldProps'> & {\n    commonComponentProps: Record<string, any>;\n    formFieldProps: Record<string, any>;\n  })[] => {\n    const {\n      colon = false,\n      componentProps = {},\n      controlClass = '',\n      disabled,\n      disabledOnChangeListener = true,\n      disabledOnInputListener = true,\n      emptyStateValue = undefined,\n      formFieldProps = {},\n      formItemClass = '',\n      hideLabel = false,\n      hideRequiredMark = false,\n      labelClass = '',\n      labelWidth = 100,\n      modelPropName = '',\n      wrapperClass = '',\n    } = mergeWithArrayOverride(props.commonConfig, props.globalCommonConfig);\n    return (props.schema || []).map((schema, index) => {\n      const keepIndex = keepFormItemIndex.value;\n\n      const hidden =\n        // 折叠状态 & 显示折叠按钮 & 当前索引大于保留索引\n        props.showCollapseButton && !!formCollapsed.value && keepIndex\n          ? keepIndex <= index\n          : false;\n\n      // 处理函数形式的formItemClass\n      let resolvedSchemaFormItemClass = schema.formItemClass;\n      if (isFunction(schema.formItemClass)) {\n        try {\n          resolvedSchemaFormItemClass = schema.formItemClass();\n        } catch (error) {\n          console.error('Error calling formItemClass function:', error);\n          resolvedSchemaFormItemClass = '';\n        }\n      }\n\n      return {\n        colon,\n        disabled,\n        disabledOnChangeListener,\n        disabledOnInputListener,\n        emptyStateValue,\n        hideLabel,\n        hideRequiredMark,\n        labelWidth,\n        modelPropName,\n        wrapperClass,\n        ...schema,\n        commonComponentProps: componentProps,\n        componentProps: schema.componentProps,\n        controlClass: cn(controlClass, schema.controlClass),\n        formFieldProps: {\n          ...formFieldProps,\n          ...schema.formFieldProps,\n        },\n        formItemClass: cn(\n          'flex-shrink-0',\n          { hidden },\n          formItemClass,\n          resolvedSchemaFormItemClass,\n        ),\n        labelClass: cn(labelClass, schema.labelClass),\n      };\n    });\n  },\n);\n</script>\n\n<template>\n  <component :is=\"formComponent\" v-bind=\"formComponentProps\">\n    <div ref=\"wrapperRef\" :class=\"wrapperClass\">\n      <template v-for=\"cSchema in computedSchema\" :key=\"cSchema.fieldName\">\n        <!-- <div v-if=\"$slots[cSchema.fieldName]\" :class=\"cSchema.formItemClass\">\n          <slot :definition=\"cSchema\" :name=\"cSchema.fieldName\"> </slot>\n        </div> -->\n        <FormField\n          v-bind=\"cSchema\"\n          :class=\"cSchema.formItemClass\"\n          :rules=\"cSchema.rules\"\n        >\n          <template #default=\"slotProps\">\n            <slot v-bind=\"slotProps\" :name=\"cSchema.fieldName\"> </slot>\n          </template>\n        </FormField>\n      </template>\n      <slot :shapes=\"shapes\"></slot>\n    </div>\n  </component>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-render/helper.ts",
    "content": "import type {\n  AnyZodObject,\n  ZodDefault,\n  ZodEffects,\n  ZodNumber,\n  ZodString,\n  ZodTypeAny,\n} from 'zod';\n\nimport { isObject, isString } from '@vben-core/shared/utils';\n\n/**\n * Get the lowest level Zod type.\n * This will unpack optionals, refinements, etc.\n */\nexport function getBaseRules<\n  ChildType extends AnyZodObject | ZodTypeAny = ZodTypeAny,\n>(schema: ChildType | ZodEffects<ChildType>): ChildType | null {\n  if (!schema || isString(schema)) return null;\n  if ('innerType' in schema._def)\n    return getBaseRules(schema._def.innerType as ChildType);\n\n  if ('schema' in schema._def)\n    return getBaseRules(schema._def.schema as ChildType);\n\n  return schema as ChildType;\n}\n\n/**\n * Search for a \"ZodDefault\" in the Zod stack and return its value.\n */\nexport function getDefaultValueInZodStack(schema: ZodTypeAny): any {\n  if (!schema || isString(schema)) {\n    return;\n  }\n  const typedSchema = schema as unknown as ZodDefault<ZodNumber | ZodString>;\n\n  if (typedSchema._def.typeName === 'ZodDefault')\n    return typedSchema._def.defaultValue();\n\n  if ('innerType' in typedSchema._def) {\n    return getDefaultValueInZodStack(\n      typedSchema._def.innerType as unknown as ZodTypeAny,\n    );\n  }\n  if ('schema' in typedSchema._def) {\n    return getDefaultValueInZodStack(\n      (typedSchema._def as any).schema as ZodTypeAny,\n    );\n  }\n\n  return undefined;\n}\n\nexport function isEventObjectLike(obj: any) {\n  if (!obj || !isObject(obj)) {\n    return false;\n  }\n  return Reflect.has(obj, 'target') && Reflect.has(obj, 'stopPropagation');\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/form-render/index.ts",
    "content": "export { default as FormField } from './form-field.vue';\nexport { default as FormLabel } from './form-label.vue';\nexport { default as Form } from './form.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/index.ts",
    "content": "export { setupVbenForm } from './config';\n\nexport type {\n  BaseFormComponentType,\n  ExtendedFormApi,\n  VbenFormProps,\n  FormSchema as VbenFormSchema,\n} from './types';\n\nexport * from './use-vben-form';\n// export { default as VbenForm } from './vben-form.vue';\nexport * as z from 'zod';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/types.ts",
    "content": "import type { FieldOptions, FormContext, GenericObject } from 'vee-validate';\nimport type { ZodTypeAny } from 'zod';\n\nimport type { Component, HtmlHTMLAttributes, Ref } from 'vue';\n\nimport type { VbenButtonProps } from '@vben-core/shadcn-ui';\nimport type { ClassType, MaybeComputedRef } from '@vben-core/typings';\n\nimport type { FormApi } from './form-api';\n\nexport type FormLayout = 'horizontal' | 'inline' | 'vertical';\n\nexport type BaseFormComponentType =\n  | 'DefaultButton'\n  | 'PrimaryButton'\n  | 'VbenCheckbox'\n  | 'VbenInput'\n  | 'VbenInputPassword'\n  | 'VbenPinInput'\n  | 'VbenSelect'\n  | (Record<never, never> & string);\n\ntype Breakpoints = '2xl:' | '3xl:' | '' | 'lg:' | 'md:' | 'sm:' | 'xl:';\n\ntype GridCols = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;\n\nexport type WrapperClassType =\n  | `${Breakpoints}grid-cols-${GridCols}`\n  | (Record<never, never> & string);\n\nexport type FormItemClassType =\n  | `${Breakpoints}cols-end-${'auto' | GridCols}`\n  | `${Breakpoints}cols-span-${'auto' | 'full' | GridCols}`\n  | `${Breakpoints}cols-start-${'auto' | GridCols}`\n  | (Record<never, never> & string)\n  | WrapperClassType;\n\nexport type FormFieldOptions = Partial<\n  FieldOptions & {\n    validateOnBlur?: boolean;\n    validateOnChange?: boolean;\n    validateOnInput?: boolean;\n    validateOnModelUpdate?: boolean;\n  }\n>;\n\nexport interface FormShape {\n  /** 默认值 */\n  default?: any;\n  /** 字段名 */\n  fieldName: string;\n  /** 是否必填 */\n  required?: boolean;\n  rules?: ZodTypeAny;\n}\n\nexport type MaybeComponentPropKey =\n  | 'options'\n  | 'placeholder'\n  | 'title'\n  | keyof HtmlHTMLAttributes\n  | (Record<never, never> & string);\n\nexport type MaybeComponentProps = { [K in MaybeComponentPropKey]?: any };\n\nexport type FormActions = FormContext<GenericObject>;\n\nexport type CustomRenderType = (() => Component | string) | string;\n\nexport type FormSchemaRuleType =\n  | 'required'\n  | 'selectRequired'\n  | null\n  | (Record<never, never> & string)\n  | ZodTypeAny;\n\ntype FormItemDependenciesCondition<T = boolean | PromiseLike<boolean>> = (\n  value: Partial<Record<string, any>>,\n  actions: FormActions,\n) => T;\n\ntype FormItemDependenciesConditionWithRules = (\n  value: Partial<Record<string, any>>,\n  actions: FormActions,\n) => FormSchemaRuleType | PromiseLike<FormSchemaRuleType>;\n\ntype FormItemDependenciesConditionWithProps = (\n  value: Partial<Record<string, any>>,\n  actions: FormActions,\n) => MaybeComponentProps | PromiseLike<MaybeComponentProps>;\n\nexport interface FormItemDependencies {\n  /**\n   * 组件参数\n   * @returns 组件参数\n   */\n  componentProps?: FormItemDependenciesConditionWithProps;\n  /**\n   * 是否禁用\n   * @returns 是否禁用\n   */\n  disabled?: boolean | FormItemDependenciesCondition;\n  /**\n   * 是否渲染（删除dom）\n   * @returns 是否渲染\n   */\n  if?: boolean | FormItemDependenciesCondition;\n  /**\n   * 是否必填\n   * @returns 是否必填\n   */\n  required?: FormItemDependenciesCondition;\n  /**\n   * 字段规则\n   */\n  rules?: FormItemDependenciesConditionWithRules;\n  /**\n   * 是否隐藏(Css)\n   * @returns 是否隐藏\n   */\n  show?: boolean | FormItemDependenciesCondition;\n  /**\n   * 任意触发都会执行\n   */\n  trigger?: FormItemDependenciesCondition<void>;\n  /**\n   * 触发字段\n   */\n  triggerFields: string[];\n}\n\ntype ComponentProps =\n  | ((\n      value: Partial<Record<string, any>>,\n      actions: FormActions,\n    ) => MaybeComponentProps)\n  | MaybeComponentProps;\n\nexport interface FormCommonConfig {\n  /**\n   * 在Label后显示一个冒号\n   */\n  colon?: boolean;\n  /**\n   * 所有表单项的props\n   */\n  componentProps?: ComponentProps;\n  /**\n   * 所有表单项的控件样式\n   */\n  controlClass?: string;\n  /**\n   * 所有表单项的禁用状态\n   * @default false\n   */\n  disabled?: boolean;\n  /**\n   * 是否禁用所有表单项的change事件监听\n   * @default true\n   */\n  disabledOnChangeListener?: boolean;\n  /**\n   * 是否禁用所有表单项的input事件监听\n   * @default true\n   */\n  disabledOnInputListener?: boolean;\n  /**\n   * 所有表单项的空状态值,默认都是undefined，naive-ui的空状态值是null\n   */\n  emptyStateValue?: null | undefined;\n  /**\n   * 所有表单项的控件样式\n   * @default {}\n   */\n  formFieldProps?: FormFieldOptions;\n  /**\n   * 所有表单项的栅格布局，支持函数形式\n   * @default \"\"\n   */\n  formItemClass?: (() => string) | string;\n  /**\n   * 隐藏所有表单项label\n   * @default false\n   */\n  hideLabel?: boolean;\n  /**\n   * 是否隐藏必填标记\n   * @default false\n   */\n  hideRequiredMark?: boolean;\n  /**\n   * 所有表单项的label样式\n   * @default \"\"\n   */\n  labelClass?: string;\n  /**\n   * 所有表单项的label宽度\n   */\n  labelWidth?: number;\n  /**\n   * 所有表单项的model属性名\n   * @default \"modelValue\"\n   */\n  modelPropName?: string;\n  /**\n   * 所有表单项的wrapper样式\n   */\n  wrapperClass?: string;\n}\n\ntype RenderComponentContentType = (\n  value: Partial<Record<string, any>>,\n  api: FormActions,\n) => Record<string, any>;\n\nexport type HandleSubmitFn = (\n  values: Record<string, any>,\n) => Promise<void> | void;\n\nexport type HandleResetFn = (\n  values: Record<string, any>,\n) => Promise<void> | void;\n\nexport type FieldMappingTime = [\n  string,\n  [string, string],\n  (\n    | ((value: any, fieldName: string) => any)\n    | [string, string]\n    | null\n    | string\n  )?,\n][];\n\nexport type ArrayToStringFields = Array<\n  | [string[], string?] // 嵌套数组格式，可选分隔符\n  | string // 单个字段，使用默认分隔符\n  | string[] // 简单数组格式，最后一个元素可以是分隔符\n>;\n\nexport interface FormSchema<\n  T extends BaseFormComponentType = BaseFormComponentType,\n> extends FormCommonConfig {\n  /** 组件 */\n  component: Component | T;\n  /** 组件参数 */\n  componentProps?: ComponentProps;\n  /** 默认值 */\n  defaultValue?: any;\n  /** 依赖 */\n  dependencies?: FormItemDependencies;\n  /** 描述 */\n  description?: CustomRenderType;\n  /** 字段名 */\n  fieldName: string;\n  /** 帮助信息 */\n  help?: CustomRenderType;\n  /** 是否隐藏表单项 */\n  hide?: boolean;\n  /** 表单项 */\n  label?: CustomRenderType;\n  // 自定义组件内部渲染\n  renderComponentContent?: RenderComponentContentType;\n  /** 字段规则 */\n  rules?: FormSchemaRuleType;\n  /** 后缀 */\n  suffix?: CustomRenderType;\n}\n\nexport interface FormFieldProps extends FormSchema {\n  required?: boolean;\n}\n\nexport interface FormRenderProps<\n  T extends BaseFormComponentType = BaseFormComponentType,\n> {\n  /**\n   * 表单字段数组映射字符串配置 默认使用\",\"\n   */\n  arrayToStringFields?: ArrayToStringFields;\n  /**\n   * 是否折叠，在showCollapseButton=true下生效\n   * true:折叠 false:展开\n   */\n  collapsed?: boolean;\n  /**\n   * 折叠时保持行数\n   * @default 1\n   */\n  collapsedRows?: number;\n  /**\n   * 是否触发resize事件\n   * @default false\n   */\n  collapseTriggerResize?: boolean;\n  /**\n   * 表单项通用后备配置，当子项目没配置时使用这里的配置，子项目配置优先级高于此配置\n   */\n  commonConfig?: FormCommonConfig;\n  /**\n   * 紧凑模式（移除表单每一项底部为校验信息预留的空间）\n   */\n  compact?: boolean;\n  /**\n   * 组件v-model事件绑定\n   */\n  componentBindEventMap?: Partial<Record<BaseFormComponentType, string>>;\n  /**\n   * 组件集合\n   */\n  componentMap: Record<BaseFormComponentType, Component>;\n  /**\n   * 表单字段映射到时间格式\n   */\n  fieldMappingTime?: FieldMappingTime;\n  /**\n   * 表单实例\n   */\n  form?: FormContext<GenericObject>;\n  /**\n   * 表单项布局\n   */\n  layout?: FormLayout;\n  /**\n   * 表单定义\n   */\n  schema?: FormSchema<T>[];\n\n  /**\n   * 是否显示展开/折叠\n   */\n  showCollapseButton?: boolean;\n  /**\n   * 格式化日期\n   */\n\n  /**\n   * 表单栅格布局\n   * @default \"grid-cols-1\"\n   */\n  wrapperClass?: WrapperClassType;\n}\n\nexport interface ActionButtonOptions extends VbenButtonProps {\n  [key: string]: any;\n  content?: MaybeComputedRef<string>;\n  show?: boolean;\n}\n\nexport interface VbenFormProps<\n  T extends BaseFormComponentType = BaseFormComponentType,\n> extends Omit<\n    FormRenderProps<T>,\n    'componentBindEventMap' | 'componentMap' | 'form'\n  > {\n  /**\n   * 操作按钮是否反转（提交按钮前置）\n   */\n  actionButtonsReverse?: boolean;\n  /**\n   * 操作按钮组的样式\n   * newLine: 在新行显示。rowEnd: 在行内显示，靠右对齐（默认）。inline: 使用grid默认样式\n   */\n  actionLayout?: 'inline' | 'newLine' | 'rowEnd';\n  /**\n   * 操作按钮组显示位置，默认靠右显示\n   */\n  actionPosition?: 'center' | 'left' | 'right';\n  /**\n   * 表单操作区域class\n   */\n  actionWrapperClass?: ClassType;\n  /**\n   * 表单字段数组映射字符串配置 默认使用\",\"\n   */\n  arrayToStringFields?: ArrayToStringFields;\n\n  /**\n   * 表单字段映射\n   */\n  fieldMappingTime?: FieldMappingTime;\n  /**\n   * 表单重置回调\n   */\n  handleReset?: HandleResetFn;\n  /**\n   * 表单提交回调\n   */\n  handleSubmit?: HandleSubmitFn;\n  /**\n   * 表单值变化回调\n   */\n  handleValuesChange?: (\n    values: Record<string, any>,\n    fieldsChanged: string[],\n  ) => void;\n  /**\n   * 重置按钮参数\n   */\n  resetButtonOptions?: ActionButtonOptions;\n\n  /**\n   * 验证失败时是否自动滚动到第一个错误字段\n   * @default false\n   */\n  scrollToFirstError?: boolean;\n\n  /**\n   * 是否显示默认操作按钮\n   * @default true\n   */\n  showDefaultActions?: boolean;\n\n  /**\n   * 提交按钮参数\n   */\n  submitButtonOptions?: ActionButtonOptions;\n\n  /**\n   * 是否在字段值改变时提交表单\n   * @default false\n   */\n  submitOnChange?: boolean;\n\n  /**\n   * 是否在回车时提交表单\n   * @default false\n   */\n  submitOnEnter?: boolean;\n}\n\nexport type ExtendedFormApi = FormApi & {\n  useStore: <T = NoInfer<VbenFormProps>>(\n    selector?: (state: NoInfer<VbenFormProps>) => T,\n  ) => Readonly<Ref<T>>;\n};\n\nexport interface VbenFormAdapterOptions<\n  T extends BaseFormComponentType = BaseFormComponentType,\n> {\n  config?: {\n    baseModelPropName?: string;\n    disabledOnChangeListener?: boolean;\n    disabledOnInputListener?: boolean;\n    emptyStateValue?: null | undefined;\n    modelPropNameMap?: Partial<Record<T, string>>;\n  };\n  defineRules?: {\n    required?: (\n      value: any,\n      params: any,\n      ctx: Record<string, any>,\n    ) => boolean | string;\n    selectRequired?: (\n      value: any,\n      params: any,\n      ctx: Record<string, any>,\n    ) => boolean | string;\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/use-form-context.ts",
    "content": "import type { ZodRawShape } from 'zod';\n\nimport type { ComputedRef } from 'vue';\n\nimport type { ExtendedFormApi, FormActions, VbenFormProps } from './types';\n\nimport { computed, unref, useSlots } from 'vue';\n\nimport { createContext } from '@vben-core/shadcn-ui';\nimport { isString, mergeWithArrayOverride, set } from '@vben-core/shared/utils';\n\nimport { useForm } from 'vee-validate';\nimport { object, ZodIntersection, ZodNumber, ZodObject, ZodString } from 'zod';\nimport { getDefaultsForSchema } from 'zod-defaults';\n\ntype ExtendFormProps = VbenFormProps & { formApi: ExtendedFormApi };\n\nexport const [injectFormProps, provideFormProps] =\n  createContext<[ComputedRef<ExtendFormProps> | ExtendFormProps, FormActions]>(\n    'VbenFormProps',\n  );\n\nexport const [injectComponentRefMap, provideComponentRefMap] =\n  createContext<Map<string, unknown>>('ComponentRefMap');\n\nexport function useFormInitial(\n  props: ComputedRef<VbenFormProps> | VbenFormProps,\n) {\n  const slots = useSlots();\n  const initialValues = generateInitialValues();\n\n  const form = useForm({\n    ...(Object.keys(initialValues)?.length ? { initialValues } : {}),\n  });\n\n  const delegatedSlots = computed(() => {\n    const resultSlots: string[] = [];\n\n    for (const key of Object.keys(slots)) {\n      if (key !== 'default') {\n        resultSlots.push(key);\n      }\n    }\n    return resultSlots;\n  });\n\n  function generateInitialValues() {\n    const initialValues: Record<string, any> = {};\n\n    const zodObject: ZodRawShape = {};\n    (unref(props).schema || []).forEach((item) => {\n      if (Reflect.has(item, 'defaultValue')) {\n        set(initialValues, item.fieldName, item.defaultValue);\n      } else if (item.rules && !isString(item.rules)) {\n        // 检查规则是否适合提取默认值\n        const customDefaultValue = getCustomDefaultValue(item.rules);\n        zodObject[item.fieldName] = item.rules;\n        if (customDefaultValue !== undefined) {\n          initialValues[item.fieldName] = customDefaultValue;\n        }\n      }\n    });\n\n    const schemaInitialValues = getDefaultsForSchema(object(zodObject));\n\n    const zodDefaults: Record<string, any> = {};\n    for (const key in schemaInitialValues) {\n      set(zodDefaults, key, schemaInitialValues[key]);\n    }\n    return mergeWithArrayOverride(initialValues, zodDefaults);\n  }\n  // 自定义默认值提取逻辑\n  function getCustomDefaultValue(rule: any): any {\n    if (rule instanceof ZodString) {\n      return ''; // 默认为空字符串\n    } else if (rule instanceof ZodNumber) {\n      return null; // 默认为 null（避免显示 0）\n    } else if (rule instanceof ZodObject) {\n      // 递归提取嵌套对象的默认值\n      const defaultValues: Record<string, any> = {};\n      for (const [key, valueSchema] of Object.entries(rule.shape)) {\n        defaultValues[key] = getCustomDefaultValue(valueSchema);\n      }\n      return defaultValues;\n    } else if (rule instanceof ZodIntersection) {\n      // 对于交集类型，从schema 提取默认值\n      const leftDefaultValue = getCustomDefaultValue(rule._def.left);\n      const rightDefaultValue = getCustomDefaultValue(rule._def.right);\n\n      // 如果左右两边都能提取默认值，合并它们\n      if (\n        typeof leftDefaultValue === 'object' &&\n        typeof rightDefaultValue === 'object'\n      ) {\n        return { ...leftDefaultValue, ...rightDefaultValue };\n      }\n\n      // 否则优先使用左边的默认值\n      return leftDefaultValue ?? rightDefaultValue;\n    } else {\n      return undefined; // 其他类型不提供默认值\n    }\n  }\n\n  return {\n    delegatedSlots,\n    form,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/use-vben-form.ts",
    "content": "import type {\n  BaseFormComponentType,\n  ExtendedFormApi,\n  VbenFormProps,\n} from './types';\n\nimport { defineComponent, h, isReactive, onBeforeUnmount, watch } from 'vue';\n\nimport { useStore } from '@vben-core/shared/store';\n\nimport { FormApi } from './form-api';\nimport VbenUseForm from './vben-use-form.vue';\n\nexport function useVbenForm<\n  T extends BaseFormComponentType = BaseFormComponentType,\n>(options: VbenFormProps<T>) {\n  const IS_REACTIVE = isReactive(options);\n  const api = new FormApi(options);\n  const extendedApi: ExtendedFormApi = api as never;\n  extendedApi.useStore = (selector) => {\n    return useStore(api.store, selector);\n  };\n\n  const Form = defineComponent(\n    (props: VbenFormProps, { attrs, slots }) => {\n      onBeforeUnmount(() => {\n        api.unmount();\n      });\n      api.setState({ ...props, ...attrs });\n      return () =>\n        h(VbenUseForm, { ...props, ...attrs, formApi: extendedApi }, slots);\n    },\n    {\n      name: 'VbenUseForm',\n      inheritAttrs: false,\n    },\n  );\n  // Add reactivity support\n  if (IS_REACTIVE) {\n    watch(\n      () => options.schema,\n      () => {\n        api.setState({ schema: options.schema });\n      },\n      { immediate: true },\n    );\n  }\n\n  return [Form, extendedApi] as const;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/vben-form.vue",
    "content": "<script setup lang=\"ts\">\nimport type { VbenFormProps } from './types';\n\nimport { ref, watchEffect } from 'vue';\n\nimport { useForwardPropsEmits } from '@vben-core/composables';\n\nimport FormActions from './components/form-actions.vue';\nimport {\n  COMPONENT_BIND_EVENT_MAP,\n  COMPONENT_MAP,\n  DEFAULT_FORM_COMMON_CONFIG,\n} from './config';\nimport { Form } from './form-render';\nimport { provideFormProps, useFormInitial } from './use-form-context';\n\n// 通过 extends 会导致热更新卡死\ninterface Props extends VbenFormProps {}\nconst props = withDefaults(defineProps<Props>(), {\n  actionWrapperClass: '',\n  collapsed: false,\n  collapsedRows: 1,\n  commonConfig: () => ({}),\n  handleReset: undefined,\n  handleSubmit: undefined,\n  layout: 'horizontal',\n  resetButtonOptions: () => ({}),\n  showCollapseButton: false,\n  showDefaultActions: true,\n  submitButtonOptions: () => ({}),\n  wrapperClass: 'grid-cols-1',\n});\n\nconst forward = useForwardPropsEmits(props);\n\nconst currentCollapsed = ref(false);\n\nconst { delegatedSlots, form } = useFormInitial(props);\n\nprovideFormProps([props, form]);\n\nconst handleUpdateCollapsed = (value: boolean) => {\n  currentCollapsed.value = !!value;\n};\n\nwatchEffect(() => {\n  currentCollapsed.value = props.collapsed;\n});\n</script>\n\n<template>\n  <Form\n    v-bind=\"forward\"\n    :collapsed=\"currentCollapsed\"\n    :component-bind-event-map=\"COMPONENT_BIND_EVENT_MAP\"\n    :component-map=\"COMPONENT_MAP\"\n    :form=\"form\"\n    :global-common-config=\"DEFAULT_FORM_COMMON_CONFIG\"\n  >\n    <template\n      v-for=\"slotName in delegatedSlots\"\n      :key=\"slotName\"\n      #[slotName]=\"slotProps\"\n    >\n      <slot :name=\"slotName\" v-bind=\"slotProps\"></slot>\n    </template>\n    <template #default=\"slotProps\">\n      <slot v-bind=\"slotProps\">\n        <FormActions\n          v-if=\"showDefaultActions\"\n          :model-value=\"currentCollapsed\"\n          @update:model-value=\"handleUpdateCollapsed\"\n        />\n      </slot>\n    </template>\n  </Form>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/src/vben-use-form.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Recordable } from '@vben-core/typings';\n\nimport type { ExtendedFormApi, VbenFormProps } from './types';\n\n// import { toRaw, watch } from 'vue';\nimport { nextTick, onMounted, watch } from 'vue';\n\nimport { useForwardPriorityValues } from '@vben-core/composables';\nimport { cloneDeep, get, isEqual, set } from '@vben-core/shared/utils';\n\nimport { useDebounceFn } from '@vueuse/core';\n\nimport FormActions from './components/form-actions.vue';\nimport {\n  COMPONENT_BIND_EVENT_MAP,\n  COMPONENT_MAP,\n  DEFAULT_FORM_COMMON_CONFIG,\n} from './config';\nimport { Form } from './form-render';\nimport {\n  provideComponentRefMap,\n  provideFormProps,\n  useFormInitial,\n} from './use-form-context';\n// 通过 extends 会导致热更新卡死，所以重复写了一遍\ninterface Props extends VbenFormProps {\n  formApi: ExtendedFormApi;\n}\n\nconst props = defineProps<Props>();\n\nconst state = props.formApi?.useStore?.();\n\nconst forward = useForwardPriorityValues(props, state);\n\nconst componentRefMap = new Map<string, unknown>();\n\nconst { delegatedSlots, form } = useFormInitial(forward);\n\nprovideFormProps([forward, form]);\nprovideComponentRefMap(componentRefMap);\n\nprops.formApi?.mount?.(form, componentRefMap);\n\nconst handleUpdateCollapsed = (value: boolean) => {\n  props.formApi?.setState({ collapsed: !!value });\n};\n\nfunction handleKeyDownEnter(event: KeyboardEvent) {\n  if (!state.value.submitOnEnter || !forward.value.formApi?.isMounted) {\n    return;\n  }\n  // 如果是 textarea 不阻止默认行为，否则会导致无法换行。\n  // 跳过 textarea 的回车提交处理\n  if (event.target instanceof HTMLTextAreaElement) {\n    return;\n  }\n  event.preventDefault();\n\n  forward.value.formApi.validateAndSubmitForm();\n}\n\nconst handleValuesChangeDebounced = useDebounceFn(async () => {\n  state.value.submitOnChange && forward.value.formApi?.validateAndSubmitForm();\n}, 300);\n\nconst valuesCache: Recordable<any> = {};\n\nonMounted(async () => {\n  // 只在挂载后开始监听，form.values会有一个初始化的过程\n  await nextTick();\n  watch(\n    () => form.values,\n    async (newVal) => {\n      if (forward.value.handleValuesChange) {\n        const fields = state.value.schema?.map((item) => {\n          return item.fieldName;\n        });\n\n        if (fields && fields.length > 0) {\n          const changedFields: string[] = [];\n          fields.forEach((field) => {\n            const newFieldValue = get(newVal, field);\n            const oldFieldValue = get(valuesCache, field);\n            if (!isEqual(newFieldValue, oldFieldValue)) {\n              changedFields.push(field);\n              set(valuesCache, field, newFieldValue);\n            }\n          });\n\n          if (changedFields.length > 0) {\n            // 调用handleValuesChange回调，传入所有表单值的深拷贝和变更的字段列表\n            forward.value.handleValuesChange(\n              cloneDeep(await forward.value.formApi.getValues()),\n              changedFields,\n            );\n          }\n        }\n      }\n      handleValuesChangeDebounced();\n    },\n    { deep: true },\n  );\n});\n</script>\n\n<template>\n  <Form\n    @keydown.enter=\"handleKeyDownEnter\"\n    v-bind=\"forward\"\n    :collapsed=\"state.collapsed\"\n    :component-bind-event-map=\"COMPONENT_BIND_EVENT_MAP\"\n    :component-map=\"COMPONENT_MAP\"\n    :form=\"form\"\n    :global-common-config=\"DEFAULT_FORM_COMMON_CONFIG\"\n  >\n    <template\n      v-for=\"slotName in delegatedSlots\"\n      :key=\"slotName\"\n      #[slotName]=\"slotProps\"\n    >\n      <slot :name=\"slotName\" v-bind=\"slotProps\"></slot>\n    </template>\n    <template #default=\"slotProps\">\n      <slot v-bind=\"slotProps\">\n        <FormActions\n          v-if=\"forward.showDefaultActions\"\n          :model-value=\"state.collapsed\"\n          @update:model-value=\"handleUpdateCollapsed\"\n        >\n          <template #reset-before=\"resetSlotProps\">\n            <slot name=\"reset-before\" v-bind=\"resetSlotProps\"></slot>\n          </template>\n          <template #submit-before=\"submitSlotProps\">\n            <slot name=\"submit-before\" v-bind=\"submitSlotProps\"></slot>\n          </template>\n          <template #expand-before=\"expandBeforeSlotProps\">\n            <slot name=\"expand-before\" v-bind=\"expandBeforeSlotProps\"></slot>\n          </template>\n          <template #expand-after=\"expandAfterSlotProps\">\n            <slot name=\"expand-after\" v-bind=\"expandAfterSlotProps\"></slot>\n          </template>\n        </FormActions>\n      </slot>\n    </template>\n  </Form>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/form-ui/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\", \"__tests__\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: [\n    {\n      builder: 'mkdist',\n      input: './src',\n      loaders: ['vue'],\n      pattern: ['**/*.vue'],\n    },\n    {\n      builder: 'mkdist',\n      format: 'esm',\n      input: './src',\n      loaders: ['js'],\n      pattern: ['**/*.ts'],\n    },\n  ],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/package.json",
    "content": "{\n  \"name\": \"@vben-core/layout-ui\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/uikit/layout-ui\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/composables\": \"workspace:*\",\n    \"@vben-core/icons\": \"workspace:*\",\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/index.ts",
    "content": "export { default as LayoutContent } from './layout-content.vue';\nexport { default as LayoutFooter } from './layout-footer.vue';\nexport { default as LayoutHeader } from './layout-header.vue';\nexport { default as LayoutSidebar } from './layout-sidebar.vue';\nexport { default as LayoutTabbar } from './layout-tabbar.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport type { ContentCompactType } from '@vben-core/typings';\n\nimport { computed } from 'vue';\n\nimport { useLayoutContentStyle } from '@vben-core/composables';\nimport { Slot } from '@vben-core/shadcn-ui';\n\ninterface Props {\n  /**\n   * 内容区域定宽\n   */\n  contentCompact: ContentCompactType;\n  /**\n   * 定宽布局宽度\n   */\n  contentCompactWidth: number;\n  padding: number;\n  paddingBottom: number;\n  paddingLeft: number;\n  paddingRight: number;\n  paddingTop: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {});\n\nconst { contentElement, overlayStyle } = useLayoutContentStyle();\n\nconst style = computed((): CSSProperties => {\n  const {\n    contentCompact,\n    padding,\n    paddingBottom,\n    paddingLeft,\n    paddingRight,\n    paddingTop,\n  } = props;\n\n  const compactStyle: CSSProperties =\n    contentCompact === 'compact'\n      ? { margin: '0 auto', width: `${props.contentCompactWidth}px` }\n      : {};\n  return {\n    ...compactStyle,\n    flex: 1,\n    padding: `${padding}px`,\n    paddingBottom: `${paddingBottom}px`,\n    paddingLeft: `${paddingLeft}px`,\n    paddingRight: `${paddingRight}px`,\n    paddingTop: `${paddingTop}px`,\n  };\n});\n</script>\n\n<template>\n  <main ref=\"contentElement\" :style=\"style\" class=\"bg-background-deep relative\">\n    <Slot :style=\"overlayStyle\">\n      <slot name=\"overlay\"></slot>\n    </Slot>\n    <slot></slot>\n  </main>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport { computed } from 'vue';\n\ninterface Props {\n  /**\n   * 是否固定在底部\n   */\n  fixed?: boolean;\n  height: number;\n  /**\n   * 是否显示\n   * @default true\n   */\n  show?: boolean;\n  width: string;\n  zIndex: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  show: true,\n});\n\nconst style = computed((): CSSProperties => {\n  const { fixed, height, show, width, zIndex } = props;\n  return {\n    height: `${height}px`,\n    marginBottom: show ? '0' : `-${height}px`,\n    position: fixed ? 'fixed' : 'static',\n    width,\n    zIndex,\n  };\n});\n</script>\n\n<template>\n  <footer\n    :style=\"style\"\n    class=\"bg-background-deep bottom-0 w-full transition-all duration-200\"\n  >\n    <slot></slot>\n  </footer>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport { computed, useSlots } from 'vue';\n\ninterface Props {\n  /**\n   * 横屏\n   */\n  fullWidth: boolean;\n  /**\n   * 高度\n   */\n  height: number;\n  /**\n   * 是否移动端\n   */\n  isMobile: boolean;\n  /**\n   * 是否显示\n   */\n  show: boolean;\n  /**\n   * 侧边菜单宽度\n   */\n  sidebarWidth: number;\n  /**\n   * 主题\n   */\n  theme: string | undefined;\n  /**\n   * 宽度\n   */\n  width: string;\n  /**\n   * zIndex\n   */\n  zIndex: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {});\n\nconst slots = useSlots();\n\nconst style = computed((): CSSProperties => {\n  const { fullWidth, height, show } = props;\n  const right = !show || !fullWidth ? undefined : 0;\n\n  return {\n    height: `${height}px`,\n    marginTop: show ? 0 : `-${height}px`,\n    right,\n  };\n});\n\nconst logoStyle = computed((): CSSProperties => {\n  return {\n    minWidth: `${props.isMobile ? 40 : props.sidebarWidth}px`,\n  };\n});\n</script>\n\n<template>\n  <header\n    :class=\"theme\"\n    :style=\"style\"\n    class=\"border-border bg-header top-0 flex w-full flex-[0_0_auto] items-center border-b pl-2 transition-[margin-top] duration-200\"\n  >\n    <div v-if=\"slots.logo\" :style=\"logoStyle\">\n      <slot name=\"logo\"></slot>\n    </div>\n\n    <slot name=\"toggle-button\"> </slot>\n\n    <slot></slot>\n  </header>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport { computed, shallowRef, useSlots, watchEffect } from 'vue';\n\nimport { VbenScrollbar } from '@vben-core/shadcn-ui';\n\nimport { useScrollLock } from '@vueuse/core';\n\nimport { SidebarCollapseButton, SidebarFixedButton } from './widgets';\n\ninterface Props {\n  /**\n   * 折叠区域高度\n   * @default 42\n   */\n  collapseHeight?: number;\n  /**\n   * 折叠宽度\n   * @default 48\n   */\n  collapseWidth?: number;\n  /**\n   * 隐藏的dom是否可见\n   * @default true\n   */\n  domVisible?: boolean;\n  /**\n   * 扩展区域宽度\n   */\n  extraWidth: number;\n  /**\n   * 固定扩展区域\n   * @default false\n   */\n  fixedExtra?: boolean;\n  /**\n   * 头部高度\n   */\n  headerHeight: number;\n  /**\n   * 是否侧边混合模式\n   * @default false\n   */\n  isSidebarMixed?: boolean;\n  /**\n   * 顶部margin\n   * @default 60\n   */\n  marginTop?: number;\n  /**\n   * 混合菜单宽度\n   * @default 80\n   */\n  mixedWidth?: number;\n  /**\n   * 顶部padding\n   * @default 60\n   */\n  paddingTop?: number;\n  /**\n   * 是否显示\n   * @default true\n   */\n  show?: boolean;\n  /**\n   * 显示折叠按钮\n   * @default true\n   */\n  showCollapseButton?: boolean;\n  /**\n   * 显示固定按钮\n   * @default true\n   */\n  showFixedButton?: boolean;\n  /**\n   * 主题\n   */\n  theme: string;\n\n  /**\n   * 宽度\n   */\n  width: number;\n  /**\n   * zIndex\n   * @default 0\n   */\n  zIndex?: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  collapseHeight: 42,\n  collapseWidth: 48,\n  domVisible: true,\n  fixedExtra: false,\n  isSidebarMixed: false,\n  marginTop: 0,\n  mixedWidth: 70,\n  paddingTop: 0,\n  show: true,\n  showCollapseButton: true,\n  showFixedButton: true,\n  zIndex: 0,\n});\n\nconst emit = defineEmits<{ leave: [] }>();\nconst collapse = defineModel<boolean>('collapse');\nconst extraCollapse = defineModel<boolean>('extraCollapse');\nconst expandOnHovering = defineModel<boolean>('expandOnHovering');\nconst expandOnHover = defineModel<boolean>('expandOnHover');\nconst extraVisible = defineModel<boolean>('extraVisible');\n\nconst isLocked = useScrollLock(document.body);\nconst slots = useSlots();\n\nconst asideRef = shallowRef<HTMLDivElement | null>();\n\nconst hiddenSideStyle = computed((): CSSProperties => calcMenuWidthStyle(true));\n\nconst style = computed((): CSSProperties => {\n  const { isSidebarMixed, marginTop, paddingTop, zIndex } = props;\n\n  return {\n    '--scroll-shadow': 'var(--sidebar)',\n    ...calcMenuWidthStyle(false),\n    height: `calc(100% - ${marginTop}px)`,\n    marginTop: `${marginTop}px`,\n    paddingTop: `${paddingTop}px`,\n    zIndex,\n    ...(isSidebarMixed && extraVisible.value ? { transition: 'none' } : {}),\n  };\n});\n\nconst extraStyle = computed((): CSSProperties => {\n  const { extraWidth, show, width, zIndex } = props;\n\n  return {\n    left: `${width}px`,\n    width: extraVisible.value && show ? `${extraWidth}px` : 0,\n    zIndex,\n  };\n});\n\nconst extraTitleStyle = computed((): CSSProperties => {\n  const { headerHeight } = props;\n\n  return {\n    height: `${headerHeight - 1}px`,\n  };\n});\n\nconst contentWidthStyle = computed((): CSSProperties => {\n  const { collapseWidth, fixedExtra, isSidebarMixed, mixedWidth } = props;\n  if (isSidebarMixed && fixedExtra) {\n    return { width: `${collapse.value ? collapseWidth : mixedWidth}px` };\n  }\n  return {};\n});\n\nconst contentStyle = computed((): CSSProperties => {\n  const { collapseHeight, headerHeight } = props;\n\n  return {\n    height: `calc(100% - ${headerHeight + collapseHeight}px)`,\n    paddingTop: '8px',\n    ...contentWidthStyle.value,\n  };\n});\n\nconst headerStyle = computed((): CSSProperties => {\n  const { headerHeight, isSidebarMixed } = props;\n\n  return {\n    ...(isSidebarMixed ? { display: 'flex', justifyContent: 'center' } : {}),\n    height: `${headerHeight - 1}px`,\n    ...contentWidthStyle.value,\n  };\n});\n\nconst extraContentStyle = computed((): CSSProperties => {\n  const { collapseHeight, headerHeight } = props;\n  return {\n    height: `calc(100% - ${headerHeight + collapseHeight}px)`,\n  };\n});\n\nconst collapseStyle = computed((): CSSProperties => {\n  return {\n    height: `${props.collapseHeight}px`,\n  };\n});\n\nwatchEffect(() => {\n  extraVisible.value = props.fixedExtra ? true : extraVisible.value;\n});\n\nfunction calcMenuWidthStyle(isHiddenDom: boolean): CSSProperties {\n  const { extraWidth, fixedExtra, isSidebarMixed, show, width } = props;\n\n  let widthValue =\n    width === 0\n      ? '0px'\n      : `${width + (isSidebarMixed && fixedExtra && extraVisible.value ? extraWidth : 0)}px`;\n\n  const { collapseWidth } = props;\n\n  if (isHiddenDom && expandOnHovering.value && !expandOnHover.value) {\n    widthValue = `${collapseWidth}px`;\n  }\n\n  return {\n    ...(widthValue === '0px' ? { overflow: 'hidden' } : {}),\n    flex: `0 0 ${widthValue}`,\n    marginLeft: show ? 0 : `-${widthValue}`,\n    maxWidth: widthValue,\n    minWidth: widthValue,\n    width: widthValue,\n  };\n}\n\nfunction handleMouseenter(e: MouseEvent) {\n  if (e?.offsetX < 10) {\n    return;\n  }\n\n  // 未开启和未折叠状态不生效\n  if (expandOnHover.value) {\n    return;\n  }\n  if (!expandOnHovering.value) {\n    collapse.value = false;\n  }\n  if (props.isSidebarMixed) {\n    isLocked.value = true;\n  }\n  expandOnHovering.value = true;\n}\n\nfunction handleMouseleave() {\n  emit('leave');\n  if (props.isSidebarMixed) {\n    isLocked.value = false;\n  }\n  if (expandOnHover.value) {\n    return;\n  }\n\n  expandOnHovering.value = false;\n  collapse.value = true;\n  extraVisible.value = false;\n}\n</script>\n\n<template>\n  <div\n    v-if=\"domVisible\"\n    :class=\"theme\"\n    :style=\"hiddenSideStyle\"\n    class=\"h-full transition-all duration-150\"\n  ></div>\n  <aside\n    :class=\"[\n      theme,\n      {\n        'bg-sidebar-deep': isSidebarMixed,\n        'bg-sidebar border-border border-r': !isSidebarMixed,\n      },\n    ]\"\n    :style=\"style\"\n    class=\"fixed left-0 top-0 h-full transition-all duration-150\"\n    @mouseenter=\"handleMouseenter\"\n    @mouseleave=\"handleMouseleave\"\n  >\n    <SidebarFixedButton\n      v-if=\"!collapse && !isSidebarMixed && showFixedButton\"\n      v-model:expand-on-hover=\"expandOnHover\"\n    />\n    <div v-if=\"slots.logo\" :style=\"headerStyle\">\n      <slot name=\"logo\"></slot>\n    </div>\n    <VbenScrollbar :style=\"contentStyle\" shadow shadow-border>\n      <slot></slot>\n    </VbenScrollbar>\n\n    <div :style=\"collapseStyle\"></div>\n    <SidebarCollapseButton\n      v-if=\"showCollapseButton && !isSidebarMixed\"\n      v-model:collapsed=\"collapse\"\n    />\n    <div\n      v-if=\"isSidebarMixed\"\n      ref=\"asideRef\"\n      :class=\"{\n        'border-l': extraVisible,\n      }\"\n      :style=\"extraStyle\"\n      class=\"border-border bg-sidebar fixed top-0 h-full overflow-hidden border-r transition-all duration-200\"\n    >\n      <SidebarCollapseButton\n        v-if=\"isSidebarMixed && expandOnHover\"\n        v-model:collapsed=\"extraCollapse\"\n      />\n\n      <SidebarFixedButton\n        v-if=\"!extraCollapse\"\n        v-model:expand-on-hover=\"expandOnHover\"\n      />\n      <div v-if=\"!extraCollapse\" :style=\"extraTitleStyle\" class=\"pl-2\">\n        <slot name=\"extra-title\"></slot>\n      </div>\n      <VbenScrollbar\n        :style=\"extraContentStyle\"\n        class=\"border-border py-2\"\n        shadow\n        shadow-border\n      >\n        <slot name=\"extra\"></slot>\n      </VbenScrollbar>\n    </div>\n  </aside>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport { computed } from 'vue';\n\ninterface Props {\n  /**\n   * 高度\n   */\n  height: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {});\n\nconst style = computed((): CSSProperties => {\n  const { height } = props;\n  return {\n    height: `${height}px`,\n  };\n});\n</script>\n\n<template>\n  <section\n    :style=\"style\"\n    class=\"border-border bg-background flex w-full border-b transition-all\"\n  >\n    <slot></slot>\n  </section>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/widgets/index.ts",
    "content": "export { default as SidebarCollapseButton } from './sidebar-collapse-button.vue';\nexport { default as SidebarFixedButton } from './sidebar-fixed-button.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue",
    "content": "<script setup lang=\"ts\">\nimport { ChevronsLeft, ChevronsRight } from '@vben-core/icons';\n\nconst collapsed = defineModel<boolean>('collapsed');\n\nfunction handleCollapsed() {\n  collapsed.value = !collapsed.value;\n}\n</script>\n\n<template>\n  <div\n    class=\"flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent absolute bottom-2 left-3 z-10 cursor-pointer rounded-sm p-1\"\n    @click.stop=\"handleCollapsed\"\n  >\n    <ChevronsRight v-if=\"collapsed\" class=\"size-4\" />\n    <ChevronsLeft v-else class=\"size-4\" />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-fixed-button.vue",
    "content": "<script setup lang=\"ts\">\nimport { Pin, PinOff } from '@vben-core/icons';\n\nconst expandOnHover = defineModel<boolean>('expandOnHover');\n\nfunction toggleFixed() {\n  expandOnHover.value = !expandOnHover.value;\n}\n</script>\n\n<template>\n  <div\n    class=\"flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent absolute bottom-2 right-3 z-10 cursor-pointer rounded-sm p-[5px] transition-all duration-300\"\n    @click=\"toggleFixed\"\n  >\n    <PinOff v-if=\"!expandOnHover\" class=\"size-3.5\" />\n    <Pin v-else class=\"size-3.5\" />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts",
    "content": "import type { LayoutType } from '@vben-core/typings';\n\nimport type { VbenLayoutProps } from '../vben-layout';\n\nimport { computed } from 'vue';\n\nexport function useLayout(props: VbenLayoutProps) {\n  const currentLayout = computed(() =>\n    props.isMobile ? 'sidebar-nav' : (props.layout as LayoutType),\n  );\n\n  /**\n   * 是否全屏显示content，不需要侧边、底部、顶部、tab区域\n   */\n  const isFullContent = computed(() => currentLayout.value === 'full-content');\n\n  /**\n   * 是否侧边混合模式\n   */\n  const isSidebarMixedNav = computed(\n    () => currentLayout.value === 'sidebar-mixed-nav',\n  );\n\n  /**\n   * 是否为头部导航模式\n   */\n  const isHeaderNav = computed(() => currentLayout.value === 'header-nav');\n\n  /**\n   * 是否为混合导航模式\n   */\n  const isMixedNav = computed(\n    () =>\n      currentLayout.value === 'mixed-nav' ||\n      currentLayout.value === 'header-sidebar-nav',\n  );\n\n  /**\n   * 是否为头部混合模式\n   */\n  const isHeaderMixedNav = computed(\n    () => currentLayout.value === 'header-mixed-nav',\n  );\n\n  return {\n    currentLayout,\n    isFullContent,\n    isHeaderMixedNav,\n    isHeaderNav,\n    isMixedNav,\n    isSidebarMixedNav,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/index.ts",
    "content": "export type * from './vben-layout';\nexport { default as VbenAdminLayout } from './vben-layout.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/vben-layout.ts",
    "content": "import type {\n  ContentCompactType,\n  LayoutHeaderModeType,\n  LayoutType,\n  ThemeModeType,\n} from '@vben-core/typings';\n\ninterface VbenLayoutProps {\n  /**\n   * 内容区域定宽\n   * @default 'wide'\n   */\n  contentCompact?: ContentCompactType;\n  /**\n   * 定宽布局宽度\n   * @default 1200\n   */\n  contentCompactWidth?: number;\n  /**\n   * padding\n   * @default 16\n   */\n  contentPadding?: number;\n  /**\n   * paddingBottom\n   * @default 16\n   */\n  contentPaddingBottom?: number;\n  /**\n   * paddingLeft\n   * @default 16\n   */\n  contentPaddingLeft?: number;\n  /**\n   * paddingRight\n   * @default 16\n   */\n  contentPaddingRight?: number;\n  /**\n   * paddingTop\n   * @default 16\n   */\n  contentPaddingTop?: number;\n  /**\n   * footer 是否可见\n   * @default false\n   */\n  footerEnable?: boolean;\n  /**\n   * footer 是否固定\n   * @default true\n   */\n  footerFixed?: boolean;\n  /**\n   * footer 高度\n   * @default 32\n   */\n  footerHeight?: number;\n\n  /**\n   * header高度\n   * @default 48\n   */\n  headerHeight?: number;\n  /**\n   * 顶栏是否隐藏\n   * @default false\n   */\n  headerHidden?: boolean;\n  /**\n   * header 显示模式\n   * @default 'fixed'\n   */\n  headerMode?: LayoutHeaderModeType;\n  /**\n   * header 顶栏主题\n   */\n  headerTheme?: ThemeModeType;\n  /**\n   * 是否显示header切换侧边栏按钮\n   * @default\n   */\n  headerToggleSidebarButton?: boolean;\n  /**\n   * header是否显示\n   * @default true\n   */\n  headerVisible?: boolean;\n  /**\n   * 是否移动端显示\n   * @default false\n   */\n  isMobile?: boolean;\n  /**\n   * 布局方式\n   * sidebar-nav 侧边菜单布局\n   * header-nav 顶部菜单布局\n   * mixed-nav 侧边&顶部菜单布局\n   * sidebar-mixed-nav 侧边混合菜单布局\n   * full-content 全屏内容布局\n   * @default sidebar-nav\n   */\n  layout?: LayoutType;\n  /**\n   * 侧边菜单折叠状态\n   * @default false\n   */\n  sidebarCollapse?: boolean;\n  /**\n   * 侧边菜单折叠按钮\n   * @default true\n   */\n  sidebarCollapsedButton?: boolean;\n  /**\n   * 侧边菜单是否折叠时，是否显示title\n   * @default true\n   */\n  sidebarCollapseShowTitle?: boolean;\n  /**\n   * 侧边栏是否可见\n   * @default true\n   */\n  sidebarEnable?: boolean;\n  /**\n   * 侧边菜单折叠额外宽度\n   * @default 48\n   */\n  sidebarExtraCollapsedWidth?: number;\n  /**\n   * 侧边菜单折叠按钮是否固定\n   * @default true\n   */\n  sidebarFixedButton?: boolean;\n  /**\n   * 侧边栏是否隐藏\n   * @default false\n   */\n  sidebarHidden?: boolean;\n  /**\n   * 混合侧边栏宽度\n   * @default 80\n   */\n  sidebarMixedWidth?: number;\n  /**\n   * 侧边栏\n   * @default dark\n   */\n  sidebarTheme?: ThemeModeType;\n  /**\n   * 侧边栏宽度\n   * @default 210\n   */\n  sidebarWidth?: number;\n  /**\n   *  侧边菜单折叠宽度\n   * @default 48\n   */\n  sideCollapseWidth?: number;\n  /**\n   * tab是否可见\n   * @default true\n   */\n  tabbarEnable?: boolean;\n  /**\n   * tab高度\n   * @default 30\n   */\n  tabbarHeight?: number;\n  /**\n   * zIndex\n   * @default 100\n   */\n  zIndex?: number;\n}\nexport type { VbenLayoutProps };\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/src/vben-layout.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport type { VbenLayoutProps } from './vben-layout';\n\nimport { computed, ref, watch } from 'vue';\n\nimport {\n  SCROLL_FIXED_CLASS,\n  useLayoutFooterStyle,\n  useLayoutHeaderStyle,\n} from '@vben-core/composables';\nimport { Menu } from '@vben-core/icons';\nimport { VbenIconButton } from '@vben-core/shadcn-ui';\nimport { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';\n\nimport { useMouse, useScroll, useThrottleFn } from '@vueuse/core';\n\nimport {\n  LayoutContent,\n  LayoutFooter,\n  LayoutHeader,\n  LayoutSidebar,\n  LayoutTabbar,\n} from './components';\nimport { useLayout } from './hooks/use-layout';\n\ninterface Props extends VbenLayoutProps {}\n\ndefineOptions({\n  name: 'VbenLayout',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  contentCompact: 'wide',\n  contentCompactWidth: 1200,\n  contentPadding: 0,\n  contentPaddingBottom: 0,\n  contentPaddingLeft: 0,\n  contentPaddingRight: 0,\n  contentPaddingTop: 0,\n  footerEnable: false,\n  footerFixed: true,\n  footerHeight: 32,\n  headerHeight: 50,\n  headerHidden: false,\n  headerMode: 'fixed',\n  headerToggleSidebarButton: true,\n  headerVisible: true,\n  isMobile: false,\n  layout: 'sidebar-nav',\n  sidebarCollapsedButton: true,\n  sidebarCollapseShowTitle: false,\n  sidebarExtraCollapsedWidth: 60,\n  sidebarFixedButton: true,\n  sidebarHidden: false,\n  sidebarMixedWidth: 80,\n  sidebarTheme: 'dark',\n  sidebarWidth: 180,\n  sideCollapseWidth: 60,\n  tabbarEnable: true,\n  tabbarHeight: 40,\n  zIndex: 200,\n});\n\nconst emit = defineEmits<{ sideMouseLeave: []; toggleSidebar: [] }>();\nconst sidebarCollapse = defineModel<boolean>('sidebarCollapse', {\n  default: false,\n});\nconst sidebarExtraVisible = defineModel<boolean>('sidebarExtraVisible');\nconst sidebarExtraCollapse = defineModel<boolean>('sidebarExtraCollapse', {\n  default: false,\n});\nconst sidebarExpandOnHover = defineModel<boolean>('sidebarExpandOnHover', {\n  default: false,\n});\nconst sidebarEnable = defineModel<boolean>('sidebarEnable', { default: true });\n\n// side是否处于hover状态展开菜单中\nconst sidebarExpandOnHovering = ref(false);\nconst headerIsHidden = ref(false);\nconst contentRef = ref();\n\nconst {\n  arrivedState,\n  directions,\n  isScrolling,\n  y: scrollY,\n} = useScroll(document);\n\nconst { setLayoutHeaderHeight } = useLayoutHeaderStyle();\nconst { setLayoutFooterHeight } = useLayoutFooterStyle();\n\nconst { y: mouseY } = useMouse({ target: contentRef, type: 'client' });\n\nconst {\n  currentLayout,\n  isFullContent,\n  isHeaderMixedNav,\n  isHeaderNav,\n  isMixedNav,\n  isSidebarMixedNav,\n} = useLayout(props);\n\n/**\n * 顶栏是否自动隐藏\n */\nconst isHeaderAutoMode = computed(() => props.headerMode === 'auto');\n\nconst headerWrapperHeight = computed(() => {\n  let height = 0;\n  if (props.headerVisible && !props.headerHidden) {\n    height += props.headerHeight;\n  }\n  if (props.tabbarEnable) {\n    height += props.tabbarHeight;\n  }\n  return height;\n});\n\nconst getSideCollapseWidth = computed(() => {\n  const { sidebarCollapseShowTitle, sidebarMixedWidth, sideCollapseWidth } =\n    props;\n\n  return sidebarCollapseShowTitle ||\n    isSidebarMixedNav.value ||\n    isHeaderMixedNav.value\n    ? sidebarMixedWidth\n    : sideCollapseWidth;\n});\n\n/**\n * 动态获取侧边区域是否可见\n */\nconst sidebarEnableState = computed(() => {\n  return !isHeaderNav.value && sidebarEnable.value;\n});\n\n/**\n * 侧边区域离顶部高度\n */\nconst sidebarMarginTop = computed(() => {\n  const { headerHeight, isMobile } = props;\n  return isMixedNav.value && !isMobile ? headerHeight : 0;\n});\n\n/**\n * 动态获取侧边宽度\n */\nconst getSidebarWidth = computed(() => {\n  const { isMobile, sidebarHidden, sidebarMixedWidth, sidebarWidth } = props;\n  let width = 0;\n\n  if (sidebarHidden) {\n    return width;\n  }\n\n  if (\n    !sidebarEnableState.value ||\n    (sidebarHidden &&\n      !isSidebarMixedNav.value &&\n      !isMixedNav.value &&\n      !isHeaderMixedNav.value)\n  ) {\n    return width;\n  }\n\n  if ((isHeaderMixedNav.value || isSidebarMixedNav.value) && !isMobile) {\n    width = sidebarMixedWidth;\n  } else if (sidebarCollapse.value) {\n    width = isMobile ? 0 : getSideCollapseWidth.value;\n  } else {\n    width = sidebarWidth;\n  }\n  return width;\n});\n\n/**\n * 获取扩展区域宽度\n */\nconst sidebarExtraWidth = computed(() => {\n  const { sidebarExtraCollapsedWidth, sidebarWidth } = props;\n\n  return sidebarExtraCollapse.value ? sidebarExtraCollapsedWidth : sidebarWidth;\n});\n\n/**\n * 是否侧边栏模式，包含混合侧边\n */\nconst isSideMode = computed(\n  () =>\n    currentLayout.value === 'mixed-nav' ||\n    currentLayout.value === 'sidebar-mixed-nav' ||\n    currentLayout.value === 'sidebar-nav' ||\n    currentLayout.value === 'header-mixed-nav' ||\n    currentLayout.value === 'header-sidebar-nav',\n);\n\n/**\n * header fixed值\n */\nconst headerFixed = computed(() => {\n  const { headerMode } = props;\n  return (\n    isMixedNav.value ||\n    headerMode === 'fixed' ||\n    headerMode === 'auto-scroll' ||\n    headerMode === 'auto'\n  );\n});\n\nconst showSidebar = computed(() => {\n  return isSideMode.value && sidebarEnable.value && !props.sidebarHidden;\n});\n\n/**\n * 遮罩可见性\n */\nconst maskVisible = computed(() => !sidebarCollapse.value && props.isMobile);\n\nconst mainStyle = computed(() => {\n  let width = '100%';\n  let sidebarAndExtraWidth = 'unset';\n  if (\n    headerFixed.value &&\n    currentLayout.value !== 'header-nav' &&\n    currentLayout.value !== 'mixed-nav' &&\n    currentLayout.value !== 'header-sidebar-nav' &&\n    showSidebar.value &&\n    !props.isMobile\n  ) {\n    // fixed模式下生效\n    const isSideNavEffective =\n      (isSidebarMixedNav.value || isHeaderMixedNav.value) &&\n      sidebarExpandOnHover.value &&\n      sidebarExtraVisible.value;\n\n    if (isSideNavEffective) {\n      const sideCollapseWidth = sidebarCollapse.value\n        ? getSideCollapseWidth.value\n        : props.sidebarMixedWidth;\n      const sideWidth = sidebarExtraCollapse.value\n        ? props.sidebarExtraCollapsedWidth\n        : props.sidebarWidth;\n\n      // 100% - 侧边菜单混合宽度 - 菜单宽度\n      sidebarAndExtraWidth = `${sideCollapseWidth + sideWidth}px`;\n      width = `calc(100% - ${sidebarAndExtraWidth})`;\n    } else {\n      sidebarAndExtraWidth =\n        sidebarExpandOnHovering.value && !sidebarExpandOnHover.value\n          ? `${getSideCollapseWidth.value}px`\n          : `${getSidebarWidth.value}px`;\n      width = `calc(100% - ${sidebarAndExtraWidth})`;\n    }\n  }\n  return {\n    sidebarAndExtraWidth,\n    width,\n  };\n});\n\n// 计算 tabbar 的样式\nconst tabbarStyle = computed((): CSSProperties => {\n  let width = '';\n  let marginLeft = 0;\n\n  // 如果不是混合导航，tabbar 的宽度为 100%\n  if (!isMixedNav.value || props.sidebarHidden) {\n    width = '100%';\n  } else if (sidebarEnable.value) {\n    // 鼠标在侧边栏上时，且侧边栏展开时的宽度\n    const onHoveringWidth = sidebarExpandOnHover.value\n      ? props.sidebarWidth\n      : getSideCollapseWidth.value;\n\n    // 设置 marginLeft，根据侧边栏是否折叠来决定\n    marginLeft = sidebarCollapse.value\n      ? getSideCollapseWidth.value\n      : onHoveringWidth;\n\n    // 设置 tabbar 的宽度，计算方式为 100% 减去侧边栏的宽度\n    width = `calc(100% - ${sidebarCollapse.value ? getSidebarWidth.value : onHoveringWidth}px)`;\n  } else {\n    // 默认情况下，tabbar 的宽度为 100%\n    width = '100%';\n  }\n\n  return {\n    marginLeft: `${marginLeft}px`,\n    width,\n  };\n});\n\nconst contentStyle = computed((): CSSProperties => {\n  const fixed = headerFixed.value;\n\n  const { footerEnable, footerFixed, footerHeight } = props;\n  return {\n    marginTop:\n      fixed &&\n      !isFullContent.value &&\n      !headerIsHidden.value &&\n      (!isHeaderAutoMode.value || scrollY.value < headerWrapperHeight.value)\n        ? `${headerWrapperHeight.value}px`\n        : 0,\n    paddingBottom: `${footerEnable && footerFixed ? footerHeight : 0}px`,\n  };\n});\n\nconst headerZIndex = computed(() => {\n  const { zIndex } = props;\n  const offset = isMixedNav.value ? 1 : 0;\n  return zIndex + offset;\n});\n\nconst headerWrapperStyle = computed((): CSSProperties => {\n  const fixed = headerFixed.value;\n  return {\n    height: isFullContent.value ? '0' : `${headerWrapperHeight.value}px`,\n    left: isMixedNav.value ? 0 : mainStyle.value.sidebarAndExtraWidth,\n    position: fixed ? 'fixed' : 'static',\n    top:\n      headerIsHidden.value || isFullContent.value\n        ? `-${headerWrapperHeight.value}px`\n        : 0,\n    width: mainStyle.value.width,\n    'z-index': headerZIndex.value,\n  };\n});\n\n/**\n * 侧边栏z-index\n */\nconst sidebarZIndex = computed(() => {\n  const { isMobile, zIndex } = props;\n  let offset = isMobile || isSideMode.value ? 1 : -1;\n\n  if (isMixedNav.value) {\n    offset += 1;\n  }\n\n  return zIndex + offset;\n});\n\nconst footerWidth = computed(() => {\n  if (!props.footerFixed) {\n    return '100%';\n  }\n\n  return mainStyle.value.width;\n});\n\nconst maskStyle = computed((): CSSProperties => {\n  return { zIndex: props.zIndex };\n});\n\nconst showHeaderToggleButton = computed(() => {\n  return (\n    props.isMobile ||\n    (props.headerToggleSidebarButton &&\n      isSideMode.value &&\n      !isSidebarMixedNav.value &&\n      !isMixedNav.value &&\n      !props.isMobile)\n  );\n});\n\nconst showHeaderLogo = computed(() => {\n  return !isSideMode.value || isMixedNav.value || props.isMobile;\n});\n\nwatch(\n  () => props.isMobile,\n  (val) => {\n    if (val) {\n      sidebarCollapse.value = true;\n    }\n  },\n  {\n    immediate: true,\n  },\n);\n\nwatch(\n  [() => headerWrapperHeight.value, () => isFullContent.value],\n  ([height]) => {\n    setLayoutHeaderHeight(isFullContent.value ? 0 : height);\n  },\n  {\n    immediate: true,\n  },\n);\n\nwatch(\n  () => props.footerHeight,\n  (height: number) => {\n    setLayoutFooterHeight(height);\n  },\n  {\n    immediate: true,\n  },\n);\n\n{\n  const mouseMove = () => {\n    mouseY.value > headerWrapperHeight.value\n      ? (headerIsHidden.value = true)\n      : (headerIsHidden.value = false);\n  };\n  watch(\n    [() => props.headerMode, () => mouseY.value],\n    () => {\n      if (!isHeaderAutoMode.value || isMixedNav.value || isFullContent.value) {\n        if (props.headerMode !== 'auto-scroll') {\n          headerIsHidden.value = false;\n        }\n        return;\n      }\n      headerIsHidden.value = true;\n      mouseMove();\n    },\n    {\n      immediate: true,\n    },\n  );\n}\n\n{\n  const checkHeaderIsHidden = useThrottleFn((top, bottom, topArrived) => {\n    if (scrollY.value < headerWrapperHeight.value) {\n      headerIsHidden.value = false;\n      return;\n    }\n    if (topArrived) {\n      headerIsHidden.value = false;\n      return;\n    }\n\n    if (top) {\n      headerIsHidden.value = false;\n    } else if (bottom) {\n      headerIsHidden.value = true;\n    }\n  }, 300);\n\n  watch(\n    () => scrollY.value,\n    () => {\n      if (\n        props.headerMode !== 'auto-scroll' ||\n        isMixedNav.value ||\n        isFullContent.value\n      ) {\n        return;\n      }\n      if (isScrolling.value) {\n        checkHeaderIsHidden(\n          directions.top,\n          directions.bottom,\n          arrivedState.top,\n        );\n      }\n    },\n  );\n}\n\nfunction handleClickMask() {\n  sidebarCollapse.value = true;\n}\n\nfunction handleHeaderToggle() {\n  if (props.isMobile) {\n    sidebarCollapse.value = false;\n  } else {\n    emit('toggleSidebar');\n  }\n}\n\nconst idMainContent = ELEMENT_ID_MAIN_CONTENT;\n</script>\n\n<template>\n  <div class=\"relative flex min-h-full w-full\">\n    <LayoutSidebar\n      v-if=\"sidebarEnableState\"\n      v-model:collapse=\"sidebarCollapse\"\n      v-model:expand-on-hover=\"sidebarExpandOnHover\"\n      v-model:expand-on-hovering=\"sidebarExpandOnHovering\"\n      v-model:extra-collapse=\"sidebarExtraCollapse\"\n      v-model:extra-visible=\"sidebarExtraVisible\"\n      :show-collapse-button=\"sidebarCollapsedButton\"\n      :show-fixed-button=\"sidebarFixedButton\"\n      :collapse-width=\"getSideCollapseWidth\"\n      :dom-visible=\"!isMobile\"\n      :extra-width=\"sidebarExtraWidth\"\n      :fixed-extra=\"sidebarExpandOnHover\"\n      :header-height=\"isMixedNav ? 0 : headerHeight\"\n      :is-sidebar-mixed=\"isSidebarMixedNav || isHeaderMixedNav\"\n      :margin-top=\"sidebarMarginTop\"\n      :mixed-width=\"sidebarMixedWidth\"\n      :show=\"showSidebar\"\n      :theme=\"sidebarTheme\"\n      :width=\"getSidebarWidth\"\n      :z-index=\"sidebarZIndex\"\n      @leave=\"() => emit('sideMouseLeave')\"\n    >\n      <template v-if=\"isSideMode && !isMixedNav\" #logo>\n        <slot name=\"logo\"></slot>\n      </template>\n\n      <template v-if=\"isSidebarMixedNav || isHeaderMixedNav\">\n        <slot name=\"mixed-menu\"></slot>\n      </template>\n      <template v-else>\n        <slot name=\"menu\"></slot>\n      </template>\n\n      <template #extra>\n        <slot name=\"side-extra\"></slot>\n      </template>\n      <template #extra-title>\n        <slot name=\"side-extra-title\"></slot>\n      </template>\n    </LayoutSidebar>\n\n    <div\n      ref=\"contentRef\"\n      class=\"flex flex-1 flex-col overflow-hidden transition-all duration-300 ease-in\"\n    >\n      <div\n        :class=\"[\n          {\n            'shadow-[0_16px_24px_hsl(var(--background))]': scrollY > 20,\n          },\n          SCROLL_FIXED_CLASS,\n        ]\"\n        :style=\"headerWrapperStyle\"\n        class=\"overflow-hidden transition-all duration-200\"\n      >\n        <LayoutHeader\n          v-if=\"headerVisible\"\n          :full-width=\"!isSideMode\"\n          :height=\"headerHeight\"\n          :is-mobile=\"isMobile\"\n          :show=\"!isFullContent && !headerHidden\"\n          :sidebar-width=\"sidebarWidth\"\n          :theme=\"headerTheme\"\n          :width=\"mainStyle.width\"\n          :z-index=\"headerZIndex\"\n        >\n          <template v-if=\"showHeaderLogo\" #logo>\n            <slot name=\"logo\"></slot>\n          </template>\n\n          <template #toggle-button>\n            <VbenIconButton\n              v-if=\"showHeaderToggleButton\"\n              class=\"my-0 mr-1 rounded-md\"\n              @click=\"handleHeaderToggle\"\n            >\n              <Menu class=\"size-4\" />\n            </VbenIconButton>\n          </template>\n          <slot name=\"header\"></slot>\n        </LayoutHeader>\n\n        <LayoutTabbar\n          v-if=\"tabbarEnable\"\n          :height=\"tabbarHeight\"\n          :style=\"tabbarStyle\"\n        >\n          <slot name=\"tabbar\"></slot>\n        </LayoutTabbar>\n      </div>\n\n      <!-- </div> -->\n      <LayoutContent\n        :id=\"idMainContent\"\n        :content-compact=\"contentCompact\"\n        :content-compact-width=\"contentCompactWidth\"\n        :padding=\"contentPadding\"\n        :padding-bottom=\"contentPaddingBottom\"\n        :padding-left=\"contentPaddingLeft\"\n        :padding-right=\"contentPaddingRight\"\n        :padding-top=\"contentPaddingTop\"\n        :style=\"contentStyle\"\n        class=\"transition-[margin-top] duration-200\"\n      >\n        <slot name=\"content\"></slot>\n\n        <template #overlay>\n          <slot name=\"content-overlay\"></slot>\n        </template>\n      </LayoutContent>\n\n      <LayoutFooter\n        v-if=\"footerEnable\"\n        :fixed=\"footerFixed\"\n        :height=\"footerHeight\"\n        :show=\"!isFullContent\"\n        :width=\"footerWidth\"\n        :z-index=\"zIndex\"\n      >\n        <slot name=\"footer\"></slot>\n      </LayoutFooter>\n    </div>\n    <slot name=\"extra\"></slot>\n    <div\n      v-if=\"maskVisible\"\n      :style=\"maskStyle\"\n      class=\"bg-overlay fixed left-0 top-0 h-full w-full transition-[background-color] duration-200\"\n      @click=\"handleClickMask\"\n    ></div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/layout-ui/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/README.md",
    "content": "# 菜单组件\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: [\n    {\n      builder: 'mkdist',\n      input: './src',\n      pattern: ['**/*'],\n    },\n    {\n      builder: 'mkdist',\n      input: './src',\n      loaders: ['vue'],\n      pattern: ['**/*.vue'],\n    },\n    {\n      builder: 'mkdist',\n      format: 'esm',\n      input: './src',\n      loaders: ['js'],\n      pattern: ['**/*.ts'],\n    },\n  ],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/package.json",
    "content": "{\n  \"name\": \"@vben-core/menu-ui\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/uikit/menu-ui\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/composables\": \"workspace:*\",\n    \"@vben-core/icons\": \"workspace:*\",\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/collapse-transition.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { RendererElement } from 'vue';\n\ndefineOptions({\n  name: 'CollapseTransition',\n});\n\nconst reset = (el: RendererElement) => {\n  el.style.maxHeight = '';\n  el.style.overflow = el.dataset.oldOverflow;\n  el.style.paddingTop = el.dataset.oldPaddingTop;\n  el.style.paddingBottom = el.dataset.oldPaddingBottom;\n};\n\nconst on = {\n  afterEnter(el: RendererElement) {\n    el.style.maxHeight = '';\n    el.style.overflow = el.dataset.oldOverflow;\n  },\n\n  afterLeave(el: RendererElement) {\n    reset(el);\n  },\n\n  beforeEnter(el: RendererElement) {\n    if (!el.dataset) el.dataset = {};\n\n    el.dataset.oldPaddingTop = el.style.paddingTop;\n    el.dataset.oldMarginTop = el.style.marginTop;\n\n    el.dataset.oldPaddingBottom = el.style.paddingBottom;\n    el.dataset.oldMarginBottom = el.style.marginBottom;\n    if (el.style.height) el.dataset.elExistsHeight = el.style.height;\n\n    el.style.maxHeight = 0;\n    el.style.paddingTop = 0;\n    el.style.marginTop = 0;\n    el.style.paddingBottom = 0;\n    el.style.marginBottom = 0;\n  },\n\n  beforeLeave(el: RendererElement) {\n    if (!el.dataset) el.dataset = {};\n    el.dataset.oldPaddingTop = el.style.paddingTop;\n    el.dataset.oldMarginTop = el.style.marginTop;\n    el.dataset.oldPaddingBottom = el.style.paddingBottom;\n    el.dataset.oldMarginBottom = el.style.marginBottom;\n    el.dataset.oldOverflow = el.style.overflow;\n    el.style.maxHeight = `${el.scrollHeight}px`;\n    el.style.overflow = 'hidden';\n  },\n\n  enter(el: RendererElement) {\n    requestAnimationFrame(() => {\n      el.dataset.oldOverflow = el.style.overflow;\n      if (el.dataset.elExistsHeight) {\n        el.style.maxHeight = el.dataset.elExistsHeight;\n      } else if (el.scrollHeight === 0) {\n        el.style.maxHeight = 0;\n      } else {\n        el.style.maxHeight = `${el.scrollHeight}px`;\n      }\n\n      el.style.paddingTop = el.dataset.oldPaddingTop;\n      el.style.paddingBottom = el.dataset.oldPaddingBottom;\n      el.style.marginTop = el.dataset.oldMarginTop;\n      el.style.marginBottom = el.dataset.oldMarginBottom;\n      el.style.overflow = 'hidden';\n    });\n  },\n\n  enterCancelled(el: RendererElement) {\n    reset(el);\n  },\n\n  leave(el: RendererElement) {\n    if (el.scrollHeight !== 0) {\n      el.style.maxHeight = 0;\n      el.style.paddingTop = 0;\n      el.style.paddingBottom = 0;\n      el.style.marginTop = 0;\n      el.style.marginBottom = 0;\n    }\n  },\n\n  leaveCancelled(el: RendererElement) {\n    reset(el);\n  },\n};\n</script>\n\n<template>\n  <transition name=\"collapse-transition\" v-on=\"on\">\n    <slot></slot>\n  </transition>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/index.ts",
    "content": "export { default as MenuBadge } from './menu-badge.vue';\nexport { default as MenuItem } from './menu-item.vue';\nexport { default as Menu } from './menu.vue';\nexport { default as SubMenu } from './sub-menu.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/menu-badge-dot.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\ninterface Props {\n  dotClass?: string;\n  dotStyle?: CSSProperties;\n}\n\nwithDefaults(defineProps<Props>(), {\n  dotClass: '',\n  dotStyle: () => ({}),\n});\n</script>\n<template>\n  <span class=\"relative mr-1 flex size-1.5\">\n    <span\n      :class=\"dotClass\"\n      :style=\"dotStyle\"\n      class=\"absolute inline-flex h-full w-full animate-ping rounded-full opacity-75\"\n    >\n    </span>\n    <span\n      :class=\"dotClass\"\n      :style=\"dotStyle\"\n      class=\"relative inline-flex size-1.5 rounded-full\"\n    ></span>\n  </span>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/menu-badge.vue",
    "content": "<script setup lang=\"ts\">\nimport type { MenuRecordBadgeRaw } from '@vben-core/typings';\n\nimport { computed } from 'vue';\n\nimport { isValidColor } from '@vben-core/shared/color';\n\nimport BadgeDot from './menu-badge-dot.vue';\n\ninterface Props extends MenuRecordBadgeRaw {\n  hasChildren?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {});\n\nconst variantsMap: Record<string, string> = {\n  default: 'bg-green-500',\n  destructive: 'bg-destructive',\n  primary: 'bg-primary',\n  success: 'bg-green-500',\n  warning: 'bg-yellow-500',\n};\n\nconst isDot = computed(() => props.badgeType === 'dot');\n\nconst badgeClass = computed(() => {\n  const { badgeVariants } = props;\n\n  if (!badgeVariants) {\n    return variantsMap.default;\n  }\n\n  return variantsMap[badgeVariants] || badgeVariants;\n});\n\nconst badgeStyle = computed(() => {\n  if (badgeClass.value && isValidColor(badgeClass.value)) {\n    return {\n      backgroundColor: badgeClass.value,\n    };\n  }\n  return {};\n});\n</script>\n<template>\n  <span v-if=\"isDot || badge\" :class=\"$attrs.class\" class=\"absolute\">\n    <BadgeDot v-if=\"isDot\" :dot-class=\"badgeClass\" :dot-style=\"badgeStyle\" />\n    <div\n      v-else\n      :class=\"badgeClass\"\n      :style=\"badgeStyle\"\n      class=\"text-primary-foreground flex-center rounded-xl px-1.5 py-0.5 text-[10px]\"\n    >\n      {{ badge }}\n    </div>\n  </span>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/menu-item.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { MenuItemProps, MenuItemRegistered } from '../types';\n\nimport { computed, onBeforeUnmount, onMounted, reactive, useSlots } from 'vue';\n\nimport { useNamespace } from '@vben-core/composables';\nimport { VbenIcon, VbenTooltip } from '@vben-core/shadcn-ui';\n\nimport { MenuBadge } from '../components';\nimport { useMenu, useMenuContext, useSubMenuContext } from '../hooks';\n\ninterface Props extends MenuItemProps {}\n\ndefineOptions({ name: 'MenuItem' });\n\nconst props = withDefaults(defineProps<Props>(), {\n  disabled: false,\n});\n\nconst emit = defineEmits<{ click: [MenuItemRegistered] }>();\n\nconst slots = useSlots();\nconst { b, e, is } = useNamespace('menu-item');\nconst nsMenu = useNamespace('menu');\nconst rootMenu = useMenuContext();\nconst subMenu = useSubMenuContext();\nconst { parentMenu, parentPaths } = useMenu();\n\nconst active = computed(() => props.path === rootMenu?.activePath);\nconst menuIcon = computed(() =>\n  active.value ? props.activeIcon || props.icon : props.icon,\n);\n\nconst isTopLevelMenuItem = computed(\n  () => parentMenu.value?.type.name === 'Menu',\n);\n\nconst collapseShowTitle = computed(\n  () =>\n    rootMenu.props?.collapseShowTitle &&\n    isTopLevelMenuItem.value &&\n    rootMenu.props.collapse,\n);\n\nconst showTooltip = computed(\n  () =>\n    rootMenu.props.mode === 'vertical' &&\n    isTopLevelMenuItem.value &&\n    rootMenu.props?.collapse &&\n    slots.title,\n);\n\nconst item: MenuItemRegistered = reactive({\n  active,\n  parentPaths: parentPaths.value,\n  path: props.path || '',\n});\n\n/**\n * 菜单项点击事件\n */\nfunction handleClick() {\n  if (props.disabled) {\n    return;\n  }\n  rootMenu?.handleMenuItemClick?.({\n    parentPaths: parentPaths.value,\n    path: props.path,\n  });\n  emit('click', item);\n}\n\nonMounted(() => {\n  subMenu?.addSubMenu?.(item);\n  rootMenu?.addMenuItem?.(item);\n});\n\nonBeforeUnmount(() => {\n  subMenu?.removeSubMenu?.(item);\n  rootMenu?.removeMenuItem?.(item);\n});\n</script>\n<template>\n  <li\n    :class=\"[\n      rootMenu.theme,\n      b(),\n      is('active', active),\n      is('disabled', disabled),\n      is('collapse-show-title', collapseShowTitle),\n    ]\"\n    role=\"menuitem\"\n    @click.stop=\"handleClick\"\n  >\n    <VbenTooltip\n      v-if=\"showTooltip\"\n      :content-class=\"[rootMenu.theme]\"\n      side=\"right\"\n    >\n      <template #trigger>\n        <div :class=\"[nsMenu.be('tooltip', 'trigger')]\">\n          <VbenIcon :class=\"nsMenu.e('icon')\" :icon=\"menuIcon\" fallback />\n          <slot></slot>\n          <span v-if=\"collapseShowTitle\" :class=\"nsMenu.e('name')\">\n            <slot name=\"title\"></slot>\n          </span>\n        </div>\n      </template>\n      <slot name=\"title\"></slot>\n    </VbenTooltip>\n    <div v-show=\"!showTooltip\" :class=\"[e('content')]\">\n      <MenuBadge\n        v-if=\"rootMenu.props.mode !== 'horizontal'\"\n        class=\"right-2\"\n        v-bind=\"props\"\n      />\n      <VbenIcon :class=\"nsMenu.e('icon')\" :icon=\"menuIcon\" />\n      <slot></slot>\n      <slot name=\"title\"></slot>\n    </div>\n  </li>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/menu.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { UseResizeObserverReturn } from '@vueuse/core';\n\nimport type { SetupContext, VNodeArrayChildren } from 'vue';\n\nimport type {\n  MenuItemClicked,\n  MenuItemRegistered,\n  MenuProps,\n  MenuProvider,\n} from '../types';\n\nimport {\n  computed,\n  nextTick,\n  reactive,\n  ref,\n  toRef,\n  useSlots,\n  watch,\n  watchEffect,\n} from 'vue';\n\nimport { useNamespace } from '@vben-core/composables';\nimport { Ellipsis } from '@vben-core/icons';\n\nimport { useResizeObserver } from '@vueuse/core';\n\nimport {\n  createMenuContext,\n  createSubMenuContext,\n  useMenuStyle,\n} from '../hooks';\nimport { useMenuScroll } from '../hooks/use-menu-scroll';\nimport { flattedChildren } from '../utils';\nimport SubMenu from './sub-menu.vue';\n\ninterface Props extends MenuProps {}\n\ndefineOptions({ name: 'Menu' });\n\nconst props = withDefaults(defineProps<Props>(), {\n  accordion: true,\n  collapse: false,\n  mode: 'vertical',\n  rounded: true,\n  theme: 'dark',\n  scrollToActive: false,\n});\n\nconst emit = defineEmits<{\n  close: [string, string[]];\n  open: [string, string[]];\n  select: [string, string[]];\n}>();\n\nconst { b, is } = useNamespace('menu');\nconst menuStyle = useMenuStyle();\nconst slots: SetupContext['slots'] = useSlots();\nconst menu = ref<HTMLUListElement>();\nconst sliceIndex = ref(-1);\nconst openedMenus = ref<MenuProvider['openedMenus']>(\n  props.defaultOpeneds && !props.collapse ? [...props.defaultOpeneds] : [],\n);\nconst activePath = ref<MenuProvider['activePath']>(props.defaultActive);\nconst items = ref<MenuProvider['items']>({});\nconst subMenus = ref<MenuProvider['subMenus']>({});\nconst mouseInChild = ref(false);\n\nconst isMenuPopup = computed<MenuProvider['isMenuPopup']>(() => {\n  return (\n    props.mode === 'horizontal' || (props.mode === 'vertical' && props.collapse)\n  );\n});\n\nconst getSlot = computed(() => {\n  // 更新插槽内容\n  const defaultSlots: VNodeArrayChildren = slots.default?.() ?? [];\n\n  const originalSlot = flattedChildren(defaultSlots) as VNodeArrayChildren;\n  const slotDefault =\n    sliceIndex.value === -1\n      ? originalSlot\n      : originalSlot.slice(0, sliceIndex.value);\n\n  const slotMore =\n    sliceIndex.value === -1 ? [] : originalSlot.slice(sliceIndex.value);\n\n  return { showSlotMore: slotMore.length > 0, slotDefault, slotMore };\n});\n\nwatch(\n  () => props.collapse,\n  (value) => {\n    if (value) openedMenus.value = [];\n  },\n);\n\nwatch(items.value, initMenu);\n\nwatch(\n  () => props.defaultActive,\n  (currentActive = '') => {\n    if (!items.value[currentActive]) {\n      activePath.value = '';\n    }\n    updateActiveName(currentActive);\n  },\n);\n\nlet resizeStopper: UseResizeObserverReturn['stop'];\nwatchEffect(() => {\n  if (props.mode === 'horizontal') {\n    resizeStopper = useResizeObserver(menu, handleResize).stop;\n  } else {\n    resizeStopper?.();\n  }\n});\n\n// 注入上下文\ncreateMenuContext(\n  reactive({\n    activePath,\n    addMenuItem,\n    addSubMenu,\n    closeMenu,\n    handleMenuItemClick,\n    handleSubMenuClick,\n    isMenuPopup,\n    openedMenus,\n    openMenu,\n    props,\n    removeMenuItem,\n    removeSubMenu,\n    subMenus,\n    theme: toRef(props, 'theme'),\n    items,\n  }),\n);\n\ncreateSubMenuContext({\n  addSubMenu,\n  level: 1,\n  mouseInChild,\n  removeSubMenu,\n});\n\nfunction calcMenuItemWidth(menuItem: HTMLElement) {\n  const computedStyle = getComputedStyle(menuItem);\n  const marginLeft = Number.parseInt(computedStyle.marginLeft, 10);\n  const marginRight = Number.parseInt(computedStyle.marginRight, 10);\n  return menuItem.offsetWidth + marginLeft + marginRight || 0;\n}\n\nfunction calcSliceIndex() {\n  if (!menu.value) {\n    return -1;\n  }\n  const items = [...(menu.value?.childNodes ?? [])].filter(\n    (item) =>\n      // remove comment type node #12634\n      item.nodeName !== '#comment' &&\n      (item.nodeName !== '#text' || item.nodeValue),\n  ) as HTMLElement[];\n\n  const moreItemWidth = 46;\n  const computedMenuStyle = getComputedStyle(menu?.value);\n\n  const paddingLeft = Number.parseInt(computedMenuStyle.paddingLeft, 10);\n  const paddingRight = Number.parseInt(computedMenuStyle.paddingRight, 10);\n  const menuWidth = menu.value?.clientWidth - paddingLeft - paddingRight;\n\n  let calcWidth = 0;\n  let sliceIndex = 0;\n  items.forEach((item, index) => {\n    calcWidth += calcMenuItemWidth(item);\n    if (calcWidth <= menuWidth - moreItemWidth) {\n      sliceIndex = index + 1;\n    }\n  });\n  return sliceIndex === items.length ? -1 : sliceIndex;\n}\n\nfunction debounce(fn: () => void, wait = 33.34) {\n  let timer: null | ReturnType<typeof setTimeout>;\n  return () => {\n    timer && clearTimeout(timer);\n    timer = setTimeout(() => {\n      fn();\n    }, wait);\n  };\n}\n\nlet isFirstTimeRender = true;\nfunction handleResize() {\n  if (sliceIndex.value === calcSliceIndex()) {\n    return;\n  }\n  const callback = () => {\n    sliceIndex.value = -1;\n    nextTick(() => {\n      sliceIndex.value = calcSliceIndex();\n    });\n  };\n  callback();\n  // // execute callback directly when first time resize to avoid shaking\n  isFirstTimeRender ? callback() : debounce(callback)();\n  isFirstTimeRender = false;\n}\n\nconst enableScroll = computed(\n  () => props.scrollToActive && props.mode === 'vertical' && !props.collapse,\n);\n\nconst { scrollToActiveItem } = useMenuScroll(activePath, {\n  enable: enableScroll,\n  delay: 320,\n});\n\n// 监听 activePath 变化，自动滚动到激活项\nwatch(activePath, () => {\n  scrollToActiveItem();\n});\n\n// 默认展开菜单\nfunction initMenu() {\n  const parentPaths = getActivePaths();\n\n  // 展开该菜单项的路径上所有子菜单\n  // expand all subMenus of the menu item\n  parentPaths.forEach((path) => {\n    const subMenu = subMenus.value[path];\n    subMenu && openMenu(path, subMenu.parentPaths);\n  });\n}\n\nfunction updateActiveName(val: string) {\n  const itemsInData = items.value;\n  const item =\n    itemsInData[val] ||\n    (activePath.value && itemsInData[activePath.value]) ||\n    itemsInData[props.defaultActive || ''];\n\n  activePath.value = item ? item.path : val;\n}\n\nfunction handleMenuItemClick(data: MenuItemClicked) {\n  const { collapse, mode } = props;\n  if (mode === 'horizontal' || collapse) {\n    openedMenus.value = [];\n  }\n  const { parentPaths, path } = data;\n  if (!path || !parentPaths) {\n    return;\n  }\n\n  emit('select', path, parentPaths);\n}\n\nfunction handleSubMenuClick({ parentPaths, path }: MenuItemRegistered) {\n  const isOpened = openedMenus.value.includes(path);\n\n  if (isOpened) {\n    closeMenu(path, parentPaths);\n  } else {\n    openMenu(path, parentPaths);\n  }\n}\n\nfunction close(path: string) {\n  const i = openedMenus.value.indexOf(path);\n\n  if (i !== -1) {\n    openedMenus.value.splice(i, 1);\n  }\n}\n\n/**\n * 关闭、折叠菜单\n */\nfunction closeMenu(path: string, parentPaths: string[]) {\n  if (props.accordion) {\n    openedMenus.value = subMenus.value[path]?.parentPaths ?? [];\n  }\n\n  close(path);\n\n  emit('close', path, parentPaths);\n}\n\n/**\n * 点击展开菜单\n */\nfunction openMenu(path: string, parentPaths: string[]) {\n  if (openedMenus.value.includes(path)) {\n    return;\n  }\n  // 手风琴模式菜单\n  if (props.accordion) {\n    const activeParentPaths = getActivePaths();\n    if (activeParentPaths.includes(path)) {\n      parentPaths = activeParentPaths;\n    }\n    openedMenus.value = openedMenus.value.filter((path: string) =>\n      parentPaths.includes(path),\n    );\n  }\n  openedMenus.value.push(path);\n  emit('open', path, parentPaths);\n}\n\nfunction addMenuItem(item: MenuItemRegistered) {\n  items.value[item.path] = item;\n}\n\nfunction addSubMenu(subMenu: MenuItemRegistered) {\n  subMenus.value[subMenu.path] = subMenu;\n}\n\nfunction removeSubMenu(subMenu: MenuItemRegistered) {\n  Reflect.deleteProperty(subMenus.value, subMenu.path);\n}\n\nfunction removeMenuItem(item: MenuItemRegistered) {\n  Reflect.deleteProperty(items.value, item.path);\n}\n\nfunction getActivePaths() {\n  const activeItem = activePath.value && items.value[activePath.value];\n\n  if (!activeItem || props.mode === 'horizontal' || props.collapse) {\n    return [];\n  }\n\n  return activeItem.parentPaths;\n}\n</script>\n<template>\n  <ul\n    ref=\"menu\"\n    :class=\"[\n      theme,\n      b(),\n      is(mode, true),\n      is(theme, true),\n      is('rounded', rounded),\n      is('collapse', collapse),\n      is('menu-align', mode === 'horizontal'),\n    ]\"\n    :style=\"menuStyle\"\n    role=\"menu\"\n  >\n    <template v-if=\"mode === 'horizontal' && getSlot.showSlotMore\">\n      <template v-for=\"item in getSlot.slotDefault\" :key=\"item.key\">\n        <component :is=\"item\" />\n      </template>\n      <SubMenu is-sub-menu-more path=\"sub-menu-more\">\n        <template #title>\n          <Ellipsis class=\"size-4\" />\n        </template>\n        <template v-for=\"item in getSlot.slotMore\" :key=\"item.key\">\n          <component :is=\"item\" />\n        </template>\n      </SubMenu>\n    </template>\n    <template v-else>\n      <slot></slot>\n    </template>\n  </ul>\n</template>\n\n<style lang=\"scss\">\n$namespace: vben;\n\n@mixin menu-item-active {\n  color: var(--menu-item-active-color);\n  text-decoration: none;\n  cursor: pointer;\n  background: var(--menu-item-active-background-color);\n}\n\n@mixin menu-item {\n  position: relative;\n  display: flex;\n  // gap: 12px;\n  align-items: center;\n  height: var(--menu-item-height);\n  padding: var(--menu-item-padding-y) var(--menu-item-padding-x);\n  margin: 0 var(--menu-item-margin-x) var(--menu-item-margin-y)\n    var(--menu-item-margin-x);\n  font-size: var(--menu-font-size);\n  color: var(--menu-item-color);\n  white-space: nowrap;\n  text-decoration: none;\n  cursor: pointer;\n  list-style: none;\n  background: var(--menu-item-background-color);\n  border: none;\n  border-radius: var(--menu-item-radius);\n  transition:\n    background 0.15s ease,\n    color 0.15s ease,\n    padding 0.15s ease,\n    border-color 0.15s ease;\n\n  &.is-disabled {\n    cursor: not-allowed;\n    background: none !important;\n    opacity: 0.25;\n  }\n\n  .#{$namespace}-menu__icon {\n    transition: transform 0.25s;\n  }\n\n  &:hover {\n    .#{$namespace}-menu__icon {\n      transform: scale(1.2);\n    }\n  }\n\n  &:hover,\n  &:focus {\n    outline: none;\n  }\n\n  * {\n    vertical-align: bottom;\n  }\n}\n\n@mixin menu-title {\n  max-width: var(--menu-title-width);\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  opacity: 1;\n}\n\n.is-menu-align {\n  justify-content: var(--menu-align, start);\n}\n\n.#{$namespace}-menu__popup-container,\n.#{$namespace}-menu {\n  --menu-title-width: 140px;\n  --menu-item-icon-size: 16px;\n  --menu-item-height: 38px;\n  --menu-item-padding-y: 21px;\n  --menu-item-padding-x: 12px;\n  --menu-item-popup-padding-y: 20px;\n  --menu-item-popup-padding-x: 12px;\n  --menu-item-margin-y: 2px;\n  --menu-item-margin-x: 0px;\n  --menu-item-collapse-padding-y: 23.5px;\n  --menu-item-collapse-padding-x: 0px;\n  --menu-item-collapse-margin-y: 4px;\n  --menu-item-collapse-margin-x: 0px;\n  --menu-item-radius: 0px;\n  --menu-item-indent: 16px;\n  --menu-font-size: 14px;\n\n  &.is-dark {\n    --menu-background-color: hsl(var(--menu));\n    // --menu-submenu-opened-background-color: hsl(var(--menu-opened-dark));\n    --menu-item-background-color: var(--menu-background-color);\n    --menu-item-color: hsl(var(--foreground) / 80%);\n    --menu-item-hover-color: hsl(var(--accent-foreground));\n    --menu-item-hover-background-color: hsl(var(--accent));\n    --menu-item-active-color: hsl(var(--accent-foreground));\n    --menu-item-active-background-color: hsl(var(--accent));\n    --menu-submenu-hover-color: hsl(var(--foreground));\n    --menu-submenu-hover-background-color: hsl(var(--accent));\n    --menu-submenu-active-color: hsl(var(--foreground));\n    --menu-submenu-active-background-color: transparent;\n    --menu-submenu-background-color: var(--menu-background-color);\n  }\n\n  &.is-light {\n    --menu-background-color: hsl(var(--menu));\n    // --menu-submenu-opened-background-color: hsl(var(--menu-opened));\n    --menu-item-background-color: var(--menu-background-color);\n    --menu-item-color: hsl(var(--foreground));\n    --menu-item-hover-color: var(--menu-item-color);\n    --menu-item-hover-background-color: hsl(var(--accent));\n    --menu-item-active-color: hsl(var(--primary));\n    --menu-item-active-background-color: hsl(var(--primary) / 15%);\n    --menu-submenu-hover-color: hsl(var(--primary));\n    --menu-submenu-hover-background-color: hsl(var(--accent));\n    --menu-submenu-active-color: hsl(var(--primary));\n    --menu-submenu-active-background-color: transparent;\n    --menu-submenu-background-color: var(--menu-background-color);\n  }\n\n  &.is-rounded {\n    --menu-item-margin-x: 8px;\n    --menu-item-collapse-margin-x: 6px;\n    --menu-item-radius: 8px;\n  }\n\n  &.is-horizontal:not(.is-rounded) {\n    --menu-item-height: 40px;\n    --menu-item-radius: 6px;\n  }\n\n  &.is-horizontal.is-rounded {\n    --menu-item-height: 40px;\n    --menu-item-radius: 6px;\n    --menu-item-padding-x: 12px;\n  }\n\n  // .vben-menu__popup,\n  &.is-horizontal {\n    --menu-item-padding-y: 0px;\n    --menu-item-padding-x: 10px;\n    --menu-item-margin-y: 0px;\n    --menu-item-margin-x: 1px;\n    --menu-background-color: transparent;\n\n    &.is-dark {\n      --menu-item-hover-color: hsl(var(--accent-foreground));\n      --menu-item-hover-background-color: hsl(var(--accent));\n      --menu-item-active-color: hsl(var(--accent-foreground));\n      --menu-item-active-background-color: hsl(var(--accent));\n      --menu-submenu-active-color: hsl(var(--foreground));\n      --menu-submenu-active-background-color: hsl(var(--accent));\n      --menu-submenu-hover-color: hsl(var(--accent-foreground));\n      --menu-submenu-hover-background-color: hsl(var(--accent));\n    }\n\n    &.is-light {\n      --menu-item-active-color: hsl(var(--primary));\n      --menu-item-active-background-color: hsl(var(--primary) / 15%);\n      --menu-item-hover-background-color: hsl(var(--accent));\n      --menu-item-hover-color: hsl(var(--primary));\n      --menu-submenu-active-color: hsl(var(--primary));\n      --menu-submenu-active-background-color: hsl(var(--primary) / 15%);\n      --menu-submenu-hover-color: hsl(var(--primary));\n      --menu-submenu-hover-background-color: hsl(var(--accent));\n    }\n  }\n}\n\n.#{$namespace}-menu {\n  position: relative;\n  box-sizing: border-box;\n  padding-left: 0;\n  margin: 0;\n  list-style: none;\n  background: hsl(var(--menu-background-color));\n\n  // 垂直菜单\n  &.is-vertical {\n    &:not(.#{$namespace}-menu.is-collapse) {\n      & .#{$namespace}-menu-item,\n      & .#{$namespace}-sub-menu-content,\n      & .#{$namespace}-menu-item-group__title {\n        padding-left: calc(\n          var(--menu-item-indent) + var(--menu-level) * var(--menu-item-indent)\n        );\n        white-space: nowrap;\n      }\n\n      & > .#{$namespace}-sub-menu {\n        & > .#{$namespace}-menu {\n          & > .#{$namespace}-menu-item {\n            padding-left: calc(\n              0px + var(--menu-item-indent) + var(--menu-level) *\n                var(--menu-item-indent)\n            );\n          }\n        }\n\n        & > .#{$namespace}-sub-menu-content {\n          padding-left: calc(var(--menu-item-indent) - 8px);\n        }\n      }\n      & > .#{$namespace}-menu-item {\n        padding-left: calc(var(--menu-item-indent) - 8px);\n      }\n    }\n  }\n\n  &.is-horizontal {\n    display: flex;\n    flex-wrap: nowrap;\n    max-width: 100%;\n    height: var(--height-horizontal-height);\n    border-right: none;\n\n    .#{$namespace}-menu-item {\n      display: inline-flex;\n      align-items: center;\n      justify-content: center;\n      height: var(--menu-item-height);\n      padding-right: calc(var(--menu-item-padding-x) + 6px);\n      margin: 0;\n      margin-right: 2px;\n      // border-bottom: 2px solid transparent;\n      border-radius: var(--menu-item-radius);\n    }\n\n    & > .#{$namespace}-sub-menu {\n      height: var(--menu-item-height);\n      margin-right: 2px;\n\n      &:focus,\n      &:hover {\n        outline: none;\n      }\n\n      & .#{$namespace}-sub-menu-content {\n        height: 100%;\n        padding-right: 40px;\n        // border-bottom: 2px solid transparent;\n        border-radius: var(--menu-item-radius);\n      }\n    }\n\n    & .#{$namespace}-menu-item:not(.is-disabled):hover,\n    & .#{$namespace}-menu-item:not(.is-disabled):focus {\n      outline: none;\n    }\n\n    & > .#{$namespace}-menu-item.is-active {\n      color: var(--menu-item-active-color);\n    }\n\n    // &.is-light {\n    //   & > .#{$namespace}-sub-menu {\n    //     &.is-active {\n    //       border-bottom: 2px solid var(--menu-item-active-color);\n    //     }\n    //     &:not(.is-active) .#{$namespace}-sub-menu-content {\n    //       &:hover {\n    //         border-bottom: 2px solid var(--menu-item-active-color);\n    //       }\n    //     }\n    //   }\n    //   & > .#{$namespace}-menu-item.is-active {\n    //     border-bottom: 2px solid var(--menu-item-active-color);\n    //   }\n\n    //   & .#{$namespace}-menu-item:not(.is-disabled):hover,\n    //   & .#{$namespace}-menu-item:not(.is-disabled):focus {\n    //     border-bottom: 2px solid var(--menu-item-active-color);\n    //   }\n    // }\n  }\n  // 折叠菜单\n\n  &.is-collapse {\n    .#{$namespace}-menu__icon {\n      margin-right: 0;\n    }\n    .#{$namespace}-sub-menu__icon-arrow {\n      display: none;\n    }\n\n    .#{$namespace}-sub-menu-content,\n    .#{$namespace}-menu-item {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      padding: var(--menu-item-collapse-padding-y)\n        var(--menu-item-collapse-padding-x);\n      margin: var(--menu-item-collapse-margin-y)\n        var(--menu-item-collapse-margin-x);\n      transition: all 0.3s;\n\n      &.is-active {\n        background: var(--menu-item-active-background-color) !important;\n        border-radius: var(--menu-item-radius);\n      }\n    }\n\n    &.is-light {\n      .#{$namespace}-sub-menu-content,\n      .#{$namespace}-menu-item {\n        &.is-active {\n          // color: hsl(var(--primary-foreground)) !important;\n          background: var(--menu-item-active-background-color) !important;\n        }\n      }\n    }\n\n    &.is-rounded {\n      .#{$namespace}-sub-menu-content,\n      .#{$namespace}-menu-item {\n        &.is-collapse-show-title {\n          // padding: 32px 0 !important;\n          margin: 4px 8px !important;\n        }\n      }\n    }\n  }\n\n  &__popup-container {\n    max-width: 240px;\n    height: unset;\n    padding: 0;\n    background: var(--menu-background-color);\n  }\n\n  &__popup {\n    padding: 10px 0;\n    border-radius: var(--menu-item-radius);\n\n    .#{$namespace}-sub-menu-content,\n    .#{$namespace}-menu-item {\n      padding: var(--menu-item-popup-padding-y) var(--menu-item-popup-padding-x);\n    }\n  }\n\n  &__icon {\n    flex-shrink: 0;\n    width: var(--menu-item-icon-size);\n    height: var(--menu-item-icon-size);\n    margin-right: 8px;\n    vertical-align: middle;\n    text-align: center;\n  }\n}\n\n.#{$namespace}-menu-item {\n  fill: var(--menu-item-color);\n\n  @include menu-item;\n\n  &.is-active {\n    fill: var(--menu-item-active-color);\n\n    @include menu-item-active;\n  }\n\n  &__content {\n    display: inline-flex;\n    align-items: center;\n    width: 100%;\n    height: var(--menu-item-height);\n\n    span {\n      @include menu-title;\n    }\n  }\n\n  &.is-collapse-show-title {\n    padding: 32px 0 !important;\n    // margin: 4px 8px !important;\n    .#{$namespace}-menu-tooltip__trigger {\n      flex-direction: column;\n    }\n    .#{$namespace}-menu__icon {\n      display: block;\n      font-size: 20px !important;\n      transition: all 0.25s ease;\n    }\n\n    .#{$namespace}-menu__name {\n      display: inline-flex;\n      margin-top: 8px;\n      margin-bottom: 0;\n      font-size: 12px;\n      font-weight: 400;\n      line-height: normal;\n      transition: all 0.25s ease;\n    }\n  }\n\n  &:not(.is-active):hover {\n    color: var(--menu-item-hover-color);\n    text-decoration: none;\n    cursor: pointer;\n    background: var(--menu-item-hover-background-color) !important;\n  }\n\n  .#{$namespace}-menu-tooltip__trigger {\n    position: absolute;\n    top: 0;\n    left: 0;\n    box-sizing: border-box;\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    width: 100%;\n    height: 100%;\n    padding: 0 var(--menu-item-padding-x);\n    font-size: var(--menu-font-size);\n    line-height: var(--menu-item-height);\n  }\n}\n\n.#{$namespace}-sub-menu {\n  padding-left: 0;\n  margin: 0;\n  list-style: none;\n  background: var(--menu-submenu-background-color);\n  fill: var(--menu-item-color);\n\n  &.is-active {\n    div[data-state='open'] > .#{$namespace}-sub-menu-content,\n    > .#{$namespace}-sub-menu-content {\n      // font-weight: 500;\n      color: var(--menu-submenu-active-color);\n      text-decoration: none;\n      cursor: pointer;\n      background: var(--menu-submenu-active-background-color);\n      fill: var(--menu-submenu-active-color);\n    }\n  }\n}\n\n.#{$namespace}-sub-menu-content {\n  height: var(--menu-item-height);\n\n  @include menu-item;\n\n  &__icon-arrow {\n    position: absolute;\n    top: 50%;\n    right: 10px;\n    width: inherit;\n    margin-top: -8px;\n    margin-right: 0;\n    // font-size: 16px;\n    font-weight: normal;\n    opacity: 1;\n    transition: transform 0.25s ease;\n  }\n\n  &__title {\n    @include menu-title;\n  }\n\n  &.is-collapse-show-title {\n    flex-direction: column;\n    padding: 32px 0 !important;\n    // margin: 4px 8px !important;\n    .#{$namespace}-menu__icon {\n      display: block;\n      font-size: 20px !important;\n      transition: all 0.25s ease;\n    }\n    .#{$namespace}-sub-menu-content__title {\n      display: inline-flex;\n      flex-shrink: 0;\n      margin-top: 8px;\n      margin-bottom: 0;\n      font-size: 12px;\n      font-weight: 400;\n      line-height: normal;\n      transition: all 0.25s ease;\n    }\n  }\n\n  &.is-more {\n    padding-right: 12px !important;\n  }\n\n  // &:not(.is-active):hover {\n  &:hover {\n    color: var(--menu-submenu-hover-color);\n    text-decoration: none;\n    cursor: pointer;\n    background: var(--menu-submenu-hover-background-color) !important;\n\n    // svg {\n    //   fill: var(--menu-submenu-hover-color);\n    // }\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/normal-menu/index.ts",
    "content": "export type * from './normal-menu';\nexport { default as NormalMenu } from './normal-menu.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts",
    "content": "import type { MenuRecordRaw } from '@vben-core/typings';\n\ninterface NormalMenuProps {\n  /**\n   * 菜单数据\n   */\n  activePath?: string;\n  /**\n   * 是否折叠\n   */\n  collapse?: boolean;\n  /**\n   * 菜单项\n   */\n  menus?: MenuRecordRaw[];\n  /**\n   * @zh_CN 是否圆润风格\n   * @default true\n   */\n  rounded?: boolean;\n  /**\n   * 主题\n   */\n  theme?: 'dark' | 'light';\n}\n\nexport type { NormalMenuProps };\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.vue",
    "content": "<script setup lang=\"ts\">\nimport type { MenuRecordRaw } from '@vben-core/typings';\n\nimport type { NormalMenuProps } from './normal-menu';\n\nimport { useNamespace } from '@vben-core/composables';\nimport { VbenIcon } from '@vben-core/shadcn-ui';\n\ninterface Props extends NormalMenuProps {}\n\ndefineOptions({\n  name: 'NormalMenu',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  activePath: '',\n  collapse: false,\n  menus: () => [],\n  theme: 'dark',\n});\n\nconst emit = defineEmits<{\n  enter: [MenuRecordRaw];\n  select: [MenuRecordRaw];\n}>();\n\nconst { b, e, is } = useNamespace('normal-menu');\n\nfunction menuIcon(menu: MenuRecordRaw) {\n  return props.activePath === menu.path\n    ? menu.activeIcon || menu.icon\n    : menu.icon;\n}\n</script>\n\n<template>\n  <ul\n    :class=\"[\n      theme,\n      b(),\n      is('collapse', collapse),\n      is(theme, true),\n      is('rounded', rounded),\n    ]\"\n    class=\"relative\"\n  >\n    <template v-for=\"menu in menus\" :key=\"menu.path\">\n      <li\n        :class=\"[e('item'), is('active', activePath === menu.path)]\"\n        @click=\"() => emit('select', menu)\"\n        @mouseenter=\"() => emit('enter', menu)\"\n      >\n        <VbenIcon :class=\"e('icon')\" :icon=\"menuIcon(menu)\" fallback />\n\n        <span :class=\"e('name')\" class=\"truncate\"> {{ menu.name }}</span>\n      </li>\n    </template>\n  </ul>\n</template>\n<style lang=\"scss\" scoped>\n$namespace: vben;\n\n.#{$namespace}-normal-menu {\n  --menu-item-margin-y: 4px;\n  --menu-item-margin-x: 0px;\n  --menu-item-padding-y: 9px;\n  --menu-item-padding-x: 0px;\n  --menu-item-radius: 0px;\n\n  height: calc(100% - 4px);\n\n  &.is-rounded {\n    --menu-item-radius: 6px;\n    --menu-item-margin-x: 8px;\n  }\n\n  &.is-dark {\n    .#{$namespace}-normal-menu__item {\n      @apply text-foreground/80;\n      // color: hsl(var(--foreground) / 80%);\n\n      &:not(.is-active):hover {\n        @apply text-foreground;\n      }\n\n      &.is-active {\n        .#{$namespace}-normal-menu__name,\n        .#{$namespace}-normal-menu__icon {\n          @apply text-foreground;\n        }\n      }\n    }\n  }\n\n  &.is-collapse {\n    .#{$namespace}-normal-menu__name {\n      width: 0;\n      height: 0;\n      margin-top: 0;\n      overflow: hidden;\n      opacity: 0;\n    }\n\n    .#{$namespace}-normal-menu__icon {\n      font-size: 20px;\n    }\n  }\n\n  &__item {\n    position: relative;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    // max-width: 64px;\n    // max-height: 64px;\n    padding: var(--menu-item-padding-y) var(--menu-item-padding-x);\n    margin: var(--menu-item-margin-y) var(--menu-item-margin-x);\n    color: hsl(var(--foreground) / 90%);\n    cursor: pointer;\n    border-radius: var(--menu-item-radius);\n    transition:\n      background 0.15s ease,\n      padding 0.15s ease,\n      border-color 0.15s ease;\n\n    &.is-active {\n      @apply text-primary bg-primary dark:bg-accent;\n\n      .#{$namespace}-normal-menu__name,\n      .#{$namespace}-normal-menu__icon {\n        @apply text-primary-foreground font-semibold;\n      }\n    }\n\n    &:not(.is-active):hover {\n      @apply dark:bg-accent text-primary bg-heavy dark:text-foreground;\n    }\n\n    &:hover {\n      .#{$namespace}-normal-menu__icon {\n        transform: scale(1.2);\n      }\n    }\n  }\n\n  &__icon {\n    max-height: 20px;\n    font-size: 20px;\n    transition: all 0.25s ease;\n  }\n\n  &__name {\n    margin-top: 8px;\n    margin-bottom: 0;\n    font-size: 12px;\n    font-weight: 400;\n    transition: all 0.25s ease;\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { MenuItemProps } from '../types';\n\nimport { computed } from 'vue';\n\nimport { useNamespace } from '@vben-core/composables';\nimport { ChevronDown, ChevronRight } from '@vben-core/icons';\nimport { VbenIcon } from '@vben-core/shadcn-ui';\n\nimport { useMenuContext } from '../hooks';\n\ninterface Props extends MenuItemProps {\n  isMenuMore?: boolean;\n  isTopLevelMenuSubmenu: boolean;\n  level?: number;\n}\n\ndefineOptions({ name: 'SubMenuContent' });\n\nconst props = withDefaults(defineProps<Props>(), {\n  isMenuMore: false,\n  level: 0,\n});\n\nconst rootMenu = useMenuContext();\nconst { b, e, is } = useNamespace('sub-menu-content');\nconst nsMenu = useNamespace('menu');\n\nconst opened = computed(() => {\n  return rootMenu?.openedMenus.includes(props.path);\n});\n\nconst collapse = computed(() => {\n  return rootMenu.props.collapse;\n});\n\nconst isFirstLevel = computed(() => {\n  return props.level === 1;\n});\n\nconst getCollapseShowTitle = computed(() => {\n  return (\n    rootMenu.props.collapseShowTitle && isFirstLevel.value && collapse.value\n  );\n});\n\nconst mode = computed(() => {\n  return rootMenu?.props.mode;\n});\n\nconst showArrowIcon = computed(() => {\n  return mode.value === 'horizontal' || !(isFirstLevel.value && collapse.value);\n});\n\nconst hiddenTitle = computed(() => {\n  return (\n    mode.value === 'vertical' &&\n    isFirstLevel.value &&\n    collapse.value &&\n    !getCollapseShowTitle.value\n  );\n});\n\nconst iconComp = computed(() => {\n  return (mode.value === 'horizontal' && !isFirstLevel.value) ||\n    (mode.value === 'vertical' && collapse.value)\n    ? ChevronRight\n    : ChevronDown;\n});\n\nconst iconArrowStyle = computed(() => {\n  return opened.value ? { transform: `rotate(180deg)` } : {};\n});\n</script>\n<template>\n  <div\n    :class=\"[\n      b(),\n      is('collapse-show-title', getCollapseShowTitle),\n      is('more', isMenuMore),\n    ]\"\n  >\n    <slot></slot>\n\n    <VbenIcon\n      v-if=\"!isMenuMore\"\n      :class=\"nsMenu.e('icon')\"\n      :icon=\"icon\"\n      fallback\n    />\n\n    <div v-if=\"!hiddenTitle\" :class=\"[e('title')]\">\n      <slot name=\"title\"></slot>\n    </div>\n\n    <component\n      :is=\"iconComp\"\n      v-if=\"!isMenuMore\"\n      v-show=\"showArrowIcon\"\n      :class=\"[e('icon-arrow')]\"\n      :style=\"iconArrowStyle\"\n      class=\"size-4\"\n    />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { HoverCardContentProps } from '@vben-core/shadcn-ui';\n\nimport type { MenuItemRegistered, MenuProvider, SubMenuProps } from '../types';\n\nimport { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';\n\nimport { useNamespace } from '@vben-core/composables';\nimport { VbenHoverCard } from '@vben-core/shadcn-ui';\n\nimport {\n  createSubMenuContext,\n  useMenu,\n  useMenuContext,\n  useMenuStyle,\n  useSubMenuContext,\n} from '../hooks';\nimport CollapseTransition from './collapse-transition.vue';\nimport SubMenuContent from './sub-menu-content.vue';\n\ninterface Props extends SubMenuProps {\n  isSubMenuMore?: boolean;\n}\n\ndefineOptions({ name: 'SubMenu' });\n\nconst props = withDefaults(defineProps<Props>(), {\n  disabled: false,\n  isSubMenuMore: false,\n});\n\nconst { parentMenu, parentPaths } = useMenu();\nconst { b, is } = useNamespace('sub-menu');\nconst nsMenu = useNamespace('menu');\nconst rootMenu = useMenuContext();\nconst subMenu = useSubMenuContext();\nconst subMenuStyle = useMenuStyle(subMenu);\n\nconst mouseInChild = ref(false);\n\nconst items = ref<MenuProvider['items']>({});\nconst subMenus = ref<MenuProvider['subMenus']>({});\nconst timer = ref<null | ReturnType<typeof setTimeout>>(null);\n\ncreateSubMenuContext({\n  addSubMenu,\n  handleMouseleave,\n  level: (subMenu?.level ?? 0) + 1,\n  mouseInChild,\n  removeSubMenu,\n});\n\nconst opened = computed(() => {\n  return rootMenu?.openedMenus.includes(props.path);\n});\nconst isTopLevelMenuSubmenu = computed(\n  () => parentMenu.value?.type.name === 'Menu',\n);\nconst mode = computed(() => rootMenu?.props.mode ?? 'vertical');\nconst rounded = computed(() => rootMenu?.props.rounded);\nconst currentLevel = computed(() => subMenu?.level ?? 0);\nconst isFirstLevel = computed(() => {\n  return currentLevel.value === 1;\n});\n\nconst contentProps = computed((): HoverCardContentProps => {\n  const isHorizontal = mode.value === 'horizontal';\n  const side = isHorizontal && isFirstLevel.value ? 'bottom' : 'right';\n  return {\n    collisionPadding: { top: 20 },\n    side,\n    sideOffset: isHorizontal ? 5 : 10,\n  };\n});\n\nconst active = computed(() => {\n  let isActive = false;\n\n  Object.values(items.value).forEach((item) => {\n    if (item.active) {\n      isActive = true;\n    }\n  });\n\n  Object.values(subMenus.value).forEach((subItem) => {\n    if (subItem.active) {\n      isActive = true;\n    }\n  });\n  return isActive;\n});\n\nfunction addSubMenu(subMenu: MenuItemRegistered) {\n  subMenus.value[subMenu.path] = subMenu;\n}\n\nfunction removeSubMenu(subMenu: MenuItemRegistered) {\n  Reflect.deleteProperty(subMenus.value, subMenu.path);\n}\n\n/**\n * 点击submenu展开/关闭\n */\nfunction handleClick() {\n  const mode = rootMenu?.props.mode;\n  if (\n    // 当前菜单禁用时，不展开\n    props.disabled ||\n    (rootMenu?.props.collapse && mode === 'vertical') ||\n    // 水平模式下不展开\n    mode === 'horizontal'\n  ) {\n    return;\n  }\n\n  rootMenu?.handleSubMenuClick({\n    active: active.value,\n    parentPaths: parentPaths.value,\n    path: props.path,\n  });\n}\n\nfunction handleMouseenter(event: FocusEvent | MouseEvent, showTimeout = 300) {\n  if (event.type === 'focus') {\n    return;\n  }\n\n  if (\n    (!rootMenu?.props.collapse && rootMenu?.props.mode === 'vertical') ||\n    props.disabled\n  ) {\n    if (subMenu) {\n      subMenu.mouseInChild.value = true;\n    }\n    return;\n  }\n  if (subMenu) {\n    subMenu.mouseInChild.value = true;\n  }\n\n  timer.value && window.clearTimeout(timer.value);\n  timer.value = setTimeout(() => {\n    rootMenu?.openMenu(props.path, parentPaths.value);\n  }, showTimeout);\n  parentMenu.value?.vnode.el?.dispatchEvent(new MouseEvent('mouseenter'));\n}\n\nfunction handleMouseleave(deepDispatch = false) {\n  if (\n    !rootMenu?.props.collapse &&\n    rootMenu?.props.mode === 'vertical' &&\n    subMenu\n  ) {\n    subMenu.mouseInChild.value = false;\n    return;\n  }\n\n  timer.value && window.clearTimeout(timer.value);\n\n  if (subMenu) {\n    subMenu.mouseInChild.value = false;\n  }\n  timer.value = setTimeout(() => {\n    !mouseInChild.value && rootMenu?.closeMenu(props.path, parentPaths.value);\n  }, 300);\n\n  if (deepDispatch) {\n    subMenu?.handleMouseleave?.(true);\n  }\n}\n\nconst menuIcon = computed(() =>\n  active.value ? props.activeIcon || props.icon : props.icon,\n);\n\nconst item = reactive({\n  active,\n  parentPaths,\n  path: props.path,\n});\n\nonMounted(() => {\n  subMenu?.addSubMenu?.(item);\n  rootMenu?.addSubMenu?.(item);\n});\n\nonBeforeUnmount(() => {\n  subMenu?.removeSubMenu?.(item);\n  rootMenu?.removeSubMenu?.(item);\n});\n</script>\n<template>\n  <li\n    :class=\"[\n      b(),\n      is('opened', opened),\n      is('active', active),\n      is('disabled', disabled),\n    ]\"\n    @focus=\"handleMouseenter\"\n    @mouseenter=\"handleMouseenter\"\n    @mouseleave=\"() => handleMouseleave()\"\n  >\n    <template v-if=\"rootMenu.isMenuPopup\">\n      <VbenHoverCard\n        :content-class=\"[\n          rootMenu.theme,\n          nsMenu.e('popup-container'),\n          is(rootMenu.theme, true),\n          opened ? '' : 'hidden',\n          'overflow-auto',\n          'max-h-[calc(var(--radix-hover-card-content-available-height)-20px)]',\n        ]\"\n        :content-props=\"contentProps\"\n        :open=\"true\"\n        :open-delay=\"0\"\n      >\n        <template #trigger>\n          <SubMenuContent\n            :class=\"is('active', active)\"\n            :icon=\"menuIcon\"\n            :is-menu-more=\"isSubMenuMore\"\n            :is-top-level-menu-submenu=\"isTopLevelMenuSubmenu\"\n            :level=\"currentLevel\"\n            :path=\"path\"\n            @click.stop=\"handleClick\"\n          >\n            <template #title>\n              <slot name=\"title\"></slot>\n            </template>\n          </SubMenuContent>\n        </template>\n        <div\n          :class=\"[nsMenu.is(mode, true), nsMenu.e('popup')]\"\n          @focus=\"(e) => handleMouseenter(e, 100)\"\n          @mouseenter=\"(e) => handleMouseenter(e, 100)\"\n          @mouseleave=\"() => handleMouseleave(true)\"\n        >\n          <ul\n            :class=\"[nsMenu.b(), is('rounded', rounded)]\"\n            :style=\"subMenuStyle\"\n          >\n            <slot></slot>\n          </ul>\n        </div>\n      </VbenHoverCard>\n    </template>\n\n    <template v-else>\n      <SubMenuContent\n        :class=\"is('active', active)\"\n        :icon=\"menuIcon\"\n        :is-menu-more=\"isSubMenuMore\"\n        :is-top-level-menu-submenu=\"isTopLevelMenuSubmenu\"\n        :level=\"currentLevel\"\n        :path=\"path\"\n        @click.stop=\"handleClick\"\n      >\n        <slot name=\"content\"></slot>\n        <template #title>\n          <slot name=\"title\"></slot>\n        </template>\n      </SubMenuContent>\n      <CollapseTransition>\n        <ul\n          v-show=\"opened\"\n          :class=\"[nsMenu.b(), is('rounded', rounded)]\"\n          :style=\"subMenuStyle\"\n        >\n          <slot></slot>\n        </ul>\n      </CollapseTransition>\n    </template>\n  </li>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/hooks/index.ts",
    "content": "export * from './use-menu';\nexport * from './use-menu-context';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts",
    "content": "import type { MenuProvider, SubMenuProvider } from '../types';\n\nimport { getCurrentInstance, inject, provide } from 'vue';\n\nimport { findComponentUpward } from '../utils';\n\nconst menuContextKey = Symbol('menuContext');\n\n/**\n * @zh_CN Provide menu context\n */\nfunction createMenuContext(injectMenuData: MenuProvider) {\n  provide(menuContextKey, injectMenuData);\n}\n\n/**\n * @zh_CN Provide menu context\n */\nfunction createSubMenuContext(injectSubMenuData: SubMenuProvider) {\n  const instance = getCurrentInstance();\n\n  provide(`subMenu:${instance?.uid}`, injectSubMenuData);\n}\n\n/**\n * @zh_CN Inject menu context\n */\nfunction useMenuContext() {\n  const instance = getCurrentInstance();\n  if (!instance) {\n    throw new Error('instance is required');\n  }\n  const rootMenu = inject(menuContextKey) as MenuProvider;\n  return rootMenu;\n}\n\n/**\n * @zh_CN Inject menu context\n */\nfunction useSubMenuContext() {\n  const instance = getCurrentInstance();\n  if (!instance) {\n    throw new Error('instance is required');\n  }\n  const parentMenu = findComponentUpward(instance, ['Menu', 'SubMenu']);\n  const subMenu = inject(`subMenu:${parentMenu?.uid}`) as SubMenuProvider;\n  return subMenu;\n}\n\nexport {\n  createMenuContext,\n  createSubMenuContext,\n  useMenuContext,\n  useSubMenuContext,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-scroll.ts",
    "content": "import type { Ref } from 'vue';\n\nimport { watch } from 'vue';\n\nimport { useDebounceFn } from '@vueuse/core';\n\ninterface UseMenuScrollOptions {\n  delay?: number;\n  enable?: boolean | Ref<boolean>;\n}\n\nexport function useMenuScroll(\n  activePath: Ref<string | undefined>,\n  options: UseMenuScrollOptions = {},\n) {\n  const { enable = true, delay = 320 } = options;\n\n  function scrollToActiveItem() {\n    const isEnabled = typeof enable === 'boolean' ? enable : enable.value;\n    if (!isEnabled) return;\n\n    const activeElement = document.querySelector(\n      `aside li[role=menuitem].is-active`,\n    );\n    if (activeElement) {\n      activeElement.scrollIntoView({\n        behavior: 'smooth',\n        block: 'center',\n        inline: 'center',\n      });\n    }\n  }\n\n  const debouncedScroll = useDebounceFn(scrollToActiveItem, delay);\n\n  watch(activePath, () => {\n    const isEnabled = typeof enable === 'boolean' ? enable : enable.value;\n    if (!isEnabled) return;\n\n    debouncedScroll();\n  });\n\n  return {\n    scrollToActiveItem,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts",
    "content": "import type { SubMenuProvider } from '../types';\n\nimport { computed, getCurrentInstance } from 'vue';\n\nimport { findComponentUpward } from '../utils';\n\nfunction useMenu() {\n  const instance = getCurrentInstance();\n  if (!instance) {\n    throw new Error('instance is required');\n  }\n\n  /**\n   * @zh_CN 获取所有父级菜单链路\n   */\n  const parentPaths = computed(() => {\n    let parent = instance.parent;\n    const paths: string[] = [instance.props.path as string];\n    while (parent?.type.name !== 'Menu') {\n      if (parent?.props.path) {\n        paths.unshift(parent.props.path as string);\n      }\n      parent = parent?.parent ?? null;\n    }\n\n    return paths;\n  });\n\n  const parentMenu = computed(() => {\n    return findComponentUpward(instance, ['Menu', 'SubMenu']);\n  });\n\n  return {\n    parentMenu,\n    parentPaths,\n  };\n}\n\nfunction useMenuStyle(menu?: SubMenuProvider) {\n  const subMenuStyle = computed(() => {\n    return {\n      '--menu-level': menu ? (menu?.level ?? 0 + 1) : 0,\n    };\n  });\n  return subMenuStyle;\n}\n\nexport { useMenu, useMenuStyle };\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/index.ts",
    "content": "export { default as MenuBadge } from './components/menu-badge.vue';\nexport * from './components/normal-menu';\nexport { default as Menu } from './menu.vue';\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/menu.vue",
    "content": "<script setup lang=\"ts\">\nimport type { MenuRecordRaw } from '@vben-core/typings';\n\nimport type { MenuProps } from './types';\n\nimport { useForwardProps } from '@vben-core/composables';\n\nimport { Menu } from './components';\nimport SubMenu from './sub-menu.vue';\n\ninterface Props extends MenuProps {\n  menus: MenuRecordRaw[];\n}\n\ndefineOptions({\n  name: 'MenuView',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  collapse: false,\n});\n\nconst forward = useForwardProps(props);\n</script>\n\n<template>\n  <Menu v-bind=\"forward\">\n    <template v-for=\"menu in menus\" :key=\"menu.path\">\n      <SubMenu :menu=\"menu\" />\n    </template>\n  </Menu>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/sub-menu.vue",
    "content": "<script setup lang=\"ts\">\nimport type { MenuRecordRaw } from '@vben-core/typings';\n\nimport { computed } from 'vue';\n\nimport { MenuBadge, MenuItem, SubMenu as SubMenuComp } from './components';\n// eslint-disable-next-line import/no-self-import\nimport SubMenu from './sub-menu.vue';\n\ninterface Props {\n  /**\n   * 菜单项\n   */\n  menu: MenuRecordRaw;\n}\n\ndefineOptions({\n  name: 'SubMenuUi',\n});\n\nconst props = withDefaults(defineProps<Props>(), {});\n\n/**\n * 判断是否有子节点，动态渲染 menu-item/sub-menu-item\n */\nconst hasChildren = computed(() => {\n  const { menu } = props;\n  return (\n    Reflect.has(menu, 'children') && !!menu.children && menu.children.length > 0\n  );\n});\n</script>\n\n<template>\n  <MenuItem\n    v-if=\"!hasChildren\"\n    :key=\"menu.path\"\n    :active-icon=\"menu.activeIcon\"\n    :badge=\"menu.badge\"\n    :badge-type=\"menu.badgeType\"\n    :badge-variants=\"menu.badgeVariants\"\n    :icon=\"menu.icon\"\n    :path=\"menu.path\"\n  >\n    <template #title>\n      <span>{{ menu.name }}</span>\n    </template>\n  </MenuItem>\n  <SubMenuComp\n    v-else\n    :key=\"`${menu.path}_sub`\"\n    :active-icon=\"menu.activeIcon\"\n    :icon=\"menu.icon\"\n    :path=\"menu.path\"\n  >\n    <template #content>\n      <MenuBadge\n        :badge=\"menu.badge\"\n        :badge-type=\"menu.badgeType\"\n        :badge-variants=\"menu.badgeVariants\"\n        class=\"right-6\"\n      />\n    </template>\n    <template #title>\n      <span>{{ menu.name }}</span>\n    </template>\n    <template v-for=\"childItem in menu.children || []\" :key=\"childItem.path\">\n      <SubMenu :menu=\"childItem\" />\n    </template>\n  </SubMenuComp>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/types.ts",
    "content": "import type { Component, Ref } from 'vue';\n\nimport type { MenuRecordBadgeRaw, ThemeModeType } from '@vben-core/typings';\n\ninterface MenuProps {\n  /**\n   * @zh_CN 是否开启手风琴模式\n   * @default true\n   */\n  accordion?: boolean;\n  /**\n   * @zh_CN 菜单是否折叠\n   * @default false\n   */\n  collapse?: boolean;\n\n  /**\n   * @zh_CN 菜单折叠时是否显示菜单名称\n   * @default false\n   */\n  collapseShowTitle?: boolean;\n\n  /**\n   * @zh_CN 默认激活的菜单\n   */\n  defaultActive?: string;\n\n  /**\n   * @zh_CN 默认展开的菜单\n   */\n  defaultOpeneds?: string[];\n\n  /**\n   * @zh_CN 菜单模式\n   * @default vertical\n   */\n  mode?: 'horizontal' | 'vertical';\n\n  /**\n   * @zh_CN 是否圆润风格\n   * @default true\n   */\n  rounded?: boolean;\n\n  /**\n   * @zh_CN 是否自动滚动到激活的菜单项\n   * @default false\n   */\n  scrollToActive?: boolean;\n\n  /**\n   * @zh_CN 菜单主题\n   * @default dark\n   */\n  theme?: ThemeModeType;\n}\n\ninterface SubMenuProps extends MenuRecordBadgeRaw {\n  /**\n   * @zh_CN 激活图标\n   */\n  activeIcon?: string;\n  /**\n   * @zh_CN 是否禁用\n   */\n  disabled?: boolean;\n  /**\n   * @zh_CN 图标\n   */\n  icon?: Component | string;\n  /**\n   * @zh_CN submenu 名称\n   */\n  path: string;\n}\n\ninterface MenuItemProps extends MenuRecordBadgeRaw {\n  /**\n   * @zh_CN 图标\n   */\n  activeIcon?: string;\n  /**\n   * @zh_CN 是否禁用\n   */\n  disabled?: boolean;\n  /**\n   * @zh_CN 图标\n   */\n  icon?: Component | string;\n  /**\n   * @zh_CN menuitem 名称\n   */\n  path: string;\n}\n\ninterface MenuItemRegistered {\n  active: boolean;\n  parentPaths: string[];\n  path: string;\n}\n\ninterface MenuItemClicked {\n  parentPaths: string[];\n  path: string;\n}\n\ninterface MenuProvider {\n  activePath?: string;\n  addMenuItem: (item: MenuItemRegistered) => void;\n\n  addSubMenu: (item: MenuItemRegistered) => void;\n  closeMenu: (path: string, parentLinks: string[]) => void;\n  handleMenuItemClick: (item: MenuItemClicked) => void;\n  handleSubMenuClick: (subMenu: MenuItemRegistered) => void;\n  isMenuPopup: boolean;\n  items: Record<string, MenuItemRegistered>;\n\n  openedMenus: string[];\n  openMenu: (path: string, parentLinks: string[]) => void;\n  props: MenuProps;\n  removeMenuItem: (item: MenuItemRegistered) => void;\n\n  removeSubMenu: (item: MenuItemRegistered) => void;\n\n  subMenus: Record<string, MenuItemRegistered>;\n  theme: string;\n}\n\ninterface SubMenuProvider {\n  addSubMenu: (item: MenuItemRegistered) => void;\n  handleMouseleave?: (deepDispatch: boolean) => void;\n  level: number;\n  mouseInChild: Ref<boolean>;\n  removeSubMenu: (item: MenuItemRegistered) => void;\n}\n\nexport type {\n  MenuItemClicked,\n  MenuItemProps,\n  MenuItemRegistered,\n  MenuProps,\n  MenuProvider,\n  SubMenuProps,\n  SubMenuProvider,\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/src/utils/index.ts",
    "content": "import type {\n  ComponentInternalInstance,\n  VNode,\n  VNodeChild,\n  VNodeNormalizedChildren,\n} from 'vue';\n\nimport { isVNode } from 'vue';\n\ntype VNodeChildAtom = Exclude<VNodeChild, Array<any>>;\ntype RawSlots = Exclude<VNodeNormalizedChildren, Array<any> | null | string>;\n\ntype FlattenVNodes = Array<RawSlots | VNodeChildAtom>;\n\n/**\n * @zh_CN Find the parent component upward\n * @param instance\n * @param parentNames\n */\nfunction findComponentUpward(\n  instance: ComponentInternalInstance,\n  parentNames: string[],\n) {\n  let parent = instance.parent;\n  while (parent && !parentNames.includes(parent?.type?.name ?? '')) {\n    parent = parent.parent;\n  }\n  return parent;\n}\n\nconst flattedChildren = (\n  children: FlattenVNodes | VNode | VNodeNormalizedChildren,\n): FlattenVNodes => {\n  const vNodes = Array.isArray(children) ? children : [children];\n  const result: FlattenVNodes = [];\n\n  vNodes.forEach((child) => {\n    if (Array.isArray(child)) {\n      result.push(...flattedChildren(child));\n    } else if (isVNode(child) && Array.isArray(child.children)) {\n      result.push(...flattedChildren(child.children));\n    } else {\n      result.push(child);\n      if (isVNode(child) && child.component?.subTree) {\n        result.push(...flattedChildren(child.component.subTree));\n      }\n    }\n  });\n  return result;\n};\n\nexport { findComponentUpward, flattedChildren };\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/menu-ui/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: [\n    {\n      builder: 'mkdist',\n      input: './src',\n      loaders: ['vue'],\n      pattern: ['**/*.vue'],\n    },\n    {\n      builder: 'mkdist',\n      format: 'esm',\n      input: './src',\n      loaders: ['js'],\n      pattern: ['**/*.ts'],\n    },\n  ],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/package.json",
    "content": "{\n  \"name\": \"@vben-core/popup-ui\",\n  \"version\": \"5.2.1\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/uikit/popup-ui\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/composables\": \"workspace:*\",\n    \"@vben-core/icons\": \"workspace:*\",\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts",
    "content": "import type { Component, VNode } from 'vue';\n\nimport type { Recordable } from '@vben-core/typings';\n\nimport type { AlertProps, BeforeCloseScope, PromptProps } from './alert';\n\nimport { h, nextTick, ref, render } from 'vue';\n\nimport { useSimpleLocale } from '@vben-core/composables';\nimport { Input, VbenRenderContent } from '@vben-core/shadcn-ui';\nimport { isFunction, isString } from '@vben-core/shared/utils';\n\nimport Alert from './alert.vue';\n\nconst alerts = ref<Array<{ container: HTMLElement; instance: Component }>>([]);\n\nconst { $t } = useSimpleLocale();\n\nexport function vbenAlert(options: AlertProps): Promise<void>;\nexport function vbenAlert(\n  message: string,\n  options?: Partial<AlertProps>,\n): Promise<void>;\nexport function vbenAlert(\n  message: string,\n  title?: string,\n  options?: Partial<AlertProps>,\n): Promise<void>;\n\nexport function vbenAlert(\n  arg0: AlertProps | string,\n  arg1?: Partial<AlertProps> | string,\n  arg2?: Partial<AlertProps>,\n): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const options: AlertProps = isString(arg0)\n      ? {\n          content: arg0,\n        }\n      : { ...arg0 };\n    if (arg1) {\n      if (isString(arg1)) {\n        options.title = arg1;\n      } else if (!isString(arg1)) {\n        // 如果第二个参数是对象，则合并到选项中\n        Object.assign(options, arg1);\n      }\n    }\n\n    if (arg2 && !isString(arg2)) {\n      Object.assign(options, arg2);\n    }\n    // 创建容器元素\n    const container = document.createElement('div');\n    document.body.append(container);\n\n    // 创建一个引用，用于在回调中访问实例\n    const alertRef = { container, instance: null as any };\n\n    const props: AlertProps & Recordable<any> = {\n      onClosed: (isConfirm: boolean) => {\n        // 移除组件实例以及创建的所有dom（恢复页面到打开前的状态）\n        // 从alerts数组中移除该实例\n        alerts.value = alerts.value.filter((item) => item !== alertRef);\n\n        // 从DOM中移除容器\n        render(null, container);\n        if (container.parentNode) {\n          container.remove();\n        }\n\n        // 解析 Promise，传递用户操作结果\n        if (isConfirm) {\n          resolve();\n        } else {\n          reject(new Error('dialog cancelled'));\n        }\n      },\n      ...options,\n      open: true,\n      title: options.title ?? $t.value('prompt'),\n    };\n\n    // 创建Alert组件的VNode\n    const vnode = h(Alert, props);\n\n    // 渲染组件到容器\n    render(vnode, container);\n\n    // 保存组件实例引用\n    alertRef.instance = vnode.component?.proxy as Component;\n\n    // 将实例和容器添加到alerts数组中\n    alerts.value.push(alertRef);\n  });\n}\n\nexport function vbenConfirm(options: AlertProps): Promise<void>;\nexport function vbenConfirm(\n  message: string,\n  options?: Partial<AlertProps>,\n): Promise<void>;\nexport function vbenConfirm(\n  message: string,\n  title?: string,\n  options?: Partial<AlertProps>,\n): Promise<void>;\n\nexport function vbenConfirm(\n  arg0: AlertProps | string,\n  arg1?: Partial<AlertProps> | string,\n  arg2?: Partial<AlertProps>,\n): Promise<void> {\n  const defaultProps: Partial<AlertProps> = {\n    showCancel: true,\n  };\n  if (!arg1) {\n    return isString(arg0)\n      ? vbenAlert(arg0, defaultProps)\n      : vbenAlert({ ...defaultProps, ...arg0 });\n  } else if (!arg2) {\n    return isString(arg1)\n      ? vbenAlert(arg0 as string, arg1, defaultProps)\n      : vbenAlert(arg0 as string, { ...defaultProps, ...arg1 });\n  }\n  return vbenAlert(arg0 as string, arg1 as string, {\n    ...defaultProps,\n    ...arg2,\n  });\n}\n\nexport async function vbenPrompt<T = any>(\n  options: PromptProps<T>,\n): Promise<T | undefined> {\n  const {\n    component: _component,\n    componentProps: _componentProps,\n    componentSlots,\n    content,\n    defaultValue,\n    modelPropName: _modelPropName,\n    ...delegated\n  } = options;\n\n  const modelValue = ref<T | undefined>(defaultValue);\n  const inputComponentRef = ref<null | VNode>(null);\n  const staticContents: Component[] = [];\n\n  staticContents.push(h(VbenRenderContent, { content, renderBr: true }));\n\n  const modelPropName = _modelPropName || 'modelValue';\n  const componentProps = { ..._componentProps };\n\n  // 每次渲染时都会重新计算的内容函数\n  const contentRenderer = () => {\n    const currentProps = { ...componentProps };\n\n    // 设置当前值\n    currentProps[modelPropName] = modelValue.value;\n\n    // 设置更新处理函数\n    currentProps[`onUpdate:${modelPropName}`] = (val: T) => {\n      modelValue.value = val;\n    };\n\n    // 创建输入组件\n    inputComponentRef.value = h(\n      _component || Input,\n      currentProps,\n      componentSlots,\n    );\n\n    // 返回包含静态内容和输入组件的数组\n    return h(\n      'div',\n      { class: 'flex flex-col gap-2' },\n      { default: () => [...staticContents, inputComponentRef.value] },\n    );\n  };\n\n  const props: AlertProps & Recordable<any> = {\n    ...delegated,\n    async beforeClose(scope: BeforeCloseScope) {\n      if (delegated.beforeClose) {\n        return await delegated.beforeClose({\n          ...scope,\n          value: modelValue.value,\n        });\n      }\n    },\n    // 使用函数形式，每次渲染都会重新计算内容\n    content: contentRenderer,\n    contentMasking: true,\n    async onOpened() {\n      await nextTick();\n      const componentRef: null | VNode = inputComponentRef.value;\n      if (componentRef) {\n        if (\n          componentRef.component?.exposed &&\n          isFunction(componentRef.component.exposed.focus)\n        ) {\n          componentRef.component.exposed.focus();\n        } else {\n          if (componentRef.el) {\n            if (\n              isFunction(componentRef.el.focus) &&\n              ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'].includes(\n                componentRef.el.tagName,\n              )\n            ) {\n              componentRef.el.focus();\n            } else if (isFunction(componentRef.el.querySelector)) {\n              const focusableElement = componentRef.el.querySelector(\n                'input, select, textarea, button',\n              );\n              if (focusableElement && isFunction(focusableElement.focus)) {\n                focusableElement.focus();\n              }\n            } else if (\n              componentRef.el.nextElementSibling &&\n              isFunction(componentRef.el.nextElementSibling.focus)\n            ) {\n              componentRef.el.nextElementSibling.focus();\n            }\n          }\n        }\n      }\n    },\n  };\n\n  await vbenConfirm(props);\n  return modelValue.value;\n}\n\nexport function clearAllAlerts() {\n  alerts.value.forEach((alert) => {\n    // 从DOM中移除容器\n    render(null, alert.container);\n    if (alert.container.parentNode) {\n      alert.container.remove();\n    }\n  });\n  alerts.value = [];\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/alert/alert.ts",
    "content": "import type { Component, VNode, VNodeArrayChildren } from 'vue';\n\nimport type { Recordable } from '@vben-core/typings';\n\nimport { createContext } from '@vben-core/shadcn-ui';\n\nexport type IconType = 'error' | 'info' | 'question' | 'success' | 'warning';\n\nexport type BeforeCloseScope = {\n  isConfirm: boolean;\n};\n\nexport type AlertProps = {\n  /** 关闭前的回调，如果返回false，则终止关闭 */\n  beforeClose?: (\n    scope: BeforeCloseScope,\n  ) => boolean | Promise<boolean | undefined> | undefined;\n  /** 边框 */\n  bordered?: boolean;\n  /**\n   * 按钮对齐方式\n   * @default 'end'\n   */\n  buttonAlign?: 'center' | 'end' | 'start';\n  /** 取消按钮的标题 */\n  cancelText?: string;\n  /** 是否居中显示 */\n  centered?: boolean;\n  /** 确认按钮的标题 */\n  confirmText?: string;\n  /** 弹窗容器的额外样式 */\n  containerClass?: string;\n  /** 弹窗提示内容 */\n  content: Component | string;\n  /** 弹窗内容的额外样式 */\n  contentClass?: string;\n  /** 执行beforeClose回调期间，在内容区域显示一个loading遮罩*/\n  contentMasking?: boolean;\n  /** 弹窗底部内容（与按钮在同一个容器中） */\n  footer?: Component | string;\n  /** 弹窗的图标（在标题的前面） */\n  icon?: Component | IconType;\n  /**\n   * 弹窗遮罩模糊效果\n   */\n  overlayBlur?: number;\n  /** 是否显示取消按钮 */\n  showCancel?: boolean;\n  /** 弹窗标题 */\n  title?: string;\n};\n\n/** Prompt属性 */\nexport type PromptProps<T = any> = {\n  /** 关闭前的回调，如果返回false，则终止关闭 */\n  beforeClose?: (scope: {\n    isConfirm: boolean;\n    value: T | undefined;\n  }) => boolean | Promise<boolean | undefined> | undefined;\n  /** 用于接受用户输入的组件 */\n  component?: Component;\n  /** 输入组件的属性 */\n  componentProps?: Recordable<any>;\n  /** 输入组件的插槽 */\n  componentSlots?:\n    | (() => any)\n    | Recordable<unknown>\n    | VNode\n    | VNodeArrayChildren;\n  /** 默认值 */\n  defaultValue?: T;\n  /** 输入组件的值属性名 */\n  modelPropName?: string;\n} & Omit<AlertProps, 'beforeClose'>;\n\n/**\n * Alert上下文\n */\nexport type AlertContext = {\n  /** 执行取消操作 */\n  doCancel: () => void;\n  /** 执行确认操作 */\n  doConfirm: () => void;\n};\n\nexport const [injectAlertContext, provideAlertContext] =\n  createContext<AlertContext>('VbenAlertContext');\n\n/**\n * 获取Alert上下文\n * @returns AlertContext\n */\nexport function useAlertContext() {\n  const context = injectAlertContext();\n  if (!context) {\n    throw new Error('useAlertContext must be used within an AlertProvider');\n  }\n  return context;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/alert/alert.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Component } from 'vue';\n\nimport type { AlertProps } from './alert';\n\nimport { computed, h, nextTick, ref } from 'vue';\n\nimport { useSimpleLocale } from '@vben-core/composables';\nimport {\n  CircleAlert,\n  CircleCheckBig,\n  CircleHelp,\n  CircleX,\n  Info,\n  X,\n} from '@vben-core/icons';\nimport {\n  AlertDialog,\n  AlertDialogAction,\n  AlertDialogCancel,\n  AlertDialogContent,\n  AlertDialogDescription,\n  AlertDialogTitle,\n  VbenButton,\n  VbenLoading,\n  VbenRenderContent,\n} from '@vben-core/shadcn-ui';\nimport { globalShareState } from '@vben-core/shared/global-state';\nimport { cn } from '@vben-core/shared/utils';\n\nimport { provideAlertContext } from './alert';\n\nconst props = withDefaults(defineProps<AlertProps>(), {\n  bordered: true,\n  buttonAlign: 'end',\n  centered: true,\n});\nconst emits = defineEmits(['closed', 'confirm', 'opened']);\nconst open = defineModel<boolean>('open', { default: false });\nconst { $t } = useSimpleLocale();\nconst components = globalShareState.getComponents();\nconst isConfirm = ref(false);\n\nfunction onAlertClosed() {\n  emits('closed', isConfirm.value);\n  isConfirm.value = false;\n}\n\nfunction onEscapeKeyDown() {\n  isConfirm.value = false;\n}\n\nconst getIconRender = computed(() => {\n  let iconRender: Component | null = null;\n  if (props.icon) {\n    if (typeof props.icon === 'string') {\n      switch (props.icon) {\n        case 'error': {\n          iconRender = h(CircleX, {\n            style: { color: 'hsl(var(--destructive))' },\n          });\n          break;\n        }\n        case 'info': {\n          iconRender = h(Info, { style: { color: 'hsl(var(--info))' } });\n          break;\n        }\n        case 'question': {\n          iconRender = CircleHelp;\n          break;\n        }\n        case 'success': {\n          iconRender = h(CircleCheckBig, {\n            style: { color: 'hsl(var(--success))' },\n          });\n          break;\n        }\n        case 'warning': {\n          iconRender = h(CircleAlert, {\n            style: { color: 'hsl(var(--warning))' },\n          });\n          break;\n        }\n        default: {\n          iconRender = null;\n          break;\n        }\n      }\n    }\n  } else {\n    iconRender = props.icon ?? null;\n  }\n  return iconRender;\n});\n\nfunction doCancel() {\n  handleCancel();\n  handleOpenChange(false);\n}\n\nfunction doConfirm() {\n  handleConfirm();\n  handleOpenChange(false);\n}\n\nprovideAlertContext({\n  doCancel,\n  doConfirm,\n});\n\nfunction handleConfirm() {\n  isConfirm.value = true;\n  emits('confirm');\n}\n\nfunction handleCancel() {\n  isConfirm.value = false;\n}\n\nconst loading = ref(false);\nasync function handleOpenChange(val: boolean) {\n  await nextTick(); // 等待标记isConfirm状态\n  if (!val && props.beforeClose) {\n    loading.value = true;\n    try {\n      const res = await props.beforeClose({ isConfirm: isConfirm.value });\n      if (res !== false) {\n        open.value = false;\n      }\n    } finally {\n      loading.value = false;\n    }\n  } else {\n    open.value = val;\n  }\n}\n</script>\n<template>\n  <AlertDialog :open=\"open\" @update:open=\"handleOpenChange\">\n    <AlertDialogContent\n      :open=\"open\"\n      :centered=\"centered\"\n      :overlay-blur=\"overlayBlur\"\n      @opened=\"emits('opened')\"\n      @closed=\"onAlertClosed\"\n      @escape-key-down=\"onEscapeKeyDown\"\n      :class=\"\n        cn(\n          containerClass,\n          'left-0 right-0 mx-auto flex max-h-[80%] flex-col p-0 duration-300 sm:w-[520px] sm:max-w-[80%] sm:rounded-[var(--radius)]',\n          {\n            'border-border border': bordered,\n            'shadow-3xl': !bordered,\n          },\n        )\n      \"\n    >\n      <div :class=\"cn('relative flex-1 overflow-y-auto p-3', contentClass)\">\n        <AlertDialogTitle v-if=\"title\">\n          <div class=\"flex items-center\">\n            <component :is=\"getIconRender\" class=\"mr-2\" />\n            <span class=\"flex-auto\">{{ $t(title) }}</span>\n            <AlertDialogCancel v-if=\"showCancel\" as-child>\n              <VbenButton\n                variant=\"ghost\"\n                size=\"icon\"\n                class=\"rounded-full\"\n                :disabled=\"loading\"\n                @click=\"handleCancel\"\n              >\n                <X class=\"text-muted-foreground size-4\" />\n              </VbenButton>\n            </AlertDialogCancel>\n          </div>\n        </AlertDialogTitle>\n        <AlertDialogDescription>\n          <div class=\"m-4 min-h-[30px]\">\n            <VbenRenderContent :content=\"content\" render-br />\n          </div>\n          <VbenLoading v-if=\"loading && contentMasking\" :spinning=\"loading\" />\n        </AlertDialogDescription>\n        <div\n          class=\"flex items-center justify-end gap-x-2\"\n          :class=\"`justify-${buttonAlign}`\"\n        >\n          <VbenRenderContent :content=\"footer\" />\n          <AlertDialogCancel v-if=\"showCancel\" as-child>\n            <component\n              :is=\"components.DefaultButton || VbenButton\"\n              :disabled=\"loading\"\n              variant=\"ghost\"\n              @click=\"handleCancel\"\n            >\n              {{ cancelText || $t('cancel') }}\n            </component>\n          </AlertDialogCancel>\n          <AlertDialogAction as-child>\n            <component\n              :is=\"components.PrimaryButton || VbenButton\"\n              :loading=\"loading\"\n              @click=\"handleConfirm\"\n            >\n              {{ confirmText || $t('confirm') }}\n            </component>\n          </AlertDialogAction>\n        </div>\n      </div>\n    </AlertDialogContent>\n  </AlertDialog>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/alert/index.ts",
    "content": "export type {\n  AlertProps,\n  BeforeCloseScope,\n  IconType,\n  PromptProps,\n} from './alert';\nexport { useAlertContext } from './alert';\nexport { default as Alert } from './alert.vue';\nexport {\n  vbenAlert as alert,\n  clearAllAlerts,\n  vbenConfirm as confirm,\n  vbenPrompt as prompt,\n} from './AlertBuilder';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts",
    "content": "import type { DrawerState } from '../drawer';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { DrawerApi } from '../drawer-api';\n\n// 模拟 Store 类\nvi.mock('@vben-core/shared/store', () => {\n  return {\n    isFunction: (fn: any) => typeof fn === 'function',\n    Store: class {\n      get state() {\n        return this._state;\n      }\n      private _state: DrawerState;\n\n      private options: any;\n\n      constructor(initialState: DrawerState, options: any) {\n        this._state = initialState;\n        this.options = options;\n      }\n\n      batch(cb: () => void) {\n        cb();\n      }\n\n      setState(fn: (prev: DrawerState) => DrawerState) {\n        this._state = fn(this._state);\n        this.options.onUpdate();\n      }\n    },\n  };\n});\n\ndescribe('drawerApi', () => {\n  let drawerApi: DrawerApi;\n  let drawerState: DrawerState;\n\n  beforeEach(() => {\n    drawerApi = new DrawerApi();\n    drawerState = drawerApi.store.state;\n  });\n\n  it('should initialize with default state', () => {\n    expect(drawerState.isOpen).toBe(false);\n    expect(drawerState.cancelText).toBe(undefined);\n    expect(drawerState.confirmText).toBe(undefined);\n  });\n\n  it('should open the drawer', () => {\n    drawerApi.open();\n    expect(drawerApi.store.state.isOpen).toBe(true);\n  });\n\n  it('should close the drawer if onBeforeClose allows it', () => {\n    drawerApi.close();\n    expect(drawerApi.store.state.isOpen).toBe(false);\n  });\n\n  it('should not close the drawer if onBeforeClose returns false', () => {\n    const onBeforeClose = vi.fn(() => false);\n    const drawerApiWithHook = new DrawerApi({ onBeforeClose });\n    drawerApiWithHook.open();\n    drawerApiWithHook.close();\n    expect(drawerApiWithHook.store.state.isOpen).toBe(true);\n    expect(onBeforeClose).toHaveBeenCalled();\n  });\n\n  it('should trigger onCancel and keep drawer open if onCancel is provided', () => {\n    const onCancel = vi.fn();\n    const drawerApiWithHook = new DrawerApi({ onCancel });\n    drawerApiWithHook.open();\n    drawerApiWithHook.onCancel();\n    expect(onCancel).toHaveBeenCalled();\n    expect(drawerApiWithHook.store.state.isOpen).toBe(true); // 关闭逻辑不在 onCancel 内\n  });\n\n  it('should update shared data correctly', () => {\n    const testData = { key: 'value' };\n    drawerApi.setData(testData);\n    expect(drawerApi.getData()).toEqual(testData);\n  });\n\n  it('should set state correctly using an object', () => {\n    drawerApi.setState({ title: 'New Title' });\n    expect(drawerApi.store.state.title).toBe('New Title');\n  });\n\n  it('should set state correctly using a function', () => {\n    drawerApi.setState((prev) => ({ ...prev, confirmText: 'Yes' }));\n    expect(drawerApi.store.state.confirmText).toBe('Yes');\n  });\n\n  it('should call onOpenChange when state changes', () => {\n    const onOpenChange = vi.fn();\n    const drawerApiWithHook = new DrawerApi({ onOpenChange });\n    drawerApiWithHook.open();\n    expect(onOpenChange).toHaveBeenCalledWith(true);\n  });\n\n  it('should call onClosed callback when provided', () => {\n    const onClosed = vi.fn();\n    const drawerApiWithHook = new DrawerApi({ onClosed });\n    drawerApiWithHook.onClosed();\n    expect(onClosed).toHaveBeenCalled();\n  });\n\n  it('should call onOpened callback when provided', () => {\n    const onOpened = vi.fn();\n    const drawerApiWithHook = new DrawerApi({ onOpened });\n    drawerApiWithHook.open();\n    drawerApiWithHook.onOpened();\n    expect(onOpened).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts",
    "content": "import type { DrawerApiOptions, DrawerState } from './drawer';\n\nimport { Store } from '@vben-core/shared/store';\nimport { bindMethods, isFunction } from '@vben-core/shared/utils';\n\nexport class DrawerApi {\n  // 共享数据\n  public sharedData: Record<'payload', any> = {\n    payload: {},\n  };\n  public store: Store<DrawerState>;\n\n  private api: Pick<\n    DrawerApiOptions,\n    | 'onBeforeClose'\n    | 'onCancel'\n    | 'onClosed'\n    | 'onConfirm'\n    | 'onOpenChange'\n    | 'onOpened'\n  >;\n\n  // private prevState!: DrawerState;\n  private state!: DrawerState;\n\n  constructor(options: DrawerApiOptions = {}) {\n    const {\n      connectedComponent: _,\n      onBeforeClose,\n      onCancel,\n      onClosed,\n      onConfirm,\n      onOpenChange,\n      onOpened,\n      ...storeState\n    } = options;\n\n    const defaultState: DrawerState = {\n      class: '',\n      closable: true,\n      closeIconPlacement: 'right',\n      closeOnClickModal: true,\n      closeOnPressEscape: true,\n      confirmLoading: false,\n      contentClass: '',\n      footer: true,\n      header: true,\n      isOpen: false,\n      loading: false,\n      modal: true,\n      openAutoFocus: false,\n      placement: 'right',\n      showCancelButton: true,\n      showConfirmButton: true,\n      submitting: false,\n      title: '',\n    };\n\n    this.store = new Store<DrawerState>(\n      {\n        ...defaultState,\n        ...storeState,\n      },\n      {\n        onUpdate: () => {\n          const state = this.store.state;\n          if (state?.isOpen === this.state?.isOpen) {\n            this.state = state;\n          } else {\n            this.state = state;\n            this.api.onOpenChange?.(!!state?.isOpen);\n          }\n        },\n      },\n    );\n    this.state = this.store.state;\n    this.api = {\n      onBeforeClose,\n      onCancel,\n      onClosed,\n      onConfirm,\n      onOpenChange,\n      onOpened,\n    };\n    bindMethods(this);\n  }\n\n  /**\n   * 关闭抽屉\n   * @description 关闭抽屉时会调用 onBeforeClose 钩子函数，如果 onBeforeClose 返回 false，则不关闭弹窗\n   */\n  async close() {\n    // 通过 onBeforeClose 钩子函数来判断是否允许关闭弹窗\n    // 如果 onBeforeClose 返回 false，则不关闭弹窗\n    const allowClose = (await this.api.onBeforeClose?.()) ?? true;\n    if (allowClose) {\n      this.store.setState((prev) => ({\n        ...prev,\n        isOpen: false,\n        submitting: false,\n      }));\n    }\n  }\n\n  getData<T extends object = Record<string, any>>() {\n    return (this.sharedData?.payload ?? {}) as T;\n  }\n\n  /**\n   * 锁定抽屉状态（用于提交过程中的等待状态）\n   * @description 锁定状态将禁用默认的取消按钮，使用spinner覆盖抽屉内容，隐藏关闭按钮，阻止手动关闭弹窗，将默认的提交按钮标记为loading状态\n   * @param isLocked 是否锁定\n   */\n  lock(isLocked: boolean = true) {\n    return this.setState({ submitting: isLocked });\n  }\n\n  /**\n   * 取消操作\n   */\n  onCancel() {\n    if (this.api.onCancel) {\n      this.api.onCancel?.();\n    } else {\n      this.close();\n    }\n  }\n\n  /**\n   * 弹窗关闭动画播放完毕后的回调\n   */\n  onClosed() {\n    if (!this.state.isOpen) {\n      this.api.onClosed?.();\n    }\n  }\n\n  /**\n   * 确认操作\n   */\n  onConfirm() {\n    this.api.onConfirm?.();\n  }\n\n  /**\n   * 弹窗打开动画播放完毕后的回调\n   */\n  onOpened() {\n    if (this.state.isOpen) {\n      this.api.onOpened?.();\n    }\n  }\n\n  open() {\n    this.store.setState((prev) => ({ ...prev, isOpen: true }));\n  }\n\n  setData<T>(payload: T) {\n    this.sharedData.payload = payload;\n    return this;\n  }\n\n  setState(\n    stateOrFn:\n      | ((prev: DrawerState) => Partial<DrawerState>)\n      | Partial<DrawerState>,\n  ) {\n    if (isFunction(stateOrFn)) {\n      this.store.setState(stateOrFn);\n    } else {\n      this.store.setState((prev) => ({ ...prev, ...stateOrFn }));\n    }\n    return this;\n  }\n\n  /**\n   * 解除抽屉的锁定状态\n   * @description 解除由lock方法设置的锁定状态，是lock(false)的别名\n   */\n  unlock() {\n    return this.lock(false);\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts",
    "content": "import type { Component, Ref } from 'vue';\n\nimport type { ClassType, MaybePromise } from '@vben-core/typings';\n\nimport type { DrawerApi } from './drawer-api';\n\nexport type DrawerPlacement = 'bottom' | 'left' | 'right' | 'top';\n\nexport type CloseIconPlacement = 'left' | 'right';\n\nexport interface DrawerProps {\n  /**\n   * 是否挂载到内容区域\n   * @default false\n   */\n  appendToMain?: boolean;\n  /**\n   * 取消按钮文字\n   */\n  cancelText?: string;\n  class?: ClassType;\n  /**\n   * 是否显示关闭按钮\n   * @default true\n   */\n  closable?: boolean;\n  /**\n   * 关闭按钮的位置\n   */\n  closeIconPlacement?: CloseIconPlacement;\n  /**\n   * 点击弹窗遮罩是否关闭弹窗\n   * @default true\n   */\n  closeOnClickModal?: boolean;\n  /**\n   * 按下 ESC 键是否关闭弹窗\n   * @default true\n   */\n  closeOnPressEscape?: boolean;\n  /**\n   * 确定按钮 loading\n   * @default false\n   */\n  confirmLoading?: boolean;\n  /**\n   * 确定按钮文字\n   */\n  confirmText?: string;\n  contentClass?: string;\n  /**\n   * 弹窗描述\n   */\n  description?: string;\n  /**\n   * 在关闭时销毁抽屉\n   */\n  destroyOnClose?: boolean;\n  /**\n   * 是否显示底部\n   * @default true\n   */\n  footer?: boolean;\n  /**\n   * 弹窗底部样式\n   */\n  footerClass?: ClassType;\n  /**\n   * 是否显示顶栏\n   * @default true\n   */\n  header?: boolean;\n  /**\n   * 弹窗头部样式\n   */\n  headerClass?: ClassType;\n  /**\n   * 弹窗是否显示\n   * @default false\n   */\n  loading?: boolean;\n  /**\n   * 是否显示遮罩\n   * @default true\n   */\n  modal?: boolean;\n\n  /**\n   * 是否自动聚焦\n   */\n  openAutoFocus?: boolean;\n  /**\n   * 弹窗遮罩模糊效果\n   */\n  overlayBlur?: number;\n  /**\n   * 抽屉位置\n   * @default right\n   */\n  placement?: DrawerPlacement;\n\n  /**\n   * 是否显示取消按钮\n   * @default true\n   */\n  showCancelButton?: boolean;\n  /**\n   * 是否显示确认按钮\n   * @default true\n   */\n  showConfirmButton?: boolean;\n  /**\n   * 提交中（锁定抽屉状态）\n   */\n  submitting?: boolean;\n  /**\n   * 弹窗标题\n   */\n  title?: string;\n  /**\n   * 弹窗标题提示\n   */\n  titleTooltip?: string;\n  /**\n   * 抽屉层级\n   */\n  zIndex?: number;\n}\n\nexport interface DrawerState extends DrawerProps {\n  /** 弹窗打开状态 */\n  isOpen?: boolean;\n  /**\n   * 共享数据\n   */\n  sharedData?: Record<string, any>;\n}\n\nexport type ExtendedDrawerApi = DrawerApi & {\n  useStore: <T = NoInfer<DrawerState>>(\n    selector?: (state: NoInfer<DrawerState>) => T,\n  ) => Readonly<Ref<T>>;\n};\n\nexport interface DrawerApiOptions extends DrawerState {\n  /**\n   * 独立的抽屉组件\n   */\n  connectedComponent?: Component;\n  /**\n   * 关闭前的回调，返回 false 可以阻止关闭\n   * @returns\n   */\n  onBeforeClose?: () => MaybePromise<boolean | undefined>;\n  /**\n   * 点击取消按钮的回调\n   */\n  onCancel?: () => void;\n  /**\n   * 弹窗关闭动画结束的回调\n   * @returns\n   */\n  onClosed?: () => void;\n  /**\n   * 点击确定按钮的回调\n   */\n  onConfirm?: () => void;\n  /**\n   * 弹窗状态变化回调\n   * @param isOpen\n   * @returns\n   */\n  onOpenChange?: (isOpen: boolean) => void;\n  /**\n   * 弹窗打开动画结束的回调\n   * @returns\n   */\n  onOpened?: () => void;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DrawerProps, ExtendedDrawerApi } from './drawer';\n\nimport {\n  computed,\n  onDeactivated,\n  provide,\n  ref,\n  unref,\n  useId,\n  watch,\n} from 'vue';\n\nimport {\n  useIsMobile,\n  usePriorityValues,\n  useSimpleLocale,\n} from '@vben-core/composables';\nimport { X } from '@vben-core/icons';\nimport {\n  Separator,\n  Sheet,\n  SheetClose,\n  SheetContent,\n  SheetDescription,\n  SheetFooter,\n  SheetHeader,\n  SheetTitle,\n  VbenButton,\n  VbenHelpTooltip,\n  VbenIconButton,\n  VbenLoading,\n  VisuallyHidden,\n} from '@vben-core/shadcn-ui';\nimport { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';\nimport { globalShareState } from '@vben-core/shared/global-state';\nimport { cn } from '@vben-core/shared/utils';\n\ninterface Props extends DrawerProps {\n  drawerApi?: ExtendedDrawerApi;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  appendToMain: false,\n  closeIconPlacement: 'right',\n  destroyOnClose: false,\n  drawerApi: undefined,\n  submitting: false,\n  zIndex: 1000,\n});\n\nconst components = globalShareState.getComponents();\n\nconst id = useId();\nprovide('DISMISSABLE_DRAWER_ID', id);\n\nconst wrapperRef = ref<HTMLElement>();\nconst { $t } = useSimpleLocale();\nconst { isMobile } = useIsMobile();\n\nconst state = props.drawerApi?.useStore?.();\n\nconst {\n  appendToMain,\n  cancelText,\n  class: drawerClass,\n  closable,\n  closeIconPlacement,\n  closeOnClickModal,\n  closeOnPressEscape,\n  confirmLoading,\n  confirmText,\n  contentClass,\n  description,\n  destroyOnClose,\n  footer: showFooter,\n  footerClass,\n  header: showHeader,\n  headerClass,\n  loading: showLoading,\n  modal,\n  openAutoFocus,\n  overlayBlur,\n  placement,\n  showCancelButton,\n  showConfirmButton,\n  submitting,\n  title,\n  titleTooltip,\n  zIndex,\n} = usePriorityValues(props, state);\n\n// watch(\n//   () => showLoading.value,\n//   (v) => {\n//     if (v && wrapperRef.value) {\n//       wrapperRef.value.scrollTo({\n//         // behavior: 'smooth',\n//         top: 0,\n//       });\n//     }\n//   },\n// );\n\n/**\n * 在开启keepAlive情况下 直接通过浏览器按钮/手势等返回 不会关闭弹窗\n */\nonDeactivated(() => {\n  // 如果弹窗没有被挂载到内容区域，则关闭弹窗\n  if (!appendToMain.value) {\n    props.drawerApi?.close();\n  }\n});\n\nfunction interactOutside(e: Event) {\n  if (!closeOnClickModal.value || submitting.value) {\n    e.preventDefault();\n  }\n}\nfunction escapeKeyDown(e: KeyboardEvent) {\n  if (!closeOnPressEscape.value || submitting.value) {\n    e.preventDefault();\n  }\n}\n// pointer-down-outside\nfunction pointerDownOutside(e: Event) {\n  const target = e.target as HTMLElement;\n  const dismissableDrawer = target?.dataset.dismissableDrawer;\n  if (\n    submitting.value ||\n    !closeOnClickModal.value ||\n    dismissableDrawer !== id\n  ) {\n    e.preventDefault();\n  }\n}\n\nfunction handerOpenAutoFocus(e: Event) {\n  if (!openAutoFocus.value) {\n    e?.preventDefault();\n  }\n}\n\nfunction handleFocusOutside(e: Event) {\n  e.preventDefault();\n  e.stopPropagation();\n}\n\nconst getAppendTo = computed(() => {\n  return appendToMain.value\n    ? `#${ELEMENT_ID_MAIN_CONTENT}>div:not(.absolute)>div`\n    : undefined;\n});\n\n/**\n * destroyOnClose功能完善\n */\n// 是否打开过\nconst hasOpened = ref(false);\nconst isClosed = ref(true);\nwatch(\n  () => state?.value?.isOpen,\n  (value) => {\n    isClosed.value = false;\n    if (value && !unref(hasOpened)) {\n      hasOpened.value = true;\n    }\n  },\n);\nfunction handleClosed() {\n  isClosed.value = true;\n  props.drawerApi?.onClosed();\n}\nconst getForceMount = computed(() => {\n  return !unref(destroyOnClose) && unref(hasOpened);\n});\n</script>\n<template>\n  <Sheet\n    :modal=\"false\"\n    :open=\"state?.isOpen\"\n    @update:open=\"() => drawerApi?.close()\"\n  >\n    <SheetContent\n      :append-to=\"getAppendTo\"\n      :class=\"\n        cn('flex w-[520px] flex-col', drawerClass, {\n          '!w-full': isMobile || placement === 'bottom' || placement === 'top',\n          'max-h-[100vh]': placement === 'bottom' || placement === 'top',\n          hidden: isClosed,\n        })\n      \"\n      :modal=\"modal\"\n      :open=\"state?.isOpen\"\n      :side=\"placement\"\n      :z-index=\"zIndex\"\n      :force-mount=\"getForceMount\"\n      :overlay-blur=\"overlayBlur\"\n      @close-auto-focus=\"handleFocusOutside\"\n      @closed=\"handleClosed\"\n      @escape-key-down=\"escapeKeyDown\"\n      @focus-outside=\"handleFocusOutside\"\n      @interact-outside=\"interactOutside\"\n      @open-auto-focus=\"handerOpenAutoFocus\"\n      @opened=\"() => drawerApi?.onOpened()\"\n      @pointer-down-outside=\"pointerDownOutside\"\n    >\n      <SheetHeader\n        v-if=\"showHeader\"\n        :class=\"\n          cn(\n            '!flex flex-row items-center justify-between border-b px-6 py-5',\n            headerClass,\n            {\n              'px-4 py-3': closable,\n              'pl-2': closable && closeIconPlacement === 'left',\n            },\n          )\n        \"\n      >\n        <div class=\"flex items-center\">\n          <SheetClose\n            v-if=\"closable && closeIconPlacement === 'left'\"\n            as-child\n            :disabled=\"submitting\"\n            class=\"data-[state=open]:bg-secondary ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none\"\n          >\n            <slot name=\"close-icon\">\n              <VbenIconButton>\n                <X class=\"size-4\" />\n              </VbenIconButton>\n            </slot>\n          </SheetClose>\n          <Separator\n            v-if=\"closable && closeIconPlacement === 'left'\"\n            class=\"ml-1 mr-2 h-8\"\n            decorative\n            orientation=\"vertical\"\n          />\n          <SheetTitle v-if=\"title\" class=\"text-left\">\n            <slot name=\"title\">\n              {{ title }}\n\n              <VbenHelpTooltip v-if=\"titleTooltip\" trigger-class=\"pb-1\">\n                {{ titleTooltip }}\n              </VbenHelpTooltip>\n            </slot>\n          </SheetTitle>\n          <SheetDescription v-if=\"description\" class=\"mt-1 text-xs\">\n            <slot name=\"description\">\n              {{ description }}\n            </slot>\n          </SheetDescription>\n        </div>\n\n        <VisuallyHidden v-if=\"!title || !description\">\n          <SheetTitle v-if=\"!title\" />\n          <SheetDescription v-if=\"!description\" />\n        </VisuallyHidden>\n\n        <div class=\"flex-center\">\n          <slot name=\"extra\"></slot>\n          <SheetClose\n            v-if=\"closable && closeIconPlacement === 'right'\"\n            as-child\n            :disabled=\"submitting\"\n            class=\"data-[state=open]:bg-secondary ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none\"\n          >\n            <slot name=\"close-icon\">\n              <VbenIconButton>\n                <X class=\"size-4\" />\n              </VbenIconButton>\n            </slot>\n          </SheetClose>\n        </div>\n      </SheetHeader>\n      <template v-else>\n        <VisuallyHidden>\n          <SheetTitle />\n          <SheetDescription />\n        </VisuallyHidden>\n      </template>\n      <div\n        ref=\"wrapperRef\"\n        :class=\"\n          cn('relative flex-1 overflow-y-auto p-3', contentClass, {\n            'pointer-events-none': showLoading || submitting,\n          })\n        \"\n      >\n        <slot></slot>\n      </div>\n      <VbenLoading v-if=\"showLoading || submitting\" spinning />\n      <SheetFooter\n        v-if=\"showFooter\"\n        :class=\"\n          cn(\n            'w-full flex-row items-center justify-end border-t p-2 px-3',\n            footerClass,\n          )\n        \"\n      >\n        <slot name=\"prepend-footer\"></slot>\n        <slot name=\"footer\">\n          <component\n            :is=\"components.DefaultButton || VbenButton\"\n            v-if=\"showCancelButton\"\n            variant=\"ghost\"\n            :disabled=\"submitting\"\n            @click=\"() => drawerApi?.onCancel()\"\n          >\n            <slot name=\"cancelText\">\n              {{ cancelText || $t('cancel') }}\n            </slot>\n          </component>\n          <slot name=\"center-footer\"></slot>\n          <component\n            :is=\"components.PrimaryButton || VbenButton\"\n            v-if=\"showConfirmButton\"\n            :loading=\"confirmLoading || submitting\"\n            @click=\"() => drawerApi?.onConfirm()\"\n          >\n            <slot name=\"confirmText\">\n              {{ confirmText || $t('confirm') }}\n            </slot>\n          </component>\n        </slot>\n        <slot name=\"append-footer\"></slot>\n      </SheetFooter>\n    </SheetContent>\n  </Sheet>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/drawer/index.ts",
    "content": "export type * from './drawer';\nexport { default as VbenDrawer } from './drawer.vue';\nexport { setDefaultDrawerProps, useVbenDrawer } from './use-drawer';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts",
    "content": "import type {\n  DrawerApiOptions,\n  DrawerProps,\n  ExtendedDrawerApi,\n} from './drawer';\n\nimport {\n  defineComponent,\n  h,\n  inject,\n  nextTick,\n  provide,\n  reactive,\n  ref,\n} from 'vue';\n\nimport { useStore } from '@vben-core/shared/store';\n\nimport { DrawerApi } from './drawer-api';\nimport VbenDrawer from './drawer.vue';\n\nconst USER_DRAWER_INJECT_KEY = Symbol('VBEN_DRAWER_INJECT');\n\nconst DEFAULT_DRAWER_PROPS: Partial<DrawerProps> = {};\n\nexport function setDefaultDrawerProps(props: Partial<DrawerProps>) {\n  Object.assign(DEFAULT_DRAWER_PROPS, props);\n}\n\nexport function useVbenDrawer<\n  TParentDrawerProps extends DrawerProps = DrawerProps,\n>(options: DrawerApiOptions = {}) {\n  // Drawer一般会抽离出来，所以如果有传入 connectedComponent，则表示为外部调用，与内部组件进行连接\n  // 外部的Drawer通过provide/inject传递api\n\n  const { connectedComponent } = options;\n  if (connectedComponent) {\n    const extendedApi = reactive({});\n    const isDrawerReady = ref(true);\n    const Drawer = defineComponent(\n      (props: TParentDrawerProps, { attrs, slots }) => {\n        provide(USER_DRAWER_INJECT_KEY, {\n          extendApi(api: ExtendedDrawerApi) {\n            // 不能直接给 reactive 赋值，会丢失响应\n            // 不能用 Object.assign,会丢失 api 的原型函数\n            Object.setPrototypeOf(extendedApi, api);\n          },\n          options,\n          async reCreateDrawer() {\n            isDrawerReady.value = false;\n            await nextTick();\n            isDrawerReady.value = true;\n          },\n        });\n        checkProps(extendedApi as ExtendedDrawerApi, {\n          ...props,\n          ...attrs,\n          ...slots,\n        });\n        return () =>\n          h(\n            isDrawerReady.value ? connectedComponent : 'div',\n            { ...props, ...attrs },\n            slots,\n          );\n      },\n      // eslint-disable-next-line vue/one-component-per-file\n      {\n        name: 'VbenParentDrawer',\n        inheritAttrs: false,\n      },\n    );\n\n    return [Drawer, extendedApi as ExtendedDrawerApi] as const;\n  }\n\n  const injectData = inject<any>(USER_DRAWER_INJECT_KEY, {});\n\n  const mergedOptions = {\n    ...DEFAULT_DRAWER_PROPS,\n    ...injectData.options,\n    ...options,\n  } as DrawerApiOptions;\n\n  mergedOptions.onOpenChange = (isOpen: boolean) => {\n    options.onOpenChange?.(isOpen);\n    injectData.options?.onOpenChange?.(isOpen);\n  };\n\n  const onClosed = mergedOptions.onClosed;\n  mergedOptions.onClosed = () => {\n    onClosed?.();\n    if (mergedOptions.destroyOnClose) {\n      injectData.reCreateDrawer?.();\n    }\n  };\n  const api = new DrawerApi(mergedOptions);\n\n  const extendedApi: ExtendedDrawerApi = api as never;\n\n  extendedApi.useStore = (selector) => {\n    return useStore(api.store, selector);\n  };\n\n  const Drawer = defineComponent(\n    (props: DrawerProps, { attrs, slots }) => {\n      return () =>\n        h(VbenDrawer, { ...props, ...attrs, drawerApi: extendedApi }, slots);\n    },\n    // eslint-disable-next-line vue/one-component-per-file\n    {\n      name: 'VbenDrawer',\n      inheritAttrs: false,\n    },\n  );\n  injectData.extendApi?.(extendedApi);\n  return [Drawer, extendedApi] as const;\n}\n\nasync function checkProps(api: ExtendedDrawerApi, attrs: Record<string, any>) {\n  if (!attrs || Object.keys(attrs).length === 0) {\n    return;\n  }\n  await nextTick();\n\n  const state = api?.store?.state;\n\n  if (!state) {\n    return;\n  }\n\n  const stateKeys = new Set(Object.keys(state));\n\n  for (const attr of Object.keys(attrs)) {\n    if (stateKeys.has(attr) && !['class'].includes(attr)) {\n      // connectedComponent存在时，不要传入Drawer的props，会造成复杂度提升，如果你需要修改Drawer的props，请使用 useVbenDrawer 或者api\n      console.warn(\n        `[Vben Drawer]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Drawer, please use useVbenDrawer or api.`,\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/index.ts",
    "content": "export * from './alert';\nexport * from './drawer';\nexport * from './modal';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts",
    "content": "import type { ModalState } from '../modal';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { ModalApi } from '../modal-api';\n\nvi.mock('@vben-core/shared/store', () => {\n  return {\n    isFunction: (fn: any) => typeof fn === 'function',\n    Store: class {\n      get state() {\n        return this._state;\n      }\n      private _state: ModalState;\n\n      private options: any;\n\n      constructor(initialState: ModalState, options: any) {\n        this._state = initialState;\n        this.options = options;\n      }\n\n      batch(cb: () => void) {\n        cb();\n      }\n\n      setState(fn: (prev: ModalState) => ModalState) {\n        this._state = fn(this._state);\n        this.options.onUpdate();\n      }\n    },\n  };\n});\n\ndescribe('modalApi', () => {\n  let modalApi: ModalApi;\n  // 使用 modalState 而不是 state\n  let modalState: ModalState;\n\n  beforeEach(() => {\n    modalApi = new ModalApi();\n    // 获取 modalApi 内的 state\n    modalState = modalApi.store.state;\n  });\n\n  it('should initialize with default state', () => {\n    expect(modalState.isOpen).toBe(false);\n    expect(modalState.cancelText).toBe(undefined);\n    expect(modalState.confirmText).toBe(undefined);\n  });\n\n  it('should open the modal', () => {\n    modalApi.open();\n    expect(modalApi.store.state.isOpen).toBe(true);\n  });\n\n  it('should close the modal if onBeforeClose allows it', () => {\n    modalApi.close();\n    expect(modalApi.store.state.isOpen).toBe(false);\n  });\n\n  it('should not close the modal if onBeforeClose returns false', () => {\n    const onBeforeClose = vi.fn(() => false);\n    const modalApiWithHook = new ModalApi({ onBeforeClose });\n    modalApiWithHook.open();\n    modalApiWithHook.close();\n    expect(modalApiWithHook.store.state.isOpen).toBe(true);\n    expect(onBeforeClose).toHaveBeenCalled();\n  });\n\n  it('should trigger onCancel and close the modal if no onCancel hook is provided', () => {\n    const onCancel = vi.fn();\n    const modalApiWithHook = new ModalApi({ onCancel });\n    modalApiWithHook.open();\n    modalApiWithHook.onCancel();\n    expect(onCancel).toHaveBeenCalled();\n    expect(modalApiWithHook.store.state.isOpen).toBe(true);\n  });\n\n  it('should update shared data correctly', () => {\n    const testData = { key: 'value' };\n    modalApi.setData(testData);\n    expect(modalApi.getData()).toEqual(testData);\n  });\n\n  it('should set state correctly using an object', () => {\n    modalApi.setState({ title: 'New Title' });\n    expect(modalApi.store.state.title).toBe('New Title');\n  });\n\n  it('should set state correctly using a function', () => {\n    modalApi.setState((prev) => ({ ...prev, confirmText: 'Yes' }));\n    expect(modalApi.store.state.confirmText).toBe('Yes');\n  });\n\n  it('should call onOpenChange when state changes', () => {\n    const onOpenChange = vi.fn();\n    const modalApiWithHook = new ModalApi({ onOpenChange });\n    modalApiWithHook.open();\n    expect(onOpenChange).toHaveBeenCalledWith(true);\n  });\n\n  it('should call onClosed callback when provided', () => {\n    const onClosed = vi.fn();\n    const modalApiWithHook = new ModalApi({ onClosed });\n    modalApiWithHook.onClosed();\n    expect(onClosed).toHaveBeenCalled();\n  });\n\n  it('should call onOpened callback when provided', () => {\n    const onOpened = vi.fn();\n    const modalApiWithHook = new ModalApi({ onOpened });\n    modalApiWithHook.open();\n    modalApiWithHook.onOpened();\n    expect(onOpened).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/modal/index.ts",
    "content": "export type * from './modal';\nexport { default as VbenModal } from './modal.vue';\nexport { setDefaultModalProps, useVbenModal } from './use-modal';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts",
    "content": "import type { ModalApiOptions, ModalState } from './modal';\n\nimport { Store } from '@vben-core/shared/store';\nimport { bindMethods, isFunction } from '@vben-core/shared/utils';\n\nexport class ModalApi {\n  // 共享数据\n  public sharedData: Record<'payload', any> = {\n    payload: {},\n  };\n  public store: Store<ModalState>;\n\n  private api: Pick<\n    ModalApiOptions,\n    | 'onBeforeClose'\n    | 'onCancel'\n    | 'onClosed'\n    | 'onConfirm'\n    | 'onOpenChange'\n    | 'onOpened'\n  >;\n\n  // private prevState!: ModalState;\n  private state!: ModalState;\n\n  constructor(options: ModalApiOptions = {}) {\n    const {\n      connectedComponent: _,\n      onBeforeClose,\n      onCancel,\n      onClosed,\n      onConfirm,\n      onOpenChange,\n      onOpened,\n      ...storeState\n    } = options;\n\n    const defaultState: ModalState = {\n      bordered: true,\n      centered: false,\n      class: '',\n      closeOnClickModal: true,\n      closeOnPressEscape: true,\n      confirmDisabled: false,\n      confirmLoading: false,\n      contentClass: '',\n      destroyOnClose: true,\n      draggable: false,\n      footer: true,\n      footerClass: '',\n      fullscreen: false,\n      fullscreenButton: true,\n      header: true,\n      headerClass: '',\n      isOpen: false,\n      loading: false,\n      modal: true,\n      openAutoFocus: false,\n      showCancelButton: true,\n      showConfirmButton: true,\n      title: '',\n      animationType: 'slide',\n    };\n\n    this.store = new Store<ModalState>(\n      {\n        ...defaultState,\n        ...storeState,\n      },\n      {\n        onUpdate: () => {\n          const state = this.store.state;\n\n          // 每次更新状态时，都会调用 onOpenChange 回调函数\n          if (state?.isOpen === this.state?.isOpen) {\n            this.state = state;\n          } else {\n            this.state = state;\n            this.api.onOpenChange?.(!!state?.isOpen);\n          }\n        },\n      },\n    );\n\n    this.state = this.store.state;\n\n    this.api = {\n      onBeforeClose,\n      onCancel,\n      onClosed,\n      onConfirm,\n      onOpenChange,\n      onOpened,\n    };\n    bindMethods(this);\n  }\n\n  /**\n   * 关闭弹窗\n   * @description 关闭弹窗时会调用 onBeforeClose 钩子函数，如果 onBeforeClose 返回 false，则不关闭弹窗\n   */\n  async close() {\n    // 通过 onBeforeClose 钩子函数来判断是否允许关闭弹窗\n    // 如果 onBeforeClose 返回 false，则不关闭弹窗\n    const allowClose = (await this.api.onBeforeClose?.()) ?? true;\n    if (allowClose) {\n      this.store.setState((prev) => ({\n        ...prev,\n        isOpen: false,\n      }));\n    }\n  }\n\n  getData<T extends object = Record<string, any>>() {\n    return (this.sharedData?.payload ?? {}) as T;\n  }\n\n  /**\n   * 锁定弹窗状态（用于提交过程中的等待状态）\n   * @description 锁定状态将禁用默认的取消按钮，使用spinner覆盖弹窗内容，隐藏关闭按钮，阻止手动关闭弹窗，将默认的提交按钮标记为loading状态\n   * @param isLocked 是否锁定\n   */\n  lock(isLocked = true) {\n    return this.setState({ submitting: isLocked });\n  }\n\n  /**\n   * 取消操作\n   */\n  onCancel() {\n    if (this.api.onCancel) {\n      this.api.onCancel?.();\n    } else {\n      this.close();\n    }\n  }\n\n  /**\n   * 弹窗关闭动画播放完毕后的回调\n   */\n  onClosed() {\n    if (!this.state.isOpen) {\n      this.api.onClosed?.();\n    }\n  }\n\n  /**\n   * 确认操作\n   */\n  onConfirm() {\n    this.api.onConfirm?.();\n  }\n\n  /**\n   * 弹窗打开动画播放完毕后的回调\n   */\n  onOpened() {\n    if (this.state.isOpen) {\n      this.api.onOpened?.();\n    }\n  }\n\n  open() {\n    this.store.setState((prev) => ({\n      ...prev,\n      isOpen: true,\n      submitting: false,\n    }));\n  }\n\n  setData<T>(payload: T) {\n    this.sharedData.payload = payload;\n    return this;\n  }\n\n  setState(\n    stateOrFn:\n      | ((prev: ModalState) => Partial<ModalState>)\n      | Partial<ModalState>,\n  ) {\n    if (isFunction(stateOrFn)) {\n      this.store.setState(stateOrFn);\n    } else {\n      this.store.setState((prev) => ({ ...prev, ...stateOrFn }));\n    }\n    return this;\n  }\n\n  /**\n   * 解除弹窗的锁定状态\n   * @description 解除由lock方法设置的锁定状态，是lock(false)的别名\n   */\n  unlock() {\n    return this.lock(false);\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/modal/modal.ts",
    "content": "import type { Component, Ref } from 'vue';\n\nimport type { MaybePromise } from '@vben-core/typings';\n\nimport type { ModalApi } from './modal-api';\n\nexport interface ModalProps {\n  /**\n   * 动画类型\n   * @default 'slide'\n   */\n  animationType?: 'scale' | 'slide';\n  /**\n   * 是否要挂载到内容区域\n   * @default false\n   */\n  appendToMain?: boolean;\n  /**\n   * 是否显示边框\n   * @default false\n   */\n  bordered?: boolean;\n  /**\n   * 取消按钮文字\n   */\n  cancelText?: string;\n  /**\n   * 是否居中\n   * @default false\n   */\n  centered?: boolean;\n\n  class?: string;\n\n  /**\n   * 是否显示右上角的关闭按钮\n   * @default true\n   */\n  closable?: boolean;\n  /**\n   * 点击弹窗遮罩是否关闭弹窗\n   * @default true\n   */\n  closeOnClickModal?: boolean;\n  /**\n   * 按下 ESC 键是否关闭弹窗\n   * @default true\n   */\n  closeOnPressEscape?: boolean;\n  /**\n   * 禁用确认按钮\n   */\n  confirmDisabled?: boolean;\n  /**\n   * 确定按钮 loading\n   * @default false\n   */\n  confirmLoading?: boolean;\n  /**\n   * 确定按钮文字\n   */\n  confirmText?: string;\n  contentClass?: string;\n  /**\n   * 弹窗描述\n   */\n  description?: string;\n  /**\n   * 在关闭时销毁弹窗\n   */\n  destroyOnClose?: boolean;\n  /**\n   * 是否可拖拽\n   * @default false\n   */\n  draggable?: boolean;\n  /**\n   * 是否显示底部\n   * @default true\n   */\n  footer?: boolean;\n  footerClass?: string;\n  /**\n   * 是否全屏\n   * @default false\n   */\n  fullscreen?: boolean;\n  /**\n   * 是否显示全屏按钮\n   * @default true\n   */\n  fullscreenButton?: boolean;\n  /**\n   * 是否显示顶栏\n   * @default true\n   */\n  header?: boolean;\n  headerClass?: string;\n  /**\n   * 弹窗是否显示\n   * @default false\n   */\n  loading?: boolean;\n  /**\n   * 是否显示遮罩\n   * @default true\n   */\n  modal?: boolean;\n  /**\n   * 是否自动聚焦\n   */\n  openAutoFocus?: boolean;\n  /**\n   * 弹窗遮罩模糊效果\n   */\n  overlayBlur?: number;\n  /**\n   * 是否显示取消按钮\n   * @default true\n   */\n  showCancelButton?: boolean;\n  /**\n   * 是否显示确认按钮\n   * @default true\n   */\n  showConfirmButton?: boolean;\n  /**\n   * 提交中（锁定弹窗状态）\n   */\n  submitting?: boolean;\n  /**\n   * 弹窗标题\n   */\n  title?: string;\n  /**\n   * 弹窗标题提示\n   */\n  titleTooltip?: string;\n  /**\n   * 弹窗层级\n   */\n  zIndex?: number;\n}\n\nexport interface ModalState extends ModalProps {\n  /** 弹窗打开状态 */\n  isOpen?: boolean;\n  /**\n   * 共享数据\n   */\n  sharedData?: Record<string, any>;\n}\n\nexport type ExtendedModalApi = ModalApi & {\n  useStore: <T = NoInfer<ModalState>>(\n    selector?: (state: NoInfer<ModalState>) => T,\n  ) => Readonly<Ref<T>>;\n};\n\nexport interface ModalApiOptions extends ModalState {\n  /**\n   * 独立的弹窗组件\n   */\n  connectedComponent?: Component;\n  /**\n   * 关闭前的回调，返回 false 可以阻止关闭\n   * @returns\n   */\n  onBeforeClose?: () => MaybePromise<boolean | undefined>;\n  /**\n   * 点击取消按钮的回调\n   */\n  onCancel?: () => void;\n  /**\n   * 弹窗关闭动画结束的回调\n   * @returns\n   */\n  onClosed?: () => void;\n  /**\n   * 点击确定按钮的回调\n   */\n  onConfirm?: () => void;\n  /**\n   * 弹窗状态变化回调\n   * @param isOpen\n   * @returns\n   */\n  onOpenChange?: (isOpen: boolean) => void;\n  /**\n   * 弹窗打开动画结束的回调\n   * @returns\n   */\n  onOpened?: () => void;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/modal/modal.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { ExtendedModalApi, ModalProps } from './modal';\n\nimport {\n  computed,\n  nextTick,\n  onDeactivated,\n  provide,\n  ref,\n  unref,\n  useId,\n  watch,\n} from 'vue';\n\nimport {\n  useIsMobile,\n  usePriorityValues,\n  useSimpleLocale,\n} from '@vben-core/composables';\nimport { Expand, Shrink } from '@vben-core/icons';\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  VbenButton,\n  VbenHelpTooltip,\n  VbenIconButton,\n  VbenLoading,\n  VisuallyHidden,\n} from '@vben-core/shadcn-ui';\nimport { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';\nimport { globalShareState } from '@vben-core/shared/global-state';\nimport { cn } from '@vben-core/shared/utils';\n\nimport { useModalDraggable } from './use-modal-draggable';\n\ninterface Props extends ModalProps {\n  modalApi?: ExtendedModalApi;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  appendToMain: false,\n  destroyOnClose: false,\n  modalApi: undefined,\n});\n\nconst components = globalShareState.getComponents();\n\nconst contentRef = ref();\nconst wrapperRef = ref<HTMLElement>();\nconst dialogRef = ref();\nconst headerRef = ref();\nconst footerRef = ref();\n\nconst id = useId();\n\nprovide('DISMISSABLE_MODAL_ID', id);\n\nconst { $t } = useSimpleLocale();\nconst { isMobile } = useIsMobile();\nconst state = props.modalApi?.useStore?.();\n\nconst {\n  appendToMain,\n  bordered,\n  cancelText,\n  centered,\n  class: modalClass,\n  closable,\n  closeOnClickModal,\n  closeOnPressEscape,\n  confirmDisabled,\n  confirmLoading,\n  confirmText,\n  contentClass,\n  description,\n  destroyOnClose,\n  draggable,\n  footer: showFooter,\n  footerClass,\n  fullscreen,\n  fullscreenButton,\n  header,\n  headerClass,\n  loading: showLoading,\n  modal,\n  openAutoFocus,\n  overlayBlur,\n  showCancelButton,\n  showConfirmButton,\n  submitting,\n  title,\n  titleTooltip,\n  animationType,\n  zIndex,\n} = usePriorityValues(props, state);\n\nconst shouldFullscreen = computed(() => fullscreen.value || isMobile.value);\n\nconst shouldDraggable = computed(\n  () => draggable.value && !shouldFullscreen.value && header.value,\n);\n\nconst getAppendTo = computed(() => {\n  return appendToMain.value\n    ? `#${ELEMENT_ID_MAIN_CONTENT}>div:not(.absolute)>div`\n    : undefined;\n});\n\nconst { dragging, transform } = useModalDraggable(\n  dialogRef,\n  headerRef,\n  shouldDraggable,\n  getAppendTo,\n);\n\nconst firstOpened = ref(false);\nconst isClosed = ref(true);\n\nwatch(\n  () => state?.value?.isOpen,\n  async (v) => {\n    if (v) {\n      isClosed.value = false;\n      if (!firstOpened.value) firstOpened.value = true;\n      await nextTick();\n      if (!contentRef.value) return;\n      const innerContentRef = contentRef.value.getContentRef();\n      dialogRef.value = innerContentRef.$el;\n      // reopen modal reassign value\n      const { offsetX, offsetY } = transform;\n      dialogRef.value.style.transform = `translate(${offsetX}px, ${offsetY}px)`;\n    }\n  },\n  { immediate: true },\n);\n\n// watch(\n//   () => [showLoading.value, submitting.value],\n//   ([l, s]) => {\n//     if ((s || l) && wrapperRef.value) {\n//       wrapperRef.value.scrollTo({\n//         // behavior: 'smooth',\n//         top: 0,\n//       });\n//     }\n//   },\n// );\n\n/**\n * 在开启keepAlive情况下 直接通过浏览器按钮/手势等返回 不会关闭弹窗\n */\nonDeactivated(() => {\n  // 如果弹窗没有被挂载到内容区域，则关闭弹窗\n  if (!appendToMain.value) {\n    props.modalApi?.close();\n  }\n});\n\nfunction handleFullscreen() {\n  props.modalApi?.setState((prev) => {\n    // if (prev.fullscreen) {\n    //   resetPosition();\n    // }\n    return { ...prev, fullscreen: !fullscreen.value };\n  });\n}\nfunction interactOutside(e: Event) {\n  if (!closeOnClickModal.value || submitting.value) {\n    e.preventDefault();\n    e.stopPropagation();\n  }\n}\nfunction escapeKeyDown(e: KeyboardEvent) {\n  if (!closeOnPressEscape.value || submitting.value) {\n    e.preventDefault();\n  }\n}\n\nfunction handerOpenAutoFocus(e: Event) {\n  if (!openAutoFocus.value) {\n    e?.preventDefault();\n  }\n}\n\n// pointer-down-outside\nfunction pointerDownOutside(e: Event) {\n  const target = e.target as HTMLElement;\n  const isDismissableModal = target?.dataset.dismissableModal;\n  if (\n    !closeOnClickModal.value ||\n    isDismissableModal !== id ||\n    submitting.value\n  ) {\n    e.preventDefault();\n    e.stopPropagation();\n  }\n}\n\nfunction handleFocusOutside(e: Event) {\n  e.preventDefault();\n  e.stopPropagation();\n}\n\nconst getForceMount = computed(() => {\n  return !unref(destroyOnClose) && unref(firstOpened);\n});\n\nfunction handleClosed() {\n  isClosed.value = true;\n  props.modalApi?.onClosed();\n}\n</script>\n<template>\n  <Dialog\n    :modal=\"false\"\n    :open=\"state?.isOpen\"\n    @update:open=\"() => (!submitting ? modalApi?.close() : undefined)\"\n  >\n    <DialogContent\n      ref=\"contentRef\"\n      :append-to=\"getAppendTo\"\n      :class=\"\n        cn(\n          'left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col p-0',\n          shouldFullscreen ? 'sm:rounded-none' : 'sm:rounded-[var(--radius)]',\n          modalClass,\n          {\n            'border-border border': bordered,\n            'shadow-3xl': !bordered,\n            'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0':\n              shouldFullscreen,\n            'top-1/2 !-translate-y-1/2': centered && !shouldFullscreen,\n            'duration-300': !dragging,\n            hidden: isClosed,\n          },\n        )\n      \"\n      :force-mount=\"getForceMount\"\n      :modal=\"modal\"\n      :open=\"state?.isOpen\"\n      :show-close=\"closable\"\n      :animation-type=\"animationType\"\n      :z-index=\"zIndex\"\n      :overlay-blur=\"overlayBlur\"\n      close-class=\"top-3\"\n      @close-auto-focus=\"handleFocusOutside\"\n      @closed=\"handleClosed\"\n      :close-disabled=\"submitting\"\n      @escape-key-down=\"escapeKeyDown\"\n      @focus-outside=\"handleFocusOutside\"\n      @interact-outside=\"interactOutside\"\n      @open-auto-focus=\"handerOpenAutoFocus\"\n      @opened=\"() => modalApi?.onOpened()\"\n      @pointer-down-outside=\"pointerDownOutside\"\n    >\n      <DialogHeader\n        ref=\"headerRef\"\n        :class=\"\n          cn(\n            'px-5 py-4',\n            {\n              'border-b': bordered,\n              hidden: !header,\n              'cursor-move select-none': shouldDraggable,\n            },\n            headerClass,\n          )\n        \"\n      >\n        <DialogTitle v-if=\"title\" class=\"text-left\">\n          <slot name=\"title\">\n            {{ title }}\n\n            <slot v-if=\"titleTooltip\" name=\"titleTooltip\">\n              <VbenHelpTooltip trigger-class=\"pb-1\">\n                {{ titleTooltip }}\n              </VbenHelpTooltip>\n            </slot>\n          </slot>\n        </DialogTitle>\n        <DialogDescription v-if=\"description\">\n          <slot name=\"description\">\n            {{ description }}\n          </slot>\n        </DialogDescription>\n        <VisuallyHidden v-if=\"!title || !description\">\n          <DialogTitle v-if=\"!title\" />\n          <DialogDescription v-if=\"!description\" />\n        </VisuallyHidden>\n      </DialogHeader>\n      <div\n        ref=\"wrapperRef\"\n        :class=\"\n          cn('relative min-h-40 flex-1 overflow-y-auto p-3', contentClass, {\n            'pointer-events-none': showLoading || submitting,\n          })\n        \"\n      >\n        <slot></slot>\n      </div>\n      <VbenLoading v-if=\"showLoading || submitting\" spinning />\n      <VbenIconButton\n        v-if=\"fullscreenButton\"\n        class=\"hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-10 top-3 hidden size-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none sm:block\"\n        @click=\"handleFullscreen\"\n      >\n        <Shrink v-if=\"fullscreen\" class=\"size-3.5\" />\n        <Expand v-else class=\"size-3.5\" />\n      </VbenIconButton>\n\n      <DialogFooter\n        v-if=\"showFooter\"\n        ref=\"footerRef\"\n        :class=\"\n          cn(\n            'flex-row items-center justify-end p-2',\n            {\n              'border-t': bordered,\n            },\n            footerClass,\n          )\n        \"\n      >\n        <slot name=\"prepend-footer\"></slot>\n        <slot name=\"footer\">\n          <component\n            :is=\"components.DefaultButton || VbenButton\"\n            v-if=\"showCancelButton\"\n            variant=\"ghost\"\n            :disabled=\"submitting\"\n            @click=\"() => modalApi?.onCancel()\"\n          >\n            <slot name=\"cancelText\">\n              {{ cancelText || $t('cancel') }}\n            </slot>\n          </component>\n          <slot name=\"center-footer\"></slot>\n          <component\n            :is=\"components.PrimaryButton || VbenButton\"\n            v-if=\"showConfirmButton\"\n            :disabled=\"confirmDisabled\"\n            :loading=\"confirmLoading || submitting\"\n            @click=\"() => modalApi?.onConfirm()\"\n          >\n            <slot name=\"confirmText\">\n              {{ confirmText || $t('confirm') }}\n            </slot>\n          </component>\n        </slot>\n        <slot name=\"append-footer\"></slot>\n      </DialogFooter>\n    </DialogContent>\n  </Dialog>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts",
    "content": "/**\n * @copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-draggable/index.ts\n * 调整部分细节\n */\n\nimport type { ComputedRef, Ref } from 'vue';\n\nimport { onBeforeUnmount, onMounted, reactive, ref, watchEffect } from 'vue';\n\nimport { unrefElement } from '@vueuse/core';\n\nexport function useModalDraggable(\n  targetRef: Ref<HTMLElement | undefined>,\n  dragRef: Ref<HTMLElement | undefined>,\n  draggable: ComputedRef<boolean>,\n  containerSelector?: ComputedRef<string | undefined>,\n) {\n  const transform = reactive({\n    offsetX: 0,\n    offsetY: 0,\n  });\n\n  const dragging = ref(false);\n\n  const onMousedown = (e: MouseEvent) => {\n    const downX = e.clientX;\n    const downY = e.clientY;\n\n    if (!targetRef.value) {\n      return;\n    }\n\n    const targetRect = targetRef.value.getBoundingClientRect();\n    const { offsetX, offsetY } = transform;\n    const targetLeft = targetRect.left;\n    const targetTop = targetRect.top;\n    const targetWidth = targetRect.width;\n    const targetHeight = targetRect.height;\n\n    let containerRect: DOMRect | null = null;\n\n    if (containerSelector?.value) {\n      const container = document.querySelector(containerSelector.value);\n      if (container) {\n        containerRect = container.getBoundingClientRect();\n      }\n    }\n\n    let maxLeft, maxTop, minLeft, minTop;\n    if (containerRect) {\n      minLeft = containerRect.left - targetLeft + offsetX;\n      maxLeft = containerRect.right - targetLeft - targetWidth + offsetX;\n      minTop = containerRect.top - targetTop + offsetY;\n      maxTop = containerRect.bottom - targetTop - targetHeight + offsetY;\n    } else {\n      const docElement = document.documentElement;\n      const clientWidth = docElement.clientWidth;\n      const clientHeight = docElement.clientHeight;\n      minLeft = -targetLeft + offsetX;\n      minTop = -targetTop + offsetY;\n      maxLeft = clientWidth - targetLeft - targetWidth + offsetX;\n      maxTop = clientHeight - targetTop - targetHeight + offsetY;\n    }\n\n    const onMousemove = (e: MouseEvent) => {\n      let moveX = offsetX + e.clientX - downX;\n      let moveY = offsetY + e.clientY - downY;\n\n      moveX = Math.min(Math.max(moveX, minLeft), maxLeft);\n      moveY = Math.min(Math.max(moveY, minTop), maxTop);\n\n      transform.offsetX = moveX;\n      transform.offsetY = moveY;\n\n      if (targetRef.value) {\n        targetRef.value.style.transform = `translate(${moveX}px, ${moveY}px)`;\n        dragging.value = true;\n      }\n    };\n\n    const onMouseup = () => {\n      dragging.value = false;\n      document.removeEventListener('mousemove', onMousemove);\n      document.removeEventListener('mouseup', onMouseup);\n    };\n\n    document.addEventListener('mousemove', onMousemove);\n    document.addEventListener('mouseup', onMouseup);\n  };\n\n  const onDraggable = () => {\n    const dragDom = unrefElement(dragRef);\n    if (dragDom && targetRef.value) {\n      dragDom.addEventListener('mousedown', onMousedown);\n    }\n  };\n\n  const offDraggable = () => {\n    const dragDom = unrefElement(dragRef);\n    if (dragDom && targetRef.value) {\n      dragDom.removeEventListener('mousedown', onMousedown);\n    }\n  };\n\n  const resetPosition = () => {\n    transform.offsetX = 0;\n    transform.offsetY = 0;\n\n    const target = unrefElement(targetRef);\n    if (target) {\n      target.style.transform = 'none';\n    }\n  };\n\n  onMounted(() => {\n    watchEffect(() => {\n      if (draggable.value) {\n        onDraggable();\n      } else {\n        offDraggable();\n      }\n    });\n  });\n\n  onBeforeUnmount(() => {\n    offDraggable();\n  });\n\n  return {\n    dragging,\n    resetPosition,\n    transform,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts",
    "content": "import type { ExtendedModalApi, ModalApiOptions, ModalProps } from './modal';\n\nimport {\n  defineComponent,\n  h,\n  inject,\n  nextTick,\n  provide,\n  reactive,\n  ref,\n} from 'vue';\n\nimport { useStore } from '@vben-core/shared/store';\n\nimport { ModalApi } from './modal-api';\nimport VbenModal from './modal.vue';\n\nconst USER_MODAL_INJECT_KEY = Symbol('VBEN_MODAL_INJECT');\n\nconst DEFAULT_MODAL_PROPS: Partial<ModalProps> = {};\n\nexport function setDefaultModalProps(props: Partial<ModalProps>) {\n  Object.assign(DEFAULT_MODAL_PROPS, props);\n}\n\nexport function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(\n  options: ModalApiOptions = {},\n) {\n  // Modal一般会抽离出来，所以如果有传入 connectedComponent，则表示为外部调用，与内部组件进行连接\n  // 外部的Modal通过provide/inject传递api\n\n  const { connectedComponent } = options;\n  if (connectedComponent) {\n    const extendedApi = reactive({});\n    const isModalReady = ref(true);\n    const Modal = defineComponent(\n      (props: TParentModalProps, { attrs, slots }) => {\n        provide(USER_MODAL_INJECT_KEY, {\n          extendApi(api: ExtendedModalApi) {\n            // 不能直接给 reactive 赋值，会丢失响应\n            // 不能用 Object.assign,会丢失 api 的原型函数\n            Object.setPrototypeOf(extendedApi, api);\n          },\n          options,\n          async reCreateModal() {\n            isModalReady.value = false;\n            await nextTick();\n            isModalReady.value = true;\n          },\n        });\n        checkProps(extendedApi as ExtendedModalApi, {\n          ...props,\n          ...attrs,\n          ...slots,\n        });\n        return () =>\n          h(\n            isModalReady.value ? connectedComponent : 'div',\n            {\n              ...props,\n              ...attrs,\n            },\n            slots,\n          );\n      },\n      // eslint-disable-next-line vue/one-component-per-file\n      {\n        name: 'VbenParentModal',\n        inheritAttrs: false,\n      },\n    );\n\n    return [Modal, extendedApi as ExtendedModalApi] as const;\n  }\n\n  const injectData = inject<any>(USER_MODAL_INJECT_KEY, {});\n\n  const mergedOptions = {\n    ...DEFAULT_MODAL_PROPS,\n    ...injectData.options,\n    ...options,\n  } as ModalApiOptions;\n\n  mergedOptions.onOpenChange = (isOpen: boolean) => {\n    options.onOpenChange?.(isOpen);\n    injectData.options?.onOpenChange?.(isOpen);\n  };\n\n  const onClosed = mergedOptions.onClosed;\n  mergedOptions.onClosed = () => {\n    onClosed?.();\n    if (mergedOptions.destroyOnClose) {\n      injectData.reCreateModal?.();\n    }\n  };\n\n  const api = new ModalApi(mergedOptions);\n\n  const extendedApi: ExtendedModalApi = api as never;\n\n  extendedApi.useStore = (selector) => {\n    return useStore(api.store, selector);\n  };\n\n  const Modal = defineComponent(\n    (props: ModalProps, { attrs, slots }) => {\n      return () =>\n        h(\n          VbenModal,\n          {\n            ...props,\n            ...attrs,\n            modalApi: extendedApi,\n          },\n          slots,\n        );\n    },\n    // eslint-disable-next-line vue/one-component-per-file\n    {\n      name: 'VbenModal',\n      inheritAttrs: false,\n    },\n  );\n  injectData.extendApi?.(extendedApi);\n\n  return [Modal, extendedApi] as const;\n}\n\nasync function checkProps(api: ExtendedModalApi, attrs: Record<string, any>) {\n  if (!attrs || Object.keys(attrs).length === 0) {\n    return;\n  }\n  await nextTick();\n\n  const state = api?.store?.state;\n\n  if (!state) {\n    return;\n  }\n\n  const stateKeys = new Set(Object.keys(state));\n\n  for (const attr of Object.keys(attrs)) {\n    if (stateKeys.has(attr) && !['class'].includes(attr)) {\n      // connectedComponent存在时，不要传入Modal的props，会造成复杂度提升，如果你需要修改Modal的props，请使用 useModal 或者api\n      console.warn(\n        `[Vben Modal]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Modal, please use useVbenModal or api.`,\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/popup-ui/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: [\n    {\n      builder: 'mkdist',\n      input: './src',\n\n      pattern: ['**/*'],\n    },\n    {\n      builder: 'mkdist',\n      input: './src',\n      loaders: ['vue'],\n      pattern: ['**/*.vue'],\n    },\n    {\n      builder: 'mkdist',\n      format: 'esm',\n      input: './src',\n      loaders: ['js'],\n      pattern: ['**/*.ts'],\n    },\n  ],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/components.json",
    "content": "{\n  \"$schema\": \"https://shadcn-vue.com/schema.json\",\n  \"style\": \"new-york\",\n  \"typescript\": true,\n  \"tailwind\": {\n    \"config\": \"tailwind.config.mjs\",\n    \"css\": \"src/assets/index.css\",\n    \"baseColor\": \"slate\",\n    \"cssVariables\": true\n  },\n  \"framework\": \"vite\",\n  \"aliases\": {\n    \"components\": \"@vben-core/shadcn-ui/components\",\n    \"utils\": \"@vben-core/shared/utils\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/package.json",
    "content": "{\n  \"name\": \"@vben-core/shadcn-ui\",\n  \"version\": \"5.5.9\",\n  \"#main\": \"./dist/index.mjs\",\n  \"#module\": \"./dist/index.mjs\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/uikit/shadcn-ui\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"#build\": \"pnpm unbuild\",\n    \"#prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"main\": \"./src/index.ts\",\n  \"module\": \"./src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\",\n      \"//default\": \"./dist/index.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"default\": \"./src/index.ts\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/composables\": \"workspace:*\",\n    \"@vben-core/icons\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"class-variance-authority\": \"catalog:\",\n    \"lucide-vue-next\": \"catalog:\",\n    \"radix-vue\": \"catalog:\",\n    \"vee-validate\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  AvatarFallbackProps,\n  AvatarImageProps,\n  AvatarRootProps,\n} from 'radix-vue';\n\nimport type { CSSProperties } from 'vue';\n\nimport type { ClassType } from '@vben-core/typings';\n\nimport { computed } from 'vue';\n\nimport { Avatar, AvatarFallback, AvatarImage } from '../../ui';\n\ninterface Props extends AvatarFallbackProps, AvatarImageProps, AvatarRootProps {\n  alt?: string;\n  class?: ClassType;\n  dot?: boolean;\n  dotClass?: ClassType;\n  fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\n  size?: number;\n}\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  alt: 'avatar',\n  as: 'button',\n  dot: false,\n  dotClass: 'bg-green-500',\n  fit: 'cover',\n});\n\nconst imageStyle = computed<CSSProperties>(() => {\n  const { fit } = props;\n  if (fit) {\n    return { objectFit: fit };\n  }\n  return {};\n});\n\nconst text = computed(() => {\n  return props.alt.slice(-2).toUpperCase();\n});\n\nconst rootStyle = computed(() => {\n  return props.size !== undefined && props.size > 0\n    ? {\n        height: `${props.size}px`,\n        width: `${props.size}px`,\n      }\n    : {};\n});\n</script>\n\n<template>\n  <div\n    :class=\"props.class\"\n    :style=\"rootStyle\"\n    class=\"relative flex flex-shrink-0 items-center\"\n  >\n    <Avatar :class=\"props.class\" class=\"size-full\">\n      <AvatarImage :alt=\"alt\" :src=\"src\" :style=\"imageStyle\" />\n      <AvatarFallback>{{ text }}</AvatarFallback>\n    </Avatar>\n    <span\n      v-if=\"dot\"\n      :class=\"dotClass\"\n      class=\"border-background absolute bottom-0 right-0 size-3 rounded-full border-2\"\n    >\n    </span>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/avatar/index.ts",
    "content": "export { default as VbenAvatar } from './avatar.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { BacktopProps } from './backtop';\n\nimport { computed } from 'vue';\n\nimport { ArrowUpToLine } from '@vben-core/icons';\n\nimport { VbenButton } from '../button';\nimport { useBackTop } from './use-backtop';\n\ninterface Props extends BacktopProps {}\n\ndefineOptions({ name: 'BackTop' });\n\nconst props = withDefaults(defineProps<Props>(), {\n  bottom: 20,\n  isGroup: false,\n  right: 24,\n  target: '',\n  visibilityHeight: 200,\n});\n\nconst backTopStyle = computed(() => ({\n  bottom: `${props.bottom}px`,\n  right: `${props.right}px`,\n}));\n\nconst { handleClick, visible } = useBackTop(props);\n</script>\n<template>\n  <transition name=\"fade-down\">\n    <VbenButton\n      v-if=\"visible\"\n      :style=\"backTopStyle\"\n      class=\"dark:bg-accent dark:hover:bg-heavy bg-background hover:bg-heavy data shadow-float z-popup fixed bottom-10 size-10 rounded-full duration-500\"\n      size=\"icon\"\n      variant=\"icon\"\n      @click=\"handleClick\"\n    >\n      <ArrowUpToLine class=\"size-4\" />\n    </VbenButton>\n  </transition>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts",
    "content": "export const backtopProps = {\n  /**\n   * @zh_CN bottom distance.\n   */\n  bottom: {\n    default: 40,\n    type: Number,\n  },\n  /**\n   * @zh_CN right distance.\n   */\n  right: {\n    default: 40,\n    type: Number,\n  },\n  /**\n   * @zh_CN the target to trigger scroll.\n   */\n  target: {\n    default: '',\n    type: String,\n  },\n  /**\n   * @zh_CN the button will not show until the scroll height reaches this value.\n   */\n  visibilityHeight: {\n    default: 200,\n    type: Number,\n  },\n} as const;\n\nexport interface BacktopProps {\n  bottom?: number;\n  isGroup?: boolean;\n  right?: number;\n  target?: string;\n  visibilityHeight?: number;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/back-top/index.ts",
    "content": "export { default as VbenBackTop } from './back-top.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts",
    "content": "import type { BacktopProps } from './backtop';\n\nimport { onMounted, ref, shallowRef } from 'vue';\n\nimport { useEventListener, useThrottleFn } from '@vueuse/core';\n\nexport const useBackTop = (props: BacktopProps) => {\n  const el = shallowRef<HTMLElement>();\n  const container = shallowRef<Document | HTMLElement>();\n  const visible = ref(false);\n\n  const handleScroll = () => {\n    if (el.value) {\n      visible.value = el.value.scrollTop >= (props?.visibilityHeight ?? 0);\n    }\n  };\n\n  const handleClick = () => {\n    el.value?.scrollTo({ behavior: 'smooth', top: 0 });\n  };\n\n  const handleScrollThrottled = useThrottleFn(handleScroll, 300, true);\n\n  useEventListener(container, 'scroll', handleScrollThrottled);\n  onMounted(() => {\n    container.value = document;\n    el.value = document.documentElement;\n\n    if (props.target) {\n      el.value = document.querySelector<HTMLElement>(props.target) ?? undefined;\n\n      if (!el.value) {\n        throw new Error(`target does not exist: ${props.target}`);\n      }\n      container.value = el.value;\n    }\n    // Give visible an initial value, fix #13066\n    handleScroll();\n  });\n\n  return {\n    handleClick,\n    visible,\n  };\n};\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-background.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { BreadcrumbProps } from './types';\n\nimport { VbenIcon } from '../icon';\n\ninterface Props extends BreadcrumbProps {}\n\ndefineOptions({ name: 'Breadcrumb' });\nconst { breadcrumbs, showIcon } = defineProps<Props>();\n\nconst emit = defineEmits<{ select: [string] }>();\n\nfunction handleClick(index: number, path?: string) {\n  if (!path || index === breadcrumbs.length - 1) {\n    return;\n  }\n  emit('select', path);\n}\n</script>\n<template>\n  <ul class=\"flex\">\n    <TransitionGroup name=\"breadcrumb-transition\">\n      <template\n        v-for=\"(item, index) in breadcrumbs\"\n        :key=\"`${item.path}-${item.title}-${index}`\"\n      >\n        <li>\n          <a\n            href=\"javascript:void 0\"\n            @click.stop=\"handleClick(index, item.path)\"\n          >\n            <span class=\"flex-center z-10 h-full\">\n              <VbenIcon\n                v-if=\"showIcon\"\n                :icon=\"item.icon\"\n                class=\"mr-1 size-4 flex-shrink-0\"\n              />\n              <span\n                :class=\"{\n                  'text-foreground font-normal':\n                    index === breadcrumbs.length - 1,\n                }\"\n                >{{ item.title }}\n              </span>\n            </span>\n          </a>\n        </li>\n      </template>\n    </TransitionGroup>\n  </ul>\n</template>\n<style scoped>\nli {\n  @apply h-7;\n}\n\nli a {\n  @apply text-muted-foreground bg-accent relative mr-9 flex h-7 items-center py-0 pl-[5px] pr-2 text-[13px];\n}\n\nli a > span {\n  @apply -ml-3;\n}\n\nli:first-child a > span {\n  @apply -ml-1;\n}\n\nli:first-child a {\n  @apply rounded-[4px_0_0_4px] pl-[15px];\n}\n\nli:first-child a::before {\n  @apply border-none;\n}\n\nli:last-child a {\n  @apply rounded-[0_4px_4px_0] pr-[15px];\n}\n\nli:last-child a::after {\n  @apply border-none;\n}\n\nli a::before,\nli a::after {\n  @apply border-accent absolute top-0 h-0 w-0 border-[.875rem] border-solid content-[''];\n}\n\nli a::before {\n  @apply -left-7 z-10 border-l-transparent;\n}\n\nli a::after {\n  @apply border-l-accent left-full border-transparent;\n}\n\nli:not(:last-child) a:hover {\n  @apply bg-accent-hover;\n}\n\nli:not(:last-child) a:hover::before {\n  @apply border-accent-hover border-l-transparent;\n}\n\nli:not(:last-child) a:hover::after {\n  @apply border-l-accent-hover;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-view.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { BreadcrumbProps } from './types';\n\nimport { useForwardPropsEmits } from 'radix-vue';\n\nimport BreadcrumbBackground from './breadcrumb-background.vue';\nimport Breadcrumb from './breadcrumb.vue';\n\ninterface Props extends BreadcrumbProps {\n  class?: any;\n}\n\nconst props = withDefaults(defineProps<Props>(), {});\n\nconst emit = defineEmits<{ select: [string] }>();\n\nconst forward = useForwardPropsEmits(props, emit);\n</script>\n<template>\n  <Breadcrumb\n    v-if=\"styleType === 'normal'\"\n    v-bind=\"forward\"\n    class=\"vben-breadcrumb\"\n  />\n  <BreadcrumbBackground\n    v-if=\"styleType === 'background'\"\n    v-bind=\"forward\"\n    class=\"vben-breadcrumb\"\n  />\n</template>\n<style lang=\"scss\" scoped>\n/** 修复全局引入Antd时，ol和ul的默认样式会被修改的问题 */\n.vben-breadcrumb {\n  :deep(ol),\n  :deep(ul) {\n    margin-bottom: 0;\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { BreadcrumbProps } from './types';\n\nimport { ChevronDown } from '@vben-core/icons';\n\nimport {\n  Breadcrumb,\n  BreadcrumbItem,\n  BreadcrumbLink,\n  BreadcrumbList,\n  BreadcrumbPage,\n  BreadcrumbSeparator,\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from '../../ui';\nimport { VbenIcon } from '../icon';\n\ninterface Props extends BreadcrumbProps {}\n\ndefineOptions({ name: 'Breadcrumb' });\nwithDefaults(defineProps<Props>(), {\n  showIcon: false,\n});\n\nconst emit = defineEmits<{ select: [string] }>();\n\nfunction handleClick(path?: string) {\n  if (!path) {\n    return;\n  }\n  emit('select', path);\n}\n</script>\n<template>\n  <Breadcrumb>\n    <BreadcrumbList>\n      <TransitionGroup name=\"breadcrumb-transition\">\n        <template\n          v-for=\"(item, index) in breadcrumbs\"\n          :key=\"`${item.path}-${item.title}-${index}`\"\n        >\n          <BreadcrumbItem>\n            <div v-if=\"item.items?.length ?? 0 > 0\">\n              <DropdownMenu>\n                <DropdownMenuTrigger class=\"flex items-center gap-1\">\n                  <VbenIcon v-if=\"showIcon\" :icon=\"item.icon\" class=\"size-5\" />\n                  {{ item.title }}\n                  <ChevronDown class=\"size-4\" />\n                </DropdownMenuTrigger>\n                <DropdownMenuContent align=\"start\">\n                  <template\n                    v-for=\"menuItem in item.items\"\n                    :key=\"`sub-${menuItem.path}`\"\n                  >\n                    <DropdownMenuItem @click.stop=\"handleClick(menuItem.path)\">\n                      {{ menuItem.title }}\n                    </DropdownMenuItem>\n                  </template>\n                </DropdownMenuContent>\n              </DropdownMenu>\n            </div>\n            <BreadcrumbLink\n              v-else-if=\"index !== breadcrumbs.length - 1\"\n              href=\"javascript:void 0\"\n              @click.stop=\"handleClick(item.path)\"\n            >\n              <div class=\"flex-center\">\n                <VbenIcon\n                  v-if=\"showIcon\"\n                  :class=\"{ 'size-5': item.isHome }\"\n                  :icon=\"item.icon\"\n                  class=\"mr-1 size-4\"\n                />\n                {{ item.title }}\n              </div>\n            </BreadcrumbLink>\n            <BreadcrumbPage v-else>\n              <div class=\"flex-center\">\n                <VbenIcon\n                  v-if=\"showIcon\"\n                  :class=\"{ 'size-5': item.isHome }\"\n                  :icon=\"item.icon\"\n                  class=\"mr-1 size-4\"\n                />\n                {{ item.title }}\n              </div>\n            </BreadcrumbPage>\n            <BreadcrumbSeparator\n              v-if=\"index < breadcrumbs.length - 1 && !item.isHome\"\n            />\n          </BreadcrumbItem>\n        </template>\n      </TransitionGroup>\n    </BreadcrumbList>\n  </Breadcrumb>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/index.ts",
    "content": "export { default as VbenBreadcrumbView } from './breadcrumb-view.vue';\n\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/types.ts",
    "content": "import type { Component } from 'vue';\n\nimport type { BreadcrumbStyleType } from '@vben-core/typings';\n\nexport interface IBreadcrumb {\n  icon?: Component | string;\n  isHome?: boolean;\n  items?: IBreadcrumb[];\n  path?: string;\n  title?: string;\n}\n\nexport interface BreadcrumbProps {\n  breadcrumbs: IBreadcrumb[];\n  showIcon?: boolean;\n  styleType?: BreadcrumbStyleType;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/button/button-group.vue",
    "content": "<script lang=\"ts\" setup>\nimport { cn } from '@vben-core/shared/utils';\n\ndefineOptions({ name: 'VbenButtonGroup' });\n\nwithDefaults(\n  defineProps<{\n    border?: boolean;\n    gap?: number;\n    size?: 'large' | 'middle' | 'small';\n  }>(),\n  { border: false, gap: 0, size: 'middle' },\n);\n</script>\n<template>\n  <div\n    :class=\"\n      cn(\n        'vben-button-group rounded-md',\n        `size-${size}`,\n        gap ? 'with-gap' : 'no-gap',\n        $attrs.class as string,\n      )\n    \"\n    :style=\"{ gap: gap ? `${gap}px` : '0px' }\"\n  >\n    <slot></slot>\n  </div>\n</template>\n\n<style lang=\"scss\" scoped>\n.vben-button-group {\n  display: inline-flex;\n\n  &.size-large :deep(button) {\n    height: 2.25rem;\n    padding: 0.5rem 0.75rem;\n    font-size: 0.875rem;\n    line-height: 1.25rem;\n\n    .icon-wrapper {\n      margin-right: 0.4rem;\n\n      svg {\n        width: 1rem;\n        height: 1rem;\n      }\n    }\n  }\n\n  &.size-middle :deep(button) {\n    height: 2rem;\n    padding: 0.25rem 0.5rem;\n    font-size: 0.75rem;\n    line-height: 1rem;\n\n    .icon-wrapper {\n      margin-right: 0.2rem;\n\n      svg {\n        width: 0.75rem;\n        height: 0.75rem;\n      }\n    }\n  }\n\n  &.size-small :deep(button) {\n    height: 1.75rem;\n    padding: 0.2rem 0.4rem;\n    font-size: 0.65rem;\n    line-height: 0.75rem;\n\n    .icon-wrapper {\n      margin-right: 0.1rem;\n\n      svg {\n        width: 0.65rem;\n        height: 0.65rem;\n      }\n    }\n  }\n\n  &.no-gap > :deep(button):nth-of-type(1) {\n    border-radius: calc(var(--radius) - 2px) 0 0 calc(var(--radius) - 2px);\n  }\n\n  &.no-gap > :deep(button):last-of-type {\n    border-radius: 0 calc(var(--radius) - 2px) calc(var(--radius) - 2px) 0;\n  }\n\n  &.no-gap {\n    :deep(button + button) {\n      border-left-width: 0;\n      border-radius: 0;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts",
    "content": "import type { AsTag } from 'radix-vue';\n\nimport type { Component } from 'vue';\n\nimport type { ButtonVariants, ButtonVariantSize } from '../../ui';\n\nexport interface VbenButtonProps {\n  /**\n   * The element or component this component should render as. Can be overwrite by `asChild`\n   * @defaultValue \"div\"\n   */\n  as?: AsTag | Component;\n  /**\n   * Change the default rendered element for the one passed as a child, merging their props and behavior.\n   *\n   * Read our [Composition](https://www.radix-vue.com/guides/composition.html) guide for more details.\n   */\n  asChild?: boolean;\n  class?: any;\n  disabled?: boolean;\n  loading?: boolean;\n  size?: ButtonVariantSize;\n  variant?: ButtonVariants;\n}\n\nexport type CustomRenderType = (() => Component | string) | string;\n\nexport type ValueType = boolean | number | string;\n\nexport interface VbenButtonGroupProps\n  extends Pick<VbenButtonProps, 'disabled'> {\n  /** 单选模式下允许清除选中 */\n  allowClear?: boolean;\n  /** 值改变前的回调 */\n  beforeChange?: (\n    value: ValueType,\n    isChecked: boolean,\n  ) => boolean | PromiseLike<boolean | undefined> | undefined;\n  /** 按钮样式 */\n  btnClass?: any;\n  /** 按钮间隔距离 */\n  gap?: number;\n  /** 多选模式下限制最多选择的数量。0表示不限制 */\n  maxCount?: number;\n  /** 是否允许多选 */\n  multiple?: boolean;\n  /** 选项 */\n  options?: { [key: string]: any; label: CustomRenderType; value: ValueType }[];\n  /** 显示图标 */\n  showIcon?: boolean;\n  /** 尺寸 */\n  size?: 'large' | 'middle' | 'small';\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue",
    "content": "<script setup lang=\"ts\">\nimport type { VbenButtonProps } from './button';\n\nimport { computed } from 'vue';\n\nimport { LoaderCircle } from '@vben-core/icons';\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Primitive } from 'radix-vue';\n\nimport { buttonVariants } from '../../ui';\n\ninterface Props extends VbenButtonProps {}\n\nconst props = withDefaults(defineProps<Props>(), {\n  as: 'button',\n  class: '',\n  disabled: false,\n  loading: false,\n  size: 'default',\n  variant: 'default',\n});\n\nconst isDisabled = computed(() => {\n  return props.disabled || props.loading;\n});\n</script>\n\n<template>\n  <Primitive\n    :as=\"as\"\n    :as-child=\"asChild\"\n    :class=\"cn(buttonVariants({ variant, size }), props.class)\"\n    :disabled=\"isDisabled\"\n  >\n    <LoaderCircle\n      v-if=\"loading\"\n      class=\"text-md mr-2 size-4 flex-shrink-0 animate-spin\"\n    />\n    <slot></slot>\n  </Primitive>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/button/check-button-group.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Arrayable } from '@vueuse/core';\n\nimport type { ValueType, VbenButtonGroupProps } from './button';\n\nimport { computed, ref, watch } from 'vue';\n\nimport { Circle, CircleCheckBig, LoaderCircle } from '@vben-core/icons';\nimport { cn, isFunction } from '@vben-core/shared/utils';\n\nimport { objectOmit } from '@vueuse/core';\n\nimport { VbenRenderContent } from '../render-content';\nimport VbenButtonGroup from './button-group.vue';\nimport Button from './button.vue';\n\nconst props = withDefaults(defineProps<VbenButtonGroupProps>(), {\n  gap: 0,\n  multiple: false,\n  showIcon: true,\n  size: 'middle',\n  allowClear: false,\n  maxCount: 0,\n});\nconst emit = defineEmits(['btnClick']);\nconst btnDefaultProps = computed(() => {\n  return {\n    ...objectOmit(props, ['options', 'btnClass', 'size', 'disabled']),\n    class: cn(props.btnClass),\n  };\n});\nconst modelValue = defineModel<Arrayable<ValueType> | undefined>();\n\nconst innerValue = ref<Array<ValueType>>([]);\nconst loadingValues = ref<Array<ValueType>>([]);\nwatch(\n  () => props.multiple,\n  (val) => {\n    if (val) {\n      modelValue.value = innerValue.value;\n    } else {\n      modelValue.value =\n        innerValue.value.length > 0 ? innerValue.value[0] : undefined;\n    }\n  },\n);\n\nwatch(\n  () => modelValue.value,\n  (val) => {\n    if (Array.isArray(val)) {\n      const arrVal = val.filter((v) => v !== undefined);\n      if (arrVal.length > 0) {\n        innerValue.value = props.multiple\n          ? [...arrVal]\n          : [arrVal[0] as ValueType];\n      } else {\n        innerValue.value = [];\n      }\n    } else {\n      innerValue.value = val === undefined ? [] : [val as ValueType];\n    }\n  },\n  { deep: true, immediate: true },\n);\n\nasync function onBtnClick(value: ValueType) {\n  if (props.beforeChange && isFunction(props.beforeChange)) {\n    try {\n      loadingValues.value.push(value);\n      const canChange = await props.beforeChange(\n        value,\n        !innerValue.value.includes(value),\n      );\n      if (canChange === false) {\n        return;\n      }\n    } finally {\n      loadingValues.value.splice(loadingValues.value.indexOf(value), 1);\n    }\n  }\n\n  if (props.multiple) {\n    if (innerValue.value.includes(value)) {\n      innerValue.value = innerValue.value.filter((item) => item !== value);\n    } else {\n      if (props.maxCount > 0 && innerValue.value.length >= props.maxCount) {\n        innerValue.value = innerValue.value.slice(0, props.maxCount - 1);\n      }\n      innerValue.value.push(value);\n    }\n    modelValue.value = innerValue.value;\n  } else {\n    if (props.allowClear && innerValue.value.includes(value)) {\n      innerValue.value = [];\n      modelValue.value = undefined;\n      emit('btnClick', undefined);\n      return;\n    } else {\n      innerValue.value = [value];\n      modelValue.value = value;\n    }\n  }\n  emit('btnClick', value);\n}\n</script>\n<template>\n  <VbenButtonGroup\n    :size=\"props.size\"\n    :gap=\"props.gap\"\n    class=\"vben-check-button-group\"\n  >\n    <Button\n      v-for=\"(btn, index) in props.options\"\n      :key=\"index\"\n      :class=\"cn('border', props.btnClass)\"\n      :disabled=\"\n        props.disabled ||\n        loadingValues.includes(btn.value) ||\n        (!props.multiple && loadingValues.length > 0)\n      \"\n      v-bind=\"btnDefaultProps\"\n      :variant=\"innerValue.includes(btn.value) ? 'default' : 'outline'\"\n      @click=\"onBtnClick(btn.value)\"\n      type=\"button\"\n    >\n      <div class=\"icon-wrapper\" v-if=\"props.showIcon\">\n        <slot\n          name=\"icon\"\n          :loading=\"loadingValues.includes(btn.value)\"\n          :checked=\"innerValue.includes(btn.value)\"\n        >\n          <LoaderCircle\n            class=\"animate-spin\"\n            v-if=\"loadingValues.includes(btn.value)\"\n          />\n          <CircleCheckBig v-else-if=\"innerValue.includes(btn.value)\" />\n          <Circle v-else />\n        </slot>\n      </div>\n      <slot name=\"option\" :label=\"btn.label\" :value=\"btn.value\" :data=\"btn\">\n        <VbenRenderContent :content=\"btn.label\" />\n      </slot>\n    </Button>\n  </VbenButtonGroup>\n</template>\n<style lang=\"scss\" scoped>\n.vben-check-button-group {\n  display: flex;\n  flex-wrap: wrap;\n\n  &:deep(.size-large) button {\n    .icon-wrapper {\n      margin-right: 0.3rem;\n\n      svg {\n        width: 1rem;\n        height: 1rem;\n      }\n    }\n  }\n\n  &:deep(.size-middle) button {\n    .icon-wrapper {\n      margin-right: 0.2rem;\n\n      svg {\n        width: 0.75rem;\n        height: 0.75rem;\n      }\n    }\n  }\n\n  &:deep(.size-small) button {\n    .icon-wrapper {\n      margin-right: 0.1rem;\n\n      svg {\n        width: 0.65rem;\n        height: 0.65rem;\n      }\n    }\n  }\n\n  &.no-gap > :deep(button):nth-of-type(1) {\n    border-right-width: 0;\n  }\n\n  &.no-gap {\n    :deep(button + button) {\n      margin-right: -1px;\n      border-left-width: 1px;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ButtonVariants } from '../../ui';\nimport type { VbenButtonProps } from './button';\n\nimport { computed, useSlots } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { VbenTooltip } from '../tooltip';\nimport VbenButton from './button.vue';\n\ninterface Props extends VbenButtonProps {\n  class?: any;\n  disabled?: boolean;\n  onClick?: () => void;\n  tooltip?: string;\n  tooltipDelayDuration?: number;\n  tooltipSide?: 'bottom' | 'left' | 'right' | 'top';\n  variant?: ButtonVariants;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  disabled: false,\n  onClick: () => {},\n  tooltipDelayDuration: 200,\n  tooltipSide: 'bottom',\n  variant: 'icon',\n});\n\nconst slots = useSlots();\n\nconst showTooltip = computed(() => !!slots.tooltip || !!props.tooltip);\n</script>\n\n<template>\n  <VbenButton\n    v-if=\"!showTooltip\"\n    :class=\"cn('rounded-full', props.class)\"\n    :disabled=\"disabled\"\n    :variant=\"variant\"\n    size=\"icon\"\n    @click=\"onClick\"\n  >\n    <slot></slot>\n  </VbenButton>\n\n  <VbenTooltip\n    v-else\n    :delay-duration=\"tooltipDelayDuration\"\n    :side=\"tooltipSide\"\n  >\n    <template #trigger>\n      <VbenButton\n        :class=\"cn('rounded-full', props.class)\"\n        :disabled=\"disabled\"\n        :variant=\"variant\"\n        size=\"icon\"\n        @click=\"onClick\"\n      >\n        <slot></slot>\n      </VbenButton>\n    </template>\n    <slot v-if=\"slots.tooltip\" name=\"tooltip\"> </slot>\n    <template v-else>\n      {{ tooltip }}\n    </template>\n  </VbenTooltip>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/button/index.ts",
    "content": "export type * from './button';\nexport { default as VbenButtonGroup } from './button-group.vue';\nexport { default as VbenButton } from './button.vue';\nexport { default as VbenCheckButtonGroup } from './check-button-group.vue';\nexport { default as VbenIconButton } from './icon-button.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/checkbox.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue';\n\nimport { useId } from 'vue';\n\nimport { useForwardPropsEmits } from 'radix-vue';\n\nimport { Checkbox } from '../../ui/checkbox';\n\nconst props = defineProps<CheckboxRootProps & { indeterminate?: boolean }>();\n\nconst emits = defineEmits<CheckboxRootEmits>();\n\nconst checked = defineModel<boolean>('checked');\n\nconst forwarded = useForwardPropsEmits(props, emits);\n\nconst id = useId();\n</script>\n\n<template>\n  <div class=\"flex items-center\">\n    <Checkbox v-bind=\"forwarded\" :id=\"id\" v-model:checked=\"checked\" />\n    <label :for=\"id\" class=\"ml-2 cursor-pointer text-sm\"> <slot></slot> </label>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/index.ts",
    "content": "export { default as VbenCheckbox } from './checkbox.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  ContextMenuContentProps,\n  ContextMenuRootEmits,\n  ContextMenuRootProps,\n} from 'radix-vue';\n\nimport type { ClassType } from '@vben-core/typings';\n\nimport type { IContextMenuItem } from './interface';\n\nimport { computed } from 'vue';\n\nimport { useForwardPropsEmits } from 'radix-vue';\n\nimport {\n  ContextMenu,\n  ContextMenuContent,\n  ContextMenuItem,\n  ContextMenuSeparator,\n  ContextMenuShortcut,\n  ContextMenuTrigger,\n} from '../../ui/context-menu';\n\nconst props = defineProps<\n  ContextMenuRootProps & {\n    class?: ClassType;\n    contentClass?: ClassType;\n    contentProps?: ContextMenuContentProps;\n    handlerData?: Record<string, any>;\n    itemClass?: ClassType;\n    menus: (data: any) => IContextMenuItem[];\n  }\n>();\n\nconst emits = defineEmits<ContextMenuRootEmits>();\n\nconst delegatedProps = computed(() => {\n  const {\n    class: _cls,\n    contentClass: _,\n    contentProps: _cProps,\n    itemClass: _iCls,\n    ...delegated\n  } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n\nconst menusView = computed(() => {\n  return props.menus?.(props.handlerData);\n});\n\nfunction handleClick(menu: IContextMenuItem) {\n  if (menu.disabled) {\n    return;\n  }\n  menu?.handler?.(props.handlerData);\n}\n</script>\n\n<template>\n  <ContextMenu v-bind=\"forwarded\">\n    <ContextMenuTrigger as-child>\n      <slot></slot>\n    </ContextMenuTrigger>\n    <ContextMenuContent\n      :class=\"contentClass\"\n      v-bind=\"contentProps\"\n      class=\"side-content z-popup\"\n    >\n      <template v-for=\"menu in menusView\" :key=\"menu.key\">\n        <ContextMenuItem\n          :class=\"itemClass\"\n          :disabled=\"menu.disabled\"\n          :inset=\"menu.inset || !menu.icon\"\n          class=\"cursor-pointer\"\n          @click=\"handleClick(menu)\"\n        >\n          <component\n            :is=\"menu.icon\"\n            v-if=\"menu.icon\"\n            class=\"mr-2 size-4 text-lg\"\n          />\n\n          {{ menu.text }}\n          <ContextMenuShortcut v-if=\"menu.shortcut\">\n            {{ menu.shortcut }}\n          </ContextMenuShortcut>\n        </ContextMenuItem>\n        <ContextMenuSeparator v-if=\"menu.separator\" />\n      </template>\n    </ContextMenuContent>\n  </ContextMenu>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/index.ts",
    "content": "export { default as VbenContextMenu } from './context-menu.vue';\n\nexport type * from './interface';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts",
    "content": "import type { Component } from 'vue';\n\ninterface IContextMenuItem {\n  /**\n   * @zh_CN 是否禁用\n   */\n  disabled?: boolean;\n  /**\n   * @zh_CN 点击事件处理\n   * @param data\n   */\n  handler?: (data: any) => void;\n  /**\n   * @zh_CN 图标\n   */\n  icon?: Component;\n  /**\n   * @zh_CN 是否显示图标\n   */\n  inset?: boolean;\n  /**\n   * @zh_CN 唯一标识\n   */\n  key: string;\n  /**\n   * @zh_CN 是否是分割线\n   */\n  separator?: boolean;\n  /**\n   * @zh_CN 快捷键\n   */\n  shortcut?: string;\n  /**\n   * @zh_CN 标题\n   */\n  text: string;\n}\nexport type { IContextMenuItem };\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed, onMounted, ref, unref, watch, watchEffect } from 'vue';\n\nimport { isNumber } from '@vben-core/shared/utils';\n\nimport { TransitionPresets, useTransition } from '@vueuse/core';\n\ninterface Props {\n  autoplay?: boolean;\n  color?: string;\n  decimal?: string;\n  decimals?: number;\n  duration?: number;\n  endVal?: number;\n  prefix?: string;\n  separator?: string;\n  startVal?: number;\n  suffix?: string;\n  transition?: keyof typeof TransitionPresets;\n  useEasing?: boolean;\n}\n\ndefineOptions({ name: 'CountToAnimator' });\n\nconst props = withDefaults(defineProps<Props>(), {\n  autoplay: true,\n  color: '',\n  decimal: '.',\n  decimals: 0,\n  duration: 1500,\n  endVal: 2021,\n  prefix: '',\n  separator: ',',\n  startVal: 0,\n  suffix: '',\n  transition: 'linear',\n  useEasing: true,\n});\n\nconst emit = defineEmits<{\n  finished: [];\n  /**\n   * @deprecated 请使用{@link finished}事件\n   */\n  onFinished: [];\n  /**\n   * @deprecated 请使用{@link started}事件\n   */\n  onStarted: [];\n  started: [];\n}>();\n\nconst source = ref(props.startVal);\nconst disabled = ref(false);\nlet outputValue = useTransition(source);\n\nconst value = computed(() => formatNumber(unref(outputValue)));\n\nwatchEffect(() => {\n  source.value = props.startVal;\n});\n\nwatch([() => props.startVal, () => props.endVal], () => {\n  if (props.autoplay) {\n    start();\n  }\n});\n\nonMounted(() => {\n  props.autoplay && start();\n});\n\nfunction start() {\n  run();\n  source.value = props.endVal;\n}\n\nfunction reset() {\n  source.value = props.startVal;\n  run();\n}\n\nfunction run() {\n  outputValue = useTransition(source, {\n    disabled,\n    duration: props.duration,\n    onFinished: () => {\n      emit('finished');\n      emit('onFinished');\n    },\n    onStarted: () => {\n      emit('started');\n      emit('onStarted');\n    },\n    ...(props.useEasing\n      ? { transition: TransitionPresets[props.transition] }\n      : {}),\n  });\n}\n\nfunction formatNumber(num: number | string) {\n  if (!num && num !== 0) {\n    return '';\n  }\n  const { decimal, decimals, prefix, separator, suffix } = props;\n  num = Number(num).toFixed(decimals);\n  num += '';\n\n  const x = num.split('.');\n  let x1 = x[0];\n  const x2 = x.length > 1 ? decimal + x[1] : '';\n\n  const rgx = /(\\d+)(\\d{3})/;\n  if (separator && !isNumber(separator) && x1) {\n    while (rgx.test(x1)) {\n      x1 = x1.replace(rgx, `$1${separator}$2`);\n    }\n  }\n  return prefix + x1 + x2 + suffix;\n}\n\ndefineExpose({ reset });\n</script>\n<template>\n  <span :style=\"{ color }\">\n    {{ value }}\n  </span>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/index.ts",
    "content": "export { default as VbenCountToAnimator } from './count-to-animator.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-menu.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  DropdownMenuProps,\n  VbenDropdownMenuItem as IDropdownMenuItem,\n} from './interface';\n\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '../../ui';\n\ninterface Props extends DropdownMenuProps {}\n\ndefineOptions({ name: 'DropdownMenu' });\nconst props = withDefaults(defineProps<Props>(), {});\n\nfunction handleItemClick(menu: IDropdownMenuItem) {\n  if (menu.disabled) {\n    return;\n  }\n  menu?.handler?.(props);\n}\n</script>\n<template>\n  <DropdownMenu>\n    <DropdownMenuTrigger class=\"flex h-full items-center gap-1\">\n      <slot></slot>\n    </DropdownMenuTrigger>\n    <DropdownMenuContent align=\"start\">\n      <DropdownMenuGroup>\n        <template v-for=\"menu in menus\" :key=\"menu.value\">\n          <DropdownMenuItem\n            :disabled=\"menu.disabled\"\n            class=\"data-[state=checked]:bg-accent data-[state=checked]:text-accent-foreground text-foreground/80 mb-1 cursor-pointer\"\n            @click=\"handleItemClick(menu)\"\n          >\n            <component :is=\"menu.icon\" v-if=\"menu.icon\" class=\"mr-2 size-4\" />\n            {{ menu.label }}\n          </DropdownMenuItem>\n          <DropdownMenuSeparator v-if=\"menu.separator\" class=\"bg-border\" />\n        </template>\n      </DropdownMenuGroup>\n    </DropdownMenuContent>\n  </DropdownMenu>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-radio-menu.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DropdownMenuProps } from './interface';\n\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from '../../ui';\n\ninterface Props extends DropdownMenuProps {}\n\ndefineOptions({ name: 'DropdownRadioMenu' });\nwithDefaults(defineProps<Props>(), {});\n\nconst modelValue = defineModel<string>();\n\nfunction handleItemClick(value: string) {\n  modelValue.value = value;\n}\n</script>\n<template>\n  <DropdownMenu>\n    <DropdownMenuTrigger as-child class=\"flex items-center gap-1\">\n      <slot></slot>\n    </DropdownMenuTrigger>\n    <DropdownMenuContent align=\"start\">\n      <DropdownMenuGroup>\n        <template v-for=\"menu in menus\" :key=\"menu.key\">\n          <DropdownMenuItem\n            :class=\"\n              menu.value === modelValue\n                ? 'bg-accent text-accent-foreground'\n                : ''\n            \"\n            class=\"data-[state=checked]:bg-accent data-[state=checked]:text-accent-foreground text-foreground/80 mb-1 cursor-pointer\"\n            @click=\"handleItemClick(menu.value)\"\n          >\n            <component :is=\"menu.icon\" v-if=\"menu.icon\" class=\"mr-2 size-4\" />\n            <span\n              v-if=\"!menu.icon\"\n              :class=\"menu.value === modelValue ? 'bg-foreground' : ''\"\n              class=\"mr-2 size-1.5 rounded-full\"\n            ></span>\n            {{ menu.label }}\n          </DropdownMenuItem>\n        </template>\n      </DropdownMenuGroup>\n    </DropdownMenuContent>\n  </DropdownMenu>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/index.ts",
    "content": "export { default as VbenDropdownMenu } from './dropdown-menu.vue';\nexport { default as VbenDropdownRadioMenu } from './dropdown-radio-menu.vue';\n\nexport type * from './interface';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts",
    "content": "import type { Component } from 'vue';\n\ninterface VbenDropdownMenuItem {\n  disabled?: boolean;\n  /**\n   * @zh_CN 点击事件处理\n   * @param data\n   */\n  handler?: (data: any) => void;\n  /**\n   * @zh_CN 图标\n   */\n  icon?: Component;\n  /**\n   * @zh_CN 标题\n   */\n  label: string;\n  /**\n   * @zh_CN 是否是分割线\n   */\n  separator?: boolean;\n  /**\n   * @zh_CN 唯一标识\n   */\n  value: string;\n}\n\ninterface DropdownMenuProps {\n  menus: VbenDropdownMenuItem[];\n}\n\nexport type { DropdownMenuProps, VbenDropdownMenuItem };\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/expandable-arrow.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ChevronDown } from '@vben-core/icons';\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: string;\n}>();\n\n// 控制箭头展开/收起状态\nconst collapsed = defineModel({ default: false });\n</script>\n\n<template>\n  <div\n    :class=\"cn('vben-link inline-flex items-center', props.class)\"\n    @click=\"collapsed = !collapsed\"\n  >\n    <slot :is-expanded=\"collapsed\">\n      {{ collapsed }}\n      <!-- <span>{{ isExpanded ? '收起' : '展开' }}</span> -->\n    </slot>\n    <div\n      :class=\"{ 'rotate-180': !collapsed }\"\n      class=\"transition-transform duration-300\"\n    >\n      <slot name=\"icon\">\n        <ChevronDown class=\"size-4\" />\n      </slot>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/index.ts",
    "content": "export { default as VbenExpandableArrow } from './expandable-arrow.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Maximize, Minimize } from '@vben-core/icons';\n\nimport { useFullscreen } from '@vueuse/core';\n\nimport { VbenIconButton } from '../button';\n\ndefineOptions({ name: 'FullScreen' });\n\nconst { isFullscreen, toggle } = useFullscreen();\n\n// 重新检查全屏状态\nisFullscreen.value = !!(\n  document.fullscreenElement ||\n  // @ts-ignore\n  document.webkitFullscreenElement ||\n  // @ts-ignore\n  document.mozFullScreenElement ||\n  // @ts-ignore\n  document.msFullscreenElement\n);\n</script>\n<template>\n  <VbenIconButton\n    class=\"hover:animate-[shrink_0.3s_ease-in-out]\"\n    @click=\"toggle\"\n  >\n    <Minimize v-if=\"isFullscreen\" class=\"text-foreground size-4\" />\n    <Maximize v-else class=\"text-foreground size-4\" />\n  </VbenIconButton>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/index.ts",
    "content": "export { default as VbenFullScreen } from './full-screen.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  HoverCardContentProps,\n  HoverCardRootEmits,\n  HoverCardRootProps,\n} from 'radix-vue';\n\nimport type { ClassType } from '@vben-core/typings';\n\nimport { computed } from 'vue';\n\nimport { useForwardPropsEmits } from 'radix-vue';\n\nimport { HoverCard, HoverCardContent, HoverCardTrigger } from '../../ui';\n\ninterface Props extends HoverCardRootProps {\n  class?: ClassType;\n  contentClass?: ClassType;\n  contentProps?: HoverCardContentProps;\n}\n\nconst props = defineProps<Props>();\n\nconst emits = defineEmits<HoverCardRootEmits>();\n\nconst delegatedProps = computed(() => {\n  const {\n    class: _cls,\n    contentClass: _,\n    contentProps: _cProps,\n    ...delegated\n  } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <HoverCard v-bind=\"forwarded\">\n    <HoverCardTrigger as-child class=\"h-full\">\n      <div class=\"h-full cursor-pointer\">\n        <slot name=\"trigger\"></slot>\n      </div>\n    </HoverCardTrigger>\n    <HoverCardContent\n      :class=\"contentClass\"\n      v-bind=\"contentProps\"\n      class=\"side-content z-popup\"\n    >\n      <slot></slot>\n    </HoverCardContent>\n  </HoverCard>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/index.ts",
    "content": "export { default as VbenHoverCard } from './hover-card.vue';\nexport type { HoverCardContentProps } from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Component } from 'vue';\n\nimport { computed } from 'vue';\n\nimport { IconDefault, IconifyIcon } from '@vben-core/icons';\nimport {\n  isFunction,\n  isHttpUrl,\n  isObject,\n  isString,\n} from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  // 没有是否显示默认图标\n  fallback?: boolean;\n  icon?: Component | Function | string;\n}>();\n\nconst isRemoteIcon = computed(() => {\n  return isString(props.icon) && isHttpUrl(props.icon);\n});\n\nconst isComponent = computed(() => {\n  const { icon } = props;\n  return !isString(icon) && (isObject(icon) || isFunction(icon));\n});\n</script>\n\n<template>\n  <component :is=\"icon as Component\" v-if=\"isComponent\" v-bind=\"$attrs\" />\n  <img v-else-if=\"isRemoteIcon\" :src=\"icon as string\" v-bind=\"$attrs\" />\n  <IconifyIcon v-else-if=\"icon\" v-bind=\"$attrs\" :icon=\"icon as string\" />\n  <IconDefault v-else-if=\"fallback\" v-bind=\"$attrs\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/icon/index.ts",
    "content": "export { default as VbenIcon } from './icon.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/index.ts",
    "content": "export * from './avatar';\nexport * from './back-top';\nexport * from './breadcrumb';\nexport * from './button';\nexport * from './checkbox';\nexport * from './context-menu';\nexport * from './count-to-animator';\nexport * from './dropdown-menu';\nexport * from './expandable-arrow';\nexport * from './full-screen';\nexport * from './hover-card';\nexport * from './icon';\nexport * from './input-password';\nexport * from './logo';\nexport * from './pin-input';\nexport * from './popover';\nexport * from './render-content';\nexport * from './scrollbar';\nexport * from './segmented';\nexport * from './select';\nexport * from './spine-text';\nexport * from './spinner';\nexport * from './tooltip';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/input-password/index.ts",
    "content": "export { default as VbenInputPassword } from './input-password.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref, useSlots } from 'vue';\n\nimport { Eye, EyeOff } from '@vben-core/icons';\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Input } from '../../ui';\nimport PasswordStrength from './password-strength.vue';\n\ninterface Props {\n  class?: any;\n  /**\n   * 是否显示密码强度\n   */\n  passwordStrength?: boolean;\n}\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\nconst props = defineProps<Props>();\n\nconst modelValue = defineModel<string>();\n\nconst slots = useSlots();\n\nconst show = ref(false);\n</script>\n\n<template>\n  <div class=\"relative w-full\">\n    <Input\n      v-bind=\"$attrs\"\n      v-model=\"modelValue\"\n      :class=\"cn(props.class)\"\n      :type=\"show ? 'text' : 'password'\"\n    />\n    <template v-if=\"passwordStrength\">\n      <PasswordStrength :password=\"modelValue\" />\n      <p v-if=\"slots.strengthText\" class=\"text-muted-foreground mt-1.5 text-xs\">\n        <slot name=\"strengthText\"> </slot>\n      </p>\n    </template>\n    <div\n      :class=\"{\n        'top-3': !!passwordStrength,\n        'top-1/2 -translate-y-1/2 items-center': !passwordStrength,\n      }\"\n      class=\"hover:text-foreground text-foreground/60 absolute inset-y-0 right-0 flex cursor-pointer pr-3 text-lg leading-5\"\n      @click=\"show = !show\"\n    >\n      <Eye v-if=\"show\" class=\"size-4\" />\n      <EyeOff v-else class=\"size-4\" />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\nconst props = withDefaults(defineProps<{ password?: string }>(), {\n  password: '',\n});\n\nconst strengthList: string[] = [\n  '',\n  '#e74242',\n  '#ED6F6F',\n  '#EFBD47',\n  '#55D18780',\n  '#55D187',\n];\n\nconst currentStrength = computed(() => {\n  return checkPasswordStrength(props.password);\n});\n\nconst currentColor = computed(() => {\n  return strengthList[currentStrength.value];\n});\n\n/**\n * Check the strength of a password\n */\nfunction checkPasswordStrength(password: string) {\n  let strength = 0;\n\n  // Check length\n  if (password.length >= 8) strength++;\n\n  // Check for lowercase letters\n  if (/[a-z]/.test(password)) strength++;\n\n  // Check for uppercase letters\n  if (/[A-Z]/.test(password)) strength++;\n\n  // Check for numbers\n  if (/\\d/.test(password)) strength++;\n\n  // Check for special characters\n  if (/[^\\da-z]/i.test(password)) strength++;\n\n  return strength;\n}\n</script>\n\n<template>\n  <div class=\"relative mt-2 flex items-center justify-between\">\n    <template v-for=\"index in 5\" :key=\"index\">\n      <div\n        class=\"dark:bg-input-background bg-heavy relative mr-1 h-1.5 w-1/5 rounded-sm last:mr-0\"\n      >\n        <span\n          :style=\"{\n            backgroundColor: currentColor,\n            width: currentStrength >= index ? '100%' : '',\n          }\"\n          class=\"absolute left-0 h-full w-0 rounded-sm transition-all duration-500\"\n        ></span>\n      </div>\n    </template>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/logo/index.ts",
    "content": "export { default as VbenLogo } from './logo.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue",
    "content": "<script setup lang=\"ts\">\nimport { VbenAvatar } from '../avatar';\n\ninterface Props {\n  /**\n   * @zh_CN 是否收起文本\n   */\n  collapsed?: boolean;\n  /**\n   * @zh_CN Logo 图片适应方式\n   */\n  fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\n  /**\n   * @zh_CN Logo 跳转地址\n   */\n  href?: string;\n  /**\n   * @zh_CN Logo 图片大小\n   */\n  logoSize?: number;\n  /**\n   * @zh_CN Logo 图标\n   */\n  src?: string;\n  /**\n   * @zh_CN Logo 文本\n   */\n  text: string;\n  /**\n   * @zh_CN Logo 主题\n   */\n  theme?: string;\n}\n\ndefineOptions({\n  name: 'VbenLogo',\n});\n\nwithDefaults(defineProps<Props>(), {\n  collapsed: false,\n  href: 'javascript:void 0',\n  logoSize: 32,\n  src: '',\n  theme: 'light',\n  fit: 'cover',\n});\n</script>\n\n<template>\n  <div :class=\"theme\" class=\"flex h-full items-center text-lg\">\n    <a\n      :class=\"$attrs.class\"\n      :href=\"href\"\n      class=\"flex h-full items-center gap-2 overflow-hidden px-3 text-lg leading-normal transition-all duration-500\"\n    >\n      <VbenAvatar\n        v-if=\"src\"\n        :alt=\"text\"\n        :src=\"src\"\n        :size=\"logoSize\"\n        :fit=\"fit\"\n        class=\"relative rounded-none bg-transparent\"\n      />\n      <template v-if=\"!collapsed\">\n        <slot name=\"text\">\n          <span class=\"text-foreground truncate text-nowrap font-semibold\">\n            {{ text }}\n          </span>\n        </slot>\n      </template>\n    </a>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/index.ts",
    "content": "export { default as VbenPinInput } from './input.vue';\n\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PinInputProps } from './types';\n\nimport { computed, onBeforeUnmount, ref, useId, watch } from 'vue';\n\nimport { PinInput, PinInputGroup, PinInputInput } from '../../ui';\nimport { VbenButton } from '../button';\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\nconst {\n  codeLength = 6,\n  createText = async () => {},\n  disabled = false,\n  handleSendCode = async () => {},\n  loading = false,\n  maxTime = 60,\n} = defineProps<PinInputProps>();\n\nconst emit = defineEmits<{\n  complete: [];\n  sendError: [error: any];\n}>();\n\nconst timer = ref<ReturnType<typeof setTimeout>>();\n\nconst modelValue = defineModel<string>();\n\nconst inputValue = ref<string[]>([]);\nconst countdown = ref(0);\n\nconst btnText = computed(() => {\n  const countdownValue = countdown.value;\n  return createText?.(countdownValue);\n});\n\nconst btnLoading = computed(() => {\n  return loading || countdown.value > 0;\n});\n\nwatch(\n  () => modelValue.value,\n  () => {\n    inputValue.value = modelValue.value?.split('') ?? [];\n  },\n);\n\nwatch(inputValue, (val) => {\n  modelValue.value = val.join('');\n});\n\nfunction handleComplete(e: string[]) {\n  modelValue.value = e.join('');\n  emit('complete');\n}\n\nasync function handleSend(e: Event) {\n  try {\n    e?.preventDefault();\n    countdown.value = maxTime;\n    startCountdown();\n    await handleSendCode();\n  } catch (error) {\n    console.error('Failed to send code:', error);\n    // Consider emitting an error event or showing a notification\n    emit('sendError', error);\n  }\n}\n\nfunction startCountdown() {\n  if (countdown.value > 0) {\n    timer.value = setTimeout(() => {\n      countdown.value--;\n      startCountdown();\n    }, 1000);\n  }\n}\n\nonBeforeUnmount(() => {\n  countdown.value = 0;\n  clearTimeout(timer.value);\n});\n\nconst id = useId();\n</script>\n\n<template>\n  <PinInput\n    :id=\"id\"\n    v-model=\"inputValue\"\n    :disabled=\"disabled\"\n    class=\"flex w-full justify-between\"\n    otp\n    placeholder=\"○\"\n    type=\"number\"\n    @complete=\"handleComplete\"\n  >\n    <div class=\"relative flex w-full\">\n      <PinInputGroup class=\"mr-2\">\n        <PinInputInput\n          v-for=\"(item, index) in codeLength\"\n          :key=\"item\"\n          :index=\"index\"\n        />\n      </PinInputGroup>\n      <VbenButton\n        :disabled=\"disabled\"\n        :loading=\"btnLoading\"\n        class=\"flex-grow\"\n        size=\"lg\"\n        variant=\"outline\"\n        @click=\"handleSend\"\n      >\n        {{ btnText }}\n      </VbenButton>\n    </div>\n  </PinInput>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts",
    "content": "interface PinInputProps {\n  class?: any;\n  /**\n   * 验证码长度\n   */\n  codeLength?: number;\n  /**\n   * 发送验证码按钮文本\n   */\n  createText?: (countdown: number) => string;\n  /**\n   * 是否禁用\n   */\n  disabled?: boolean;\n  /**\n   * 自定义验证码发送逻辑\n   * @returns\n   */\n  handleSendCode?: () => Promise<void>;\n  /**\n   * 发送验证码按钮loading\n   */\n  loading?: boolean;\n  /**\n   * 最大重试时间\n   */\n  maxTime?: number;\n}\n\nexport type { PinInputProps };\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/popover/index.ts",
    "content": "export { default as VbenPopover } from './popover.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  PopoverContentProps,\n  PopoverRootEmits,\n  PopoverRootProps,\n} from 'radix-vue';\n\nimport type { ClassType } from '@vben-core/typings';\n\nimport { computed } from 'vue';\n\nimport { useForwardPropsEmits } from 'radix-vue';\n\nimport {\n  PopoverContent,\n  Popover as PopoverRoot,\n  PopoverTrigger,\n} from '../../ui';\n\ninterface Props extends PopoverRootProps {\n  class?: ClassType;\n  contentClass?: ClassType;\n  contentProps?: PopoverContentProps;\n  triggerClass?: ClassType;\n}\n\nconst props = withDefaults(defineProps<Props>(), {});\n\nconst emits = defineEmits<PopoverRootEmits>();\n\nconst delegatedProps = computed(() => {\n  const {\n    class: _cls,\n    contentClass: _,\n    contentProps: _cProps,\n    triggerClass: _tClass,\n    ...delegated\n  } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <PopoverRoot v-bind=\"forwarded\">\n    <PopoverTrigger :class=\"triggerClass\">\n      <slot name=\"trigger\"></slot>\n\n      <PopoverContent\n        :class=\"contentClass\"\n        class=\"side-content z-popup\"\n        v-bind=\"contentProps\"\n      >\n        <slot></slot>\n      </PopoverContent>\n    </PopoverTrigger>\n  </PopoverRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/render-content/index.ts",
    "content": "export { default as VbenRenderContent } from './render-content.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue",
    "content": "<script lang=\"ts\">\nimport type { Component, PropType } from 'vue';\n\nimport { defineComponent, h } from 'vue';\n\nimport { isFunction, isObject, isString } from '@vben-core/shared/utils';\n\nexport default defineComponent({\n  name: 'RenderContent',\n  props: {\n    content: {\n      default: undefined as\n        | PropType<(() => any) | Component | string>\n        | undefined,\n      type: [Object, String, Function],\n    },\n    renderBr: {\n      default: false,\n      type: Boolean,\n    },\n  },\n  setup(props, { attrs, slots }) {\n    return () => {\n      if (!props.content) {\n        return null;\n      }\n      const isComponent =\n        (isObject(props.content) || isFunction(props.content)) &&\n        props.content !== null;\n      if (!isComponent) {\n        if (props.renderBr && isString(props.content)) {\n          const lines = props.content.split('\\n');\n          const result = [];\n          for (const [i, line] of lines.entries()) {\n            result.push(h('p', { key: i }, line));\n            // if (i < lines.length - 1) {\n            //   result.push(h('br'));\n            // }\n          }\n          return result;\n        } else {\n          return props.content;\n        }\n      }\n      return h(props.content as never, {\n        ...attrs,\n        props: {\n          ...props,\n          ...attrs,\n        },\n        slots,\n      });\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/index.ts",
    "content": "export { default as VbenScrollbar } from './scrollbar.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ClassType } from '@vben-core/typings';\n\nimport { computed, ref } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ScrollArea, ScrollBar } from '../../ui';\n\ninterface Props {\n  class?: ClassType;\n  horizontal?: boolean;\n  scrollBarClass?: ClassType;\n  shadow?: boolean;\n  shadowBorder?: boolean;\n  shadowBottom?: boolean;\n  shadowLeft?: boolean;\n  shadowRight?: boolean;\n  shadowTop?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  class: '',\n  horizontal: false,\n  shadow: false,\n  shadowBorder: false,\n  shadowBottom: true,\n  shadowLeft: false,\n  shadowRight: false,\n  shadowTop: true,\n});\n\nconst emit = defineEmits<{\n  scrollAt: [{ bottom: boolean; left: boolean; right: boolean; top: boolean }];\n}>();\n\nconst isAtTop = ref(true);\nconst isAtRight = ref(false);\nconst isAtBottom = ref(false);\nconst isAtLeft = ref(true);\n\n/**\n * We have to check if the scroll amount is close enough to some threshold in order to\n * more accurately calculate arrivedState. This is because scrollTop/scrollLeft are non-rounded\n * numbers, while scrollHeight/scrollWidth and clientHeight/clientWidth are rounded.\n * https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#determine_if_an_element_has_been_totally_scrolled\n */\nconst ARRIVED_STATE_THRESHOLD_PIXELS = 1;\n\nconst showShadowTop = computed(() => props.shadow && props.shadowTop);\nconst showShadowBottom = computed(() => props.shadow && props.shadowBottom);\nconst showShadowLeft = computed(() => props.shadow && props.shadowLeft);\nconst showShadowRight = computed(() => props.shadow && props.shadowRight);\n\nconst computedShadowClasses = computed(() => {\n  return {\n    'both-shadow':\n      !isAtLeft.value &&\n      !isAtRight.value &&\n      showShadowLeft.value &&\n      showShadowRight.value,\n    'left-shadow': !isAtLeft.value && showShadowLeft.value,\n    'right-shadow': !isAtRight.value && showShadowRight.value,\n  };\n});\n\nfunction handleScroll(event: Event) {\n  const target = event.target as HTMLElement;\n  const scrollTop = target?.scrollTop ?? 0;\n  const scrollLeft = target?.scrollLeft ?? 0;\n  const clientHeight = target?.clientHeight ?? 0;\n  const clientWidth = target?.clientWidth ?? 0;\n  const scrollHeight = target?.scrollHeight ?? 0;\n  const scrollWidth = target?.scrollWidth ?? 0;\n  isAtTop.value = scrollTop <= 0;\n  isAtLeft.value = scrollLeft <= 0;\n  isAtBottom.value =\n    Math.abs(scrollTop) + clientHeight >=\n    scrollHeight - ARRIVED_STATE_THRESHOLD_PIXELS;\n  isAtRight.value =\n    Math.abs(scrollLeft) + clientWidth >=\n    scrollWidth - ARRIVED_STATE_THRESHOLD_PIXELS;\n\n  emit('scrollAt', {\n    bottom: isAtBottom.value,\n    left: isAtLeft.value,\n    right: isAtRight.value,\n    top: isAtTop.value,\n  });\n}\n</script>\n\n<template>\n  <ScrollArea\n    :class=\"[cn(props.class), computedShadowClasses]\"\n    :on-scroll=\"handleScroll\"\n    class=\"vben-scrollbar relative\"\n  >\n    <div\n      v-if=\"showShadowTop\"\n      :class=\"{\n        'opacity-100': !isAtTop,\n        'border-border border-t': shadowBorder && !isAtTop,\n      }\"\n      class=\"scrollbar-top-shadow pointer-events-none absolute top-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]\"\n    ></div>\n    <slot></slot>\n    <div\n      v-if=\"showShadowBottom\"\n      :class=\"{\n        'opacity-100': !isAtTop && !isAtBottom,\n        'border-border border-b': shadowBorder && !isAtTop && !isAtBottom,\n      }\"\n      class=\"scrollbar-bottom-shadow pointer-events-none absolute bottom-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]\"\n    ></div>\n    <ScrollBar\n      v-if=\"horizontal\"\n      :class=\"scrollBarClass\"\n      orientation=\"horizontal\"\n    />\n  </ScrollArea>\n</template>\n\n<style scoped>\n.vben-scrollbar {\n  &:not(.both-shadow).left-shadow {\n    mask-image: linear-gradient(90deg, transparent, #000 16px);\n  }\n\n  &:not(.both-shadow).right-shadow {\n    mask-image: linear-gradient(\n      90deg,\n      #000 0%,\n      #000 calc(100% - 16px),\n      transparent\n    );\n  }\n\n  &.both-shadow {\n    mask-image: linear-gradient(\n      90deg,\n      transparent,\n      #000 16px,\n      #000 calc(100% - 16px),\n      transparent 100%\n    );\n  }\n}\n\n.scrollbar-top-shadow {\n  background: linear-gradient(\n    to bottom,\n    hsl(var(--scroll-shadow, var(--background))),\n    transparent\n  );\n}\n\n.scrollbar-bottom-shadow {\n  background: linear-gradient(\n    to top,\n    hsl(var(--scroll-shadow, var(--background))),\n    transparent\n  );\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/segmented/index.ts",
    "content": "export { default as VbenSegmented } from './segmented.vue';\n\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/segmented/segmented.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SegmentedItem } from './types';\n\nimport { computed } from 'vue';\n\nimport { TabsTrigger } from 'radix-vue';\n\nimport { Tabs, TabsContent, TabsList } from '../../ui';\nimport TabsIndicator from './tabs-indicator.vue';\n\ninterface Props {\n  defaultValue?: string;\n  tabs?: SegmentedItem[];\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  defaultValue: '',\n  tabs: () => [],\n});\n\nconst activeTab = defineModel<string>();\n\nconst getDefaultValue = computed(() => {\n  return props.defaultValue || props.tabs[0]?.value;\n});\n\nconst tabsStyle = computed(() => {\n  return {\n    'grid-template-columns': `repeat(${props.tabs.length}, minmax(0, 1fr))`,\n  };\n});\n\nconst tabsIndicatorStyle = computed(() => {\n  return {\n    width: `${(100 / props.tabs.length).toFixed(0)}%`,\n  };\n});\n\nfunction activeClass(tab: string): string[] {\n  return tab === activeTab.value ? ['!font-bold', 'text-primary'] : [];\n}\n</script>\n\n<template>\n  <Tabs v-model=\"activeTab\" :default-value=\"getDefaultValue\">\n    <TabsList\n      :style=\"tabsStyle\"\n      class=\"bg-accent !outline-heavy relative grid w-full !outline !outline-2\"\n    >\n      <TabsIndicator :style=\"tabsIndicatorStyle\" />\n      <template v-for=\"tab in tabs\" :key=\"tab.value\">\n        <TabsTrigger\n          :value=\"tab.value\"\n          :class=\"activeClass(tab.value)\"\n          class=\"hover:text-primary z-20 inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium disabled:pointer-events-none disabled:opacity-50\"\n        >\n          {{ tab.label }}\n        </TabsTrigger>\n      </template>\n    </TabsList>\n    <template v-for=\"tab in tabs\" :key=\"tab.value\">\n      <TabsContent :value=\"tab.value\">\n        <slot :name=\"tab.value\"></slot>\n      </TabsContent>\n    </template>\n  </Tabs>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TabsIndicatorProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { TabsIndicator, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<TabsIndicatorProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <TabsIndicator\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'absolute bottom-0 left-0 z-10 h-full w-1/2 translate-x-[--radix-tabs-indicator-position] rounded-full px-0 py-1 pr-0.5 transition-[width,transform] duration-300',\n        props.class,\n      )\n    \"\n  >\n    <div\n      class=\"bg-background text-foreground inline-flex h-full w-full items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\"\n    >\n      <slot></slot>\n    </div>\n  </TabsIndicator>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/segmented/types.ts",
    "content": "interface SegmentedItem {\n  label: string;\n  value: string;\n}\n\nexport type { SegmentedItem };\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/select/index.ts",
    "content": "export { default as VbenSelect } from './select.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/select/select.vue",
    "content": "<script lang=\"ts\" setup>\nimport { CircleX } from '@vben-core/icons';\n\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from '../../ui';\n\ninterface Props {\n  allowClear?: boolean;\n  class?: any;\n  options?: Array<{ label: string; value: string }>;\n  placeholder?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  allowClear: false,\n});\n\nconst modelValue = defineModel<string>();\n\nfunction handleClear() {\n  modelValue.value = undefined;\n}\n</script>\n<template>\n  <Select v-model=\"modelValue\">\n    <SelectTrigger :class=\"props.class\" class=\"flex w-full items-center\">\n      <SelectValue class=\"flex-auto text-left\" :placeholder=\"placeholder\" />\n      <CircleX\n        @pointerdown.stop\n        @click.stop.prevent=\"handleClear\"\n        v-if=\"allowClear && modelValue\"\n        data-clear-button\n        class=\"mr-1 size-4 cursor-pointer opacity-50 hover:opacity-100\"\n      />\n    </SelectTrigger>\n    <SelectContent>\n      <template v-for=\"item in options\" :key=\"item.value\">\n        <SelectItem :value=\"item.value\"> {{ item.label }} </SelectItem>\n      </template>\n    </SelectContent>\n  </Select>\n</template>\n\n<style lang=\"scss\" scoped>\nbutton[role='combobox'][data-placeholder] {\n  color: hsl(var(--muted-foreground));\n}\n\nbutton {\n  --ring: var(--primary);\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/index.ts",
    "content": "export { default as VbenSpineText } from './spine-text.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/spine-text.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nconst { animationDuration = 2, animationIterationCount = 'infinite' } =\n  defineProps<{\n    // 动画持续时间，单位秒\n    animationDuration?: number;\n    // 动画是否只执行一次\n    animationIterationCount?: 'infinite' | number;\n  }>();\n\nconst style = computed(() => {\n  return {\n    animation: `shine ${animationDuration}s linear ${animationIterationCount}`,\n  };\n});\n</script>\n<template>\n  <div :style=\"style\" class=\"vben-spine-text !bg-clip-text text-transparent\">\n    <slot></slot>\n  </div>\n</template>\n<style>\n.vben-spine-text {\n  background:\n    radial-gradient(circle at center, rgb(255 255 255 / 80%), #f000) -200% 50% /\n      200% 100% no-repeat,\n    #000;\n\n  /* animation: shine 3s linear infinite; */\n}\n\n.dark .vben-spine-text {\n  background:\n    radial-gradient(circle at center, rgb(24 24 26 / 80%), transparent) -200%\n      50% / 200% 100% no-repeat,\n    #f4f4f4;\n}\n\n@keyframes shine {\n  0% {\n    background-position: 200% 0%;\n  }\n\n  100% {\n    background-position: -200% 0%;\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/spinner/index.ts",
    "content": "export { default as VbenLoading } from './loading.vue';\nexport { default as VbenSpinner } from './spinner.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref, watch } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\ninterface Props {\n  class?: string;\n  /**\n   * @zh_CN 最小加载时间\n   * @en_US Minimum loading time\n   */\n  minLoadingTime?: number;\n\n  /**\n   * @zh_CN loading状态开启\n   */\n  spinning?: boolean;\n  /**\n   * @zh_CN 文字\n   */\n  text?: string;\n}\n\ndefineOptions({\n  name: 'VbenLoading',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  minLoadingTime: 50,\n  text: '',\n});\n// const startTime = ref(0);\nconst showSpinner = ref(false);\nconst renderSpinner = ref(false);\nconst timer = ref<ReturnType<typeof setTimeout>>();\n\nwatch(\n  () => props.spinning,\n  (show) => {\n    if (!show) {\n      showSpinner.value = false;\n      clearTimeout(timer.value);\n      return;\n    }\n\n    // startTime.value = performance.now();\n    timer.value = setTimeout(() => {\n      // const loadingTime = performance.now() - startTime.value;\n\n      showSpinner.value = true;\n      if (showSpinner.value) {\n        renderSpinner.value = true;\n      }\n    }, props.minLoadingTime);\n  },\n  {\n    immediate: true,\n  },\n);\n\nfunction onTransitionEnd() {\n  if (!showSpinner.value) {\n    renderSpinner.value = false;\n  }\n}\n</script>\n\n<template>\n  <div\n    :class=\"\n      cn(\n        'z-100 dark:bg-overlay bg-overlay-content absolute left-0 top-0 flex size-full flex-col items-center justify-center transition-all duration-500',\n        {\n          'invisible opacity-0': !showSpinner,\n        },\n        props.class,\n      )\n    \"\n    @transitionend=\"onTransitionEnd\"\n  >\n    <slot name=\"icon\" v-if=\"renderSpinner\">\n      <span class=\"dot relative inline-block size-9 text-3xl\">\n        <i\n          v-for=\"index in 4\"\n          :key=\"index\"\n          class=\"bg-primary absolute block size-4 origin-[50%_50%] scale-75 rounded-full opacity-30\"\n        ></i>\n      </span>\n    </slot>\n\n    <div v-if=\"text\" class=\"text-primary mt-4 text-xs\">{{ text }}</div>\n    <slot></slot>\n  </div>\n</template>\n\n<style scoped>\n.dot {\n  transform: rotate(45deg);\n  animation: rotate-ani 1.2s infinite linear;\n}\n\n.dot i {\n  animation: spin-move-ani 1s infinite linear alternate;\n}\n\n.dot i:nth-child(1) {\n  top: 0;\n  left: 0;\n}\n\n.dot i:nth-child(2) {\n  top: 0;\n  right: 0;\n  animation-delay: 0.4s;\n}\n\n.dot i:nth-child(3) {\n  right: 0;\n  bottom: 0;\n  animation-delay: 0.8s;\n}\n\n.dot i:nth-child(4) {\n  bottom: 0;\n  left: 0;\n  animation-delay: 1.2s;\n}\n\n@keyframes rotate-ani {\n  to {\n    transform: rotate(405deg);\n  }\n}\n\n@keyframes spin-move-ani {\n  to {\n    opacity: 1;\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref, watch } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\ninterface Props {\n  class?: string;\n  /**\n   * @zh_CN 最小加载时间\n   * @en_US Minimum loading time\n   */\n  minLoadingTime?: number;\n  /**\n   * @zh_CN loading状态开启\n   */\n  spinning?: boolean;\n}\n\ndefineOptions({\n  name: 'VbenSpinner',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  minLoadingTime: 50,\n});\n// const startTime = ref(0);\nconst showSpinner = ref(false);\nconst renderSpinner = ref(false);\nconst timer = ref<ReturnType<typeof setTimeout>>();\n\nwatch(\n  () => props.spinning,\n  (show) => {\n    if (!show) {\n      showSpinner.value = false;\n      clearTimeout(timer.value);\n      return;\n    }\n\n    // startTime.value = performance.now();\n    timer.value = setTimeout(() => {\n      // const loadingTime = performance.now() - startTime.value;\n\n      showSpinner.value = true;\n      if (showSpinner.value) {\n        renderSpinner.value = true;\n      }\n    }, props.minLoadingTime);\n  },\n  {\n    immediate: true,\n  },\n);\n\nfunction onTransitionEnd() {\n  if (!showSpinner.value) {\n    renderSpinner.value = false;\n  }\n}\n</script>\n\n<template>\n  <div\n    :class=\"\n      cn(\n        'flex-center z-100 bg-overlay-content absolute left-0 top-0 size-full backdrop-blur-sm transition-all duration-500',\n        {\n          'invisible opacity-0': !showSpinner,\n        },\n        props.class,\n      )\n    \"\n    @transitionend=\"onTransitionEnd\"\n  >\n    <div\n      :class=\"{ paused: !renderSpinner }\"\n      v-if=\"renderSpinner\"\n      class=\"loader before:bg-primary/50 after:bg-primary relative size-12 before:absolute before:left-0 before:top-[60px] before:h-[5px] before:w-12 before:rounded-[50%] before:content-[''] after:absolute after:left-0 after:top-0 after:h-full after:w-full after:rounded after:content-['']\"\n    ></div>\n  </div>\n</template>\n\n<style scoped>\n.paused {\n  &::before {\n    animation-play-state: paused !important;\n  }\n\n  &::after {\n    animation-play-state: paused !important;\n  }\n}\n\n.loader {\n  &::before {\n    animation: loader-shadow-ani 0.5s linear infinite;\n  }\n\n  &::after {\n    animation: loader-jump-ani 0.5s linear infinite;\n  }\n}\n\n@keyframes loader-jump-ani {\n  15% {\n    border-bottom-right-radius: 3px;\n  }\n\n  25% {\n    transform: translateY(9px) rotate(22.5deg);\n  }\n\n  50% {\n    border-bottom-right-radius: 40px;\n    transform: translateY(18px) scale(1, 0.9) rotate(45deg);\n  }\n\n  75% {\n    transform: translateY(9px) rotate(67.5deg);\n  }\n\n  100% {\n    transform: translateY(0) rotate(90deg);\n  }\n}\n\n@keyframes loader-shadow-ani {\n  0%,\n  100% {\n    transform: scale(1, 1);\n  }\n\n  50% {\n    transform: scale(1.2, 1);\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/help-tooltip.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nimport { CircleHelp } from 'lucide-vue-next';\n\nimport Tooltip from './tooltip.vue';\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\ndefineProps<{ triggerClass?: string }>();\n</script>\n\n<template>\n  <Tooltip :delay-duration=\"300\" side=\"right\">\n    <template #trigger>\n      <slot name=\"trigger\">\n        <CircleHelp\n          :class=\"\n            cn(\n              'text-foreground/80 hover:text-foreground inline-flex size-5 cursor-pointer',\n              triggerClass,\n            )\n          \"\n        />\n      </slot>\n    </template>\n    <slot></slot>\n  </Tooltip>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/index.ts",
    "content": "export { default as VbenHelpTooltip } from './help-tooltip.vue';\nexport { default as VbenTooltip } from './tooltip.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TooltipContentProps } from 'radix-vue';\n\nimport type { StyleValue } from 'vue';\n\nimport type { ClassType } from '@vben-core/typings';\n\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from '../../ui';\n\ninterface Props {\n  contentClass?: ClassType;\n  contentStyle?: StyleValue;\n  delayDuration?: number;\n  side?: TooltipContentProps['side'];\n}\n\nwithDefaults(defineProps<Props>(), {\n  delayDuration: 0,\n  side: 'right',\n});\n</script>\n\n<template>\n  <TooltipProvider :delay-duration=\"delayDuration\">\n    <Tooltip>\n      <TooltipTrigger as-child tabindex=\"-1\">\n        <slot name=\"trigger\"></slot>\n      </TooltipTrigger>\n      <TooltipContent\n        :class=\"contentClass\"\n        :side=\"side\"\n        :style=\"contentStyle\"\n        class=\"side-content text-popover-foreground bg-accent rounded-md\"\n      >\n        <slot></slot>\n      </TooltipContent>\n    </Tooltip>\n  </TooltipProvider>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/index.ts",
    "content": "export * from './components';\nexport * from './ui';\nexport { createContext, Slot, VisuallyHidden } from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/Accordion.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AccordionRootEmits, AccordionRootProps } from 'radix-vue';\n\nimport { AccordionRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<AccordionRootProps>();\nconst emits = defineEmits<AccordionRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <AccordionRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </AccordionRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AccordionContentProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { AccordionContent } from 'radix-vue';\n\nconst props = defineProps<AccordionContentProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <AccordionContent\n    v-bind=\"delegatedProps\"\n    class=\"data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm\"\n  >\n    <div :class=\"cn('pb-4 pt-0', props.class)\">\n      <slot></slot>\n    </div>\n  </AccordionContent>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AccordionItemProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { AccordionItem, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<AccordionItemProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <AccordionItem v-bind=\"forwardedProps\" :class=\"cn('border-b', props.class)\">\n    <slot></slot>\n  </AccordionItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AccordionTriggerProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronDown } from 'lucide-vue-next';\nimport { AccordionHeader, AccordionTrigger } from 'radix-vue';\n\nconst props = defineProps<AccordionTriggerProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <AccordionHeader class=\"flex\">\n    <AccordionTrigger\n      v-bind=\"delegatedProps\"\n      :class=\"\n        cn(\n          'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',\n          props.class,\n        )\n      \"\n    >\n      <slot></slot>\n      <slot name=\"icon\">\n        <ChevronDown\n          class=\"text-muted-foreground h-4 w-4 shrink-0 transition-transform duration-200\"\n        />\n      </slot>\n    </AccordionTrigger>\n  </AccordionHeader>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/index.ts",
    "content": "export { default as Accordion } from './Accordion.vue';\nexport { default as AccordionContent } from './AccordionContent.vue';\nexport { default as AccordionItem } from './AccordionItem.vue';\nexport { default as AccordionTrigger } from './AccordionTrigger.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialog.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AlertDialogEmits, AlertDialogProps } from 'radix-vue';\n\nimport { AlertDialogRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<AlertDialogProps>();\nconst emits = defineEmits<AlertDialogEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <AlertDialogRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </AlertDialogRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogAction.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AlertDialogActionProps } from 'radix-vue';\n\nimport { AlertDialogAction } from 'radix-vue';\n\nconst props = defineProps<AlertDialogActionProps>();\n</script>\n\n<template>\n  <AlertDialogAction v-bind=\"props\">\n    <slot></slot>\n  </AlertDialogAction>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogCancel.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AlertDialogCancelProps } from 'radix-vue';\n\nimport { AlertDialogCancel } from 'radix-vue';\n\nconst props = defineProps<AlertDialogCancelProps>();\n</script>\n\n<template>\n  <AlertDialogCancel v-bind=\"props\">\n    <slot></slot>\n  </AlertDialogCancel>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  AlertDialogContentEmits,\n  AlertDialogContentProps,\n} from 'radix-vue';\n\nimport type { ClassType } from '@vben-core/typings';\n\nimport { computed, ref } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport {\n  AlertDialogContent,\n  AlertDialogPortal,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nimport AlertDialogOverlay from './AlertDialogOverlay.vue';\n\nconst props = withDefaults(\n  defineProps<\n    AlertDialogContentProps & {\n      centered?: boolean;\n      class?: ClassType;\n      modal?: boolean;\n      open?: boolean;\n      overlayBlur?: number;\n      zIndex?: number;\n    }\n  >(),\n  { modal: true },\n);\nconst emits = defineEmits<\n  AlertDialogContentEmits & { close: []; closed: []; opened: [] }\n>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, modal: _modal, open: _open, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n\nconst contentRef = ref<InstanceType<typeof AlertDialogContent> | null>(null);\nfunction onAnimationEnd(event: AnimationEvent) {\n  // 只有在 contentRef 的动画结束时才触发 opened/closed 事件\n  if (event.target === contentRef.value?.$el) {\n    if (props.open) {\n      emits('opened');\n    } else {\n      emits('closed');\n    }\n  }\n}\ndefineExpose({\n  getContentRef: () => contentRef.value,\n});\n</script>\n\n<template>\n  <AlertDialogPortal>\n    <Transition name=\"fade\" appear>\n      <AlertDialogOverlay\n        v-if=\"open && modal\"\n        :style=\"{\n          ...(zIndex ? { zIndex } : {}),\n          position: 'fixed',\n          backdropFilter:\n            overlayBlur && overlayBlur > 0 ? `blur(${overlayBlur}px)` : 'none',\n        }\"\n        @click=\"() => emits('close')\"\n      />\n    </Transition>\n    <AlertDialogContent\n      ref=\"contentRef\"\n      :style=\"{ ...(zIndex ? { zIndex } : {}), position: 'fixed' }\"\n      @animationend=\"onAnimationEnd\"\n      v-bind=\"forwarded\"\n      :class=\"\n        cn(\n          'z-popup bg-background p-6 shadow-lg outline-none sm:rounded-xl',\n          'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',\n          'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',\n          {\n            'data-[state=open]:slide-in-from-top-[48%] data-[state=closed]:slide-out-to-top-[48%]':\n              !centered,\n            'data-[state=open]:slide-in-from-top-[98%] data-[state=closed]:slide-out-to-top-[148%]':\n              centered,\n            'top-[10vh]': !centered,\n            'top-1/2 -translate-y-1/2': centered,\n          },\n          props.class,\n        )\n      \"\n    >\n      <slot></slot>\n    </AlertDialogContent>\n  </AlertDialogPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogDescription.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { AlertDialogDescriptionProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { AlertDialogDescription, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<AlertDialogDescriptionProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <AlertDialogDescription\n    v-bind=\"forwardedProps\"\n    :class=\"cn('text-muted-foreground text-sm', props.class)\"\n  >\n    <slot></slot>\n  </AlertDialogDescription>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogOverlay.vue",
    "content": "<script setup lang=\"ts\">\nimport { useScrollLock } from '@vben-core/composables';\n\nuseScrollLock();\n</script>\n<template>\n  <div class=\"bg-overlay z-popup inset-0\"></div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogTitle.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AlertDialogTitleProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { AlertDialogTitle, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<AlertDialogTitleProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <AlertDialogTitle\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn('text-lg font-semibold leading-none tracking-tight', props.class)\n    \"\n  >\n    <slot></slot>\n  </AlertDialogTitle>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/index.ts",
    "content": "export { default as AlertDialog } from './AlertDialog.vue';\nexport { default as AlertDialogAction } from './AlertDialogAction.vue';\nexport { default as AlertDialogCancel } from './AlertDialogCancel.vue';\nexport { default as AlertDialogContent } from './AlertDialogContent.vue';\nexport { default as AlertDialogDescription } from './AlertDialogDescription.vue';\nexport { default as AlertDialogTitle } from './AlertDialogTitle.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/Avatar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AvatarVariants } from './avatar';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { AvatarRoot } from 'radix-vue';\n\nimport { avatarVariant } from './avatar';\n\nconst props = withDefaults(\n  defineProps<{\n    class?: any;\n    shape?: AvatarVariants['shape'];\n    size?: AvatarVariants['size'];\n  }>(),\n  {\n    shape: 'circle',\n    size: 'sm',\n  },\n);\n</script>\n\n<template>\n  <AvatarRoot :class=\"cn(avatarVariant({ size, shape }), props.class)\">\n    <slot></slot>\n  </AvatarRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarFallback.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AvatarFallbackProps } from 'radix-vue';\n\nimport { AvatarFallback } from 'radix-vue';\n\nconst props = defineProps<AvatarFallbackProps>();\n</script>\n\n<template>\n  <AvatarFallback v-bind=\"props\">\n    <slot></slot>\n  </AvatarFallback>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarImage.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AvatarImageProps } from 'radix-vue';\n\nimport { AvatarImage } from 'radix-vue';\n\nconst props = defineProps<AvatarImageProps>();\n</script>\n\n<template>\n  <AvatarImage v-bind=\"props\" class=\"h-full w-full object-cover\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/avatar.ts",
    "content": "import type { VariantProps } from 'class-variance-authority';\n\nimport { cva } from 'class-variance-authority';\n\nexport const avatarVariant = cva(\n  'inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden',\n  {\n    variants: {\n      shape: {\n        circle: 'rounded-full',\n        square: 'rounded-md',\n      },\n      size: {\n        base: 'h-16 w-16 text-2xl',\n        lg: 'h-32 w-32 text-5xl',\n        sm: 'h-10 w-10 text-xs',\n      },\n    },\n  },\n);\n\nexport type AvatarVariants = VariantProps<typeof avatarVariant>;\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/index.ts",
    "content": "export * from './avatar';\nexport { default as Avatar } from './Avatar.vue';\nexport { default as AvatarFallback } from './AvatarFallback.vue';\nexport { default as AvatarImage } from './AvatarImage.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/badge/Badge.vue",
    "content": "<script setup lang=\"ts\">\nimport type { BadgeVariants } from './badge';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { badgeVariants } from './badge';\n\nconst props = defineProps<{\n  class?: any;\n  variant?: BadgeVariants['variant'];\n}>();\n</script>\n\n<template>\n  <div :class=\"cn(badgeVariants({ variant }), props.class)\">\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/badge/badge.ts",
    "content": "import type { VariantProps } from 'class-variance-authority';\n\nimport { cva } from 'class-variance-authority';\n\nexport const badgeVariants = cva(\n  'inline-flex items-center rounded-md border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',\n  {\n    defaultVariants: {\n      variant: 'default',\n    },\n    variants: {\n      variant: {\n        default:\n          'border-transparent bg-accent hover:bg-accent text-primary-foreground shadow',\n        destructive:\n          'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive-hover',\n        outline: 'text-foreground',\n        secondary:\n          'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',\n      },\n    },\n  },\n);\n\nexport type BadgeVariants = VariantProps<typeof badgeVariants>;\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/badge/index.ts",
    "content": "export * from './badge';\n\nexport { default as Badge } from './Badge.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/Breadcrumb.vue",
    "content": "<script lang=\"ts\" setup>\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <nav :class=\"props.class\" aria-label=\"breadcrumb\" role=\"navigation\">\n    <slot></slot>\n  </nav>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbEllipsis.vue",
    "content": "<script lang=\"ts\" setup>\nimport { cn } from '@vben-core/shared/utils';\n\nimport { MoreHorizontal } from 'lucide-vue-next';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <span\n    :class=\"cn('flex h-9 w-9 items-center justify-center', props.class)\"\n    aria-hidden=\"true\"\n    role=\"presentation\"\n  >\n    <slot>\n      <MoreHorizontal class=\"h-4 w-4\" />\n    </slot>\n    <span class=\"sr-only\">More</span>\n  </span>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbItem.vue",
    "content": "<script lang=\"ts\" setup>\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <li\n    :class=\"\n      cn('hover:text-foreground inline-flex items-center gap-1.5', props.class)\n    \"\n  >\n    <slot></slot>\n  </li>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbLink.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { PrimitiveProps } from 'radix-vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Primitive } from 'radix-vue';\n\nconst props = withDefaults(defineProps<PrimitiveProps & { class?: any }>(), {\n  as: 'a',\n});\n</script>\n\n<template>\n  <Primitive\n    :as=\"as\"\n    :as-child=\"asChild\"\n    :class=\"cn('hover:text-foreground transition-colors', props.class)\"\n  >\n    <slot></slot>\n  </Primitive>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbList.vue",
    "content": "<script lang=\"ts\" setup>\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <ol\n    :class=\"\n      cn(\n        'text-muted-foreground flex flex-wrap items-center gap-1.5 break-words text-sm sm:gap-2.5',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </ol>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbPage.vue",
    "content": "<script lang=\"ts\" setup>\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <span\n    :class=\"cn('text-foreground font-normal', props.class)\"\n    aria-current=\"page\"\n    aria-disabled=\"true\"\n    role=\"link\"\n  >\n    <slot></slot>\n  </span>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbSeparator.vue",
    "content": "<script lang=\"ts\" setup>\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronRight } from 'lucide-vue-next';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <li\n    :class=\"cn('[&>svg]:size-3.5', props.class)\"\n    aria-hidden=\"true\"\n    role=\"presentation\"\n  >\n    <slot>\n      <ChevronRight />\n    </slot>\n  </li>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/index.ts",
    "content": "export { default as Breadcrumb } from './Breadcrumb.vue';\nexport { default as BreadcrumbEllipsis } from './BreadcrumbEllipsis.vue';\nexport { default as BreadcrumbItem } from './BreadcrumbItem.vue';\nexport { default as BreadcrumbLink } from './BreadcrumbLink.vue';\nexport { default as BreadcrumbList } from './BreadcrumbList.vue';\nexport { default as BreadcrumbPage } from './BreadcrumbPage.vue';\nexport { default as BreadcrumbSeparator } from './BreadcrumbSeparator.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/button/Button.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PrimitiveProps } from 'radix-vue';\n\nimport type { ButtonVariants, ButtonVariantSize } from './types';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Primitive } from 'radix-vue';\n\nimport { buttonVariants } from './button';\n\ninterface Props extends PrimitiveProps {\n  class?: any;\n  size?: ButtonVariantSize;\n  variant?: ButtonVariants;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  as: 'button',\n  class: '',\n});\n</script>\n\n<template>\n  <Primitive\n    :as=\"as\"\n    :as-child=\"asChild\"\n    :class=\"cn(buttonVariants({ variant, size }), props.class)\"\n  >\n    <slot></slot>\n  </Primitive>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts",
    "content": "import { cva } from 'class-variance-authority';\n\nexport const buttonVariants = cva(\n  'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed  disabled:opacity-50',\n  {\n    defaultVariants: {\n      size: 'default',\n      variant: 'default',\n    },\n    variants: {\n      size: {\n        default: 'h-9 px-4 py-2',\n        icon: 'h-8 w-8 rounded-sm px-1 text-lg',\n        lg: 'h-10 rounded-md px-4',\n        sm: 'h-8 rounded-md px-2 text-xs',\n        xs: 'h-8 w-8 rounded-sm px-1 text-xs',\n      },\n      variant: {\n        default:\n          'bg-primary text-primary-foreground shadow hover:bg-primary/90',\n        destructive:\n          'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive-hover',\n        ghost: 'hover:bg-accent hover:text-accent-foreground',\n        heavy: 'hover:bg-heavy hover:text-heavy-foreground',\n        icon: 'hover:bg-accent hover:text-accent-foreground text-foreground/80',\n        link: 'text-primary underline-offset-4 hover:underline',\n        outline:\n          'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',\n        secondary:\n          'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',\n      },\n    },\n  },\n);\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/button/index.ts",
    "content": "export * from './button';\n\nexport { default as Button } from './Button.vue';\n\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/button/types.ts",
    "content": "export type ButtonVariantSize =\n  | 'default'\n  | 'icon'\n  | 'lg'\n  | 'sm'\n  | 'xs'\n  | null\n  | undefined;\n\nexport type ButtonVariants =\n  | 'default'\n  | 'destructive'\n  | 'ghost'\n  | 'heavy'\n  | 'icon'\n  | 'link'\n  | 'outline'\n  | 'secondary'\n  | null\n  | undefined;\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/card/Card.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <div\n    :class=\"\n      cn(\n        'bg-card text-card-foreground border-border rounded-xl border',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardContent.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <div :class=\"cn('p-6 pt-0', props.class)\">\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardDescription.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <p :class=\"cn('text-muted-foreground text-sm', props.class)\">\n    <slot></slot>\n  </p>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardFooter.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <div :class=\"cn('flex items-center p-6 pt-0', props.class)\">\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardHeader.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <div :class=\"cn('flex flex-col gap-y-1.5 p-5', props.class)\">\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardTitle.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <h3 :class=\"cn('font-semibold leading-none tracking-tight', props.class)\">\n    <slot></slot>\n  </h3>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/card/index.ts",
    "content": "export { default as Card } from './Card.vue';\nexport { default as CardContent } from './CardContent.vue';\nexport { default as CardDescription } from './CardDescription.vue';\nexport { default as CardFooter } from './CardFooter.vue';\nexport { default as CardHeader } from './CardHeader.vue';\nexport { default as CardTitle } from './CardTitle.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/Checkbox.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Check, Minus } from 'lucide-vue-next';\nimport {\n  CheckboxIndicator,\n  CheckboxRoot,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nconst props = defineProps<\n  CheckboxRootProps & { class?: any; indeterminate?: boolean }\n>();\nconst emits = defineEmits<CheckboxRootEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <CheckboxRoot\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground border-border peer h-4 w-4 shrink-0 rounded-sm border transition focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',\n        props.class,\n      )\n    \"\n  >\n    <CheckboxIndicator\n      class=\"flex h-full w-full items-center justify-center text-current\"\n    >\n      <slot>\n        <component :is=\"indeterminate ? Minus : Check\" class=\"h-4 w-4\" />\n      </slot>\n    </CheckboxIndicator>\n  </CheckboxRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/index.ts",
    "content": "export { default as Checkbox } from './Checkbox.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenu.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuRootEmits, ContextMenuRootProps } from 'radix-vue';\n\nimport { ContextMenuRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = withDefaults(defineProps<ContextMenuRootProps>(), {\n  modal: false,\n});\nconst emits = defineEmits<ContextMenuRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <ContextMenuRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </ContextMenuRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuCheckboxItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  ContextMenuCheckboxItemEmits,\n  ContextMenuCheckboxItemProps,\n} from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Check } from 'lucide-vue-next';\nimport {\n  ContextMenuCheckboxItem,\n  ContextMenuItemIndicator,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nconst props = defineProps<ContextMenuCheckboxItemProps & { class?: any }>();\nconst emits = defineEmits<ContextMenuCheckboxItemEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <ContextMenuCheckboxItem\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n        props.class,\n      )\n    \"\n  >\n    <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <ContextMenuItemIndicator>\n        <Check class=\"h-4 w-4\" />\n      </ContextMenuItemIndicator>\n    </span>\n    <slot></slot>\n  </ContextMenuCheckboxItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  ContextMenuContentEmits,\n  ContextMenuContentProps,\n} from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport {\n  ContextMenuContent,\n  ContextMenuPortal,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nconst props = defineProps<ContextMenuContentProps & { class?: any }>();\nconst emits = defineEmits<ContextMenuContentEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <ContextMenuPortal>\n    <ContextMenuContent\n      v-bind=\"forwarded\"\n      :class=\"\n        cn(\n          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-popup min-w-32 overflow-hidden rounded-md border p-1 shadow-md',\n          props.class,\n        )\n      \"\n    >\n      <slot></slot>\n    </ContextMenuContent>\n  </ContextMenuPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuGroupProps } from 'radix-vue';\n\nimport { ContextMenuGroup } from 'radix-vue';\n\nconst props = defineProps<ContextMenuGroupProps>();\n</script>\n\n<template>\n  <ContextMenuGroup v-bind=\"props\">\n    <slot></slot>\n  </ContextMenuGroup>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuItemEmits, ContextMenuItemProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ContextMenuItem, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<\n  ContextMenuItemProps & { class?: any; inset?: boolean }\n>();\nconst emits = defineEmits<ContextMenuItemEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <ContextMenuItem\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n        inset && 'pl-8',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </ContextMenuItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuLabel.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuLabelProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ContextMenuLabel } from 'radix-vue';\n\nconst props = defineProps<\n  ContextMenuLabelProps & { class?: any; inset?: boolean }\n>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <ContextMenuLabel\n    v-bind=\"delegatedProps\"\n    :class=\"\n      cn(\n        'text-foreground px-2 py-1.5 text-sm font-semibold',\n        inset && 'pl-8',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </ContextMenuLabel>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuPortal.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuPortalProps } from 'radix-vue';\n\nimport { ContextMenuPortal } from 'radix-vue';\n\nconst props = defineProps<ContextMenuPortalProps>();\n</script>\n\n<template>\n  <ContextMenuPortal v-bind=\"props\">\n    <slot></slot>\n  </ContextMenuPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  ContextMenuRadioGroupEmits,\n  ContextMenuRadioGroupProps,\n} from 'radix-vue';\n\nimport { ContextMenuRadioGroup, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<ContextMenuRadioGroupProps>();\nconst emits = defineEmits<ContextMenuRadioGroupEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <ContextMenuRadioGroup v-bind=\"forwarded\">\n    <slot></slot>\n  </ContextMenuRadioGroup>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  ContextMenuRadioItemEmits,\n  ContextMenuRadioItemProps,\n} from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Circle } from 'lucide-vue-next';\nimport {\n  ContextMenuItemIndicator,\n  ContextMenuRadioItem,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nconst props = defineProps<ContextMenuRadioItemProps & { class?: any }>();\nconst emits = defineEmits<ContextMenuRadioItemEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <ContextMenuRadioItem\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n        props.class,\n      )\n    \"\n  >\n    <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <ContextMenuItemIndicator>\n        <Circle class=\"h-2 w-2 fill-current\" />\n      </ContextMenuItemIndicator>\n    </span>\n    <slot></slot>\n  </ContextMenuRadioItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSeparator.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuSeparatorProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ContextMenuSeparator } from 'radix-vue';\n\nconst props = defineProps<ContextMenuSeparatorProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <ContextMenuSeparator\n    v-bind=\"delegatedProps\"\n    :class=\"cn('bg-border -mx-1 my-1 h-px', props.class)\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuShortcut.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <span\n    :class=\"\n      cn('text-muted-foreground ml-auto text-xs tracking-widest', props.class)\n    \"\n  >\n    <slot></slot>\n  </span>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSub.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuSubEmits, ContextMenuSubProps } from 'radix-vue';\n\nimport { ContextMenuSub, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<ContextMenuSubProps>();\nconst emits = defineEmits<ContextMenuSubEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <ContextMenuSub v-bind=\"forwarded\">\n    <slot></slot>\n  </ContextMenuSub>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  DropdownMenuSubContentEmits,\n  DropdownMenuSubContentProps,\n} from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ContextMenuSubContent, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<DropdownMenuSubContentProps & { class?: any }>();\nconst emits = defineEmits<DropdownMenuSubContentEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <ContextMenuSubContent\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-lg',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </ContextMenuSubContent>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuSubTriggerProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronRight } from 'lucide-vue-next';\nimport { ContextMenuSubTrigger, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<\n  ContextMenuSubTriggerProps & {\n    class?: any;\n    inset?: boolean;\n  }\n>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <ContextMenuSubTrigger\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',\n        inset && 'pl-8',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n    <ChevronRight class=\"ml-auto h-4 w-4\" />\n  </ContextMenuSubTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ContextMenuTriggerProps } from 'radix-vue';\n\nimport { ContextMenuTrigger, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<ContextMenuTriggerProps>();\n\nconst forwardedProps = useForwardProps(props);\n</script>\n\n<template>\n  <ContextMenuTrigger v-bind=\"forwardedProps\">\n    <slot></slot>\n  </ContextMenuTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/index.ts",
    "content": "export { default as ContextMenu } from './ContextMenu.vue';\nexport { default as ContextMenuCheckboxItem } from './ContextMenuCheckboxItem.vue';\nexport { default as ContextMenuContent } from './ContextMenuContent.vue';\nexport { default as ContextMenuGroup } from './ContextMenuGroup.vue';\nexport { default as ContextMenuItem } from './ContextMenuItem.vue';\nexport { default as ContextMenuLabel } from './ContextMenuLabel.vue';\nexport { default as ContextMenuRadioGroup } from './ContextMenuRadioGroup.vue';\nexport { default as ContextMenuRadioItem } from './ContextMenuRadioItem.vue';\nexport { default as ContextMenuSeparator } from './ContextMenuSeparator.vue';\nexport { default as ContextMenuShortcut } from './ContextMenuShortcut.vue';\nexport { default as ContextMenuSub } from './ContextMenuSub.vue';\nexport { default as ContextMenuSubContent } from './ContextMenuSubContent.vue';\nexport { default as ContextMenuSubTrigger } from './ContextMenuSubTrigger.vue';\nexport { default as ContextMenuTrigger } from './ContextMenuTrigger.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/Dialog.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogRootEmits, DialogRootProps } from 'radix-vue';\n\nimport { DialogRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<DialogRootProps>();\nconst emits = defineEmits<DialogRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <DialogRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </DialogRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogClose.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogCloseProps } from 'radix-vue';\n\nimport { DialogClose } from 'radix-vue';\n\nconst props = defineProps<DialogCloseProps>();\n</script>\n\n<template>\n  <DialogClose v-bind=\"props\">\n    <slot></slot>\n  </DialogClose>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogContentEmits, DialogContentProps } from 'radix-vue';\n\nimport type { ClassType } from '@vben-core/typings';\n\nimport { computed, ref } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { X } from 'lucide-vue-next';\nimport { DialogClose, DialogContent, useForwardPropsEmits } from 'radix-vue';\n\nimport DialogOverlay from './DialogOverlay.vue';\n\nconst props = withDefaults(\n  defineProps<\n    DialogContentProps & {\n      animationType?: 'scale' | 'slide';\n      appendTo?: HTMLElement | string;\n      class?: ClassType;\n      closeClass?: ClassType;\n      closeDisabled?: boolean;\n      modal?: boolean;\n      open?: boolean;\n      overlayBlur?: number;\n      showClose?: boolean;\n      zIndex?: number;\n    }\n  >(),\n  {\n    appendTo: 'body',\n    animationType: 'slide',\n    closeDisabled: false,\n    showClose: true,\n  },\n);\nconst emits = defineEmits<\n  DialogContentEmits & { close: []; closed: []; opened: [] }\n>();\n\nconst delegatedProps = computed(() => {\n  const {\n    class: _,\n    modal: _modal,\n    open: _open,\n    showClose: __,\n    animationType: ___,\n    ...delegated\n  } = props;\n\n  return delegated;\n});\n\nfunction isAppendToBody() {\n  return (\n    props.appendTo === 'body' ||\n    props.appendTo === document.body ||\n    !props.appendTo\n  );\n}\n\nconst position = computed(() => {\n  return isAppendToBody() ? 'fixed' : 'absolute';\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n\nconst contentRef = ref<InstanceType<typeof DialogContent> | null>(null);\nfunction onAnimationEnd(event: AnimationEvent) {\n  // 只有在 contentRef 的动画结束时才触发 opened/closed 事件\n  if (event.target === contentRef.value?.$el) {\n    if (props.open) {\n      emits('opened');\n    } else {\n      emits('closed');\n    }\n  }\n}\ndefineExpose({\n  getContentRef: () => contentRef.value,\n});\n</script>\n\n<template>\n  <Teleport defer :to=\"appendTo\">\n    <Transition name=\"fade\">\n      <DialogOverlay\n        v-if=\"open && modal\"\n        :style=\"{\n          ...(zIndex ? { zIndex } : {}),\n          position,\n          backdropFilter:\n            overlayBlur && overlayBlur > 0 ? `blur(${overlayBlur}px)` : 'none',\n        }\"\n        @click=\"() => emits('close')\"\n      />\n    </Transition>\n    <DialogContent\n      ref=\"contentRef\"\n      :style=\"{ ...(zIndex ? { zIndex } : {}), position }\"\n      @animationend=\"onAnimationEnd\"\n      v-bind=\"forwarded\"\n      :class=\"\n        cn(\n          'z-popup bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 w-full p-6 shadow-lg outline-none sm:rounded-xl',\n          {\n            'data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]':\n              animationType === 'slide',\n          },\n          props.class,\n        )\n      \"\n    >\n      <slot></slot>\n\n      <DialogClose\n        v-if=\"showClose\"\n        :disabled=\"closeDisabled\"\n        :class=\"\n          cn(\n            'data-[state=open]:bg-accent data-[state=open]:text-muted-foreground hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-3 top-3 h-6 w-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none',\n            props.closeClass,\n          )\n        \"\n        @click=\"() => emits('close')\"\n      >\n        <X class=\"h-4 w-4\" />\n      </DialogClose>\n    </DialogContent>\n  </Teleport>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogDescription.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogDescriptionProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DialogDescription, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<DialogDescriptionProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <DialogDescription\n    v-bind=\"forwardedProps\"\n    :class=\"cn('text-muted-foreground text-sm', props.class)\"\n  >\n    <slot></slot>\n  </DialogDescription>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogFooter.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{ class?: any }>();\n</script>\n\n<template>\n  <div\n    :class=\"\n      cn('flex flex-row flex-col-reverse justify-end gap-x-2', props.class)\n    \"\n  >\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogHeader.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <div\n    :class=\"cn('flex flex-col gap-y-1.5 text-center sm:text-left', props.class)\"\n  >\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogOverlay.vue",
    "content": "<script setup lang=\"ts\">\nimport { inject } from 'vue';\n\nimport { useScrollLock } from '@vben-core/composables';\n\nuseScrollLock();\nconst id = inject('DISMISSABLE_MODAL_ID');\n</script>\n<template>\n  <div :data-dismissable-modal=\"id\" class=\"bg-overlay z-popup inset-0\"></div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogScrollContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogContentEmits, DialogContentProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { X } from 'lucide-vue-next';\nimport {\n  DialogClose,\n  DialogContent,\n  DialogOverlay,\n  DialogPortal,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nconst props = withDefaults(\n  defineProps<DialogContentProps & { class?: any; zIndex?: number }>(),\n  { zIndex: 1000 },\n);\nconst emits = defineEmits<DialogContentEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <DialogPortal>\n    <DialogOverlay\n      :style=\"{ zIndex }\"\n      class=\"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 border-border absolute inset-0 grid place-items-center overflow-y-auto border bg-black/80\"\n    >\n      <DialogContent\n        :class=\"\n          cn(\n            'border-border bg-background relative z-50 my-8 grid w-full max-w-lg gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',\n            props.class,\n          )\n        \"\n        :style=\"{ zIndex }\"\n        v-bind=\"forwarded\"\n        @pointer-down-outside=\"\n          (event) => {\n            const originalEvent = event.detail.originalEvent;\n            const target = originalEvent.target as HTMLElement;\n            if (\n              originalEvent.offsetX > target.clientWidth ||\n              originalEvent.offsetY > target.clientHeight\n            ) {\n              event.preventDefault();\n            }\n          }\n        \"\n      >\n        <slot></slot>\n\n        <DialogClose\n          class=\"hover:bg-secondary absolute right-4 top-4 rounded-md p-0.5 transition-colors\"\n        >\n          <X class=\"h-4 w-4\" />\n          <span class=\"sr-only\">Close</span>\n        </DialogClose>\n      </DialogContent>\n    </DialogOverlay>\n  </DialogPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTitle.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogTitleProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DialogTitle, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<DialogTitleProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <DialogTitle\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn('text-lg font-semibold leading-none tracking-tight', props.class)\n    \"\n  >\n    <slot></slot>\n  </DialogTitle>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogTriggerProps } from 'radix-vue';\n\nimport { DialogTrigger } from 'radix-vue';\n\nconst props = defineProps<DialogTriggerProps>();\n</script>\n\n<template>\n  <DialogTrigger v-bind=\"props\">\n    <slot></slot>\n  </DialogTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/index.ts",
    "content": "export { default as Dialog } from './Dialog.vue';\nexport { default as DialogClose } from './DialogClose.vue';\nexport { default as DialogContent } from './DialogContent.vue';\nexport { default as DialogDescription } from './DialogDescription.vue';\nexport { default as DialogFooter } from './DialogFooter.vue';\nexport { default as DialogHeader } from './DialogHeader.vue';\nexport { default as DialogScrollContent } from './DialogScrollContent.vue';\nexport { default as DialogTitle } from './DialogTitle.vue';\nexport { default as DialogTrigger } from './DialogTrigger.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenu.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DropdownMenuRootEmits, DropdownMenuRootProps } from 'radix-vue';\n\nimport { DropdownMenuRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = withDefaults(defineProps<DropdownMenuRootProps>(), {\n  modal: false,\n});\nconst emits = defineEmits<DropdownMenuRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <DropdownMenuRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </DropdownMenuRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuCheckboxItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  DropdownMenuCheckboxItemEmits,\n  DropdownMenuCheckboxItemProps,\n} from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Check } from 'lucide-vue-next';\nimport {\n  DropdownMenuCheckboxItem,\n  DropdownMenuItemIndicator,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nconst props = defineProps<DropdownMenuCheckboxItemProps & { class?: any }>();\nconst emits = defineEmits<DropdownMenuCheckboxItemEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <DropdownMenuCheckboxItem\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n        props.class,\n      )\n    \"\n  >\n    <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <DropdownMenuItemIndicator>\n        <Check class=\"h-4 w-4\" />\n      </DropdownMenuItemIndicator>\n    </span>\n    <slot></slot>\n  </DropdownMenuCheckboxItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  DropdownMenuContentEmits,\n  DropdownMenuContentProps,\n} from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport {\n  DropdownMenuContent,\n  DropdownMenuPortal,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nconst props = withDefaults(\n  defineProps<DropdownMenuContentProps & { class?: any }>(),\n  {\n    sideOffset: 4,\n  },\n);\nconst emits = defineEmits<DropdownMenuContentEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <DropdownMenuPortal>\n    <DropdownMenuContent\n      v-bind=\"forwarded\"\n      :class=\"\n        cn(\n          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-popup min-w-32 overflow-hidden rounded-md border p-1 shadow-md',\n          props.class,\n        )\n      \"\n    >\n      <slot></slot>\n    </DropdownMenuContent>\n  </DropdownMenuPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DropdownMenuGroupProps } from 'radix-vue';\n\nimport { DropdownMenuGroup } from 'radix-vue';\n\nconst props = defineProps<DropdownMenuGroupProps>();\n</script>\n\n<template>\n  <DropdownMenuGroup v-bind=\"props\">\n    <slot></slot>\n  </DropdownMenuGroup>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DropdownMenuItemProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DropdownMenuItem, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<\n  DropdownMenuItemProps & { class?: any; inset?: boolean }\n>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <DropdownMenuItem\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n        inset && 'pl-8',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </DropdownMenuItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuLabel.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DropdownMenuLabelProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DropdownMenuLabel, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<\n  DropdownMenuLabelProps & { class?: any; inset?: boolean }\n>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <DropdownMenuLabel\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', props.class)\n    \"\n  >\n    <slot></slot>\n  </DropdownMenuLabel>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  DropdownMenuRadioGroupEmits,\n  DropdownMenuRadioGroupProps,\n} from 'radix-vue';\n\nimport { DropdownMenuRadioGroup, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<DropdownMenuRadioGroupProps>();\nconst emits = defineEmits<DropdownMenuRadioGroupEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <DropdownMenuRadioGroup v-bind=\"forwarded\">\n    <slot></slot>\n  </DropdownMenuRadioGroup>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  DropdownMenuRadioItemEmits,\n  DropdownMenuRadioItemProps,\n} from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Circle } from 'lucide-vue-next';\nimport {\n  DropdownMenuItemIndicator,\n  DropdownMenuRadioItem,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nconst props = defineProps<DropdownMenuRadioItemProps & { class?: any }>();\n\nconst emits = defineEmits<DropdownMenuRadioItemEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <DropdownMenuRadioItem\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n        props.class,\n      )\n    \"\n  >\n    <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <DropdownMenuItemIndicator>\n        <Circle class=\"h-2 w-2 fill-current\" />\n      </DropdownMenuItemIndicator>\n    </span>\n    <slot></slot>\n  </DropdownMenuRadioItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSeparator.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DropdownMenuSeparatorProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DropdownMenuSeparator } from 'radix-vue';\n\nconst props = defineProps<\n  DropdownMenuSeparatorProps & {\n    class?: any;\n  }\n>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <DropdownMenuSeparator\n    v-bind=\"delegatedProps\"\n    :class=\"cn('bg-border -mx-1 my-1 h-px', props.class)\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuShortcut.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <span :class=\"cn('ml-auto text-xs tracking-widest opacity-60', props.class)\">\n    <slot></slot>\n  </span>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSub.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DropdownMenuSubEmits, DropdownMenuSubProps } from 'radix-vue';\n\nimport { DropdownMenuSub, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<DropdownMenuSubProps>();\nconst emits = defineEmits<DropdownMenuSubEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <DropdownMenuSub v-bind=\"forwarded\">\n    <slot></slot>\n  </DropdownMenuSub>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  DropdownMenuSubContentEmits,\n  DropdownMenuSubContentProps,\n} from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DropdownMenuSubContent, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<DropdownMenuSubContentProps & { class?: any }>();\nconst emits = defineEmits<DropdownMenuSubContentEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <DropdownMenuSubContent\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-lg',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </DropdownMenuSubContent>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DropdownMenuSubTriggerProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronRight } from 'lucide-vue-next';\nimport { DropdownMenuSubTrigger, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<DropdownMenuSubTriggerProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <DropdownMenuSubTrigger\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'focus:bg-accent data-[state=open]:bg-accent flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n    <ChevronRight class=\"ml-auto h-4 w-4\" />\n  </DropdownMenuSubTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DropdownMenuTriggerProps } from 'radix-vue';\n\nimport { DropdownMenuTrigger, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<DropdownMenuTriggerProps>();\n\nconst forwardedProps = useForwardProps(props);\n</script>\n\n<template>\n  <DropdownMenuTrigger class=\"outline-none\" v-bind=\"forwardedProps\">\n    <slot></slot>\n  </DropdownMenuTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/index.ts",
    "content": "export { default as DropdownMenu } from './DropdownMenu.vue';\n\nexport { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue';\nexport { default as DropdownMenuContent } from './DropdownMenuContent.vue';\nexport { default as DropdownMenuGroup } from './DropdownMenuGroup.vue';\nexport { default as DropdownMenuItem } from './DropdownMenuItem.vue';\nexport { default as DropdownMenuLabel } from './DropdownMenuLabel.vue';\nexport { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue';\nexport { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue';\nexport { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue';\nexport { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue';\nexport { default as DropdownMenuSub } from './DropdownMenuSub.vue';\nexport { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue';\nexport { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue';\nexport { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue';\nexport { DropdownMenuPortal } from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormControl.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Slot } from 'radix-vue';\n\nimport { useFormField } from './useFormField';\n\nconst { error, formDescriptionId, formItemId, formMessageId } = useFormField();\n</script>\n\n<template>\n  <Slot\n    :id=\"formItemId\"\n    :aria-describedby=\"\n      !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`\n    \"\n    :aria-invalid=\"!!error\"\n  >\n    <slot></slot>\n  </Slot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormDescription.vue",
    "content": "<script lang=\"ts\" setup>\nimport { cn } from '@vben-core/shared/utils';\n\nimport { useFormField } from './useFormField';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n\nconst { formDescriptionId } = useFormField();\n</script>\n\n<template>\n  <p\n    :id=\"formDescriptionId\"\n    :class=\"cn('text-muted-foreground text-sm', props.class)\"\n  >\n    <slot></slot>\n  </p>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormItem.vue",
    "content": "<script lang=\"ts\" setup>\nimport { provide, useId } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { FORM_ITEM_INJECTION_KEY } from './injectionKeys';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n\nconst id = useId() as string;\nprovide(FORM_ITEM_INJECTION_KEY, id);\n</script>\n\n<template>\n  <div :class=\"cn(props.class)\">\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormLabel.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { LabelProps } from 'radix-vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Label } from '../label';\nimport { useFormField } from './useFormField';\n\nconst props = defineProps<LabelProps & { class?: any }>();\n\nconst { formItemId } = useFormField();\n</script>\n\n<template>\n  <Label :class=\"cn(props.class)\" :for=\"formItemId\">\n    <slot></slot>\n  </Label>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormMessage.vue",
    "content": "<script lang=\"ts\" setup>\nimport { toValue } from 'vue';\n\nimport { ErrorMessage } from 'vee-validate';\n\nimport { useFormField } from './useFormField';\n\nconst { formMessageId, name } = useFormField();\n</script>\n\n<template>\n  <ErrorMessage\n    :id=\"formMessageId\"\n    :name=\"toValue(name)\"\n    as=\"p\"\n    class=\"text-destructive text-[0.8rem]\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/form/index.ts",
    "content": "export { default as FormControl } from './FormControl.vue';\nexport { default as FormDescription } from './FormDescription.vue';\nexport { default as FormItem } from './FormItem.vue';\nexport { default as FormLabel } from './FormLabel.vue';\nexport { default as FormMessage } from './FormMessage.vue';\nexport { FORM_ITEM_INJECTION_KEY } from './injectionKeys';\nexport {\n  Form,\n  Field as FormField,\n  FieldArray as FormFieldArray,\n} from 'vee-validate';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/form/injectionKeys.ts",
    "content": "import type { InjectionKey } from 'vue';\n\n// eslint-disable-next-line symbol-description\nexport const FORM_ITEM_INJECTION_KEY = Symbol() as InjectionKey<string>;\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/form/useFormField.ts",
    "content": "import { inject } from 'vue';\n\nimport {\n  FieldContextKey,\n  useFieldError,\n  useIsFieldDirty,\n  useIsFieldTouched,\n  useIsFieldValid,\n} from 'vee-validate';\n\nimport { FORM_ITEM_INJECTION_KEY } from './injectionKeys';\n\nexport function useFormField() {\n  const fieldContext = inject(FieldContextKey);\n  const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY);\n\n  if (!fieldContext)\n    throw new Error('useFormField should be used within <FormField>');\n\n  const { name } = fieldContext;\n  const id = fieldItemContext;\n\n  const fieldState = {\n    error: useFieldError(name),\n    isDirty: useIsFieldDirty(name),\n    isTouched: useIsFieldTouched(name),\n    valid: useIsFieldValid(name),\n  };\n\n  return {\n    formDescriptionId: `${id}-form-item-description`,\n    formItemId: `${id}-form-item`,\n    formMessageId: `${id}-form-item-message`,\n    id,\n    name,\n    ...fieldState,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCard.vue",
    "content": "<script setup lang=\"ts\">\nimport type { HoverCardRootEmits, HoverCardRootProps } from 'radix-vue';\n\nimport { HoverCardRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<HoverCardRootProps>();\nconst emits = defineEmits<HoverCardRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <HoverCardRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </HoverCardRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { HoverCardContentProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { HoverCardContent, HoverCardPortal, useForwardProps } from 'radix-vue';\n\nconst props = withDefaults(\n  defineProps<HoverCardContentProps & { class?: any }>(),\n  {\n    sideOffset: 4,\n  },\n);\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <HoverCardPortal>\n    <HoverCardContent\n      v-bind=\"forwardedProps\"\n      :class=\"\n        cn(\n          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-popup w-64 rounded-md border p-4 shadow-md outline-none',\n          props.class,\n        )\n      \"\n    >\n      <slot></slot>\n    </HoverCardContent>\n  </HoverCardPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { HoverCardTriggerProps } from 'radix-vue';\n\nimport { HoverCardTrigger } from 'radix-vue';\n\nconst props = defineProps<HoverCardTriggerProps>();\n</script>\n\n<template>\n  <HoverCardTrigger v-bind=\"props\">\n    <slot></slot>\n  </HoverCardTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/index.ts",
    "content": "export { default as HoverCard } from './HoverCard.vue';\nexport { default as HoverCardContent } from './HoverCardContent.vue';\nexport { default as HoverCardTrigger } from './HoverCardTrigger.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/index.ts",
    "content": "export * from './accordion';\nexport * from './alert-dialog';\nexport * from './avatar';\nexport * from './badge';\nexport * from './breadcrumb';\nexport * from './button';\nexport * from './card';\nexport * from './checkbox';\nexport * from './dialog';\nexport * from './dropdown-menu';\nexport * from './form';\nexport * from './hover-card';\nexport * from './input';\nexport * from './label';\nexport * from './number-field';\nexport * from './pagination';\nexport * from './pin-input';\nexport * from './popover';\nexport * from './radio-group';\nexport * from './resizable';\nexport * from './scroll-area';\nexport * from './select';\nexport * from './separator';\nexport * from './sheet';\nexport * from './switch';\nexport * from './tabs';\nexport * from './textarea';\nexport * from './toggle';\nexport * from './toggle-group';\nexport * from './tooltip';\nexport * from './tree';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/input/Input.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nimport { useVModel } from '@vueuse/core';\n\nconst props = defineProps<{\n  class?: any;\n  defaultValue?: number | string;\n  modelValue?: number | string;\n}>();\n\nconst emits = defineEmits<{\n  (e: 'update:modelValue', payload: number | string): void;\n}>();\n\nconst modelValue = useVModel(props, 'modelValue', emits, {\n  defaultValue: props.defaultValue,\n  passive: true,\n});\n</script>\n\n<template>\n  <input\n    v-model=\"modelValue\"\n    :class=\"\n      cn(\n        'border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',\n        props.class,\n      )\n    \"\n  />\n</template>\n<style lang=\"scss\" scoped>\ninput {\n  --ring: var(--primary);\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/input/index.ts",
    "content": "export { default as Input } from './Input.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/label/Label.vue",
    "content": "<script setup lang=\"ts\">\nimport type { LabelProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Label } from 'radix-vue';\n\nconst props = defineProps<LabelProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <Label\n    v-bind=\"delegatedProps\"\n    :class=\"\n      cn(\n        'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </Label>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/label/index.ts",
    "content": "export { default as Label } from './Label.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberField.vue",
    "content": "<script setup lang=\"ts\">\nimport type { NumberFieldRootEmits, NumberFieldRootProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { NumberFieldRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<NumberFieldRootProps & { class?: any }>();\nconst emits = defineEmits<NumberFieldRootEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <NumberFieldRoot v-bind=\"forwarded\" :class=\"cn('grid gap-1.5', props.class)\">\n    <slot></slot>\n  </NumberFieldRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldContent.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{\n  class?: any;\n}>();\n</script>\n\n<template>\n  <div\n    :class=\"\n      cn(\n        'relative [&>[data-slot=input]]:has-[[data-slot=decrement]]:pl-5 [&>[data-slot=input]]:has-[[data-slot=increment]]:pr-5',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldDecrement.vue",
    "content": "<script setup lang=\"ts\">\nimport type { NumberFieldDecrementProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Minus } from 'lucide-vue-next';\nimport { NumberFieldDecrement, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<NumberFieldDecrementProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <NumberFieldDecrement\n    data-slot=\"decrement\"\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'absolute left-0 top-1/2 -translate-y-1/2 p-3 disabled:cursor-not-allowed disabled:opacity-20',\n        props.class,\n      )\n    \"\n  >\n    <slot>\n      <Minus class=\"h-4 w-4\" />\n    </slot>\n  </NumberFieldDecrement>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldIncrement.vue",
    "content": "<script setup lang=\"ts\">\nimport type { NumberFieldIncrementProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Plus } from 'lucide-vue-next';\nimport { NumberFieldIncrement, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<NumberFieldIncrementProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <NumberFieldIncrement\n    data-slot=\"increment\"\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'absolute right-0 top-1/2 -translate-y-1/2 p-3 disabled:cursor-not-allowed disabled:opacity-20',\n        props.class,\n      )\n    \"\n  >\n    <slot>\n      <Plus class=\"h-4 w-4\" />\n    </slot>\n  </NumberFieldIncrement>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldInput.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nimport { NumberFieldInput } from 'radix-vue';\n</script>\n\n<template>\n  <NumberFieldInput\n    :class=\"\n      cn(\n        'border-input placeholder:text-muted-foreground focus-visible:ring-ring flex h-9 w-full rounded-md border bg-transparent py-1 text-center text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',\n      )\n    \"\n    data-slot=\"input\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/index.ts",
    "content": "export { default as NumberField } from './NumberField.vue';\nexport { default as NumberFieldContent } from './NumberFieldContent.vue';\nexport { default as NumberFieldDecrement } from './NumberFieldDecrement.vue';\nexport { default as NumberFieldIncrement } from './NumberFieldIncrement.vue';\nexport { default as NumberFieldInput } from './NumberFieldInput.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationEllipsis.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PaginationEllipsisProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { MoreHorizontal } from 'lucide-vue-next';\nimport { PaginationEllipsis } from 'radix-vue';\n\nconst props = defineProps<PaginationEllipsisProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <PaginationEllipsis\n    v-bind=\"delegatedProps\"\n    :class=\"cn('flex size-8 items-center justify-center', props.class)\"\n  >\n    <slot>\n      <MoreHorizontal class=\"size-4\" />\n    </slot>\n  </PaginationEllipsis>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationFirst.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PaginationFirstProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronsLeft } from 'lucide-vue-next';\nimport { PaginationFirst } from 'radix-vue';\n\nimport { Button } from '../button';\n\nconst props = withDefaults(\n  defineProps<PaginationFirstProps & { class?: any }>(),\n  {\n    asChild: true,\n  },\n);\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <PaginationFirst v-bind=\"delegatedProps\">\n    <Button :class=\"cn('size-8 p-0', props.class)\" variant=\"outline\">\n      <slot>\n        <ChevronsLeft class=\"size-4\" />\n      </slot>\n    </Button>\n  </PaginationFirst>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationLast.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PaginationLastProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronsRight } from 'lucide-vue-next';\nimport { PaginationLast } from 'radix-vue';\n\nimport { Button } from '../button';\n\nconst props = withDefaults(\n  defineProps<PaginationLastProps & { class?: any }>(),\n  {\n    asChild: true,\n  },\n);\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <PaginationLast v-bind=\"delegatedProps\">\n    <Button :class=\"cn('size-8 p-0', props.class)\" variant=\"outline\">\n      <slot>\n        <ChevronsRight class=\"size-4\" />\n      </slot>\n    </Button>\n  </PaginationLast>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationNext.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PaginationNextProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronRight } from 'lucide-vue-next';\nimport { PaginationNext } from 'radix-vue';\n\nimport { Button } from '../button';\n\nconst props = withDefaults(\n  defineProps<PaginationNextProps & { class?: any }>(),\n  {\n    asChild: true,\n  },\n);\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <PaginationNext v-bind=\"delegatedProps\">\n    <Button :class=\"cn('size-8 p-0', props.class)\" variant=\"outline\">\n      <slot>\n        <ChevronRight class=\"size-4\" />\n      </slot>\n    </Button>\n  </PaginationNext>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationPrev.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PaginationPrevProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronLeft } from 'lucide-vue-next';\nimport { PaginationPrev } from 'radix-vue';\n\nimport { Button } from '../button';\n\nconst props = withDefaults(\n  defineProps<PaginationPrevProps & { class?: any }>(),\n  {\n    asChild: true,\n  },\n);\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <PaginationPrev v-bind=\"delegatedProps\">\n    <Button :class=\"cn('size-8 p-0', props.class)\" variant=\"outline\">\n      <slot>\n        <ChevronLeft class=\"size-4\" />\n      </slot>\n    </Button>\n  </PaginationPrev>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/index.ts",
    "content": "export { default as PaginationEllipsis } from './PaginationEllipsis.vue';\nexport { default as PaginationFirst } from './PaginationFirst.vue';\nexport { default as PaginationLast } from './PaginationLast.vue';\nexport { default as PaginationNext } from './PaginationNext.vue';\nexport { default as PaginationPrev } from './PaginationPrev.vue';\nexport {\n  PaginationRoot as Pagination,\n  PaginationList,\n  PaginationListItem,\n} from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInput.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PinInputRootEmits, PinInputRootProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { PinInputRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<PinInputRootProps & { class?: any }>();\nconst emits = defineEmits<PinInputRootEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <PinInputRoot\n    v-bind=\"forwarded\"\n    :class=\"cn('flex items-center gap-2', props.class)\"\n  >\n    <slot></slot>\n  </PinInputRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PrimitiveProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Primitive, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<PrimitiveProps & { class?: any }>();\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n  return delegated;\n});\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <Primitive\n    v-bind=\"forwardedProps\"\n    :class=\"cn('flex items-center', props.class)\"\n  >\n    <slot></slot>\n  </Primitive>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputInput.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PinInputInputProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { PinInputInput, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<PinInputInputProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <PinInputInput\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'border-input bg-background relative flex h-10 w-8 items-center justify-center border-y border-r text-center text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md focus:relative focus:z-10 focus:outline-none focus:ring-2 md:w-10',\n        props.class,\n      )\n    \"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputSeparator.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PrimitiveProps } from 'radix-vue';\n\nimport { Dot } from 'lucide-vue-next';\nimport { Primitive, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<PrimitiveProps>();\nconst forwardedProps = useForwardProps(props);\n</script>\n\n<template>\n  <Primitive v-bind=\"forwardedProps\">\n    <slot>\n      <Dot />\n    </slot>\n  </Primitive>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/index.ts",
    "content": "export { default as PinInput } from './PinInput.vue';\nexport { default as PinInputGroup } from './PinInputGroup.vue';\nexport { default as PinInputInput } from './PinInputInput.vue';\nexport { default as PinInputSeparator } from './PinInputSeparator.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/popover/Popover.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PopoverRootEmits, PopoverRootProps } from 'radix-vue';\n\nimport { PopoverRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<PopoverRootProps>();\nconst emits = defineEmits<PopoverRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <PopoverRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </PopoverRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PopoverContentEmits, PopoverContentProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { PopoverContent, PopoverPortal, useForwardPropsEmits } from 'radix-vue';\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\nconst props = withDefaults(\n  defineProps<PopoverContentProps & { class?: any }>(),\n  {\n    align: 'center',\n    sideOffset: 4,\n  },\n);\nconst emits = defineEmits<PopoverContentEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <PopoverPortal>\n    <PopoverContent\n      v-bind=\"{ ...forwarded, ...$attrs }\"\n      :class=\"\n        cn(\n          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border w-72 rounded-md border p-4 shadow-md outline-none',\n          props.class,\n        )\n      \"\n    >\n      <slot></slot>\n    </PopoverContent>\n  </PopoverPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PopoverTriggerProps } from 'radix-vue';\n\nimport { PopoverTrigger } from 'radix-vue';\n\nconst props = defineProps<PopoverTriggerProps>();\n</script>\n\n<template>\n  <PopoverTrigger v-bind=\"props\">\n    <slot></slot>\n  </PopoverTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/popover/index.ts",
    "content": "export { default as Popover } from './Popover.vue';\nexport { default as PopoverContent } from './PopoverContent.vue';\nexport { default as PopoverTrigger } from './PopoverTrigger.vue';\nexport { PopoverAnchor } from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type { RadioGroupRootEmits, RadioGroupRootProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { RadioGroupRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<RadioGroupRootProps & { class?: any }>();\nconst emits = defineEmits<RadioGroupRootEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <RadioGroupRoot :class=\"cn('grid gap-2', props.class)\" v-bind=\"forwarded\">\n    <slot></slot>\n  </RadioGroupRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroupItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { RadioGroupItemProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Circle } from 'lucide-vue-next';\nimport {\n  RadioGroupIndicator,\n  RadioGroupItem,\n  useForwardProps,\n} from 'radix-vue';\n\nconst props = defineProps<RadioGroupItemProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <RadioGroupItem\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'border-primary text-primary focus-visible:ring-ring aspect-square h-4 w-4 rounded-full border shadow focus:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',\n        props.class,\n      )\n    \"\n  >\n    <RadioGroupIndicator class=\"flex items-center justify-center\">\n      <Circle class=\"h-2.5 w-2.5 fill-current text-current\" />\n    </RadioGroupIndicator>\n  </RadioGroupItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/index.ts",
    "content": "export { default as RadioGroup } from './RadioGroup.vue';\nexport { default as RadioGroupItem } from './RadioGroupItem.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/resizable/ResizableHandle.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  SplitterResizeHandleEmits,\n  SplitterResizeHandleProps,\n} from 'radix-vue';\n\nimport type { HTMLAttributes } from 'vue';\n\nimport { computed } from 'vue';\n\nimport { GripVertical } from '@vben-core/icons';\nimport { cn } from '@vben-core/shared/utils';\n\nimport { SplitterResizeHandle, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<\n  SplitterResizeHandleProps & {\n    class?: HTMLAttributes['class'];\n    withHandle?: boolean;\n  }\n>();\nconst emits = defineEmits<SplitterResizeHandleEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <SplitterResizeHandle\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-offset-1 [&[data-orientation=vertical]>div]:rotate-90 [&[data-orientation=vertical]]:h-px [&[data-orientation=vertical]]:w-full [&[data-orientation=vertical]]:after:left-0 [&[data-orientation=vertical]]:after:h-1 [&[data-orientation=vertical]]:after:w-full [&[data-orientation=vertical]]:after:-translate-y-1/2 [&[data-orientation=vertical]]:after:translate-x-0',\n        props.class,\n      )\n    \"\n  >\n    <template v-if=\"props.withHandle\">\n      <div\n        class=\"bg-border z-10 flex h-4 w-3 items-center justify-center rounded-sm border\"\n      >\n        <GripVertical class=\"h-2.5 w-2.5\" />\n      </div>\n    </template>\n  </SplitterResizeHandle>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/resizable/ResizablePanelGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SplitterGroupEmits, SplitterGroupProps } from 'radix-vue';\n\nimport type { HTMLAttributes } from 'vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { SplitterGroup, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<\n  SplitterGroupProps & { class?: HTMLAttributes['class'] }\n>();\nconst emits = defineEmits<SplitterGroupEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <SplitterGroup\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'flex h-full w-full data-[panel-group-direction=vertical]:flex-col',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </SplitterGroup>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/resizable/index.ts",
    "content": "export { default as ResizableHandle } from './ResizableHandle.vue';\nexport { default as ResizablePanelGroup } from './ResizablePanelGroup.vue';\nexport { SplitterPanel as ResizablePanel } from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollArea.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ScrollAreaRootProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport {\n  ScrollAreaCorner,\n  ScrollAreaRoot,\n  ScrollAreaViewport,\n} from 'radix-vue';\n\nimport ScrollBar from './ScrollBar.vue';\n\nconst props = withDefaults(\n  defineProps<\n    ScrollAreaRootProps & {\n      class?: any;\n      onScroll?: (event: Event) => void;\n      viewportProps?: { onScroll: (event: Event) => void };\n    }\n  >(),\n  {\n    onScroll: () => {},\n  },\n);\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n  return delegated;\n});\n</script>\n\n<template>\n  <ScrollAreaRoot\n    v-bind=\"delegatedProps\"\n    :class=\"cn('relative overflow-hidden', props.class)\"\n  >\n    <ScrollAreaViewport\n      as-child\n      class=\"h-full w-full rounded-[inherit] focus:outline-none\"\n      @scroll=\"onScroll\"\n    >\n      <slot></slot>\n    </ScrollAreaViewport>\n    <ScrollBar />\n    <ScrollAreaCorner />\n  </ScrollAreaRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollBar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ScrollAreaScrollbarProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ScrollAreaScrollbar, ScrollAreaThumb } from 'radix-vue';\n\nconst props = withDefaults(\n  defineProps<ScrollAreaScrollbarProps & { class?: any }>(),\n  {\n    orientation: 'vertical',\n  },\n);\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <ScrollAreaScrollbar\n    v-bind=\"delegatedProps\"\n    :class=\"\n      cn(\n        'flex touch-none select-none transition-colors',\n        orientation === 'vertical' &&\n          'h-full w-2.5 border-l border-l-transparent p-px',\n        orientation === 'horizontal' &&\n          'h-2.5 flex-col border-t border-t-transparent p-px',\n        props.class,\n      )\n    \"\n  >\n    <ScrollAreaThumb class=\"bg-border relative flex-1 rounded-full\" />\n  </ScrollAreaScrollbar>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/index.ts",
    "content": "export { default as ScrollArea } from './ScrollArea.vue';\nexport { default as ScrollBar } from './ScrollBar.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/Select.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectRootEmits, SelectRootProps } from 'radix-vue';\n\nimport { SelectRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<SelectRootProps>();\nconst emits = defineEmits<SelectRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <SelectRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </SelectRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectContentEmits, SelectContentProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport {\n  SelectContent,\n  SelectPortal,\n  SelectViewport,\n  useForwardPropsEmits,\n} from 'radix-vue';\n\nimport SelectScrollDownButton from './SelectScrollDownButton.vue';\nimport SelectScrollUpButton from './SelectScrollUpButton.vue';\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\nconst props = withDefaults(\n  defineProps<SelectContentProps & { class?: any }>(),\n  {\n    position: 'popper',\n  },\n);\nconst emits = defineEmits<SelectContentEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <SelectPortal>\n    <SelectContent\n      v-bind=\"{ ...forwarded, ...$attrs }\"\n      :class=\"\n        cn(\n          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-popup relative max-h-96 min-w-32 overflow-hidden rounded-md border shadow-md',\n          position === 'popper' &&\n            'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',\n          props.class,\n        )\n      \"\n    >\n      <SelectScrollUpButton />\n      <SelectViewport\n        :class=\"\n          cn(\n            'p-1',\n            position === 'popper' &&\n              'h-[--radix-select-trigger-height] w-full min-w-[--radix-select-trigger-width]',\n          )\n        \"\n      >\n        <slot></slot>\n      </SelectViewport>\n      <SelectScrollDownButton />\n    </SelectContent>\n  </SelectPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectGroupProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { SelectGroup } from 'radix-vue';\n\nconst props = defineProps<SelectGroupProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <SelectGroup :class=\"cn('w-full p-1', props.class)\" v-bind=\"delegatedProps\">\n    <slot></slot>\n  </SelectGroup>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectItemProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Check } from 'lucide-vue-next';\nimport {\n  SelectItem,\n  SelectItemIndicator,\n  SelectItemText,\n  useForwardProps,\n} from 'radix-vue';\n\nconst props = defineProps<SelectItemProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <SelectItem\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n        props.class,\n      )\n    \"\n  >\n    <span class=\"absolute right-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <SelectItemIndicator>\n        <Check class=\"h-4 w-4\" />\n      </SelectItemIndicator>\n    </span>\n\n    <SelectItemText>\n      <slot></slot>\n    </SelectItemText>\n  </SelectItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItemText.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectItemTextProps } from 'radix-vue';\n\nimport { SelectItemText } from 'radix-vue';\n\nconst props = defineProps<SelectItemTextProps>();\n</script>\n\n<template>\n  <SelectItemText v-bind=\"props\">\n    <slot></slot>\n  </SelectItemText>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectLabel.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectLabelProps } from 'radix-vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { SelectLabel } from 'radix-vue';\n\nconst props = defineProps<SelectLabelProps & { class?: any }>();\n</script>\n\n<template>\n  <SelectLabel :class=\"cn('px-2 py-1.5 text-sm font-semibold', props.class)\">\n    <slot></slot>\n  </SelectLabel>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollDownButton.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectScrollDownButtonProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronDown } from 'lucide-vue-next';\nimport { SelectScrollDownButton, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<SelectScrollDownButtonProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <SelectScrollDownButton\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn('flex cursor-default items-center justify-center py-1', props.class)\n    \"\n  >\n    <slot>\n      <ChevronDown class=\"h-4 w-4\" />\n    </slot>\n  </SelectScrollDownButton>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollUpButton.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectScrollUpButtonProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronUp } from 'lucide-vue-next';\nimport { SelectScrollUpButton, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<SelectScrollUpButtonProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <SelectScrollUpButton\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn('flex cursor-default items-center justify-center py-1', props.class)\n    \"\n  >\n    <slot>\n      <ChevronUp class=\"h-4 w-4\" />\n    </slot>\n  </SelectScrollUpButton>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectSeparator.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectSeparatorProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { SelectSeparator } from 'radix-vue';\n\nconst props = defineProps<SelectSeparatorProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <SelectSeparator\n    v-bind=\"delegatedProps\"\n    :class=\"cn('bg-muted -mx-1 my-1 h-px', props.class)\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectTriggerProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ChevronDown } from 'lucide-vue-next';\nimport { SelectIcon, SelectTrigger, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<SelectTriggerProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <SelectTrigger\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'border-input ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-10 w-full items-center justify-between whitespace-nowrap rounded-md border bg-transparent px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n    <SelectIcon as-child>\n      <ChevronDown class=\"h-4 w-4 opacity-50\" />\n    </SelectIcon>\n  </SelectTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectValue.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectValueProps } from 'radix-vue';\n\nimport { SelectValue } from 'radix-vue';\n\nconst props = defineProps<SelectValueProps>();\n</script>\n\n<template>\n  <SelectValue v-bind=\"props\">\n    <slot></slot>\n  </SelectValue>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/select/index.ts",
    "content": "export { default as Select } from './Select.vue';\nexport { default as SelectContent } from './SelectContent.vue';\nexport { default as SelectGroup } from './SelectGroup.vue';\nexport { default as SelectItem } from './SelectItem.vue';\nexport { default as SelectItemText } from './SelectItemText.vue';\nexport { default as SelectLabel } from './SelectLabel.vue';\nexport { default as SelectScrollDownButton } from './SelectScrollDownButton.vue';\nexport { default as SelectScrollUpButton } from './SelectScrollUpButton.vue';\nexport { default as SelectSeparator } from './SelectSeparator.vue';\nexport { default as SelectTrigger } from './SelectTrigger.vue';\nexport { default as SelectValue } from './SelectValue.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/separator/Separator.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SeparatorProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Separator } from 'radix-vue';\n\nconst props = defineProps<SeparatorProps & { class?: any; label?: string }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <Separator\n    v-bind=\"delegatedProps\"\n    :class=\"\n      cn(\n        'bg-border relative shrink-0',\n        props.orientation === 'vertical' ? 'h-full w-px' : 'h-px w-full',\n        props.class,\n      )\n    \"\n  >\n    <span\n      v-if=\"props.label\"\n      :class=\"\n        cn(\n          'text-muted-foreground bg-background absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center text-xs',\n          props.orientation === 'vertical'\n            ? 'w-[1px] px-1 py-2'\n            : 'h-[1px] px-2 py-1',\n        )\n      \"\n    >\n      {{ props.label }}\n    </span>\n  </Separator>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/separator/index.ts",
    "content": "export { default as Separator } from './Separator.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/Sheet.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogRootEmits, DialogRootProps } from 'radix-vue';\n\nimport { DialogRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<DialogRootProps>();\nconst emits = defineEmits<DialogRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <DialogRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </DialogRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetClose.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogCloseProps } from 'radix-vue';\n\nimport { DialogClose } from 'radix-vue';\n\nconst props = defineProps<DialogCloseProps>();\n</script>\n\n<template>\n  <DialogClose v-bind=\"props\">\n    <slot></slot>\n  </DialogClose>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogContentEmits, DialogContentProps } from 'radix-vue';\n\nimport type { SheetVariants } from './sheet';\n\nimport { computed, ref } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DialogContent, useForwardPropsEmits } from 'radix-vue';\n\nimport { sheetVariants } from './sheet';\nimport SheetOverlay from './SheetOverlay.vue';\n\ninterface SheetContentProps extends DialogContentProps {\n  appendTo?: HTMLElement | string;\n  class?: any;\n  modal?: boolean;\n  open?: boolean;\n  overlayBlur?: number;\n  side?: SheetVariants['side'];\n  zIndex?: number;\n}\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\nconst props = withDefaults(defineProps<SheetContentProps>(), {\n  appendTo: 'body',\n});\n\nconst emits = defineEmits<\n  DialogContentEmits & { close: []; closed: []; opened: [] }\n>();\n\nconst delegatedProps = computed(() => {\n  const {\n    class: _,\n    modal: _modal,\n    open: _open,\n    side: _side,\n    ...delegated\n  } = props;\n\n  return delegated;\n});\n\nfunction isAppendToBody() {\n  return (\n    props.appendTo === 'body' ||\n    props.appendTo === document.body ||\n    !props.appendTo\n  );\n}\n\nconst position = computed(() => {\n  return isAppendToBody() ? 'fixed' : 'absolute';\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\nconst contentRef = ref<InstanceType<typeof DialogContent> | null>(null);\nfunction onAnimationEnd(event: AnimationEvent) {\n  // 只有在 contentRef 的动画结束时才触发 opened/closed 事件\n  if (event.target === contentRef.value?.$el) {\n    if (props.open) {\n      emits('opened');\n    } else {\n      emits('closed');\n    }\n  }\n}\n</script>\n\n<template>\n  <Teleport defer :to=\"appendTo\">\n    <Transition name=\"fade\">\n      <SheetOverlay\n        v-if=\"open && modal\"\n        :style=\"{\n          ...(zIndex ? { zIndex } : {}),\n          position,\n          backdropFilter:\n            overlayBlur && overlayBlur > 0 ? `blur(${overlayBlur}px)` : 'none',\n        }\"\n      />\n    </Transition>\n    <DialogContent\n      ref=\"contentRef\"\n      :class=\"cn('z-popup', sheetVariants({ side }), props.class)\"\n      :style=\"{\n        ...(zIndex ? { zIndex } : {}),\n        position,\n      }\"\n      @animationend=\"onAnimationEnd\"\n      v-bind=\"{ ...forwarded, ...$attrs }\"\n    >\n      <slot></slot>\n\n      <!-- <DialogClose\n        class=\"data-[state=open]:bg-secondary absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none\"\n      >\n        <Cross2Icon class=\"h-5 w-\" />\n      </DialogClose> -->\n    </DialogContent>\n  </Teleport>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetDescription.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogDescriptionProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DialogDescription } from 'radix-vue';\n\nconst props = defineProps<DialogDescriptionProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <DialogDescription\n    :class=\"cn('text-muted-foreground text-sm', props.class)\"\n    v-bind=\"delegatedProps\"\n  >\n    <slot></slot>\n  </DialogDescription>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{ class?: any }>();\n</script>\n\n<template>\n  <div\n    :class=\"\n      cn('flex flex-row flex-col-reverse justify-end gap-x-2', props.class)\n    \"\n  >\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetHeader.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nconst props = defineProps<{ class?: any }>();\n</script>\n\n<template>\n  <div :class=\"cn('flex flex-col text-center sm:text-left', props.class)\">\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetOverlay.vue",
    "content": "<script setup lang=\"ts\">\nimport { inject } from 'vue';\n\nimport { useScrollLock } from '@vben-core/composables';\n\nuseScrollLock();\nconst id = inject('DISMISSABLE_DRAWER_ID');\n</script>\n<template>\n  <div :data-dismissable-drawer=\"id\" class=\"bg-overlay z-popup inset-0\"></div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTitle.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogTitleProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { DialogTitle } from 'radix-vue';\n\nconst props = defineProps<DialogTitleProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <DialogTitle\n    :class=\"cn('text-foreground font-medium', props.class)\"\n    v-bind=\"delegatedProps\"\n  >\n    <slot></slot>\n  </DialogTitle>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DialogTriggerProps } from 'radix-vue';\n\nimport { DialogTrigger } from 'radix-vue';\n\nconst props = defineProps<DialogTriggerProps>();\n</script>\n\n<template>\n  <DialogTrigger v-bind=\"props\">\n    <slot></slot>\n  </DialogTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/index.ts",
    "content": "export * from './sheet';\nexport { default as Sheet } from './Sheet.vue';\nexport { default as SheetClose } from './SheetClose.vue';\nexport { default as SheetContent } from './SheetContent.vue';\nexport { default as SheetDescription } from './SheetDescription.vue';\nexport { default as SheetFooter } from './SheetFooter.vue';\nexport { default as SheetHeader } from './SheetHeader.vue';\nexport { default as SheetTitle } from './SheetTitle.vue';\n\nexport { default as SheetTrigger } from './SheetTrigger.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/sheet.ts",
    "content": "import type { VariantProps } from 'class-variance-authority';\n\nimport { cva } from 'class-variance-authority';\n\nexport const sheetVariants = cva(\n  'bg-background shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 border-border',\n  {\n    defaultVariants: {\n      side: 'right',\n    },\n    variants: {\n      side: {\n        bottom:\n          'inset-x-0 bottom-0 border-t border-border data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',\n        left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left ',\n        right:\n          'inset-y-0 right-0 w-3/4 border-l  data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right',\n        top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',\n      },\n    },\n  },\n);\n\nexport type SheetVariants = VariantProps<typeof sheetVariants>;\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/switch/Switch.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SwitchRootEmits, SwitchRootProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { SwitchRoot, SwitchThumb, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<SwitchRootProps & { class?: any }>();\n\nconst emits = defineEmits<SwitchRootEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <SwitchRoot\n    v-bind=\"forwarded\"\n    :class=\"\n      cn(\n        'focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',\n        props.class,\n      )\n    \"\n  >\n    <SwitchThumb\n      :class=\"\n        cn(\n          'bg-background pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0',\n        )\n      \"\n    />\n  </SwitchRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/switch/index.ts",
    "content": "export { default as Switch } from './Switch.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/Tabs.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TabsRootEmits, TabsRootProps } from 'radix-vue';\n\nimport { TabsRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<TabsRootProps>();\nconst emits = defineEmits<TabsRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <TabsRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </TabsRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TabsContentProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { TabsContent } from 'radix-vue';\n\nconst props = defineProps<TabsContentProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <TabsContent\n    :class=\"\n      cn(\n        'ring-offset-background focus-visible:ring-ring mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2',\n        props.class,\n      )\n    \"\n    v-bind=\"delegatedProps\"\n  >\n    <slot></slot>\n  </TabsContent>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsList.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TabsListProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { TabsList } from 'radix-vue';\n\nconst props = defineProps<TabsListProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n</script>\n\n<template>\n  <TabsList\n    v-bind=\"delegatedProps\"\n    :class=\"\n      cn(\n        'bg-muted text-muted-foreground inline-flex h-9 items-center justify-center rounded-lg p-1',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </TabsList>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TabsTriggerProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { TabsTrigger, useForwardProps } from 'radix-vue';\n\nconst props = defineProps<TabsTriggerProps & { class?: any }>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <TabsTrigger\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        'ring-offset-background focus-visible:ring-ring data-[state=active]:bg-background data-[state=active]:text-foreground inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow',\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </TabsTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/index.ts",
    "content": "export { default as Tabs } from './Tabs.vue';\nexport { default as TabsContent } from './TabsContent.vue';\nexport { default as TabsList } from './TabsList.vue';\nexport { default as TabsTrigger } from './TabsTrigger.vue';\nexport { TabsIndicator } from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/Textarea.vue",
    "content": "<script setup lang=\"ts\">\nimport { cn } from '@vben-core/shared/utils';\n\nimport { useVModel } from '@vueuse/core';\n\nconst props = defineProps<{\n  class?: any;\n  defaultValue?: number | string;\n  modelValue?: number | string;\n}>();\n\nconst emits = defineEmits<{\n  (e: 'update:modelValue', payload: number | string): void;\n}>();\n\nconst modelValue = useVModel(props, 'modelValue', emits, {\n  defaultValue: props.defaultValue,\n  passive: true,\n});\n</script>\n\n<template>\n  <textarea\n    v-model=\"modelValue\"\n    :class=\"\n      cn(\n        'border-input placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[60px] w-full rounded-md border bg-transparent px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',\n        props.class,\n      )\n    \"\n  ></textarea>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts",
    "content": "export { default as Textarea } from './Textarea.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ToggleEmits, ToggleProps } from 'radix-vue';\n\nimport type { ToggleVariants } from './toggle';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { Toggle, useForwardPropsEmits } from 'radix-vue';\n\nimport { toggleVariants } from './toggle';\n\nconst props = withDefaults(\n  defineProps<\n    ToggleProps & {\n      class?: any;\n      size?: ToggleVariants['size'];\n      variant?: ToggleVariants['variant'];\n    }\n  >(),\n  {\n    disabled: false,\n    size: 'default',\n    variant: 'default',\n  },\n);\n\nconst emits = defineEmits<ToggleEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, size: _size, variant: _variant, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <Toggle\n    v-bind=\"forwarded\"\n    :class=\"cn(toggleVariants({ variant, size }), props.class)\"\n  >\n    <slot></slot>\n  </Toggle>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts",
    "content": "export * from './toggle';\nexport { default as Toggle } from './Toggle.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts",
    "content": "import type { VariantProps } from 'class-variance-authority';\n\nimport { cva } from 'class-variance-authority';\n\nexport const toggleVariants = cva(\n  'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground',\n  {\n    defaultVariants: {\n      size: 'default',\n      variant: 'default',\n    },\n    variants: {\n      size: {\n        default: 'h-9 px-3',\n        lg: 'h-10 px-3',\n        sm: 'h-8 px-2',\n      },\n      variant: {\n        default: 'bg-transparent',\n        outline:\n          'border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground',\n      },\n    },\n  },\n);\n\nexport type ToggleVariants = VariantProps<typeof toggleVariants>;\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type { VariantProps } from 'class-variance-authority';\nimport type { ToggleGroupRootEmits, ToggleGroupRootProps } from 'radix-vue';\n\nimport type { toggleVariants } from '../toggle';\n\nimport { computed, provide } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ToggleGroupRoot, useForwardPropsEmits } from 'radix-vue';\n\ntype ToggleGroupVariants = VariantProps<typeof toggleVariants>;\n\nconst props = defineProps<\n  ToggleGroupRootProps & {\n    class?: any;\n    size?: ToggleGroupVariants['size'];\n    variant?: ToggleGroupVariants['variant'];\n  }\n>();\nconst emits = defineEmits<ToggleGroupRootEmits>();\n\nprovide('toggleGroup', {\n  size: props.size,\n  variant: props.variant,\n});\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <ToggleGroupRoot\n    v-bind=\"forwarded\"\n    :class=\"cn('flex items-center justify-center gap-1', props.class)\"\n  >\n    <slot></slot>\n  </ToggleGroupRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { VariantProps } from 'class-variance-authority';\nimport type { ToggleGroupItemProps } from 'radix-vue';\n\nimport { computed, inject } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { ToggleGroupItem, useForwardProps } from 'radix-vue';\n\nimport { toggleVariants } from '../toggle';\n\ntype ToggleGroupVariants = VariantProps<typeof toggleVariants>;\n\nconst props = defineProps<\n  ToggleGroupItemProps & {\n    class?: any;\n    size?: ToggleGroupVariants['size'];\n    variant?: ToggleGroupVariants['variant'];\n  }\n>();\n\nconst context = inject<ToggleGroupVariants>('toggleGroup');\n\nconst delegatedProps = computed(() => {\n  const { class: _, size: _size, variant: _variant, ...delegated } = props;\n  return delegated;\n});\n\nconst forwardedProps = useForwardProps(delegatedProps);\n</script>\n\n<template>\n  <ToggleGroupItem\n    v-bind=\"forwardedProps\"\n    :class=\"\n      cn(\n        toggleVariants({\n          variant: context?.variant || variant,\n          size: context?.size || size,\n        }),\n        props.class,\n      )\n    \"\n  >\n    <slot></slot>\n  </ToggleGroupItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts",
    "content": "export { default as ToggleGroup } from './ToggleGroup.vue';\nexport { default as ToggleGroupItem } from './ToggleGroupItem.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TooltipRootEmits, TooltipRootProps } from 'radix-vue';\n\nimport { TooltipRoot, useForwardPropsEmits } from 'radix-vue';\n\nconst props = defineProps<TooltipRootProps>();\nconst emits = defineEmits<TooltipRootEmits>();\n\nconst forwarded = useForwardPropsEmits(props, emits);\n</script>\n\n<template>\n  <TooltipRoot v-bind=\"forwarded\">\n    <slot></slot>\n  </TooltipRoot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TooltipContentEmits, TooltipContentProps } from 'radix-vue';\n\nimport { computed } from 'vue';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { TooltipContent, TooltipPortal, useForwardPropsEmits } from 'radix-vue';\n\ndefineOptions({\n  inheritAttrs: false,\n});\n\nconst props = withDefaults(\n  defineProps<TooltipContentProps & { class?: any }>(),\n  {\n    class: '',\n    side: 'right',\n    sideOffset: 5,\n  },\n);\n\nconst emits = defineEmits<TooltipContentEmits>();\n\nconst delegatedProps = computed(() => {\n  const { class: _, ...delegated } = props;\n\n  return delegated;\n});\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits);\n</script>\n\n<template>\n  <TooltipPortal>\n    <TooltipContent\n      v-bind=\"{ ...forwarded, ...$attrs }\"\n      :class=\"\n        cn(\n          'z-popup bg-accent text-accent-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border shadow-float overflow-hidden rounded-sm border px-4 py-2 text-xs',\n          props.class,\n        )\n      \"\n    >\n      <slot></slot>\n    </TooltipContent>\n  </TooltipPortal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TooltipProviderProps } from 'radix-vue';\n\nimport { TooltipProvider } from 'radix-vue';\n\nconst props = defineProps<TooltipProviderProps>();\n</script>\n\n<template>\n  <TooltipProvider v-bind=\"props\">\n    <slot></slot>\n  </TooltipProvider>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TooltipTriggerProps } from 'radix-vue';\n\nimport { TooltipTrigger } from 'radix-vue';\n\nconst props = defineProps<TooltipTriggerProps>();\n</script>\n\n<template>\n  <TooltipTrigger v-bind=\"props\">\n    <slot></slot>\n  </TooltipTrigger>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts",
    "content": "export { default as Tooltip } from './Tooltip.vue';\nexport { default as TooltipContent } from './TooltipContent.vue';\nexport { default as TooltipProvider } from './TooltipProvider.vue';\nexport { default as TooltipTrigger } from './TooltipTrigger.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tree/index.ts",
    "content": "export { default as VbenTree } from './tree.vue';\nexport type { TreeProps } from './types';\nexport { treePropsDefaults } from './types';\nexport type { FlattenedItem } from 'radix-vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Arrayable } from '@vueuse/core';\nimport type { FlattenedItem } from 'radix-vue';\n\nimport type { ClassType, Recordable } from '@vben-core/typings';\n\nimport type { TreeProps } from './types';\n\nimport { onMounted, ref, watchEffect } from 'vue';\n\nimport { ChevronRight, IconifyIcon } from '@vben-core/icons';\nimport { cn, get } from '@vben-core/shared/utils';\n\nimport { TreeItem, TreeRoot } from 'radix-vue';\n\nimport { Checkbox } from '../checkbox';\nimport { treePropsDefaults } from './types';\n\nconst props = withDefaults(defineProps<TreeProps>(), treePropsDefaults());\n\nconst emits = defineEmits<{\n  expand: [value: FlattenedItem<Recordable<any>>];\n  select: [value: FlattenedItem<Recordable<any>>];\n}>();\n\ninterface InnerFlattenItem<T = Recordable<any>, P = number | string> {\n  hasChildren: boolean;\n  id: P;\n  level: number;\n  parentId: null | P;\n  parents: P[];\n  value: T;\n}\n\nfunction flatten<T = Recordable<any>, P = number | string>(\n  items: T[],\n  childrenField: string = 'children',\n  level = 0,\n  parentId: null | P = null,\n  parents: P[] = [],\n): InnerFlattenItem<T, P>[] {\n  const result: InnerFlattenItem<T, P>[] = [];\n  items.forEach((item) => {\n    const children = get(item, childrenField) as Array<T>;\n    const id = get(item, props.valueField) as P;\n    const val: InnerFlattenItem<T, P> = {\n      hasChildren: Array.isArray(children) && children.length > 0,\n      id,\n      level,\n      parentId,\n      parents: [...parents],\n      value: item,\n    };\n    result.push(val);\n    if (val.hasChildren)\n      result.push(\n        ...flatten(children, childrenField, level + 1, id, [...parents, id]),\n      );\n  });\n  return result;\n}\n\nconst flattenData = ref<Array<InnerFlattenItem>>([]);\nconst modelValue = defineModel<Arrayable<number | string>>();\nconst expanded = ref<Array<number | string>>(props.defaultExpandedKeys ?? []);\n\nconst treeValue = ref();\n\nonMounted(() => {\n  watchEffect(() => {\n    flattenData.value = flatten(props.treeData, props.childrenField);\n    updateTreeValue();\n    if (\n      props.defaultExpandedLevel !== undefined &&\n      props.defaultExpandedLevel > 0\n    )\n      expandToLevel(props.defaultExpandedLevel);\n  });\n});\n\nfunction getItemByValue(value: number | string) {\n  return flattenData.value.find(\n    (item) => get(item.value, props.valueField) === value,\n  )?.value;\n}\n\nfunction updateTreeValue() {\n  const val = modelValue.value;\n  if (val === undefined) {\n    treeValue.value = undefined;\n  } else {\n    if (Array.isArray(val)) {\n      const filteredValues = val.filter((v) => {\n        const item = getItemByValue(v);\n        return item && !get(item, props.disabledField);\n      });\n      treeValue.value = filteredValues.map((v) => getItemByValue(v));\n\n      if (filteredValues.length !== val.length) {\n        modelValue.value = filteredValues;\n      }\n    } else {\n      const item = getItemByValue(val);\n      if (item && !get(item, props.disabledField)) {\n        treeValue.value = item;\n      } else {\n        treeValue.value = undefined;\n        modelValue.value = undefined;\n      }\n    }\n  }\n}\n\nfunction updateModelValue(val: Arrayable<Recordable<any>>) {\n  if (Array.isArray(val)) {\n    const filteredVal = val.filter((v) => !get(v, props.disabledField));\n    modelValue.value = filteredVal.map((v) => get(v, props.valueField));\n  } else {\n    if (val && !get(val, props.disabledField)) {\n      modelValue.value = get(val, props.valueField);\n    }\n  }\n}\n\nfunction expandToLevel(level: number) {\n  const keys: string[] = [];\n  flattenData.value.forEach((item) => {\n    if (item.level <= level - 1) {\n      keys.push(get(item.value, props.valueField));\n    }\n  });\n  expanded.value = keys;\n}\n\nfunction collapseNodes(value: Arrayable<number | string>) {\n  const keys = new Set(Array.isArray(value) ? value : [value]);\n  expanded.value = expanded.value.filter((key) => !keys.has(key));\n}\n\nfunction expandNodes(value: Arrayable<number | string>) {\n  const keys = [...(Array.isArray(value) ? value : [value])];\n  keys.forEach((key) => {\n    if (expanded.value.includes(key)) return;\n    const item = getItemByValue(key);\n    if (item) {\n      expanded.value.push(key);\n    }\n  });\n}\n\nfunction expandAll() {\n  expanded.value = flattenData.value\n    .filter((item) => item.hasChildren)\n    .map((item) => get(item.value, props.valueField));\n}\n\nfunction collapseAll() {\n  expanded.value = [];\n}\n\nfunction checkAll() {\n  if (!props.multiple) return;\n  modelValue.value = [\n    ...new Set(\n      flattenData.value\n        .filter((item) => !get(item.value, props.disabledField))\n        .map((item) => get(item.value, props.valueField)),\n    ),\n  ];\n  updateTreeValue();\n}\n\nfunction unCheckAll() {\n  if (!props.multiple) return;\n  modelValue.value = [];\n  updateTreeValue();\n}\n\nfunction isNodeDisabled(item: FlattenedItem<Recordable<any>>) {\n  return props.disabled || get(item.value, props.disabledField);\n}\n\nfunction onToggle(item: FlattenedItem<Recordable<any>>) {\n  emits('expand', item);\n}\nfunction onSelect(item: FlattenedItem<Recordable<any>>, isSelected: boolean) {\n  if (isNodeDisabled(item)) {\n    return;\n  }\n\n  if (\n    !props.checkStrictly &&\n    props.multiple &&\n    props.autoCheckParent &&\n    isSelected\n  ) {\n    flattenData.value\n      .find((i) => {\n        return (\n          get(i.value, props.valueField) === get(item.value, props.valueField)\n        );\n      })\n      ?.parents?.filter((item) => !get(item, props.disabledField))\n      ?.forEach((p) => {\n        if (Array.isArray(modelValue.value) && !modelValue.value.includes(p)) {\n          modelValue.value.push(p);\n        }\n      });\n  }\n  if (\n    !props.checkStrictly &&\n    props.multiple &&\n    props.autoCheckParent &&\n    !isSelected\n  ) {\n    flattenData.value\n      .find((i) => {\n        return (\n          get(i.value, props.valueField) === get(item.value, props.valueField)\n        );\n      })\n      ?.parents?.filter((item) => !get(item, props.disabledField))\n      ?.reverse()\n      .forEach((p) => {\n        const children = flattenData.value.filter((i) => {\n          return (\n            i.parents.length > 0 &&\n            i.parents.includes(p) &&\n            i.id !== item._id &&\n            i.parentId === p\n          );\n        });\n        if (Array.isArray(modelValue.value)) {\n          const hasSelectedChild = children.some((child) =>\n            (modelValue.value as unknown[]).includes(\n              get(child.value, props.valueField),\n            ),\n          );\n          if (!hasSelectedChild) {\n            const index = modelValue.value.indexOf(p);\n            if (index !== -1) {\n              modelValue.value.splice(index, 1);\n            }\n          }\n        }\n      });\n  }\n  updateTreeValue();\n  emits('select', item);\n}\n\ndefineExpose({\n  collapseAll,\n  collapseNodes,\n  expandAll,\n  expandNodes,\n  checkAll,\n  unCheckAll,\n  expandToLevel,\n  getItemByValue,\n});\n</script>\n<template>\n  <TreeRoot\n    :get-key=\"(item) => get(item, valueField)\"\n    :get-children=\"(item) => get(item, childrenField)\"\n    :items=\"treeData\"\n    :model-value=\"treeValue\"\n    v-model:expanded=\"expanded as string[]\"\n    :default-expanded=\"defaultExpandedKeys as string[]\"\n    :propagate-select=\"!checkStrictly\"\n    :multiple=\"multiple\"\n    :disabled=\"disabled\"\n    :selection-behavior=\"allowClear || multiple ? 'toggle' : 'replace'\"\n    @update:model-value=\"updateModelValue\"\n    v-slot=\"{ flattenItems }\"\n    :class=\"\n      cn(\n        'text-blackA11 container select-none list-none rounded-lg text-sm font-medium',\n        $attrs.class as unknown as ClassType,\n        bordered ? 'border' : '',\n      )\n    \"\n  >\n    <div\n      :class=\"\n        cn('my-0.5 flex w-full items-center p-1', bordered ? 'border-b' : '')\n      \"\n      v-if=\"$slots.header\"\n    >\n      <slot name=\"header\"> </slot>\n    </div>\n    <div\n      :class=\"\n        cn('my-0.5 flex w-full items-center p-1', bordered ? 'border-b' : '')\n      \"\n      v-if=\"treeData.length > 0\"\n    >\n      <div\n        class=\"flex size-5 flex-1 cursor-pointer items-center\"\n        @click=\"() => (expanded?.length > 0 ? collapseAll() : expandAll())\"\n      >\n        <ChevronRight\n          :class=\"{ 'rotate-90': expanded?.length > 0 }\"\n          class=\"text-foreground/80 hover:text-foreground size-4 cursor-pointer transition\"\n        />\n        <Checkbox\n          v-if=\"multiple\"\n          @click.stop\n          @update:checked=\"(checked) => (checked ? checkAll() : unCheckAll())\"\n        />\n      </div>\n    </div>\n    <TransitionGroup :name=\"transition ? 'fade' : ''\">\n      <TreeItem\n        v-for=\"item in flattenItems\"\n        v-slot=\"{\n          isExpanded,\n          isSelected,\n          isIndeterminate,\n          handleSelect,\n          handleToggle,\n        }\"\n        :key=\"item._id\"\n        :style=\"{ 'margin-left': `${item.level - 1}rem` }\"\n        :class=\"\n          cn('cursor-pointer', getNodeClass?.(item), {\n            'data-[selected]:bg-accent': !multiple,\n            'text-foreground/50 cursor-not-allowed': isNodeDisabled(item),\n          })\n        \"\n        v-bind=\"\n          Object.assign(item.bind, {\n            onfocus: isNodeDisabled(item) ? 'this.blur()' : undefined,\n            disabled: isNodeDisabled(item),\n          })\n        \"\n        @select=\"\n          (event: any) => {\n            if (isNodeDisabled(item)) {\n              event.preventDefault();\n              event.stopPropagation();\n              return;\n            }\n            if (event.detail.originalEvent.type === 'click') {\n              event.preventDefault();\n            }\n            onSelect(item, event.detail.isSelected);\n          }\n        \"\n        @toggle=\"\n          (event: any) => {\n            if (event.detail.originalEvent.type === 'click') {\n              event.preventDefault();\n            }\n            !isNodeDisabled(item) && onToggle(item);\n          }\n        \"\n        class=\"tree-node focus:ring-grass8 my-0.5 flex items-center rounded p-1 outline-none focus:ring-2\"\n      >\n        <ChevronRight\n          v-if=\"\n            item.hasChildren &&\n            Array.isArray(item.value[childrenField]) &&\n            item.value[childrenField].length > 0\n          \"\n          class=\"text-foreground/80 hover:text-foreground size-4 cursor-pointer transition\"\n          :class=\"{ 'rotate-90': isExpanded }\"\n          @click.stop=\"\n            () => {\n              handleToggle();\n              onToggle(item);\n            }\n          \"\n        />\n        <div v-else class=\"h-4 w-4\"></div>\n        <div class=\"flex items-center gap-1\">\n          <Checkbox\n            v-if=\"multiple\"\n            :checked=\"isSelected && !isNodeDisabled(item)\"\n            :disabled=\"isNodeDisabled(item)\"\n            :indeterminate=\"isIndeterminate && !isNodeDisabled(item)\"\n            @click=\"\n              (event: MouseEvent) => {\n                if (isNodeDisabled(item)) {\n                  event.preventDefault();\n                  event.stopPropagation();\n                  return;\n                }\n                handleSelect();\n              }\n            \"\n          />\n          <div\n            class=\"flex items-center gap-1\"\n            @click=\"\n              (event: MouseEvent) => {\n                if (isNodeDisabled(item)) {\n                  event.preventDefault();\n                  event.stopPropagation();\n                  return;\n                }\n                handleSelect();\n              }\n            \"\n          >\n            <slot name=\"node\" v-bind=\"item\">\n              <IconifyIcon\n                class=\"size-4\"\n                v-if=\"showIcon && get(item.value, iconField)\"\n                :icon=\"get(item.value, iconField)\"\n              />\n              {{ get(item.value, labelField) }}\n            </slot>\n          </div>\n        </div>\n        <div class=\"h-4 w-4\"></div>\n      </TreeItem>\n    </TransitionGroup>\n    <div\n      :class=\"\n        cn('my-0.5 flex w-full items-center p-1', bordered ? 'border-t' : '')\n      \"\n      v-if=\"$slots.footer\"\n    >\n      <slot name=\"footer\"> </slot>\n    </div>\n  </TreeRoot>\n</template>\n<style lang=\"scss\" scoped>\n.container {\n  position: relative;\n  padding: 0;\n  list-style-type: none;\n}\n\n.item {\n  box-sizing: border-box;\n  width: 100%;\n  height: 30px;\n  background-color: #f3f3f3;\n  border: 1px solid #666;\n}\n\n/* 1. 声明过渡效果 */\n.fade-move,\n.fade-enter-active,\n.fade-leave-active {\n  transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);\n}\n\n/* 2. 声明进入和离开的状态 */\n.fade-enter-from,\n.fade-leave-to {\n  opacity: 0;\n  transform: scaleY(0.01) translate(30px, 0);\n}\n\n/* 3. 确保离开的项目被移除出了布局流\n      以便正确地计算移动时的动画效果。 */\n.fade-leave-active {\n  position: absolute;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts",
    "content": "import type { Arrayable } from '@vueuse/core';\nimport type { FlattenedItem } from 'radix-vue';\n\nimport type { Recordable } from '@vben-core/typings';\n\nexport interface TreeProps {\n  /** 单选时允许取消已有选项 */\n  allowClear?: boolean;\n  /** 非关联选择时，自动选中上级节点 */\n  autoCheckParent?: boolean;\n  /** 显示边框 */\n  bordered?: boolean;\n  /** 取消父子关联选择 */\n  checkStrictly?: boolean;\n  /** 子级字段名 */\n  childrenField?: string;\n  /** 默认展开的键 */\n  defaultExpandedKeys?: Array<number | string>;\n  /** 默认展开的级别（优先级高于defaultExpandedKeys） */\n  defaultExpandedLevel?: number;\n  /** 默认值 */\n  defaultValue?: Arrayable<number | string>;\n  /** 禁用 */\n  disabled?: boolean;\n  /** 禁用字段名 */\n  disabledField?: string;\n  /** 自定义节点类名 */\n  getNodeClass?: (item: FlattenedItem<Recordable<any>>) => string;\n  iconField?: string;\n  /** label字段 */\n  labelField?: string;\n  /** 是否多选 */\n  multiple?: boolean;\n  /** 显示由iconField指定的图标 */\n  showIcon?: boolean;\n  /** 启用展开收缩动画 */\n  transition?: boolean;\n  /** 树数据 */\n  treeData: Recordable<any>[];\n  /** 值字段 */\n  valueField?: string;\n}\n\nexport function treePropsDefaults() {\n  return {\n    allowClear: false,\n    autoCheckParent: true,\n    bordered: false,\n    checkStrictly: false,\n    defaultExpandedKeys: () => [],\n    defaultExpandedLevel: 0,\n    disabled: false,\n    disabledField: 'disabled',\n    iconField: 'icon',\n    labelField: 'label',\n    multiple: false,\n    showIcon: true,\n    transition: true,\n    valueField: 'value',\n    childrenField: 'children',\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/shadcn-ui/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@vben-core/shadcn-ui/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: [\n    {\n      builder: 'mkdist',\n      input: './src',\n      loaders: ['vue'],\n      pattern: ['**/*.vue'],\n    },\n    {\n      builder: 'mkdist',\n      format: 'esm',\n      input: './src',\n      loaders: ['js'],\n      pattern: ['**/*.ts'],\n    },\n  ],\n});\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/package.json",
    "content": "{\n  \"name\": \"@vben-core/tabs-ui\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/@vben-core/uikit/tabs-ui\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm unbuild\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"development\": \"./src/index.ts\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"publishConfig\": {\n    \"exports\": {\n      \".\": {\n        \"default\": \"./dist/index.mjs\"\n      }\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/composables\": \"workspace:*\",\n    \"@vben-core/icons\": \"workspace:*\",\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/components/index.ts",
    "content": "export { default as TabsChrome } from './tabs-chrome/tabs.vue';\nexport { default as Tabs } from './tabs/tabs.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { TabDefinition } from '@vben-core/typings';\n\nimport type { TabConfig, TabsProps } from '../../types';\n\nimport { computed } from 'vue';\n\nimport { Pin, X } from '@vben-core/icons';\nimport { VbenContextMenu, VbenIcon } from '@vben-core/shadcn-ui';\n\ninterface Props extends TabsProps {}\n\ndefineOptions({\n  name: 'VbenTabs',\n\n  inheritAttrs: false,\n});\nconst props = withDefaults(defineProps<Props>(), {\n  contentClass: 'vben-tabs-content',\n  contextMenus: () => [],\n  tabs: () => [],\n});\n\nconst emit = defineEmits<{\n  close: [string];\n  unpin: [TabDefinition];\n}>();\nconst active = defineModel<string>('active');\n\nconst typeWithClass = computed(() => {\n  const typeClasses: Record<string, { content: string }> = {\n    brisk: {\n      content: `h-full after:content-['']  after:absolute after:bottom-0 after:left-0 after:w-full after:h-[1.5px] after:bg-primary after:scale-x-0 after:transition-[transform] after:ease-out after:duration-300 hover:after:scale-x-100 after:origin-left [&.is-active]:after:scale-x-100 [&:not(:first-child)]:border-l last:border-r last:border-r border-border`,\n    },\n    card: {\n      content:\n        'h-[calc(100%-6px)] rounded-md ml-2 border border-border  transition-all',\n    },\n    plain: {\n      content:\n        'h-full [&:not(:first-child)]:border-l last:border-r border-border',\n    },\n  };\n\n  return typeClasses[props.styleType || 'plain'] || { content: '' };\n});\n\nconst tabsView = computed(() => {\n  return props.tabs.map((tab) => {\n    const { fullPath, meta, name, path, key } = tab || {};\n    const { affixTab, icon, newTabTitle, tabClosable, title } = meta || {};\n    return {\n      affixTab: !!affixTab,\n      closable: Reflect.has(meta, 'tabClosable') ? !!tabClosable : true,\n      fullPath,\n      icon: icon as string,\n      key,\n      meta,\n      name,\n      path,\n      title: (newTabTitle || title || name) as string,\n    } as TabConfig;\n  });\n});\n\nfunction onMouseDown(e: MouseEvent, tab: TabConfig) {\n  if (\n    e.button === 1 &&\n    tab.closable &&\n    !tab.affixTab &&\n    tabsView.value.length > 1 &&\n    props.middleClickToClose\n  ) {\n    e.preventDefault();\n    e.stopPropagation();\n    emit('close', tab.key);\n  }\n}\n</script>\n\n<template>\n  <div\n    :class=\"contentClass\"\n    class=\"relative !flex h-full w-max items-center overflow-hidden pr-6\"\n  >\n    <TransitionGroup name=\"slide-left\">\n      <div\n        v-for=\"(tab, i) in tabsView\"\n        :key=\"tab.key\"\n        :class=\"[\n          {\n            'is-active dark:bg-accent bg-primary/15': tab.key === active,\n            draggable: !tab.affixTab,\n            'affix-tab': tab.affixTab,\n          },\n          typeWithClass.content,\n        ]\"\n        :data-index=\"i\"\n        class=\"tab-item [&:not(.is-active)]:hover:bg-accent translate-all group relative flex cursor-pointer select-none\"\n        data-tab-item=\"true\"\n        @click=\"active = tab.key\"\n        @mousedown=\"onMouseDown($event, tab)\"\n      >\n        <VbenContextMenu\n          :handler-data=\"tab\"\n          :menus=\"contextMenus\"\n          :modal=\"false\"\n          item-class=\"pr-6\"\n        >\n          <div class=\"relative flex size-full items-center\">\n            <!-- extra -->\n            <div\n              class=\"absolute right-1.5 top-1/2 z-[3] translate-y-[-50%] overflow-hidden\"\n            >\n              <!-- close-icon -->\n              <X\n                v-show=\"!tab.affixTab && tabsView.length > 1 && tab.closable\"\n                class=\"hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground dark:group-[.is-active]:text-accent-foreground group-[.is-active]:text-primary size-3 cursor-pointer rounded-full transition-all\"\n                @click.stop=\"() => emit('close', tab.key)\"\n              />\n              <Pin\n                v-show=\"tab.affixTab && tabsView.length > 1 && tab.closable\"\n                class=\"hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground mt-[1px] size-3.5 cursor-pointer rounded-full transition-all\"\n                @click.stop=\"() => emit('unpin', tab)\"\n              />\n            </div>\n\n            <!-- tab-item-main -->\n            <div\n              class=\"text-accent-foreground group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground mx-3 mr-4 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pr-3 transition-all duration-300\"\n            >\n              <VbenIcon\n                v-if=\"showIcon\"\n                :icon=\"tab.icon\"\n                class=\"mr-2 flex size-4 items-center overflow-hidden\"\n                fallback\n              />\n\n              <span class=\"flex-1 overflow-hidden whitespace-nowrap text-sm\">\n                {{ tab.title }}\n              </span>\n            </div>\n          </div>\n        </VbenContextMenu>\n      </div>\n    </TransitionGroup>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TabDefinition } from '@vben-core/typings';\n\nimport type { TabConfig, TabsProps } from '../../types';\n\nimport { computed, ref } from 'vue';\n\nimport { Pin, X } from '@vben-core/icons';\nimport { VbenContextMenu, VbenIcon } from '@vben-core/shadcn-ui';\n\ninterface Props extends TabsProps {}\n\ndefineOptions({\n  name: 'VbenTabsChrome',\n  inheritAttrs: false,\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  contentClass: 'vben-tabs-content',\n  contextMenus: () => [],\n  gap: 7,\n  tabs: () => [],\n});\n\nconst emit = defineEmits<{\n  close: [string];\n  unpin: [TabDefinition];\n}>();\nconst active = defineModel<string>('active');\n\nconst contentRef = ref();\nconst tabRef = ref();\n\nconst style = computed(() => {\n  const { gap } = props;\n  return {\n    '--gap': `${gap}px`,\n  };\n});\n\nconst tabsView = computed(() => {\n  return props.tabs.map((tab) => {\n    const { fullPath, meta, name, path, key } = tab || {};\n    const { affixTab, icon, newTabTitle, tabClosable, title } = meta || {};\n    return {\n      affixTab: !!affixTab,\n      closable: Reflect.has(meta, 'tabClosable') ? !!tabClosable : true,\n      fullPath,\n      icon: icon as string,\n      key,\n      meta,\n      name,\n      path,\n      title: (newTabTitle || title || name) as string,\n    } as TabConfig;\n  });\n});\n\nfunction onMouseDown(e: MouseEvent, tab: TabConfig) {\n  if (\n    e.button === 1 &&\n    tab.closable &&\n    !tab.affixTab &&\n    tabsView.value.length > 1 &&\n    props.middleClickToClose\n  ) {\n    e.preventDefault();\n    e.stopPropagation();\n    emit('close', tab.key);\n  }\n}\n</script>\n\n<template>\n  <div\n    ref=\"contentRef\"\n    :class=\"contentClass\"\n    :style=\"style\"\n    class=\"tabs-chrome !flex h-full w-max overflow-y-hidden pr-6\"\n  >\n    <TransitionGroup name=\"slide-left\">\n      <div\n        v-for=\"(tab, i) in tabsView\"\n        :key=\"tab.key\"\n        ref=\"tabRef\"\n        :class=\"[\n          {\n            'is-active': tab.key === active,\n            draggable: !tab.affixTab,\n            'affix-tab': tab.affixTab,\n          },\n        ]\"\n        :data-active-tab=\"active\"\n        :data-index=\"i\"\n        class=\"tabs-chrome__item draggable translate-all group relative -mr-3 flex h-full select-none items-center\"\n        data-tab-item=\"true\"\n        @click=\"active = tab.key\"\n        @mousedown=\"onMouseDown($event, tab)\"\n      >\n        <VbenContextMenu\n          :handler-data=\"tab\"\n          :menus=\"contextMenus\"\n          :modal=\"false\"\n          item-class=\"pr-6\"\n        >\n          <div class=\"relative size-full px-1\">\n            <!-- divider -->\n            <div\n              v-if=\"i !== 0 && tab.key !== active\"\n              class=\"tabs-chrome__divider bg-border absolute left-[var(--gap)] top-1/2 z-0 h-4 w-[1px] translate-y-[-50%] transition-all\"\n            ></div>\n            <!-- background -->\n            <div\n              class=\"tabs-chrome__background absolute z-[-1] size-full px-[calc(var(--gap)-1px)] py-0 transition-opacity duration-150\"\n            >\n              <div\n                class=\"tabs-chrome__background-content group-[.is-active]:bg-primary/15 dark:group-[.is-active]:bg-accent h-full rounded-tl-[var(--gap)] rounded-tr-[var(--gap)] duration-150\"\n              ></div>\n              <svg\n                class=\"tabs-chrome__background-before group-[.is-active]:fill-primary/15 dark:group-[.is-active]:fill-accent absolute bottom-0 left-[-1px] fill-transparent transition-all duration-150\"\n                height=\"7\"\n                width=\"7\"\n              >\n                <path d=\"M 0 7 A 7 7 0 0 0 7 0 L 7 7 Z\" />\n              </svg>\n              <svg\n                class=\"tabs-chrome__background-after group-[.is-active]:fill-primary/15 dark:group-[.is-active]:fill-accent absolute bottom-0 right-[-1px] fill-transparent transition-all duration-150\"\n                height=\"7\"\n                width=\"7\"\n              >\n                <path d=\"M 0 0 A 7 7 0 0 0 7 7 L 0 7 Z\" />\n              </svg>\n            </div>\n\n            <!-- extra -->\n            <div\n              class=\"tabs-chrome__extra absolute right-[var(--gap)] top-1/2 z-[3] size-4 translate-y-[-50%]\"\n            >\n              <!-- close-icon -->\n              <X\n                v-show=\"!tab.affixTab && tabsView.length > 1 && tab.closable\"\n                class=\"hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground text-accent-foreground/80 group-[.is-active]:text-accent-foreground mt-[2px] size-3 cursor-pointer rounded-full transition-all\"\n                @click.stop=\"() => emit('close', tab.key)\"\n              />\n              <Pin\n                v-show=\"tab.affixTab && tabsView.length > 1 && tab.closable\"\n                class=\"hover:text-accent-foreground text-accent-foreground/80 group-[.is-active]:text-accent-foreground mt-[1px] size-3.5 cursor-pointer rounded-full transition-all\"\n                @click.stop=\"() => emit('unpin', tab)\"\n              />\n            </div>\n\n            <!-- tab-item-main -->\n            <div\n              class=\"tabs-chrome__item-main group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground text-accent-foreground z-[2] mx-[calc(var(--gap)*2)] my-0 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pl-2 pr-4 duration-150\"\n            >\n              <VbenIcon\n                v-if=\"showIcon\"\n                :icon=\"tab.icon\"\n                class=\"mr-1 flex size-4 items-center overflow-hidden\"\n              />\n\n              <span class=\"flex-1 overflow-hidden whitespace-nowrap text-sm\">\n                {{ tab.title }}\n              </span>\n            </div>\n          </div>\n        </VbenContextMenu>\n      </div>\n    </TransitionGroup>\n  </div>\n</template>\n\n<style scoped>\n.tabs-chrome {\n  &__item:not(.dragging) {\n    @apply cursor-pointer;\n\n    &:hover:not(.is-active) {\n      & + .tabs-chrome__item {\n        .tabs-chrome__divider {\n          @apply opacity-0;\n        }\n      }\n\n      .tabs-chrome__divider {\n        @apply opacity-0;\n      }\n\n      .tabs-chrome__background {\n        @apply pb-[2px];\n\n        &-content {\n          @apply bg-accent mx-[2px] rounded-md;\n        }\n      }\n    }\n\n    &.is-active {\n      @apply z-[2];\n\n      & + .tabs-chrome__item {\n        .tabs-chrome__divider {\n          @apply opacity-0 !important;\n        }\n      }\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts",
    "content": "export { default as TabsToolMore } from './tool-more.vue';\nexport { default as TabsToolScreen } from './tool-screen.vue';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DropdownMenuProps } from '@vben-core/shadcn-ui';\n\nimport { ChevronDown } from '@vben-core/icons';\nimport { VbenDropdownMenu } from '@vben-core/shadcn-ui';\n\ndefineProps<DropdownMenuProps>();\n</script>\n\n<template>\n  <VbenDropdownMenu :menus=\"menus\" :modal=\"false\">\n    <div\n      class=\"flex-center hover:bg-muted hover:text-foreground text-muted-foreground border-border h-full cursor-pointer border-l px-2 text-lg font-semibold\"\n    >\n      <ChevronDown class=\"size-4\" />\n    </div>\n  </VbenDropdownMenu>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fullscreen, Minimize2 } from '@vben-core/icons';\n\nconst screen = defineModel<boolean>('screen');\n\nfunction toggleScreen() {\n  screen.value = !screen.value;\n}\n</script>\n\n<template>\n  <div\n    class=\"flex-center hover:bg-muted hover:text-foreground text-muted-foreground border-border h-full cursor-pointer border-l px-2 text-lg font-semibold\"\n    @click=\"toggleScreen\"\n  >\n    <Minimize2 v-if=\"screen\" class=\"size-4\" />\n    <Fullscreen v-else class=\"size-4\" />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/index.ts",
    "content": "export * from './components/widgets';\nexport { default as TabsView } from './tabs-view.vue';\nexport type { IContextMenuItem } from '@vben-core/shadcn-ui';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TabsEmits, TabsProps } from './types';\n\nimport { useForwardPropsEmits } from '@vben-core/composables';\nimport { ChevronLeft, ChevronRight } from '@vben-core/icons';\nimport { VbenScrollbar } from '@vben-core/shadcn-ui';\n\nimport { Tabs, TabsChrome } from './components';\nimport { useTabsDrag } from './use-tabs-drag';\nimport { useTabsViewScroll } from './use-tabs-view-scroll';\n\ninterface Props extends TabsProps {}\n\ndefineOptions({\n  name: 'TabsView',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  contentClass: 'vben-tabs-content',\n  draggable: true,\n  styleType: 'chrome',\n  wheelable: true,\n});\n\nconst emit = defineEmits<TabsEmits>();\n\nconst forward = useForwardPropsEmits(props, emit);\n\nconst {\n  handleScrollAt,\n  handleWheel,\n  scrollbarRef,\n  scrollDirection,\n  scrollIsAtLeft,\n  scrollIsAtRight,\n  showScrollButton,\n} = useTabsViewScroll(props);\n\nfunction onWheel(e: WheelEvent) {\n  if (props.wheelable) {\n    handleWheel(e);\n    e.stopPropagation();\n    e.preventDefault();\n  }\n}\n\nuseTabsDrag(props, emit);\n</script>\n\n<template>\n  <div class=\"flex h-full flex-1 overflow-hidden\">\n    <!-- 左侧滚动按钮 -->\n    <span\n      v-show=\"showScrollButton\"\n      :class=\"{\n        'hover:bg-muted text-muted-foreground cursor-pointer': !scrollIsAtLeft,\n        'pointer-events-none opacity-30': scrollIsAtLeft,\n      }\"\n      class=\"border-r px-2\"\n      @click=\"scrollDirection('left')\"\n    >\n      <ChevronLeft class=\"size-4 h-full\" />\n    </span>\n\n    <div\n      :class=\"{\n        'pt-[3px]': styleType === 'chrome',\n      }\"\n      class=\"size-full flex-1 overflow-hidden\"\n    >\n      <VbenScrollbar\n        ref=\"scrollbarRef\"\n        :shadow-bottom=\"false\"\n        :shadow-top=\"false\"\n        class=\"h-full\"\n        horizontal\n        scroll-bar-class=\"z-10 hidden \"\n        shadow\n        shadow-left\n        shadow-right\n        @scroll-at=\"handleScrollAt\"\n        @wheel=\"onWheel\"\n      >\n        <TabsChrome\n          v-if=\"styleType === 'chrome'\"\n          v-bind=\"{ ...forward, ...$attrs, ...$props }\"\n        />\n\n        <Tabs v-else v-bind=\"{ ...forward, ...$attrs, ...$props }\" />\n      </VbenScrollbar>\n    </div>\n\n    <!-- 右侧滚动按钮 -->\n    <span\n      v-show=\"showScrollButton\"\n      :class=\"{\n        'hover:bg-muted text-muted-foreground cursor-pointer': !scrollIsAtRight,\n        'pointer-events-none opacity-30': scrollIsAtRight,\n      }\"\n      class=\"hover:bg-muted text-muted-foreground cursor-pointer border-l px-2\"\n      @click=\"scrollDirection('right')\"\n    >\n      <ChevronRight class=\"size-4 h-full\" />\n    </span>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/types.ts",
    "content": "import type { IContextMenuItem } from '@vben-core/shadcn-ui';\nimport type { TabDefinition, TabsStyleType } from '@vben-core/typings';\n\nexport type TabsEmits = {\n  close: [string];\n  sortTabs: [number, number];\n  unpin: [TabDefinition];\n};\n\nexport interface TabsProps {\n  active?: string;\n  /**\n   * @zh_CN content class\n   * @default tabs-chrome\n   */\n  contentClass?: string;\n  /**\n   * @zh_CN 右键菜单\n   */\n  contextMenus?: (data: any) => IContextMenuItem[];\n  /**\n   * @zh_CN 是否可以拖拽\n   */\n  draggable?: boolean;\n  /**\n   * @zh_CN 间隙\n   * @default 7\n   * 仅限 tabs-chrome\n   */\n  gap?: number;\n  /**\n   * @zh_CN tab 最大宽度\n   * 仅限 tabs-chrome\n   */\n  maxWidth?: number;\n  /**\n   * @zh_CN 点击中键时关闭Tab\n   */\n  middleClickToClose?: boolean;\n\n  /**\n   * @zh_CN tab最小宽度\n   * 仅限 tabs-chrome\n   */\n  minWidth?: number;\n\n  /**\n   * @zh_CN 是否显示图标\n   */\n  showIcon?: boolean;\n  /**\n   * @zh_CN 标签页风格\n   */\n  styleType?: TabsStyleType;\n\n  /**\n   * @zh_CN 选项卡数据\n   */\n  tabs?: TabDefinition[];\n\n  /**\n   * @zh_CN 是否响应滚轮事件\n   */\n  wheelable?: boolean;\n}\n\nexport interface TabConfig extends TabDefinition {\n  affixTab: boolean;\n  closable: boolean;\n  icon: string;\n  key: string;\n  title: string;\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts",
    "content": "import type { Sortable } from '@vben-core/composables';\nimport type { EmitType } from '@vben-core/typings';\n\nimport type { TabsProps } from './types';\n\nimport { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport { useIsMobile, useSortable } from '@vben-core/composables';\n\n// 可能会找到拖拽的子元素，这里需要确保拖拽的dom时tab元素\nfunction findParentElement(element: HTMLElement) {\n  const parentCls = 'group';\n  return element.classList.contains(parentCls)\n    ? element\n    : element.closest(`.${parentCls}`);\n}\n\nexport function useTabsDrag(props: TabsProps, emit: EmitType) {\n  const sortableInstance = ref<null | Sortable>(null);\n\n  async function initTabsSortable() {\n    await nextTick();\n\n    const el = document.querySelectorAll(\n      `.${props.contentClass}`,\n    )?.[0] as HTMLElement;\n\n    if (!el) {\n      console.warn('Element not found for sortable initialization');\n      return;\n    }\n\n    const resetElState = async () => {\n      el.style.cursor = 'default';\n      // el.classList.remove('dragging');\n      el.querySelector('.draggable')?.classList.remove('dragging');\n    };\n\n    const { initializeSortable } = useSortable(el, {\n      filter: (_evt, target: HTMLElement) => {\n        const parent = findParentElement(target);\n        const draggable = parent?.classList.contains('draggable');\n        return !draggable || !props.draggable;\n      },\n      onEnd(evt) {\n        const { newIndex, oldIndex } = evt;\n        // const fromElement = evt.item;\n        const { srcElement } = (evt as any).originalEvent;\n\n        if (!srcElement) {\n          resetElState();\n          return;\n        }\n\n        const srcParent = findParentElement(srcElement);\n\n        if (!srcParent) {\n          resetElState();\n          return;\n        }\n\n        if (!srcParent.classList.contains('draggable')) {\n          resetElState();\n\n          return;\n        }\n\n        if (\n          oldIndex !== undefined &&\n          newIndex !== undefined &&\n          !Number.isNaN(oldIndex) &&\n          !Number.isNaN(newIndex) &&\n          oldIndex !== newIndex\n        ) {\n          emit('sortTabs', oldIndex, newIndex);\n        }\n        resetElState();\n      },\n      onMove(evt) {\n        const parent = findParentElement(evt.related);\n        if (parent?.classList.contains('draggable') && props.draggable) {\n          const isCurrentAffix = evt.dragged.classList.contains('affix-tab');\n          const isRelatedAffix = evt.related.classList.contains('affix-tab');\n          // 不允许在固定的tab和非固定的tab之间互相拖拽\n          return isCurrentAffix === isRelatedAffix;\n        } else {\n          return false;\n        }\n      },\n      onStart: () => {\n        el.style.cursor = 'grabbing';\n        el.querySelector('.draggable')?.classList.add('dragging');\n        // el.classList.add('dragging');\n      },\n    });\n\n    sortableInstance.value = await initializeSortable();\n  }\n\n  async function init() {\n    const { isMobile } = useIsMobile();\n\n    // 移动端下tab不需要拖拽\n    if (isMobile.value) {\n      return;\n    }\n    await nextTick();\n    initTabsSortable();\n  }\n\n  onMounted(init);\n\n  watch(\n    () => props.styleType,\n    () => {\n      sortableInstance.value?.destroy();\n      init();\n    },\n  );\n\n  onUnmounted(() => {\n    sortableInstance.value?.destroy();\n  });\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts",
    "content": "import type { TabsProps } from './types';\n\nimport { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport { VbenScrollbar } from '@vben-core/shadcn-ui';\n\nimport { useDebounceFn } from '@vueuse/core';\n\ntype DomElement = Element | null | undefined;\n\nexport function useTabsViewScroll(props: TabsProps) {\n  let resizeObserver: null | ResizeObserver = null;\n  let mutationObserver: MutationObserver | null = null;\n  let tabItemCount = 0;\n  const scrollbarRef = ref<InstanceType<typeof VbenScrollbar> | null>(null);\n  const scrollViewportEl = ref<DomElement>(null);\n  const showScrollButton = ref(false);\n  const scrollIsAtLeft = ref(true);\n  const scrollIsAtRight = ref(false);\n\n  function getScrollClientWidth() {\n    const scrollbarEl = scrollbarRef.value?.$el;\n    if (!scrollbarEl || !scrollViewportEl.value) return {};\n\n    const scrollbarWidth = scrollbarEl.clientWidth;\n    const scrollViewWidth = scrollViewportEl.value.clientWidth;\n\n    return {\n      scrollbarWidth,\n      scrollViewWidth,\n    };\n  }\n\n  function scrollDirection(\n    direction: 'left' | 'right',\n    distance: number = 150,\n  ) {\n    const { scrollbarWidth, scrollViewWidth } = getScrollClientWidth();\n\n    if (!scrollbarWidth || !scrollViewWidth) return;\n\n    if (scrollbarWidth > scrollViewWidth) return;\n\n    scrollViewportEl.value?.scrollBy({\n      behavior: 'smooth',\n      left:\n        direction === 'left'\n          ? -(scrollbarWidth - distance)\n          : +(scrollbarWidth - distance),\n    });\n  }\n\n  async function initScrollbar() {\n    await nextTick();\n\n    const scrollbarEl = scrollbarRef.value?.$el;\n    if (!scrollbarEl) {\n      return;\n    }\n\n    const viewportEl = scrollbarEl?.querySelector(\n      'div[data-radix-scroll-area-viewport]',\n    );\n\n    scrollViewportEl.value = viewportEl;\n    calcShowScrollbarButton();\n\n    await nextTick();\n    scrollToActiveIntoView();\n\n    // 监听大小变化\n    resizeObserver?.disconnect();\n    resizeObserver = new ResizeObserver(\n      useDebounceFn((_entries: ResizeObserverEntry[]) => {\n        calcShowScrollbarButton();\n        scrollToActiveIntoView();\n      }, 100),\n    );\n    resizeObserver.observe(viewportEl);\n\n    tabItemCount = props.tabs?.length || 0;\n    mutationObserver?.disconnect();\n    // 使用 MutationObserver 仅监听子节点数量变化\n    mutationObserver = new MutationObserver(() => {\n      const count = viewportEl.querySelectorAll(\n        `div[data-tab-item=\"true\"]`,\n      ).length;\n\n      if (count > tabItemCount) {\n        scrollToActiveIntoView();\n      }\n\n      if (count !== tabItemCount) {\n        calcShowScrollbarButton();\n        tabItemCount = count;\n      }\n    });\n\n    // 配置为仅监听子节点的添加和移除\n    mutationObserver.observe(viewportEl, {\n      attributes: false,\n      childList: true,\n      subtree: true,\n    });\n  }\n\n  async function scrollToActiveIntoView() {\n    if (!scrollViewportEl.value) {\n      return;\n    }\n    await nextTick();\n    const viewportEl = scrollViewportEl.value;\n    const { scrollbarWidth } = getScrollClientWidth();\n    const { scrollWidth } = viewportEl;\n\n    if (scrollbarWidth >= scrollWidth) {\n      return;\n    }\n\n    requestAnimationFrame(() => {\n      const activeItem = viewportEl?.querySelector('.is-active');\n      activeItem?.scrollIntoView({ behavior: 'smooth', inline: 'start' });\n    });\n  }\n\n  /**\n   * 计算tabs 宽度，用于判断是否显示左右滚动按钮\n   */\n  async function calcShowScrollbarButton() {\n    if (!scrollViewportEl.value) {\n      return;\n    }\n\n    const { scrollbarWidth } = getScrollClientWidth();\n\n    showScrollButton.value =\n      scrollViewportEl.value.scrollWidth > scrollbarWidth;\n  }\n\n  const handleScrollAt = useDebounceFn(({ left, right }) => {\n    scrollIsAtLeft.value = left;\n    scrollIsAtRight.value = right;\n  }, 100);\n\n  function handleWheel({ deltaY }: WheelEvent) {\n    scrollViewportEl.value?.scrollBy({\n      // behavior: 'smooth',\n      left: deltaY * 3,\n    });\n  }\n\n  watch(\n    () => props.active,\n    async () => {\n      // 200为了等待 tab 切换动画完成\n      // setTimeout(() => {\n      scrollToActiveIntoView();\n      // }, 300);\n    },\n    {\n      flush: 'post',\n    },\n  );\n\n  // watch(\n  //   () => props.tabs?.length,\n  //   async () => {\n  //     await nextTick();\n  //     calcShowScrollbarButton();\n  //   },\n  //   {\n  //     flush: 'post',\n  //   },\n  // );\n\n  watch(\n    () => props.styleType,\n    () => {\n      initScrollbar();\n    },\n  );\n\n  onMounted(initScrollbar);\n\n  onUnmounted(() => {\n    resizeObserver?.disconnect();\n    mutationObserver?.disconnect();\n    resizeObserver = null;\n    mutationObserver = null;\n  });\n\n  return {\n    handleScrollAt,\n    handleWheel,\n    initScrollbar,\n    scrollbarRef,\n    scrollDirection,\n    scrollIsAtLeft,\n    scrollIsAtRight,\n    showScrollButton,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/packages/@core/ui-kit/tabs-ui/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/constants/README.md",
    "content": "# @vben/constants\n\n用于多个 `app` 公用的常量，继承了 `@vben-core/shared/constants` 的所有能力。业务上有通用常量可以放在这里。\n\n## 用法\n\n### 添加依赖\n\n```bash\n# 进入目标应用目录，例如 apps/xxxx-app\n# cd apps/xxxx-app\npnpm add @vben/constants\n```\n\n### 使用\n\n```ts\nimport { LOGIN_PATH } from '@vben/constants';\n```\n"
  },
  {
    "path": "hiauth-front/packages/constants/package.json",
    "content": "{\n  \"name\": \"@vben/constants\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/constants\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/shared\": \"workspace:*\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/constants/src/core.ts",
    "content": "/**\n * @zh_CN 登录页面 url 地址\n */\nexport const LOGIN_PATH = '/auth/login';\n\nexport interface LanguageOption {\n  label: string;\n  value: 'en-US' | 'zh-CN';\n}\n\n/**\n * Supported languages\n */\nexport const SUPPORT_LANGUAGES: LanguageOption[] = [\n  {\n    label: '简体中文',\n    value: 'zh-CN',\n  },\n  {\n    label: 'English',\n    value: 'en-US',\n  },\n];\n"
  },
  {
    "path": "hiauth-front/packages/constants/src/index.ts",
    "content": "export * from './core';\nexport * from '@vben-core/shared/constants';\n"
  },
  {
    "path": "hiauth-front/packages/constants/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/README.md",
    "content": "## Effects 目录\n\n`effects` 目录专门用于存放与轻微耦合相关的代码和逻辑。如果你的包具有以下特点，建议将其放置在 `effects` 目录下：\n\n- **状态管理**：使用状态管理框架 `pinia`，并包含处理副作用（如异步操作、API 调用）的部分。\n- **用户偏好设置**：使用 `@vben-core/preferences` 处理用户偏好设置，涉及本地存储或浏览器缓存逻辑（如使用 `localStorage`）。\n- **导航和路由**：处理导航、页面跳转等场景，需要管理路由变化的逻辑。\n- **组件库依赖**：包含与特定组件库紧密耦合或依赖大型仓库的部分。\n\n通过将相关代码归类到 `effects` 目录，可以使项目结构更加清晰，便于维护和扩展。\n"
  },
  {
    "path": "hiauth-front/packages/effects/access/package.json",
    "content": "{\n  \"name\": \"@vben/access\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/effects/permissions\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/stores\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"vue\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/access/src/access-control.vue",
    "content": "<!--\n Access control component for fine-grained access control.\n TODO: 可以扩展更完善的功能：\n 1. 支持多个权限码，只要有一个权限码满足即可 或者 多个权限码全部满足\n 2. 支持多个角色，只要有一个角色满足即可 或者 多个角色全部满足\n 3. 支持自定义权限码和角色的判断逻辑\n-->\n<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { useAccess } from './use-access';\n\ninterface Props {\n  /**\n   * Specified codes is visible\n   * @default []\n   */\n  codes?: string[];\n\n  /**\n   * 通过什么方式来控制组件，如果是 role，则传入角色，如果是 code，则传入权限码\n   * @default 'role'\n   */\n  type?: 'code' | 'role';\n}\n\ndefineOptions({\n  name: 'AccessControl',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  codes: () => [],\n  type: 'role',\n});\n\nconst { hasAccessByCodes, hasAccessByRoles } = useAccess();\n\nconst hasAuth = computed(() => {\n  const { codes, type } = props;\n  return type === 'role' ? hasAccessByRoles(codes) : hasAccessByCodes(codes);\n});\n</script>\n\n<template>\n  <slot v-if=\"!codes\"></slot>\n  <slot v-else-if=\"hasAuth\"></slot>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/access/src/accessible.ts",
    "content": "import type { Component, DefineComponent } from 'vue';\n\nimport type {\n  AccessModeType,\n  GenerateMenuAndRoutesOptions,\n  RouteRecordRaw,\n} from '@vben/types';\n\nimport { defineComponent, h } from 'vue';\n\nimport {\n  cloneDeep,\n  generateMenus,\n  generateRoutesByBackend,\n  generateRoutesByFrontend,\n  isFunction,\n  isString,\n  mapTree,\n} from '@vben/utils';\n\nasync function generateAccessible(\n  mode: AccessModeType,\n  options: GenerateMenuAndRoutesOptions,\n) {\n  const { router } = options;\n\n  options.routes = cloneDeep(options.routes);\n  // 生成路由\n  const accessibleRoutes = await generateRoutes(mode, options);\n\n  const root = router.getRoutes().find((item) => item.path === '/');\n\n  // 获取已有的路由名称列表\n  const names = root?.children?.map((item) => item.name) ?? [];\n\n  // 动态添加到router实例内\n  accessibleRoutes.forEach((route) => {\n    if (root && !route.meta?.noBasicLayout) {\n      // 为了兼容之前的版本用法，如果包含子路由，则将component移除，以免出现多层BasicLayout\n      // 如果你的项目已经跟进了本次修改，移除了所有自定义菜单首级的BasicLayout，可以将这段if代码删除\n      if (route.children && route.children.length > 0) {\n        delete route.component;\n      }\n      // 根据router name判断，如果路由已经存在，则不再添加\n      if (names?.includes(route.name)) {\n        // 找到已存在的路由索引并更新，不更新会造成切换用户时，一级目录未更新，homePath 在二级目录导致的404问题\n        const index = root.children?.findIndex(\n          (item) => item.name === route.name,\n        );\n        if (index !== undefined && index !== -1 && root.children) {\n          root.children[index] = route;\n        }\n      } else {\n        root.children?.push(route);\n      }\n    } else {\n      router.addRoute(route);\n    }\n  });\n\n  if (root) {\n    if (root.name) {\n      router.removeRoute(root.name);\n    }\n    router.addRoute(root);\n  }\n\n  // 生成菜单\n  const accessibleMenus = generateMenus(accessibleRoutes, options.router);\n\n  return { accessibleMenus, accessibleRoutes };\n}\n\n/**\n * Generate routes\n * @param mode\n * @param options\n */\nasync function generateRoutes(\n  mode: AccessModeType,\n  options: GenerateMenuAndRoutesOptions,\n) {\n  const { forbiddenComponent, roles, routes } = options;\n\n  let resultRoutes: RouteRecordRaw[] = routes;\n  switch (mode) {\n    case 'backend': {\n      resultRoutes = await generateRoutesByBackend(options);\n      break;\n    }\n    case 'frontend': {\n      resultRoutes = await generateRoutesByFrontend(\n        routes,\n        roles || [],\n        forbiddenComponent,\n      );\n      break;\n    }\n    case 'mixed': {\n      const [frontend_resultRoutes, backend_resultRoutes] = await Promise.all([\n        generateRoutesByFrontend(routes, roles || [], forbiddenComponent),\n        generateRoutesByBackend(options),\n      ]);\n\n      resultRoutes = [...frontend_resultRoutes, ...backend_resultRoutes];\n      break;\n    }\n  }\n\n  /**\n   * 调整路由树，做以下处理：\n   * 1. 对未添加redirect的路由添加redirect\n   * 2. 将懒加载的组件名称修改为当前路由的名称（如果启用了keep-alive的话）\n   */\n  resultRoutes = mapTree(resultRoutes, (route) => {\n    // 重新包装component，使用与路由名称相同的name以支持keep-alive的条件缓存。\n    if (\n      route.meta?.keepAlive &&\n      isFunction(route.component) &&\n      route.name &&\n      isString(route.name)\n    ) {\n      const originalComponent = route.component as () => Promise<{\n        default: Component | DefineComponent;\n      }>;\n      route.component = async () => {\n        const component = await originalComponent();\n        if (!component.default) return component;\n        return defineComponent({\n          name: route.name as string,\n          setup(props, { attrs, slots }) {\n            return () => h(component.default, { ...props, ...attrs }, slots);\n          },\n        });\n      };\n    }\n\n    // 如果有redirect或者没有子路由，则直接返回\n    if (route.redirect || !route.children || route.children.length === 0) {\n      return route;\n    }\n    const firstChild = route.children[0];\n\n    // 如果子路由不是以/开头，则直接返回,这种情况需要计算全部父级的path才能得出正确的path，这里不做处理\n    if (!firstChild?.path || !firstChild.path.startsWith('/')) {\n      return route;\n    }\n\n    route.redirect = firstChild.path;\n    return route;\n  });\n\n  return resultRoutes;\n}\n\nexport { generateAccessible };\n"
  },
  {
    "path": "hiauth-front/packages/effects/access/src/directive.ts",
    "content": "/**\n * Global authority directive\n * Used for fine-grained control of component permissions\n * @Example v-access:role=\"[ROLE_NAME]\" or v-access:role=\"ROLE_NAME\"\n * @Example v-access:code=\"[ROLE_CODE]\" or v-access:code=\"ROLE_CODE\"\n */\nimport type { App, Directive, DirectiveBinding } from 'vue';\n\nimport { useAccess } from './use-access';\n\nfunction isAccessible(\n  el: Element,\n  binding: DirectiveBinding<string | string[]>,\n) {\n  const { accessMode, hasAccessByCodes, hasAccessByRoles } = useAccess();\n\n  const value = binding.value;\n\n  if (!value) return;\n  const authMethod =\n    accessMode.value === 'frontend' && binding.arg === 'role'\n      ? hasAccessByRoles\n      : hasAccessByCodes;\n\n  const values = Array.isArray(value) ? value : [value];\n\n  if (!authMethod(values)) {\n    el?.remove();\n  }\n}\n\nconst mounted = (el: Element, binding: DirectiveBinding<string | string[]>) => {\n  isAccessible(el, binding);\n};\n\nconst authDirective: Directive = {\n  mounted,\n};\n\nexport function registerAccessDirective(app: App) {\n  app.directive('access', authDirective);\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/access/src/index.ts",
    "content": "export { default as AccessControl } from './access-control.vue';\nexport * from './accessible';\nexport * from './directive';\nexport * from './use-access';\n"
  },
  {
    "path": "hiauth-front/packages/effects/access/src/use-access.ts",
    "content": "import { computed } from 'vue';\n\nimport { preferences, updatePreferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\n\nfunction useAccess() {\n  const accessStore = useAccessStore();\n  const userStore = useUserStore();\n  const accessMode = computed(() => {\n    return preferences.app.accessMode;\n  });\n\n  /**\n   * 基于角色判断是否有权限\n   * @description: Determine whether there is permission，The role is judged by the user's role\n   * @param roles\n   */\n  function hasAccessByRoles(roles: string[]) {\n    const userRoleSet = new Set(userStore.userRoles);\n    const intersection = roles.filter((item) => userRoleSet.has(item));\n    return intersection.length > 0;\n  }\n\n  /**\n   * 基于权限码判断是否有权限\n   * @description: Determine whether there is permission，The permission code is judged by the user's permission code\n   * @param codes\n   */\n  function hasAccessByCodes(codes: string[]) {\n    const userCodesSet = new Set(accessStore.accessCodes);\n\n    const intersection = codes.filter((item) => userCodesSet.has(item));\n    return intersection.length > 0;\n  }\n\n  async function toggleAccessMode() {\n    updatePreferences({\n      app: {\n        accessMode:\n          preferences.app.accessMode === 'frontend' ? 'backend' : 'frontend',\n      },\n    });\n  }\n\n  return {\n    accessMode,\n    hasAccessByCodes,\n    hasAccessByRoles,\n    toggleAccessMode,\n  };\n}\n\nexport { useAccess };\n"
  },
  {
    "path": "hiauth-front/packages/effects/access/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/package.json",
    "content": "{\n  \"name\": \"@vben/common-ui\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/effects/common-ui\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    },\n    \"./es/tippy\": {\n      \"types\": \"./src/components/tippy/index.ts\",\n      \"default\": \"./src/components/tippy/index.ts\"\n    },\n    \"./es/loading\": {\n      \"types\": \"./src/components/loading/index.ts\",\n      \"default\": \"./src/components/loading/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/form-ui\": \"workspace:*\",\n    \"@vben-core/popup-ui\": \"workspace:*\",\n    \"@vben-core/preferences\": \"workspace:*\",\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben/constants\": \"workspace:*\",\n    \"@vben/hooks\": \"workspace:*\",\n    \"@vben/icons\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"@vueuse/integrations\": \"catalog:\",\n    \"json-bigint\": \"catalog:\",\n    \"qrcode\": \"catalog:\",\n    \"tippy.js\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-json-viewer\": \"catalog:\",\n    \"vue-router\": \"catalog:\",\n    \"vue-tippy\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/qrcode\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/api-component/api-component.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Component } from 'vue';\n\nimport type { AnyPromiseFunction } from '@vben/types';\n\nimport { computed, nextTick, ref, unref, useAttrs, watch } from 'vue';\n\nimport { LoaderCircle } from '@vben/icons';\n\nimport { cloneDeep, get, isEqual, isFunction } from '@vben-core/shared/utils';\n\nimport { objectOmit } from '@vueuse/core';\n\ntype OptionsItem = {\n  [name: string]: any;\n  children?: OptionsItem[];\n  disabled?: boolean;\n  label?: string;\n  value?: string;\n};\n\ninterface Props {\n  /** 组件 */\n  component: Component;\n  /** 是否将value从数字转为string */\n  numberToString?: boolean;\n  /** 获取options数据的函数 */\n  api?: (arg?: any) => Promise<OptionsItem[] | Record<string, any>>;\n  /** 传递给api的参数 */\n  params?: Record<string, any>;\n  /** 从api返回的结果中提取options数组的字段名 */\n  resultField?: string;\n  /** label字段名 */\n  labelField?: string;\n  /** children字段名，需要层级数据的组件可用 */\n  childrenField?: string;\n  /** value字段名 */\n  valueField?: string;\n  /** 组件接收options数据的属性名 */\n  optionsPropName?: string;\n  /** 是否立即调用api */\n  immediate?: boolean;\n  /** 每次`visibleEvent`事件发生时都重新请求数据 */\n  alwaysLoad?: boolean;\n  /** 在api请求之前的回调函数 */\n  beforeFetch?: AnyPromiseFunction<any, any>;\n  /** 在api请求之后的回调函数 */\n  afterFetch?: AnyPromiseFunction<any, any>;\n  /** 直接传入选项数据，也作为api返回空数据时的后备数据 */\n  options?: OptionsItem[];\n  /** 组件的插槽名称，用来显示一个\"加载中\"的图标 */\n  loadingSlot?: string;\n  /** 触发api请求的事件名 */\n  visibleEvent?: string;\n  /** 组件的v-model属性名，默认为modelValue。部分组件可能为value */\n  modelPropName?: string;\n  /**\n   * 自动选择\n   * - `first`：自动选择第一个选项\n   * - `last`：自动选择最后一个选项\n   * - `one`: 当请求的结果只有一个选项时，自动选择该选项\n   * - 函数：自定义选择逻辑，函数的参数为请求的结果数组，返回值为选择的选项\n   * - false：不自动选择(默认)\n   */\n  autoSelect?:\n    | 'first'\n    | 'last'\n    | 'one'\n    | ((item: OptionsItem[]) => OptionsItem)\n    | false;\n}\n\ndefineOptions({ name: 'ApiComponent', inheritAttrs: false });\n\nconst props = withDefaults(defineProps<Props>(), {\n  labelField: 'label',\n  valueField: 'value',\n  childrenField: '',\n  optionsPropName: 'options',\n  resultField: '',\n  visibleEvent: '',\n  numberToString: false,\n  params: () => ({}),\n  immediate: true,\n  alwaysLoad: false,\n  loadingSlot: '',\n  beforeFetch: undefined,\n  afterFetch: undefined,\n  modelPropName: 'modelValue',\n  api: undefined,\n  autoSelect: false,\n  options: () => [],\n});\n\nconst emit = defineEmits<{\n  optionsChange: [OptionsItem[]];\n}>();\n\nconst modelValue = defineModel<any>({ default: undefined });\n\nconst attrs = useAttrs();\nconst innerParams = ref({});\nconst refOptions = ref<OptionsItem[]>([]);\nconst loading = ref(false);\n// 首次是否加载过了\nconst isFirstLoaded = ref(false);\n// 标记是否有待处理的请求\nconst hasPendingRequest = ref(false);\n\nconst getOptions = computed(() => {\n  const { labelField, valueField, childrenField, numberToString } = props;\n\n  const refOptionsData = unref(refOptions);\n\n  function transformData(data: OptionsItem[]): OptionsItem[] {\n    return data.map((item) => {\n      const value = get(item, valueField);\n      return {\n        ...objectOmit(item, [labelField, valueField, childrenField]),\n        label: get(item, labelField),\n        value: numberToString ? `${value}` : value,\n        ...(childrenField && item[childrenField]\n          ? { children: transformData(item[childrenField]) }\n          : {}),\n      };\n    });\n  }\n\n  const data: OptionsItem[] = transformData(refOptionsData);\n\n  return data.length > 0 ? data : props.options;\n});\n\nconst bindProps = computed(() => {\n  return {\n    [props.modelPropName]: unref(modelValue),\n    [props.optionsPropName]: unref(getOptions),\n    [`onUpdate:${props.modelPropName}`]: (val: string) => {\n      modelValue.value = val;\n    },\n    ...objectOmit(attrs, [`onUpdate:${props.modelPropName}`]),\n    ...(props.visibleEvent\n      ? {\n          [props.visibleEvent]: handleFetchForVisible,\n        }\n      : {}),\n  };\n});\n\nasync function fetchApi() {\n  const { api, beforeFetch, afterFetch, resultField } = props;\n\n  if (!api || !isFunction(api)) {\n    return;\n  }\n\n  // 如果正在加载，标记有待处理的请求并返回\n  if (loading.value) {\n    hasPendingRequest.value = true;\n    return;\n  }\n\n  refOptions.value = [];\n  try {\n    loading.value = true;\n    let finalParams = unref(mergedParams);\n    if (beforeFetch && isFunction(beforeFetch)) {\n      finalParams = (await beforeFetch(cloneDeep(finalParams))) || finalParams;\n    }\n    let res = await api(finalParams);\n    if (afterFetch && isFunction(afterFetch)) {\n      res = (await afterFetch(res)) || res;\n    }\n    isFirstLoaded.value = true;\n    if (Array.isArray(res)) {\n      refOptions.value = res;\n      emitChange();\n      return;\n    }\n    if (resultField) {\n      refOptions.value = get(res, resultField) || [];\n    }\n    emitChange();\n  } catch (error) {\n    console.warn(error);\n    // reset status\n    isFirstLoaded.value = false;\n  } finally {\n    loading.value = false;\n    // 如果有待处理的请求，立即触发新的请求\n    if (hasPendingRequest.value) {\n      hasPendingRequest.value = false;\n      // 使用 nextTick 确保状态更新完成后再触发新请求\n      await nextTick();\n      fetchApi();\n    }\n  }\n}\n\nasync function handleFetchForVisible(visible: boolean) {\n  if (visible) {\n    if (props.alwaysLoad) {\n      await fetchApi();\n    } else if (!props.immediate && !unref(isFirstLoaded)) {\n      await fetchApi();\n    }\n  }\n}\n\nconst mergedParams = computed(() => {\n  return {\n    ...props.params,\n    ...unref(innerParams),\n  };\n});\n\nwatch(\n  mergedParams,\n  (value, oldValue) => {\n    if (isEqual(value, oldValue)) {\n      return;\n    }\n    fetchApi();\n  },\n  { deep: true, immediate: props.immediate },\n);\n\nfunction emitChange() {\n  if (\n    modelValue.value === undefined &&\n    props.autoSelect &&\n    unref(getOptions).length > 0\n  ) {\n    let firstOption;\n    if (isFunction(props.autoSelect)) {\n      firstOption = props.autoSelect(unref(getOptions));\n    } else {\n      switch (props.autoSelect) {\n        case 'first': {\n          firstOption = unref(getOptions)[0];\n          break;\n        }\n        case 'last': {\n          firstOption = unref(getOptions)[unref(getOptions).length - 1];\n          break;\n        }\n        case 'one': {\n          if (unref(getOptions).length === 1) {\n            firstOption = unref(getOptions)[0];\n          }\n          break;\n        }\n      }\n    }\n\n    if (firstOption) modelValue.value = firstOption.value;\n  }\n  emit('optionsChange', unref(getOptions));\n}\nconst componentRef = ref();\ndefineExpose({\n  /** 获取options数据 */\n  getOptions: () => unref(getOptions),\n  /** 获取当前值 */\n  getValue: () => unref(modelValue),\n  /** 获取被包装的组件实例 */\n  getComponentRef: <T = any,>() => componentRef.value as T,\n  /** 更新Api参数 */\n  updateParam(newParams: Record<string, any>) {\n    innerParams.value = newParams;\n  },\n});\n</script>\n<template>\n  <component\n    :is=\"component\"\n    v-bind=\"bindProps\"\n    :placeholder=\"$attrs.placeholder\"\n    ref=\"componentRef\"\n  >\n    <template v-for=\"item in Object.keys($slots)\" #[item]=\"data\">\n      <slot :name=\"item\" v-bind=\"data || {}\"></slot>\n    </template>\n    <template v-if=\"loadingSlot && loading\" #[loadingSlot]>\n      <LoaderCircle class=\"animate-spin\" />\n    </template>\n  </component>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/api-component/index.ts",
    "content": "export { default as ApiComponent } from './api-component.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts",
    "content": "import type { CaptchaPoint } from '../types';\n\nimport { reactive } from 'vue';\n\nexport function useCaptchaPoints() {\n  const points = reactive<CaptchaPoint[]>([]);\n  function addPoint(point: CaptchaPoint) {\n    points.push(point);\n  }\n\n  function clearPoints() {\n    points.splice(0);\n  }\n  return {\n    addPoint,\n    clearPoints,\n    points,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/index.ts",
    "content": "export { default as PointSelectionCaptcha } from './point-selection-captcha/index.vue';\nexport { default as PointSelectionCaptchaCard } from './point-selection-captcha/index.vue';\n\nexport { default as SliderCaptcha } from './slider-captcha/index.vue';\nexport { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue';\nexport { default as SliderTranslateCaptcha } from './slider-translate-captcha/index.vue';\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CaptchaPoint, PointSelectionCaptchaProps } from '../types';\n\nimport { RotateCw } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport { VbenButton, VbenIconButton } from '@vben-core/shadcn-ui';\n\nimport { useCaptchaPoints } from '../hooks/useCaptchaPoints';\nimport CaptchaCard from './point-selection-captcha-card.vue';\n\nconst props = withDefaults(defineProps<PointSelectionCaptchaProps>(), {\n  height: '220px',\n  hintImage: '',\n  hintText: '',\n  paddingX: '12px',\n  paddingY: '16px',\n  showConfirm: false,\n  title: '',\n  width: '300px',\n});\nconst emit = defineEmits<{\n  click: [CaptchaPoint];\n  confirm: [Array<CaptchaPoint>, clear: () => void];\n  refresh: [];\n}>();\nconst { addPoint, clearPoints, points } = useCaptchaPoints();\n\nif (!props.hintImage && !props.hintText) {\n  console.warn('At least one of hint image or hint text must be provided');\n}\n\nconst POINT_OFFSET = 11;\n\nfunction getElementPosition(element: HTMLElement) {\n  const rect = element.getBoundingClientRect();\n  return {\n    x: rect.left + window.scrollX,\n    y: rect.top + window.scrollY,\n  };\n}\n\nfunction handleClick(e: MouseEvent) {\n  try {\n    const dom = e.currentTarget as HTMLElement;\n    if (!dom) throw new Error('Element not found');\n\n    const { x: domX, y: domY } = getElementPosition(dom);\n\n    const mouseX = e.clientX + window.scrollX;\n    const mouseY = e.clientY + window.scrollY;\n\n    if (typeof mouseX !== 'number' || typeof mouseY !== 'number') {\n      throw new TypeError('Mouse coordinates not found');\n    }\n\n    const xPos = mouseX - domX;\n    const yPos = mouseY - domY;\n\n    const rect = dom.getBoundingClientRect();\n\n    // 点击位置边界校验\n    if (xPos < 0 || yPos < 0 || xPos > rect.width || yPos > rect.height) {\n      console.warn('Click position is out of the valid range');\n      return;\n    }\n\n    const x = Math.ceil(xPos);\n    const y = Math.ceil(yPos);\n\n    const point = {\n      i: points.length,\n      t: Date.now(),\n      x,\n      y,\n    };\n\n    addPoint(point);\n\n    emit('click', point);\n    e.stopPropagation();\n    e.preventDefault();\n  } catch (error) {\n    console.error('Error in handleClick:', error);\n  }\n}\n\nfunction clear() {\n  try {\n    clearPoints();\n  } catch (error) {\n    console.error('Error in clear:', error);\n  }\n}\n\nfunction handleRefresh() {\n  try {\n    clear();\n    emit('refresh');\n  } catch (error) {\n    console.error('Error in handleRefresh:', error);\n  }\n}\n\nfunction handleConfirm() {\n  if (!props.showConfirm) return;\n  try {\n    emit('confirm', points, clear);\n  } catch (error) {\n    console.error('Error in handleConfirm:', error);\n  }\n}\n</script>\n<template>\n  <CaptchaCard\n    :captcha-image=\"captchaImage\"\n    :height=\"height\"\n    :padding-x=\"paddingX\"\n    :padding-y=\"paddingY\"\n    :title=\"title\"\n    :width=\"width\"\n    @click=\"handleClick\"\n  >\n    <template #title>\n      <slot name=\"title\">{{ $t('ui.captcha.title') }}</slot>\n    </template>\n\n    <template #extra>\n      <VbenIconButton\n        :aria-label=\"$t('ui.captcha.refreshAriaLabel')\"\n        class=\"ml-1\"\n        @click=\"handleRefresh\"\n      >\n        <RotateCw class=\"size-5\" />\n      </VbenIconButton>\n      <VbenButton\n        v-if=\"showConfirm\"\n        :aria-label=\"$t('ui.captcha.confirmAriaLabel')\"\n        class=\"ml-2\"\n        size=\"sm\"\n        @click=\"handleConfirm\"\n      >\n        {{ $t('ui.captcha.confirm') }}\n      </VbenButton>\n    </template>\n\n    <div\n      v-for=\"(point, index) in points\"\n      :key=\"index\"\n      :aria-label=\"$t('ui.captcha.pointAriaLabel') + (index + 1)\"\n      :style=\"{\n        top: `${point.y - POINT_OFFSET}px`,\n        left: `${point.x - POINT_OFFSET}px`,\n      }\"\n      class=\"bg-primary text-primary-50 border-primary-50 absolute z-20 flex h-5 w-5 cursor-default items-center justify-center rounded-full border-2\"\n      role=\"button\"\n      tabindex=\"0\"\n    >\n      {{ index + 1 }}\n    </div>\n    <template #footer>\n      <img\n        v-if=\"hintImage\"\n        :alt=\"$t('ui.captcha.alt')\"\n        :src=\"hintImage\"\n        class=\"border-border h-10 w-full rounded border\"\n      />\n      <div\n        v-else-if=\"hintText\"\n        class=\"border-border flex-center h-10 w-full rounded border\"\n      >\n        {{ `${$t('ui.captcha.clickInOrder')}` + `【${hintText}】` }}\n      </div>\n    </template>\n  </CaptchaCard>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue",
    "content": "<script setup lang=\"ts\">\nimport type { PointSelectionCaptchaCardProps } from '../types';\n\nimport { computed } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport {\n  Card,\n  CardContent,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from '@vben-core/shadcn-ui';\n\nconst props = withDefaults(defineProps<PointSelectionCaptchaCardProps>(), {\n  height: '220px',\n  paddingX: '12px',\n  paddingY: '16px',\n  title: '',\n  width: '300px',\n});\n\nconst emit = defineEmits<{\n  click: [MouseEvent];\n}>();\n\nconst parseValue = (value: number | string) => {\n  if (typeof value === 'number') {\n    return value;\n  }\n  const parsed = Number.parseFloat(value);\n  return Number.isNaN(parsed) ? 0 : parsed;\n};\n\nconst rootStyles = computed(() => ({\n  padding: `${parseValue(props.paddingY)}px ${parseValue(props.paddingX)}px`,\n  width: `${parseValue(props.width) + parseValue(props.paddingX) * 2}px`,\n}));\n\nconst captchaStyles = computed(() => {\n  return {\n    height: `${parseValue(props.height)}px`,\n    width: `${parseValue(props.width)}px`,\n  };\n});\n\nfunction handleClick(e: MouseEvent) {\n  emit('click', e);\n}\n</script>\n<template>\n  <Card :style=\"rootStyles\" aria-labelledby=\"captcha-title\" role=\"region\">\n    <CardHeader class=\"p-0\">\n      <CardTitle id=\"captcha-title\" class=\"flex items-center justify-between\">\n        <template v-if=\"$slots.title\">\n          <slot name=\"title\">{{ $t('ui.captcha.title') }}</slot>\n        </template>\n        <template v-else>\n          <span>{{ title }}</span>\n        </template>\n        <div class=\"flex items-center justify-end\">\n          <slot name=\"extra\"></slot>\n        </div>\n      </CardTitle>\n    </CardHeader>\n    <CardContent class=\"relative mt-2 flex w-full overflow-hidden rounded p-0\">\n      <img\n        v-show=\"captchaImage\"\n        :alt=\"$t('ui.captcha.alt')\"\n        :src=\"captchaImage\"\n        :style=\"captchaStyles\"\n        class=\"relative z-10\"\n        @click=\"handleClick\"\n      />\n      <div class=\"absolute inset-0\">\n        <slot></slot>\n      </div>\n    </CardContent>\n    <CardFooter class=\"mt-2 flex justify-between p-0\">\n      <slot name=\"footer\"></slot>\n    </CardFooter>\n  </Card>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  CaptchaVerifyPassingData,\n  SliderCaptchaProps,\n  SliderRotateVerifyPassingData,\n} from '../types';\n\nimport { reactive, unref, useTemplateRef, watch, watchEffect } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport { cn } from '@vben-core/shared/utils';\n\nimport { useTimeoutFn } from '@vueuse/core';\n\nimport SliderCaptchaAction from './slider-captcha-action.vue';\nimport SliderCaptchaBar from './slider-captcha-bar.vue';\nimport SliderCaptchaContent from './slider-captcha-content.vue';\n\nconst props = withDefaults(defineProps<SliderCaptchaProps>(), {\n  actionStyle: () => ({}),\n  barStyle: () => ({}),\n  contentStyle: () => ({}),\n  isSlot: false,\n  successText: '',\n  text: '',\n  wrapperStyle: () => ({}),\n});\n\nconst emit = defineEmits<{\n  end: [MouseEvent | TouchEvent];\n  move: [SliderRotateVerifyPassingData];\n  start: [MouseEvent | TouchEvent];\n  success: [CaptchaVerifyPassingData];\n}>();\n\nconst modelValue = defineModel<boolean>({ default: false });\n\nconst state = reactive({\n  endTime: 0,\n  isMoving: false,\n  isPassing: false,\n  moveDistance: 0,\n  startTime: 0,\n  toLeft: false,\n});\n\ndefineExpose({\n  resume,\n});\n\nconst wrapperRef = useTemplateRef<HTMLDivElement>('wrapperRef');\nconst barRef = useTemplateRef<typeof SliderCaptchaBar>('barRef');\nconst contentRef = useTemplateRef<typeof SliderCaptchaContent>('contentRef');\nconst actionRef = useTemplateRef<typeof SliderCaptchaAction>('actionRef');\n\nwatch(\n  () => state.isPassing,\n  (isPassing) => {\n    if (isPassing) {\n      const { endTime, startTime } = state;\n      const time = (endTime - startTime) / 1000;\n      emit('success', { isPassing, time: time.toFixed(1) });\n      modelValue.value = isPassing;\n    }\n  },\n);\n\nwatchEffect(() => {\n  state.isPassing = !!modelValue.value;\n});\n\nfunction getEventPageX(e: MouseEvent | TouchEvent): number {\n  if ('pageX' in e) {\n    return e.pageX;\n  } else if ('touches' in e && e.touches[0]) {\n    return e.touches[0].pageX;\n  }\n  return 0;\n}\n\nfunction handleDragStart(e: MouseEvent | TouchEvent) {\n  if (state.isPassing) {\n    return;\n  }\n  if (!actionRef.value) return;\n  emit('start', e);\n\n  state.moveDistance =\n    getEventPageX(e) -\n    Number.parseInt(\n      actionRef.value.getStyle().left.replace('px', '') || '0',\n      10,\n    );\n  state.startTime = Date.now();\n  state.isMoving = true;\n}\n\nfunction getOffset(actionEl: HTMLDivElement) {\n  const wrapperWidth = wrapperRef.value?.offsetWidth ?? 220;\n  const actionWidth = actionEl?.offsetWidth ?? 40;\n  const offset = wrapperWidth - actionWidth - 6;\n  return { actionWidth, offset, wrapperWidth };\n}\n\nfunction handleDragMoving(e: MouseEvent | TouchEvent) {\n  const { isMoving, moveDistance } = state;\n  if (isMoving) {\n    const actionEl = unref(actionRef);\n    const barEl = unref(barRef);\n    if (!actionEl || !barEl) return;\n    const { actionWidth, offset, wrapperWidth } = getOffset(actionEl.getEl());\n    const moveX = getEventPageX(e) - moveDistance;\n\n    emit('move', {\n      event: e,\n      moveDistance,\n      moveX,\n    });\n    if (moveX > 0 && moveX <= offset) {\n      actionEl.setLeft(`${moveX}px`);\n      barEl.setWidth(`${moveX + actionWidth / 2}px`);\n    } else if (moveX > offset) {\n      actionEl.setLeft(`${wrapperWidth - actionWidth}px`);\n      barEl.setWidth(`${wrapperWidth - actionWidth / 2}px`);\n      if (!props.isSlot) {\n        checkPass();\n      }\n    }\n  }\n}\n\nfunction handleDragOver(e: MouseEvent | TouchEvent) {\n  const { isMoving, isPassing, moveDistance } = state;\n  if (isMoving && !isPassing) {\n    emit('end', e);\n    const actionEl = actionRef.value;\n    const barEl = unref(barRef);\n    if (!actionEl || !barEl) return;\n    const moveX = getEventPageX(e) - moveDistance;\n    const { actionWidth, offset, wrapperWidth } = getOffset(actionEl.getEl());\n    if (moveX < offset) {\n      if (props.isSlot) {\n        setTimeout(() => {\n          if (modelValue.value) {\n            const contentEl = unref(contentRef);\n            if (contentEl) {\n              contentEl.getEl().style.width = `${Number.parseInt(barEl.getEl().style.width)}px`;\n            }\n          } else {\n            resume();\n          }\n        }, 0);\n      } else {\n        resume();\n      }\n    } else {\n      actionEl.setLeft(`${wrapperWidth - actionWidth}px`);\n      barEl.setWidth(`${wrapperWidth - actionWidth / 2}px`);\n      checkPass();\n    }\n    state.isMoving = false;\n  }\n}\n\nfunction checkPass() {\n  if (props.isSlot) {\n    resume();\n    return;\n  }\n  state.endTime = Date.now();\n  state.isPassing = true;\n  state.isMoving = false;\n}\n\nfunction resume() {\n  state.isMoving = false;\n  state.isPassing = false;\n  state.moveDistance = 0;\n  state.toLeft = false;\n  state.startTime = 0;\n  state.endTime = 0;\n  const actionEl = unref(actionRef);\n  const barEl = unref(barRef);\n  const contentEl = unref(contentRef);\n  if (!actionEl || !barEl || !contentEl) return;\n\n  contentEl.getEl().style.width = '100%';\n  state.toLeft = true;\n  useTimeoutFn(() => {\n    state.toLeft = false;\n    actionEl.setLeft('0');\n    barEl.setWidth('0');\n  }, 300);\n}\n</script>\n\n<template>\n  <div\n    ref=\"wrapperRef\"\n    :class=\"\n      cn(\n        'border-border bg-background-deep relative flex h-10 w-full items-center overflow-hidden rounded-md border text-center',\n        props.class,\n      )\n    \"\n    :style=\"wrapperStyle\"\n    @mouseleave=\"handleDragOver\"\n    @mousemove=\"handleDragMoving\"\n    @mouseup=\"handleDragOver\"\n    @touchend=\"handleDragOver\"\n    @touchmove=\"handleDragMoving\"\n  >\n    <SliderCaptchaBar\n      ref=\"barRef\"\n      :bar-style=\"barStyle\"\n      :to-left=\"state.toLeft\"\n    />\n    <SliderCaptchaContent\n      ref=\"contentRef\"\n      :content-style=\"contentStyle\"\n      :is-passing=\"state.isPassing\"\n      :success-text=\"successText || $t('ui.captcha.sliderSuccessText')\"\n      :text=\"text || $t('ui.captcha.sliderDefaultText')\"\n    >\n      <template v-if=\"$slots.text\" #text>\n        <slot :is-passing=\"state.isPassing\" name=\"text\"></slot>\n      </template>\n    </SliderCaptchaContent>\n\n    <SliderCaptchaAction\n      ref=\"actionRef\"\n      :action-style=\"actionStyle\"\n      :is-passing=\"state.isPassing\"\n      :to-left=\"state.toLeft\"\n      @mousedown=\"handleDragStart\"\n      @touchstart=\"handleDragStart\"\n    >\n      <template v-if=\"$slots.actionIcon\" #icon>\n        <slot :is-passing=\"state.isPassing\" name=\"actionIcon\"></slot>\n      </template>\n    </SliderCaptchaAction>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport { computed, ref, useTemplateRef } from 'vue';\n\nimport { Check, ChevronsRight } from '@vben/icons';\n\nimport { Slot } from '@vben-core/shadcn-ui';\n\nconst props = defineProps<{\n  actionStyle: CSSProperties;\n  isPassing: boolean;\n  toLeft: boolean;\n}>();\n\nconst actionRef = useTemplateRef<HTMLDivElement>('actionRef');\n\nconst left = ref('0');\n\nconst style = computed(() => {\n  const { actionStyle } = props;\n  return {\n    ...actionStyle,\n    left: left.value,\n  };\n});\n\nconst isDragging = computed(() => {\n  const currentLeft = Number.parseInt(left.value as string);\n\n  return currentLeft > 10 && !props.isPassing;\n});\n\ndefineExpose({\n  getEl: () => {\n    return actionRef.value;\n  },\n  getStyle: () => {\n    return actionRef?.value?.style;\n  },\n  setLeft: (val: string) => {\n    left.value = val;\n  },\n});\n</script>\n\n<template>\n  <div\n    ref=\"actionRef\"\n    :class=\"{\n      'transition-width !left-0 duration-300': toLeft,\n      'rounded-md': isDragging,\n    }\"\n    :style=\"style\"\n    class=\"bg-background dark:bg-accent absolute left-0 top-0 flex h-full cursor-move items-center justify-center px-3.5 shadow-md\"\n    name=\"captcha-action\"\n  >\n    <Slot :is-passing=\"isPassing\" class=\"text-foreground/60 size-4\">\n      <slot name=\"icon\">\n        <ChevronsRight v-if=\"!isPassing\" />\n        <Check v-else />\n      </slot>\n    </Slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport { computed, ref, useTemplateRef } from 'vue';\n\nconst props = defineProps<{\n  barStyle: CSSProperties;\n  toLeft: boolean;\n}>();\n\nconst barRef = useTemplateRef<HTMLDivElement>('barRef');\n\nconst width = ref('0');\n\nconst style = computed(() => {\n  const { barStyle } = props;\n  return {\n    ...barStyle,\n    width: width.value,\n  };\n});\n\ndefineExpose({\n  getEl: () => {\n    return barRef.value;\n  },\n  setWidth: (val: string) => {\n    width.value = val;\n  },\n});\n</script>\n\n<template>\n  <div\n    ref=\"barRef\"\n    :class=\"toLeft && 'transition-width !w-0 duration-300'\"\n    :style=\"style\"\n    class=\"bg-success absolute h-full\"\n  ></div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport { computed, useTemplateRef } from 'vue';\n\nimport { VbenSpineText } from '@vben-core/shadcn-ui';\n\nconst props = defineProps<{\n  contentStyle: CSSProperties;\n  isPassing: boolean;\n  successText: string;\n  text: string;\n}>();\n\nconst contentRef = useTemplateRef<HTMLDivElement>('contentRef');\n\nconst style = computed(() => {\n  const { contentStyle } = props;\n\n  return {\n    ...contentStyle,\n  };\n});\n\ndefineExpose({\n  getEl: () => {\n    return contentRef.value;\n  },\n});\n</script>\n\n<template>\n  <div\n    ref=\"contentRef\"\n    :class=\"{\n      [$style.success]: isPassing,\n    }\"\n    :style=\"style\"\n    class=\"absolute top-0 flex size-full select-none items-center justify-center text-xs\"\n  >\n    <slot name=\"text\">\n      <VbenSpineText class=\"flex h-full items-center\">\n        {{ isPassing ? successText : text }}\n      </VbenSpineText>\n    </slot>\n  </div>\n</template>\n\n<style module>\n.success {\n  -webkit-text-fill-color: hsl(0deg 0% 98%);\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  CaptchaVerifyPassingData,\n  SliderCaptchaActionType,\n  SliderRotateCaptchaProps,\n  SliderRotateVerifyPassingData,\n} from '../types';\n\nimport { computed, reactive, unref, useTemplateRef, watch } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport { useTimeoutFn } from '@vueuse/core';\n\nimport SliderCaptcha from '../slider-captcha/index.vue';\n\nconst props = withDefaults(defineProps<SliderRotateCaptchaProps>(), {\n  defaultTip: '',\n  diffDegree: 20,\n  imageSize: 260,\n  maxDegree: 300,\n  minDegree: 120,\n  src: '',\n});\n\nconst emit = defineEmits<{\n  success: [CaptchaVerifyPassingData];\n}>();\n\nconst slideBarRef = useTemplateRef<SliderCaptchaActionType>('slideBarRef');\n\nconst state = reactive({\n  currentRotate: 0,\n  dragging: false,\n  endTime: 0,\n  imgStyle: {},\n  isPassing: false,\n  randomRotate: 0,\n  showTip: false,\n  startTime: 0,\n  toOrigin: false,\n});\n\nconst modalValue = defineModel<boolean>({ default: false });\n\nwatch(\n  () => state.isPassing,\n  (isPassing) => {\n    if (isPassing) {\n      const { endTime, startTime } = state;\n      const time = (endTime - startTime) / 1000;\n      emit('success', { isPassing, time: time.toFixed(1) });\n    }\n    modalValue.value = isPassing;\n  },\n);\n\nconst getImgWrapStyleRef = computed(() => {\n  const { imageSize, imageWrapperStyle } = props;\n  return {\n    height: `${imageSize}px`,\n    width: `${imageSize}px`,\n    ...imageWrapperStyle,\n  };\n});\n\nconst getFactorRef = computed(() => {\n  const { maxDegree, minDegree } = props;\n  if (minDegree > maxDegree) {\n    console.warn('minDegree should not be greater than maxDegree');\n  }\n\n  if (minDegree === maxDegree) {\n    return Math.floor(1 + Math.random() * 1) / 10 + 1;\n  }\n  return 1;\n});\n\nfunction handleStart() {\n  state.startTime = Date.now();\n}\n\nfunction handleDragBarMove(data: SliderRotateVerifyPassingData) {\n  state.dragging = true;\n  const { imageSize, maxDegree } = props;\n  const { moveX } = data;\n  const denominator = imageSize!;\n  if (denominator === 0) {\n    return;\n  }\n  const currentRotate = Math.ceil(\n    (moveX / denominator) * 1.5 * maxDegree! * unref(getFactorRef),\n  );\n  state.currentRotate = currentRotate;\n  setImgRotate(state.randomRotate - currentRotate);\n}\n\nfunction handleImgOnLoad() {\n  const { maxDegree, minDegree } = props;\n  const ranRotate = Math.floor(\n    minDegree! + Math.random() * (maxDegree! - minDegree!),\n  ); // 生成随机角度\n  state.randomRotate = ranRotate;\n  setImgRotate(ranRotate);\n}\n\nfunction handleDragEnd() {\n  const { currentRotate, randomRotate } = state;\n  const { diffDegree } = props;\n\n  if (Math.abs(randomRotate - currentRotate) >= (diffDegree || 20)) {\n    setImgRotate(randomRotate);\n    state.toOrigin = true;\n    useTimeoutFn(() => {\n      state.toOrigin = false;\n      state.showTip = true;\n      //  时间与动画时间保持一致\n    }, 300);\n  } else {\n    checkPass();\n  }\n  state.showTip = true;\n  state.dragging = false;\n}\n\nfunction setImgRotate(deg: number) {\n  state.imgStyle = {\n    transform: `rotateZ(${deg}deg)`,\n  };\n}\n\nfunction checkPass() {\n  state.isPassing = true;\n  state.endTime = Date.now();\n}\n\nfunction resume() {\n  state.showTip = false;\n  const basicEl = unref(slideBarRef);\n  if (!basicEl) {\n    return;\n  }\n  state.isPassing = false;\n\n  basicEl.resume();\n  handleImgOnLoad();\n}\n\nconst imgCls = computed(() => {\n  return state.toOrigin ? ['transition-transform duration-300'] : [];\n});\n\nconst verifyTip = computed(() => {\n  return state.isPassing\n    ? $t('ui.captcha.sliderRotateSuccessTip', [\n        ((state.endTime - state.startTime) / 1000).toFixed(1),\n      ])\n    : $t('ui.captcha.sliderRotateFailTip');\n});\n\ndefineExpose({\n  resume,\n});\n</script>\n\n<template>\n  <div class=\"relative flex flex-col items-center\">\n    <div\n      :style=\"getImgWrapStyleRef\"\n      class=\"border-border relative cursor-pointer overflow-hidden rounded-full border shadow-md\"\n    >\n      <img\n        :class=\"imgCls\"\n        :src=\"src\"\n        :style=\"state.imgStyle\"\n        alt=\"verify\"\n        class=\"w-full rounded-full\"\n        @click=\"resume\"\n        @load=\"handleImgOnLoad\"\n      />\n      <div\n        class=\"absolute bottom-3 left-0 z-10 block h-7 w-full text-center text-xs leading-[30px] text-white\"\n      >\n        <div\n          v-if=\"state.showTip\"\n          :class=\"{\n            'bg-success/80': state.isPassing,\n            'bg-destructive/80': !state.isPassing,\n          }\"\n        >\n          {{ verifyTip }}\n        </div>\n        <div v-if=\"!state.dragging\" class=\"bg-black/30\">\n          {{ defaultTip || $t('ui.captcha.sliderRotateDefaultTip') }}\n        </div>\n      </div>\n    </div>\n\n    <SliderCaptcha\n      ref=\"slideBarRef\"\n      v-model=\"modalValue\"\n      class=\"mt-5\"\n      is-slot\n      @end=\"handleDragEnd\"\n      @move=\"handleDragBarMove\"\n      @start=\"handleStart\"\n    >\n      <template v-for=\"(_, key) in $slots\" :key=\"key\" #[key]=\"slotProps\">\n        <slot :name=\"key\" v-bind=\"slotProps\"></slot>\n      </template>\n    </SliderCaptcha>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  CaptchaVerifyPassingData,\n  SliderCaptchaActionType,\n  SliderRotateVerifyPassingData,\n  SliderTranslateCaptchaProps,\n} from '../types';\n\nimport {\n  computed,\n  onMounted,\n  reactive,\n  ref,\n  unref,\n  useTemplateRef,\n  watch,\n} from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport SliderCaptcha from '../slider-captcha/index.vue';\n\nconst props = withDefaults(defineProps<SliderTranslateCaptchaProps>(), {\n  defaultTip: '',\n  canvasWidth: 420,\n  canvasHeight: 280,\n  squareLength: 42,\n  circleRadius: 10,\n  src: '',\n  diffDistance: 3,\n});\n\nconst emit = defineEmits<{\n  success: [CaptchaVerifyPassingData];\n}>();\n\nconst PI: number = Math.PI;\nenum CanvasOpr {\n  // eslint-disable-next-line no-unused-vars\n  Clip = 'clip',\n  // eslint-disable-next-line no-unused-vars\n  Fill = 'fill',\n}\n\nconst modalValue = defineModel<boolean>({ default: false });\n\nconst slideBarRef = useTemplateRef<SliderCaptchaActionType>('slideBarRef');\nconst puzzleCanvasRef = useTemplateRef<HTMLCanvasElement>('puzzleCanvasRef');\nconst pieceCanvasRef = useTemplateRef<HTMLCanvasElement>('pieceCanvasRef');\n\nconst state = reactive({\n  dragging: false,\n  startTime: 0,\n  endTime: 0,\n  pieceX: 0,\n  pieceY: 0,\n  moveDistance: 0,\n  isPassing: false,\n  showTip: false,\n});\n\nconst left = ref('0');\n\nconst pieceStyle = computed(() => {\n  return {\n    left: left.value,\n  };\n});\n\nfunction setLeft(val: string) {\n  left.value = val;\n}\n\nconst verifyTip = computed(() => {\n  return state.isPassing\n    ? $t('ui.captcha.sliderTranslateSuccessTip', [\n        ((state.endTime - state.startTime) / 1000).toFixed(1),\n      ])\n    : $t('ui.captcha.sliderTranslateFailTip');\n});\nfunction handleStart() {\n  state.startTime = Date.now();\n}\n\nfunction handleDragBarMove(data: SliderRotateVerifyPassingData) {\n  state.dragging = true;\n  const { moveX } = data;\n  state.moveDistance = moveX;\n  setLeft(`${moveX}px`);\n}\n\nfunction handleDragEnd() {\n  const { pieceX } = state;\n  const { diffDistance } = props;\n\n  if (Math.abs(pieceX - state.moveDistance) >= (diffDistance || 3)) {\n    setLeft('0');\n    state.moveDistance = 0;\n  } else {\n    checkPass();\n  }\n  state.showTip = true;\n  state.dragging = false;\n}\n\nfunction checkPass() {\n  state.isPassing = true;\n  state.endTime = Date.now();\n}\n\nwatch(\n  () => state.isPassing,\n  (isPassing) => {\n    if (isPassing) {\n      const { endTime, startTime } = state;\n      const time = (endTime - startTime) / 1000;\n      emit('success', { isPassing, time: time.toFixed(1) });\n    }\n    modalValue.value = isPassing;\n  },\n);\n\nfunction resetCanvas() {\n  const { canvasWidth, canvasHeight } = props;\n  const puzzleCanvas = unref(puzzleCanvasRef);\n  const pieceCanvas = unref(pieceCanvasRef);\n  if (!puzzleCanvas || !pieceCanvas) return;\n  pieceCanvas.width = canvasWidth;\n  const puzzleCanvasCtx = puzzleCanvas.getContext('2d');\n  // Canvas2D: Multiple readback operations using getImageData\n  // are faster with the willReadFrequently attribute set to true.\n  // See: https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently (anonymous)\n  const pieceCanvasCtx = pieceCanvas.getContext('2d', {\n    willReadFrequently: true,\n  });\n  if (!puzzleCanvasCtx || !pieceCanvasCtx) return;\n  puzzleCanvasCtx.clearRect(0, 0, canvasWidth, canvasHeight);\n  pieceCanvasCtx.clearRect(0, 0, canvasWidth, canvasHeight);\n}\n\nfunction initCanvas() {\n  const { canvasWidth, canvasHeight, squareLength, circleRadius, src } = props;\n  const puzzleCanvas = unref(puzzleCanvasRef);\n  const pieceCanvas = unref(pieceCanvasRef);\n  if (!puzzleCanvas || !pieceCanvas) return;\n  const puzzleCanvasCtx = puzzleCanvas.getContext('2d');\n  // Canvas2D: Multiple readback operations using getImageData\n  // are faster with the willReadFrequently attribute set to true.\n  // See: https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently (anonymous)\n  const pieceCanvasCtx = pieceCanvas.getContext('2d', {\n    willReadFrequently: true,\n  });\n  if (!puzzleCanvasCtx || !pieceCanvasCtx) return;\n  const img = new Image();\n  // 解决跨域\n  img.crossOrigin = 'Anonymous';\n  img.src = src;\n  img.addEventListener('load', () => {\n    draw(puzzleCanvasCtx, pieceCanvasCtx);\n    puzzleCanvasCtx.drawImage(img, 0, 0, canvasWidth, canvasHeight);\n    pieceCanvasCtx.drawImage(img, 0, 0, canvasWidth, canvasHeight);\n    const pieceLength = squareLength + 2 * circleRadius + 3;\n    const sx = state.pieceX;\n    const sy = state.pieceY - 2 * circleRadius - 1;\n    const imageData = pieceCanvasCtx.getImageData(\n      sx,\n      sy,\n      pieceLength,\n      pieceLength,\n    );\n    pieceCanvas.width = pieceLength;\n    pieceCanvasCtx.putImageData(imageData, 0, sy);\n    setLeft('0');\n  });\n}\n\nfunction getRandomNumberByRange(start: number, end: number) {\n  return Math.round(Math.random() * (end - start) + start);\n}\n\n// 绘制拼图\nfunction draw(ctx1: CanvasRenderingContext2D, ctx2: CanvasRenderingContext2D) {\n  const { canvasWidth, canvasHeight, squareLength, circleRadius } = props;\n  state.pieceX = getRandomNumberByRange(\n    squareLength + 2 * circleRadius,\n    canvasWidth - (squareLength + 2 * circleRadius),\n  );\n  state.pieceY = getRandomNumberByRange(\n    3 * circleRadius,\n    canvasHeight - (squareLength + 2 * circleRadius),\n  );\n  drawPiece(ctx1, state.pieceX, state.pieceY, CanvasOpr.Fill);\n  drawPiece(ctx2, state.pieceX, state.pieceY, CanvasOpr.Clip);\n}\n\n// 绘制拼图切块\nfunction drawPiece(\n  ctx: CanvasRenderingContext2D,\n  x: number,\n  y: number,\n  opr: CanvasOpr,\n) {\n  const { squareLength, circleRadius } = props;\n  ctx.beginPath();\n  ctx.moveTo(x, y);\n  ctx.arc(\n    x + squareLength / 2,\n    y - circleRadius + 2,\n    circleRadius,\n    0.72 * PI,\n    2.26 * PI,\n  );\n  ctx.lineTo(x + squareLength, y);\n  ctx.arc(\n    x + squareLength + circleRadius - 2,\n    y + squareLength / 2,\n    circleRadius,\n    1.21 * PI,\n    2.78 * PI,\n  );\n  ctx.lineTo(x + squareLength, y + squareLength);\n  ctx.lineTo(x, y + squareLength);\n  ctx.arc(\n    x + circleRadius - 2,\n    y + squareLength / 2,\n    circleRadius + 0.4,\n    2.76 * PI,\n    1.24 * PI,\n    true,\n  );\n  ctx.lineTo(x, y);\n  ctx.lineWidth = 2;\n  ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';\n  ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';\n  ctx.stroke();\n  opr === CanvasOpr.Clip ? ctx.clip() : ctx.fill();\n  ctx.globalCompositeOperation = 'destination-over';\n}\n\nfunction resume() {\n  state.showTip = false;\n  const basicEl = unref(slideBarRef);\n  if (!basicEl) {\n    return;\n  }\n  state.dragging = false;\n  state.isPassing = false;\n  state.pieceX = 0;\n  state.pieceY = 0;\n\n  basicEl.resume();\n  resetCanvas();\n  initCanvas();\n}\n\nonMounted(() => {\n  initCanvas();\n});\n</script>\n\n<template>\n  <div class=\"relative flex flex-col items-center\">\n    <div\n      class=\"border-border relative flex cursor-pointer overflow-hidden border shadow-md\"\n    >\n      <canvas\n        ref=\"puzzleCanvasRef\"\n        :width=\"canvasWidth\"\n        :height=\"canvasHeight\"\n        @click=\"resume\"\n      ></canvas>\n      <canvas\n        ref=\"pieceCanvasRef\"\n        :width=\"canvasWidth\"\n        :height=\"canvasHeight\"\n        :style=\"pieceStyle\"\n        class=\"absolute\"\n        @click=\"resume\"\n      ></canvas>\n      <div\n        class=\"h-15 absolute bottom-3 left-0 z-10 block w-full text-center text-xs leading-[30px] text-white\"\n      >\n        <div\n          v-if=\"state.showTip\"\n          :class=\"{\n            'bg-success/80': state.isPassing,\n            'bg-destructive/80': !state.isPassing,\n          }\"\n        >\n          {{ verifyTip }}\n        </div>\n        <div v-if=\"!state.dragging\" class=\"bg-black/30\">\n          {{ defaultTip || $t('ui.captcha.sliderTranslateDefaultTip') }}\n        </div>\n      </div>\n    </div>\n    <SliderCaptcha\n      ref=\"slideBarRef\"\n      v-model=\"modalValue\"\n      class=\"mt-5\"\n      is-slot\n      @end=\"handleDragEnd\"\n      @move=\"handleDragBarMove\"\n      @start=\"handleStart\"\n    >\n      <template v-for=\"(_, key) in $slots\" :key=\"key\" #[key]=\"slotProps\">\n        <slot :name=\"key\" v-bind=\"slotProps\"></slot>\n      </template>\n    </SliderCaptcha>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/captcha/types.ts",
    "content": "import type { CSSProperties } from 'vue';\n\nimport type { ClassType } from '@vben/types';\n\nexport interface CaptchaData {\n  /**\n   * x\n   */\n  x: number;\n  /**\n   * y\n   */\n  y: number;\n  /**\n   * 时间戳\n   */\n  t: number;\n}\nexport interface CaptchaPoint extends CaptchaData {\n  /**\n   * 数据索引\n   */\n  i: number;\n}\nexport interface PointSelectionCaptchaCardProps {\n  /**\n   * 验证码图片\n   */\n  captchaImage: string;\n  /**\n   * 验证码图片高度\n   * @default '220px'\n   */\n  height?: number | string;\n  /**\n   * 水平内边距\n   * @default '12px'\n   */\n  paddingX?: number | string;\n  /**\n   * 垂直内边距\n   * @default '16px'\n   */\n  paddingY?: number | string;\n  /**\n   * 标题\n   * @default '请按图依次点击'\n   */\n  title?: string;\n  /**\n   * 验证码图片宽度\n   * @default '300px'\n   */\n  width?: number | string;\n}\n\nexport interface PointSelectionCaptchaProps\n  extends PointSelectionCaptchaCardProps {\n  /**\n   * 是否展示确定按钮\n   * @default false\n   */\n  showConfirm?: boolean;\n  /**\n   * 提示图片\n   * @default ''\n   */\n  hintImage?: string;\n  /**\n   * 提示文本\n   * @default ''\n   */\n  hintText?: string;\n}\n\nexport interface SliderCaptchaProps {\n  class?: ClassType;\n  /**\n   * @description 滑块的样式\n   * @default {}\n   */\n  actionStyle?: CSSProperties;\n\n  /**\n   * @description 滑块条的样式\n   * @default {}\n   */\n  barStyle?: CSSProperties;\n\n  /**\n   * @description 内容的样式\n   * @default {}\n   */\n  contentStyle?: CSSProperties;\n\n  /**\n   * @description 组件的样式\n   * @default {}\n   */\n  wrapperStyle?: CSSProperties;\n\n  /**\n   * @description 是否作为插槽使用，用于联动组件，可参考旋转校验组件\n   * @default false\n   */\n  isSlot?: boolean;\n\n  /**\n   * @description 验证成功的提示\n   * @default '验证通过'\n   */\n  successText?: string;\n\n  /**\n   * @description 提示文字\n   * @default '请按住滑块拖动'\n   */\n  text?: string;\n}\n\nexport interface SliderRotateCaptchaProps {\n  /**\n   * @description 旋转的角度\n   * @default 20\n   */\n  diffDegree?: number;\n\n  /**\n   * @description 图片的宽度\n   * @default 260\n   */\n  imageSize?: number;\n\n  /**\n   * @description 图片的样式\n   * @default {}\n   */\n  imageWrapperStyle?: CSSProperties;\n\n  /**\n   * @description 最大旋转角度\n   * @default 270\n   */\n  maxDegree?: number;\n\n  /**\n   * @description 最小旋转角度\n   * @default 90\n   */\n  minDegree?: number;\n\n  /**\n   * @description 图片的地址\n   */\n  src?: string;\n  /**\n   * @description 默认提示文本\n   */\n  defaultTip?: string;\n}\n\nexport interface SliderTranslateCaptchaProps {\n  /**\n   * @description 拼图的宽度\n   * @default 420\n   */\n  canvasWidth?: number;\n  /**\n   * @description 拼图的高度\n   * @default 280\n   */\n  canvasHeight?: number;\n  /**\n   * @description 切块上正方形的长度\n   * @default 42\n   */\n  squareLength?: number;\n  /**\n   * @description 切块上圆形的半径\n   * @default 10\n   */\n  circleRadius?: number;\n  /**\n   * @description 图片的地址\n   */\n  src?: string;\n  /**\n   * @description 允许的最大差距\n   * @default 3\n   */\n  diffDistance?: number;\n  /**\n   * @description 默认提示文本\n   */\n  defaultTip?: string;\n}\n\nexport interface CaptchaVerifyPassingData {\n  isPassing: boolean;\n  time: number | string;\n}\n\nexport interface SliderCaptchaActionType {\n  resume: () => void;\n}\n\nexport interface SliderRotateVerifyPassingData {\n  event: MouseEvent | TouchEvent;\n  moveDistance: number;\n  moveX: number;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/col-page/col-page.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { ColPageProps } from './types';\n\nimport { computed, ref, useSlots } from 'vue';\n\nimport {\n  ResizableHandle,\n  ResizablePanel,\n  ResizablePanelGroup,\n} from '@vben-core/shadcn-ui';\n\nimport Page from '../page/page.vue';\n\ndefineOptions({\n  name: 'ColPage',\n  inheritAttrs: false,\n});\n\nconst props = withDefaults(defineProps<ColPageProps>(), {\n  leftWidth: 30,\n  rightWidth: 70,\n  resizable: true,\n});\n\nconst delegatedProps = computed(() => {\n  const { leftWidth: _, ...delegated } = props;\n  return delegated;\n});\n\nconst slots = useSlots();\n\nconst delegatedSlots = computed(() => {\n  const resultSlots: string[] = [];\n\n  for (const key of Object.keys(slots)) {\n    if (!['default', 'left'].includes(key)) {\n      resultSlots.push(key);\n    }\n  }\n  return resultSlots;\n});\n\nconst leftPanelRef = ref<InstanceType<typeof ResizablePanel>>();\n\nfunction expandLeft() {\n  leftPanelRef.value?.expand();\n}\n\nfunction collapseLeft() {\n  leftPanelRef.value?.collapse();\n}\n\ndefineExpose({\n  expandLeft,\n  collapseLeft,\n});\n</script>\n<template>\n  <Page v-bind=\"delegatedProps\">\n    <!-- 继承默认的slot -->\n    <template\n      v-for=\"slotName in delegatedSlots\"\n      :key=\"slotName\"\n      #[slotName]=\"slotProps\"\n    >\n      <slot :name=\"slotName\" v-bind=\"slotProps\"></slot>\n    </template>\n\n    <ResizablePanelGroup class=\"w-full\" direction=\"horizontal\">\n      <ResizablePanel\n        ref=\"leftPanelRef\"\n        :collapsed-size=\"leftCollapsedWidth\"\n        :collapsible=\"leftCollapsible\"\n        :default-size=\"leftWidth\"\n        :max-size=\"leftMaxWidth\"\n        :min-size=\"leftMinWidth\"\n      >\n        <template #default=\"slotProps\">\n          <slot\n            name=\"left\"\n            v-bind=\"{\n              ...slotProps,\n              expand: expandLeft,\n              collapse: collapseLeft,\n            }\"\n          ></slot>\n        </template>\n      </ResizablePanel>\n      <ResizableHandle\n        v-if=\"resizable\"\n        :style=\"{ backgroundColor: splitLine ? undefined : 'transparent' }\"\n        :with-handle=\"splitHandle\"\n      />\n      <ResizablePanel\n        :collapsed-size=\"rightCollapsedWidth\"\n        :collapsible=\"rightCollapsible\"\n        :default-size=\"rightWidth\"\n        :max-size=\"rightMaxWidth\"\n        :min-size=\"rightMinWidth\"\n      >\n        <template #default>\n          <slot></slot>\n        </template>\n      </ResizablePanel>\n    </ResizablePanelGroup>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/col-page/index.ts",
    "content": "export { default as ColPage } from './col-page.vue';\nexport * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/col-page/types.ts",
    "content": "import type { PageProps } from '../page/types';\n\nexport interface ColPageProps extends PageProps {\n  /**\n   * 左侧宽度\n   * @default 30\n   */\n  leftWidth?: number;\n  leftMinWidth?: number;\n  leftMaxWidth?: number;\n  leftCollapsedWidth?: number;\n  leftCollapsible?: boolean;\n  /**\n   * 右侧宽度\n   * @default 70\n   */\n  rightWidth?: number;\n  rightMinWidth?: number;\n  rightCollapsedWidth?: number;\n  rightMaxWidth?: number;\n  rightCollapsible?: boolean;\n\n  resizable?: boolean;\n  splitLine?: boolean;\n  splitHandle?: boolean;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/count-to/count-to.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { CountToProps } from './types';\n\nimport { computed, onMounted, ref, watch } from 'vue';\n\nimport { isString } from '@vben-core/shared/utils';\n\nimport { TransitionPresets, useTransition } from '@vueuse/core';\n\nconst props = withDefaults(defineProps<CountToProps>(), {\n  startVal: 0,\n  duration: 2000,\n  separator: ',',\n  decimal: '.',\n  decimals: 0,\n  delay: 0,\n  transition: () => TransitionPresets.easeOutExpo,\n});\n\nconst emit = defineEmits(['started', 'finished']);\n\nconst lastValue = ref(props.startVal);\n\nonMounted(() => {\n  lastValue.value = props.endVal;\n});\n\nwatch(\n  () => props.endVal,\n  (val) => {\n    lastValue.value = val;\n  },\n);\n\nconst currentValue = useTransition(lastValue, {\n  delay: computed(() => props.delay),\n  duration: computed(() => props.duration),\n  disabled: computed(() => props.disabled),\n  transition: computed(() => {\n    return isString(props.transition)\n      ? TransitionPresets[props.transition]\n      : props.transition;\n  }),\n  onStarted() {\n    emit('started');\n  },\n  onFinished() {\n    emit('finished');\n  },\n});\n\nconst numMain = computed(() => {\n  const result = currentValue.value\n    .toFixed(props.decimals)\n    .split('.')[0]\n    ?.replaceAll(/\\B(?=(\\d{3})+(?!\\d))/g, props.separator);\n  return result;\n});\n\nconst numDec = computed(() => {\n  return (\n    props.decimal + currentValue.value.toFixed(props.decimals).split('.')[1]\n  );\n});\n</script>\n<template>\n  <div class=\"count-to\" v-bind=\"$attrs\">\n    <slot name=\"prefix\">\n      <div\n        class=\"count-to-prefix\"\n        :style=\"prefixStyle\"\n        :class=\"prefixClass\"\n        v-if=\"prefix\"\n      >\n        {{ prefix }}\n      </div>\n    </slot>\n    <div class=\"count-to-main\" :class=\"mainClass\" :style=\"mainStyle\">\n      <span>{{ numMain }}</span>\n      <span\n        class=\"count-to-main-decimal\"\n        v-if=\"decimals > 0\"\n        :class=\"decimalClass\"\n        :style=\"decimalStyle\"\n      >\n        {{ numDec }}\n      </span>\n    </div>\n    <slot name=\"suffix\">\n      <div\n        class=\"count-to-suffix\"\n        :style=\"suffixStyle\"\n        :class=\"suffixClass\"\n        v-if=\"suffix\"\n      >\n        {{ suffix }}\n      </div>\n    </slot>\n  </div>\n</template>\n<style lang=\"scss\" scoped>\n.count-to {\n  display: flex;\n  align-items: baseline;\n\n  &-prefix {\n    // font-size: 1rem;\n  }\n\n  &-suffix {\n    // font-size: 1rem;\n  }\n\n  &-main {\n    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n    // font-size: 1.5rem;\n\n    &-decimal {\n      // font-size: 0.8rem;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/count-to/index.ts",
    "content": "export { default as CountTo } from './count-to.vue';\nexport * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/count-to/types.ts",
    "content": "import type { CubicBezierPoints, EasingFunction } from '@vueuse/core';\n\nimport type { StyleValue } from 'vue';\n\nimport { TransitionPresets as TransitionPresetsData } from '@vueuse/core';\n\nexport type TransitionPresets = keyof typeof TransitionPresetsData;\n\nexport const TransitionPresetsKeys = Object.keys(\n  TransitionPresetsData,\n) as TransitionPresets[];\n\nexport interface CountToProps {\n  /** 初始值 */\n  startVal?: number;\n  /** 当前值 */\n  endVal: number;\n  /** 是否禁用动画 */\n  disabled?: boolean;\n  /** 延迟动画开始的时间 */\n  delay?: number;\n  /** 持续时间  */\n  duration?: number;\n  /** 小数位数  */\n  decimals?: number;\n  /** 小数点  */\n  decimal?: string;\n  /** 分隔符  */\n  separator?: string;\n  /** 前缀  */\n  prefix?: string;\n  /** 后缀  */\n  suffix?: string;\n  /** 过渡效果  */\n  transition?: CubicBezierPoints | EasingFunction | TransitionPresets;\n  /** 整数部分的类名 */\n  mainClass?: string;\n  /** 小数部分的类名 */\n  decimalClass?: string;\n  /** 前缀部分的类名 */\n  prefixClass?: string;\n  /** 后缀部分的类名 */\n  suffixClass?: string;\n\n  /** 整数部分的样式 */\n  mainStyle?: StyleValue;\n  /** 小数部分的样式 */\n  decimalStyle?: StyleValue;\n  /** 前缀部分的样式 */\n  prefixStyle?: StyleValue;\n  /** 后缀部分的样式 */\n  suffixStyle?: StyleValue;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CSSProperties } from 'vue';\n\nimport {\n  computed,\n  onBeforeUnmount,\n  onMounted,\n  onUpdated,\n  ref,\n  watchEffect,\n} from 'vue';\n\nimport { VbenTooltip } from '@vben-core/shadcn-ui';\n\nimport { useElementSize } from '@vueuse/core';\n\ninterface Props {\n  /**\n   * 是否启用点击文本展开全部\n   * @default false\n   */\n  expand?: boolean;\n  /**\n   * 文本最大行数\n   * @default 1\n   */\n  line?: number;\n  /**\n   * 文本最大宽度\n   * @default '100%'\n   */\n  maxWidth?: number | string;\n  /**\n   * 提示框位置\n   * @default 'top'\n   */\n  placement?: 'bottom' | 'left' | 'right' | 'top';\n  /**\n   * 是否启用文本提示框\n   * @default true\n   */\n  tooltip?: boolean;\n  /**\n   * 是否只在文本被截断时显示提示框\n   * @default false\n   */\n  tooltipWhenEllipsis?: boolean;\n  /**\n   * 文本截断检测的像素差异阈值，越大则判断越严格\n   * @default 3\n   */\n  ellipsisThreshold?: number;\n  /**\n   * 提示框背景颜色，优先级高于 overlayStyle\n   */\n  tooltipBackgroundColor?: string;\n  /**\n   * 提示文本字体颜色，优先级高于 overlayStyle\n   */\n  tooltipColor?: string;\n  /**\n   * 提示文本字体大小，单位px，优先级高于 overlayStyle\n   */\n  tooltipFontSize?: number;\n  /**\n   * 提示框内容最大宽度，单位px，默认不设置时，提示文本内容自动与展示文本宽度保持一致\n   */\n  tooltipMaxWidth?: number;\n  /**\n   * 提示框内容区域样式\n   * @default { textAlign: 'justify' }\n   */\n  tooltipOverlayStyle?: CSSProperties;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  expand: false,\n  line: 1,\n  maxWidth: '100%',\n  placement: 'top',\n  tooltip: true,\n  tooltipWhenEllipsis: false,\n  ellipsisThreshold: 3,\n  tooltipBackgroundColor: '',\n  tooltipColor: '',\n  tooltipFontSize: 14,\n  tooltipMaxWidth: undefined,\n  tooltipOverlayStyle: () => ({ textAlign: 'justify' }),\n});\n\nconst emit = defineEmits<{ expandChange: [boolean] }>();\n\nconst textMaxWidth = computed(() => {\n  if (typeof props.maxWidth === 'number') {\n    return `${props.maxWidth}px`;\n  }\n  return props.maxWidth;\n});\nconst ellipsis = ref();\nconst isExpand = ref(false);\nconst defaultTooltipMaxWidth = ref();\nconst isEllipsis = ref(false);\n\nconst { width: eleWidth } = useElementSize(ellipsis);\n\n// 检测文本是否被截断\nconst checkEllipsis = () => {\n  if (!ellipsis.value || !props.tooltipWhenEllipsis) return;\n\n  const element = ellipsis.value;\n\n  const originalText = element.textContent || '';\n  const originalTrimmed = originalText.trim();\n\n  // 对于空文本直接返回 false\n  if (!originalTrimmed) {\n    isEllipsis.value = false;\n    return;\n  }\n\n  const widthDiff = element.scrollWidth - element.clientWidth;\n  const heightDiff = element.scrollHeight - element.clientHeight;\n\n  // 使用足够大的差异阈值确保只有真正被截断的文本才会显示 tooltip\n  isEllipsis.value =\n    props.line === 1\n      ? widthDiff > props.ellipsisThreshold\n      : heightDiff > props.ellipsisThreshold;\n};\n\n// 使用 ResizeObserver 监听尺寸变化\nlet resizeObserver: null | ResizeObserver = null;\n\nonMounted(() => {\n  if (typeof ResizeObserver !== 'undefined' && props.tooltipWhenEllipsis) {\n    resizeObserver = new ResizeObserver(() => {\n      checkEllipsis();\n    });\n\n    if (ellipsis.value) {\n      resizeObserver.observe(ellipsis.value);\n    }\n  }\n\n  // 初始检测\n  checkEllipsis();\n});\n\n// 使用onUpdated钩子检测内容变化\nonUpdated(() => {\n  if (props.tooltipWhenEllipsis) {\n    checkEllipsis();\n  }\n});\n\nonBeforeUnmount(() => {\n  if (resizeObserver) {\n    resizeObserver.disconnect();\n    resizeObserver = null;\n  }\n});\n\nwatchEffect(\n  () => {\n    if (props.tooltip && eleWidth.value) {\n      defaultTooltipMaxWidth.value =\n        props.tooltipMaxWidth ?? eleWidth.value + 24;\n    }\n  },\n  { flush: 'post' },\n);\n\nfunction onExpand() {\n  isExpand.value = !isExpand.value;\n  emit('expandChange', isExpand.value);\n  if (props.tooltipWhenEllipsis) {\n    checkEllipsis();\n  }\n}\n\nfunction handleExpand() {\n  props.expand && onExpand();\n}\n</script>\n<template>\n  <div>\n    <VbenTooltip\n      :content-style=\"{\n        ...tooltipOverlayStyle,\n        maxWidth: `${defaultTooltipMaxWidth}px`,\n        fontSize: `${tooltipFontSize}px`,\n        color: tooltipColor,\n        backgroundColor: tooltipBackgroundColor,\n      }\"\n      :disabled=\"\n        !props.tooltip || isExpand || (props.tooltipWhenEllipsis && !isEllipsis)\n      \"\n      :side=\"placement\"\n    >\n      <slot name=\"tooltip\">\n        <slot></slot>\n      </slot>\n\n      <template #trigger>\n        <div\n          ref=\"ellipsis\"\n          :class=\"{\n            '!cursor-pointer': expand,\n            ['block truncate']: line === 1,\n            [$style.ellipsisMultiLine]: line > 1,\n          }\"\n          :style=\"{\n            '-webkit-line-clamp': isExpand ? '' : line,\n            'max-width': textMaxWidth,\n          }\"\n          class=\"cursor-text overflow-hidden\"\n          @click=\"handleExpand\"\n          v-bind=\"$attrs\"\n        >\n          <slot></slot>\n        </div>\n      </template>\n    </VbenTooltip>\n  </div>\n</template>\n\n<style module>\n.ellipsisMultiLine {\n  display: -webkit-box;\n  -webkit-box-orient: vertical;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/ellipsis-text/index.ts",
    "content": "export { default as EllipsisText } from './ellipsis-text.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue",
    "content": "<script setup lang=\"ts\">\nimport type { VNode } from 'vue';\n\nimport { computed, ref, useAttrs, watch, watchEffect } from 'vue';\n\nimport { usePagination } from '@vben/hooks';\nimport { EmptyIcon, Grip, listIcons } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport {\n  Button,\n  Input,\n  Pagination,\n  PaginationEllipsis,\n  PaginationFirst,\n  PaginationLast,\n  PaginationList,\n  PaginationListItem,\n  PaginationNext,\n  PaginationPrev,\n  VbenIcon,\n  VbenIconButton,\n  VbenPopover,\n} from '@vben-core/shadcn-ui';\nimport { isFunction } from '@vben-core/shared/utils';\n\nimport { objectOmit, refDebounced, watchDebounced } from '@vueuse/core';\n\nimport { fetchIconsData } from './icons';\n\ninterface Props {\n  pageSize?: number;\n  /** 图标集的名字 */\n  prefix?: string;\n  /** 是否自动请求API以获得图标集的数据.提供prefix时有效 */\n  autoFetchApi?: boolean;\n  /**\n   * 图标列表\n   */\n  icons?: string[];\n  /** Input组件 */\n  inputComponent?: VNode;\n  /** 图标插槽名，预览图标将被渲染到此插槽中 */\n  iconSlot?: string;\n  /** input组件的值属性名称 */\n  modelValueProp?: string;\n  /** 图标样式 */\n  iconClass?: string;\n  type?: 'icon' | 'input';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  prefix: 'ant-design',\n  pageSize: 36,\n  icons: () => [],\n  iconSlot: 'default',\n  iconClass: 'size-4',\n  autoFetchApi: true,\n  modelValueProp: 'modelValue',\n  inputComponent: undefined,\n  type: 'input',\n});\n\nconst emit = defineEmits<{\n  change: [string];\n}>();\n\nconst attrs = useAttrs();\n\nconst modelValue = defineModel({ default: '', type: String });\n\nconst visible = ref(false);\nconst currentSelect = ref('');\nconst currentPage = ref(1);\nconst keyword = ref('');\nconst keywordDebounce = refDebounced(keyword, 300);\nconst innerIcons = ref<string[]>([]);\n\n/* 当检索关键词变化时，重置分页 */\nwatch(keywordDebounce, () => {\n  currentPage.value = 1;\n  setCurrentPage(1);\n});\n\nwatchDebounced(\n  () => props.prefix,\n  async (prefix) => {\n    if (prefix && prefix !== 'svg' && props.autoFetchApi) {\n      innerIcons.value = await fetchIconsData(prefix);\n    }\n  },\n  { immediate: true, debounce: 500, maxWait: 1000 },\n);\n\nconst currentList = computed(() => {\n  try {\n    if (props.prefix) {\n      if (\n        props.prefix !== 'svg' &&\n        props.autoFetchApi &&\n        props.icons.length === 0\n      ) {\n        return innerIcons.value;\n      }\n      const icons = listIcons('', props.prefix);\n      if (icons.length === 0) {\n        console.warn(`No icons found for prefix: ${props.prefix}`);\n      }\n      return icons;\n    } else {\n      return props.icons;\n    }\n  } catch (error) {\n    console.error('Failed to load icons:', error);\n    return [];\n  }\n});\n\nconst showList = computed(() => {\n  return currentList.value.filter((item) =>\n    item.includes(keywordDebounce.value),\n  );\n});\n\nconst { paginationList, total, setCurrentPage } = usePagination(\n  showList,\n  props.pageSize,\n);\n\nwatchEffect(() => {\n  currentSelect.value = modelValue.value;\n});\n\nwatch(\n  () => currentSelect.value,\n  (v) => {\n    emit('change', v);\n  },\n);\n\nconst handleClick = (icon: string) => {\n  currentSelect.value = icon;\n  modelValue.value = icon;\n  close();\n};\n\nconst handlePageChange = (page: number) => {\n  currentPage.value = page;\n  setCurrentPage(page);\n};\n\nfunction toggleOpenState() {\n  visible.value = !visible.value;\n}\n\nfunction open() {\n  visible.value = true;\n}\n\nfunction close() {\n  visible.value = false;\n}\n\nfunction onKeywordChange(v: string) {\n  keyword.value = v;\n}\n\nconst searchInputProps = computed(() => {\n  return {\n    placeholder: $t('ui.iconPicker.search'),\n    [props.modelValueProp]: keyword.value,\n    [`onUpdate:${props.modelValueProp}`]: onKeywordChange,\n    class: 'mx-2',\n  };\n});\n\nfunction updateCurrentSelect(v: string) {\n  currentSelect.value = v;\n  const eventKey = `onUpdate:${props.modelValueProp}`;\n  if (attrs[eventKey] && isFunction(attrs[eventKey])) {\n    attrs[eventKey](v);\n  }\n}\nconst getBindAttrs = computed(() => {\n  return objectOmit(attrs, [`onUpdate:${props.modelValueProp}`]);\n});\n\ndefineExpose({ toggleOpenState, open, close });\n</script>\n<template>\n  <VbenPopover\n    v-model:open=\"visible\"\n    :content-props=\"{ align: 'end', alignOffset: -11, sideOffset: 8 }\"\n    content-class=\"p-0 pt-3 w-full\"\n    trigger-class=\"w-full\"\n  >\n    <template #trigger>\n      <template v-if=\"props.type === 'input'\">\n        <component\n          v-if=\"props.inputComponent\"\n          :is=\"inputComponent\"\n          :[modelValueProp]=\"currentSelect\"\n          :placeholder=\"$t('ui.iconPicker.placeholder')\"\n          role=\"combobox\"\n          :aria-label=\"$t('ui.iconPicker.placeholder')\"\n          aria-expanded=\"visible\"\n          :[`onUpdate:${modelValueProp}`]=\"updateCurrentSelect\"\n          v-bind=\"getBindAttrs\"\n        >\n          <template #[iconSlot]>\n            <VbenIcon\n              :icon=\"currentSelect || Grip\"\n              class=\"size-4\"\n              aria-hidden=\"true\"\n            />\n          </template>\n        </component>\n        <div class=\"relative w-full\" v-else>\n          <Input\n            v-bind=\"$attrs\"\n            v-model=\"currentSelect\"\n            :placeholder=\"$t('ui.iconPicker.placeholder')\"\n            class=\"h-8 w-full pr-8\"\n            role=\"combobox\"\n            :aria-label=\"$t('ui.iconPicker.placeholder')\"\n            aria-expanded=\"visible\"\n          />\n          <VbenIcon\n            :icon=\"currentSelect || Grip\"\n            class=\"absolute right-1 top-1 size-6\"\n            aria-hidden=\"true\"\n          />\n        </div>\n      </template>\n      <VbenIcon\n        :icon=\"currentSelect || Grip\"\n        v-else\n        class=\"size-4\"\n        v-bind=\"$attrs\"\n      />\n    </template>\n    <div class=\"mb-2 flex w-full\">\n      <component\n        v-if=\"inputComponent\"\n        :is=\"inputComponent\"\n        v-bind=\"searchInputProps\"\n      />\n      <Input\n        v-else\n        class=\"mx-2 h-8 w-full\"\n        :placeholder=\"$t('ui.iconPicker.search')\"\n        v-model=\"keyword\"\n      />\n    </div>\n\n    <template v-if=\"paginationList.length > 0\">\n      <div class=\"grid max-h-[360px] w-full grid-cols-6 justify-items-center\">\n        <VbenIconButton\n          v-for=\"(item, index) in paginationList\"\n          :key=\"index\"\n          :tooltip=\"item\"\n          tooltip-side=\"top\"\n          @click=\"handleClick(item)\"\n        >\n          <VbenIcon\n            :class=\"{\n              'text-primary transition-all': currentSelect === item,\n            }\"\n            :icon=\"item\"\n          />\n        </VbenIconButton>\n      </div>\n      <div\n        v-if=\"total >= pageSize\"\n        class=\"flex-center flex justify-end overflow-hidden border-t py-2 pr-3\"\n      >\n        <Pagination\n          :items-per-page=\"36\"\n          :sibling-count=\"1\"\n          :total=\"total\"\n          show-edges\n          size=\"small\"\n          @update:page=\"handlePageChange\"\n        >\n          <PaginationList\n            v-slot=\"{ items }\"\n            class=\"flex w-full items-center gap-1\"\n          >\n            <PaginationFirst class=\"size-5\" />\n            <PaginationPrev class=\"size-5\" />\n            <template v-for=\"(item, index) in items\">\n              <PaginationListItem\n                v-if=\"item.type === 'page'\"\n                :key=\"index\"\n                :value=\"item.value\"\n                as-child\n              >\n                <Button\n                  :variant=\"item.value === currentPage ? 'default' : 'outline'\"\n                  class=\"size-5 p-0 text-sm\"\n                >\n                  {{ item.value }}\n                </Button>\n              </PaginationListItem>\n              <PaginationEllipsis\n                v-else\n                :key=\"item.type\"\n                :index=\"index\"\n                class=\"size-5\"\n              />\n            </template>\n            <PaginationNext class=\"size-5\" />\n            <PaginationLast class=\"size-5\" />\n          </PaginationList>\n        </Pagination>\n      </div>\n    </template>\n\n    <template v-else>\n      <div class=\"flex-col-center text-muted-foreground min-h-[150px] w-full\">\n        <EmptyIcon class=\"size-10\" />\n        <div class=\"mt-1 text-sm\">{{ $t('common.noData') }}</div>\n      </div>\n    </template>\n  </VbenPopover>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/icon-picker/icons.ts",
    "content": "import type { Recordable } from '@vben/types';\n\n/**\n * 一个缓存对象，在不刷新页面时，无需重复请求远程接口\n */\nexport const ICONS_MAP: Recordable<string[]> = {};\n\ninterface IconifyResponse {\n  prefix: string;\n  total: number;\n  title: string;\n  uncategorized?: string[];\n  categories?: Recordable<string[]>;\n  aliases?: Recordable<string>;\n}\n\nconst PENDING_REQUESTS: Recordable<Promise<string[]>> = {};\n\n/**\n * 通过Iconify接口获取图标集数据。\n * 同一时间多个图标选择器同时请求同一个图标集时，实际上只会发起一次请求（所有请求共享同一份结果）。\n * 请求结果会被缓存，刷新页面前同一个图标集不会再次请求\n * @param prefix 图标集名称\n * @returns 图标集中包含的所有图标名称\n */\nexport async function fetchIconsData(prefix: string): Promise<string[]> {\n  if (Reflect.has(ICONS_MAP, prefix) && ICONS_MAP[prefix]) {\n    return ICONS_MAP[prefix];\n  }\n  if (Reflect.has(PENDING_REQUESTS, prefix) && PENDING_REQUESTS[prefix]) {\n    return PENDING_REQUESTS[prefix];\n  }\n  PENDING_REQUESTS[prefix] = (async () => {\n    try {\n      const controller = new AbortController();\n      const timeoutId = setTimeout(() => controller.abort(), 1000 * 10);\n      const response: IconifyResponse = await fetch(\n        `https://api.iconify.design/collection?prefix=${prefix}`,\n        { signal: controller.signal },\n      ).then((res) => res.json());\n      clearTimeout(timeoutId);\n      const list = response.uncategorized || [];\n      if (response.categories) {\n        for (const category in response.categories) {\n          list.push(...(response.categories[category] || []));\n        }\n      }\n      ICONS_MAP[prefix] = list.map((v) => `${prefix}:${v}`);\n    } catch (error) {\n      console.error(`Failed to fetch icons for prefix ${prefix}:`, error);\n      return [] as string[];\n    }\n    return ICONS_MAP[prefix];\n  })();\n  return PENDING_REQUESTS[prefix];\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/icon-picker/index.ts",
    "content": "export { default as IconPicker } from './icon-picker.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/index.ts",
    "content": "export * from './api-component';\nexport * from './captcha';\nexport * from './col-page';\nexport * from './count-to';\nexport * from './ellipsis-text';\nexport * from './icon-picker';\nexport * from './json-viewer';\nexport * from './loading';\nexport * from './page';\nexport * from './resize';\nexport * from './tippy';\nexport * from './tree';\nexport * from '@vben-core/form-ui';\nexport * from '@vben-core/popup-ui';\n\n// 给文档用\nexport {\n  VbenAvatar,\n  VbenButton,\n  VbenButtonGroup,\n  VbenCheckbox,\n  VbenCheckButtonGroup,\n  VbenCountToAnimator,\n  VbenFullScreen,\n  VbenInputPassword,\n  VbenLoading,\n  VbenLogo,\n  VbenPinInput,\n  VbenSelect,\n  VbenSpinner,\n} from '@vben-core/shadcn-ui';\n\nexport type { FlattenedItem } from '@vben-core/shadcn-ui';\nexport { globalShareState } from '@vben-core/shared/global-state';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/json-viewer/index.ts",
    "content": "export { default as JsonViewer } from './index.vue';\n\nexport * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/json-viewer/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { SetupContext } from 'vue';\n\nimport type { Recordable } from '@vben/types';\n\nimport type {\n  JsonViewerAction,\n  JsonViewerProps,\n  JsonViewerToggle,\n  JsonViewerValue,\n} from './types';\n\nimport { computed, useAttrs } from 'vue';\n// @ts-ignore\nimport VueJsonViewer from 'vue-json-viewer';\n\nimport { $t } from '@vben/locales';\n\nimport { isBoolean } from '@vben-core/shared/utils';\n\n// @ts-ignore\nimport JsonBigint from 'json-bigint';\n\ndefineOptions({ name: 'JsonViewer' });\n\nconst props = withDefaults(defineProps<JsonViewerProps>(), {\n  expandDepth: 1,\n  copyable: false,\n  sort: false,\n  boxed: false,\n  theme: 'default-json-theme',\n  expanded: false,\n  previewMode: false,\n  showArrayIndex: true,\n  showDoubleQuotes: false,\n});\n\nconst emit = defineEmits<{\n  click: [event: MouseEvent];\n  copied: [event: JsonViewerAction];\n  keyClick: [key: string];\n  toggle: [param: JsonViewerToggle];\n  valueClick: [value: JsonViewerValue];\n}>();\n\nconst attrs: SetupContext['attrs'] = useAttrs();\n\nfunction handleClick(event: MouseEvent) {\n  if (\n    event.target instanceof HTMLElement &&\n    event.target.classList.contains('jv-item')\n  ) {\n    const pathNode = event.target.closest('.jv-push');\n    if (!pathNode || !pathNode.hasAttribute('path')) {\n      return;\n    }\n    const param: JsonViewerValue = {\n      path: '',\n      value: '',\n      depth: 0,\n      el: event.target,\n    };\n\n    param.path = pathNode.getAttribute('path') || '';\n    param.depth = Number(pathNode.getAttribute('depth')) || 0;\n\n    param.value = event.target.textContent || undefined;\n    param.value = JSON.parse(param.value);\n    emit('valueClick', param);\n  }\n  emit('click', event);\n}\n\n// 支持显示 bigint 数据，如较长的订单号\nconst jsonData = computed<Record<string, any>>(() => {\n  if (typeof props.value !== 'string') {\n    return props.value || {};\n  }\n\n  try {\n    return JsonBigint({ storeAsString: true }).parse(props.value);\n  } catch (error) {\n    console.error('JSON parse error:', error);\n    return {};\n  }\n});\n\nconst bindProps = computed<Recordable<any>>(() => {\n  const copyable = {\n    copyText: $t('ui.jsonViewer.copy'),\n    copiedText: $t('ui.jsonViewer.copied'),\n    timeout: 2000,\n    ...(isBoolean(props.copyable) ? {} : props.copyable),\n  };\n\n  return {\n    ...props,\n    ...attrs,\n    value: jsonData.value,\n    onCopied: (event: JsonViewerAction) => emit('copied', event),\n    onKeyclick: (key: string) => emit('keyClick', key),\n    onClick: (event: MouseEvent) => handleClick(event),\n    copyable: props.copyable ? copyable : false,\n  };\n});\n</script>\n<template>\n  <VueJsonViewer v-bind=\"bindProps\">\n    <template #copy=\"slotProps\">\n      <slot name=\"copy\" v-bind=\"slotProps\"></slot>\n    </template>\n  </VueJsonViewer>\n</template>\n<style lang=\"scss\">\n@use './style.scss';\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/json-viewer/style.scss",
    "content": ".default-json-theme {\n  font-family: Consolas, Menlo, Courier, monospace;\n  font-size: 14px;\n  color: hsl(var(--foreground));\n  white-space: nowrap;\n  background: hsl(var(--background));\n\n  &.jv-container.boxed {\n    border: 1px solid hsl(var(--border));\n  }\n\n  .jv-ellipsis {\n    display: inline-block;\n    padding: 0 4px 2px;\n    font-size: 0.9em;\n    line-height: 0.9;\n    vertical-align: 2px;\n    color: hsl(var(--secondary-foreground));\n    cursor: pointer;\n    user-select: none;\n    background-color: hsl(var(--secondary));\n    border-radius: 3px;\n  }\n\n  .jv-button {\n    color: hsl(var(--primary));\n  }\n\n  .jv-key {\n    color: hsl(var(--heavy-foreground));\n  }\n\n  .jv-item {\n    &.jv-array {\n      color: hsl(var(--heavy-foreground));\n    }\n\n    &.jv-boolean {\n      color: hsl(var(--red-400));\n    }\n\n    &.jv-function {\n      color: hsl(var(--destructive-foreground));\n    }\n\n    &.jv-number {\n      color: hsl(var(--info-foreground));\n    }\n\n    &.jv-number-float {\n      color: hsl(var(--info-foreground));\n    }\n\n    &.jv-number-integer {\n      color: hsl(var(--info-foreground));\n    }\n\n    &.jv-object {\n      color: hsl(var(--accent-darker));\n    }\n\n    &.jv-undefined {\n      color: hsl(var(--secondary-foreground));\n    }\n\n    &.jv-string {\n      color: hsl(var(--primary));\n      overflow-wrap: break-word;\n      white-space: normal;\n    }\n  }\n\n  &.jv-container .jv-code {\n    padding: 10px;\n\n    &.boxed:not(.open) {\n      padding-bottom: 20px;\n      margin-bottom: 10px;\n    }\n\n    &.open {\n      padding-bottom: 10px;\n    }\n\n    .jv-toggle {\n      &::before {\n        padding: 0 2px;\n        border-radius: 2px;\n      }\n\n      &:hover {\n        &::before {\n          background: hsl(var(--accent-foreground));\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/json-viewer/types.ts",
    "content": "export interface JsonViewerProps {\n  /** 要展示的结构数据 */\n  value: any;\n  /** 展开深度 */\n  expandDepth?: number;\n  /** 是否可复制 */\n  copyable?: boolean;\n  /** 是否排序 */\n  sort?: boolean;\n  /** 显示边框 */\n  boxed?: boolean;\n  /** 主题 */\n  theme?: string;\n  /** 是否展开 */\n  expanded?: boolean;\n  /** 时间格式化函数 */\n  timeformat?: (time: Date | number | string) => string;\n  /** 预览模式 */\n  previewMode?: boolean;\n  /** 显示数组索引 */\n  showArrayIndex?: boolean;\n  /** 显示双引号 */\n  showDoubleQuotes?: boolean;\n}\n\nexport interface JsonViewerAction {\n  action: string;\n  text: string;\n  trigger: HTMLElement;\n}\n\nexport interface JsonViewerValue {\n  value: any;\n  path: string;\n  depth: number;\n  el: HTMLElement;\n}\n\nexport interface JsonViewerToggle {\n  /** 鼠标事件 */\n  event: MouseEvent;\n  /** 当前展开状态 */\n  open: boolean;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/loading/directive.ts",
    "content": "import type { App, Directive, DirectiveBinding } from 'vue';\n\nimport { h, render } from 'vue';\n\nimport { VbenLoading, VbenSpinner } from '@vben-core/shadcn-ui';\nimport { isString } from '@vben-core/shared/utils';\n\nconst LOADING_INSTANCE_KEY = Symbol('loading');\nconst SPINNER_INSTANCE_KEY = Symbol('spinner');\n\nconst CLASS_NAME_RELATIVE = 'spinner-parent--relative';\n\nconst loadingDirective: Directive = {\n  mounted(el, binding) {\n    const instance = h(VbenLoading, getOptions(binding));\n    render(instance, el);\n\n    el.classList.add(CLASS_NAME_RELATIVE);\n    el[LOADING_INSTANCE_KEY] = instance;\n  },\n  unmounted(el) {\n    const instance = el[LOADING_INSTANCE_KEY];\n    el.classList.remove(CLASS_NAME_RELATIVE);\n    render(null, el);\n    instance.el.remove();\n\n    el[LOADING_INSTANCE_KEY] = null;\n  },\n\n  updated(el, binding) {\n    const instance = el[LOADING_INSTANCE_KEY];\n    const options = getOptions(binding);\n    if (options && instance?.component) {\n      try {\n        Object.keys(options).forEach((key) => {\n          instance.component.props[key] = options[key];\n        });\n        instance.component.update();\n      } catch (error) {\n        console.error(\n          'Failed to update loading component in directive:',\n          error,\n        );\n      }\n    }\n  },\n};\n\nfunction getOptions(binding: DirectiveBinding) {\n  if (binding.value === undefined) {\n    return { spinning: true };\n  } else if (typeof binding.value === 'boolean') {\n    return { spinning: binding.value };\n  } else {\n    return { ...binding.value };\n  }\n}\n\nconst spinningDirective: Directive = {\n  mounted(el, binding) {\n    const instance = h(VbenSpinner, getOptions(binding));\n    render(instance, el);\n\n    el.classList.add(CLASS_NAME_RELATIVE);\n    el[SPINNER_INSTANCE_KEY] = instance;\n  },\n  unmounted(el) {\n    const instance = el[SPINNER_INSTANCE_KEY];\n    el.classList.remove(CLASS_NAME_RELATIVE);\n    render(null, el);\n    instance.el.remove();\n\n    el[SPINNER_INSTANCE_KEY] = null;\n  },\n\n  updated(el, binding) {\n    const instance = el[SPINNER_INSTANCE_KEY];\n    const options = getOptions(binding);\n    if (options && instance?.component) {\n      try {\n        Object.keys(options).forEach((key) => {\n          instance.component.props[key] = options[key];\n        });\n        instance.component.update();\n      } catch (error) {\n        console.error(\n          'Failed to update spinner component in directive:',\n          error,\n        );\n      }\n    }\n  },\n};\n\ntype loadingDirectiveParams = {\n  /** 是否注册loading指令。如果提供一个string，则将指令注册为指定的名称 */\n  loading?: boolean | string;\n  /** 是否注册spinning指令。如果提供一个string，则将指令注册为指定的名称 */\n  spinning?: boolean | string;\n};\n\n/**\n * 注册loading指令\n * @param app\n * @param params\n */\nexport function registerLoadingDirective(\n  app: App,\n  params?: loadingDirectiveParams,\n) {\n  // 注入一个样式供指令使用，确保容器是相对定位\n  const style = document.createElement('style');\n  style.id = CLASS_NAME_RELATIVE;\n  style.innerHTML = `\n    .${CLASS_NAME_RELATIVE} {\n      position: relative !important;\n    }\n  `;\n  document.head.append(style);\n  if (params?.loading !== false) {\n    app.directive(\n      isString(params?.loading) ? params.loading : 'loading',\n      loadingDirective,\n    );\n  }\n  if (params?.spinning !== false) {\n    app.directive(\n      isString(params?.spinning) ? params.spinning : 'spinning',\n      spinningDirective,\n    );\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/loading/index.ts",
    "content": "export * from './directive';\nexport { default as Loading } from './loading.vue';\nexport { default as Spinner } from './spinner.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/loading/loading.vue",
    "content": "<script lang=\"ts\" setup>\nimport { VbenLoading } from '@vben-core/shadcn-ui';\nimport { cn } from '@vben-core/shared/utils';\n\ninterface LoadingProps {\n  class?: string;\n  /**\n   * @zh_CN 最小加载时间\n   * @en_US Minimum loading time\n   */\n  minLoadingTime?: number;\n\n  /**\n   * @zh_CN loading状态开启\n   */\n  spinning?: boolean;\n  /**\n   * @zh_CN 文字\n   */\n  text?: string;\n}\n\ndefineOptions({ name: 'Loading' });\nconst props = defineProps<LoadingProps>();\n</script>\n<template>\n  <div :class=\"cn('relative min-h-20', props.class)\">\n    <slot></slot>\n    <VbenLoading\n      :min-loading-time=\"props.minLoadingTime\"\n      :spinning=\"props.spinning\"\n      :text=\"props.text\"\n    >\n      <template v-if=\"$slots.icon\" #icon>\n        <slot name=\"icon\"></slot>\n      </template>\n    </VbenLoading>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/loading/spinner.vue",
    "content": "<script lang=\"ts\" setup>\nimport { VbenSpinner } from '@vben-core/shadcn-ui';\nimport { cn } from '@vben-core/shared/utils';\n\ninterface SpinnerProps {\n  class?: string;\n  /**\n   * @zh_CN 最小加载时间\n   * @en_US Minimum loading time\n   */\n  minLoadingTime?: number;\n  /**\n   * @zh_CN loading状态开启\n   */\n  spinning?: boolean;\n}\ndefineOptions({ name: 'Spinner' });\nconst props = defineProps<SpinnerProps>();\n</script>\n<template>\n  <div :class=\"cn('relative min-h-20', props.class)\">\n    <slot></slot>\n    <VbenSpinner\n      :min-loading-time=\"props.minLoadingTime\"\n      :spinning=\"props.spinning\"\n    />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/page/__tests__/page.test.ts",
    "content": "import { mount } from '@vue/test-utils';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { Page } from '..';\n\ndescribe('page.vue', () => {\n  it('renders title when passed', () => {\n    const wrapper = mount(Page, {\n      props: {\n        title: 'Test Title',\n      },\n    });\n\n    expect(wrapper.text()).toContain('Test Title');\n  });\n\n  it('renders description when passed', () => {\n    const wrapper = mount(Page, {\n      props: {\n        description: 'Test Description',\n      },\n    });\n\n    expect(wrapper.text()).toContain('Test Description');\n  });\n\n  it('renders default slot content', () => {\n    const wrapper = mount(Page, {\n      slots: {\n        default: '<p>Default Slot Content</p>',\n      },\n    });\n\n    expect(wrapper.html()).toContain('<p>Default Slot Content</p>');\n  });\n\n  it('renders footer slot when showFooter is true', () => {\n    const wrapper = mount(Page, {\n      props: {\n        showFooter: true,\n      },\n      slots: {\n        footer: '<p>Footer Slot Content</p>',\n      },\n    });\n\n    expect(wrapper.html()).toContain('<p>Footer Slot Content</p>');\n  });\n\n  it('applies the custom contentClass', () => {\n    const wrapper = mount(Page, {\n      props: {\n        contentClass: 'custom-class',\n      },\n    });\n\n    const contentDiv = wrapper.find('.p-4');\n    expect(contentDiv.classes()).toContain('custom-class');\n  });\n\n  it('does not render title slot if title prop is provided', () => {\n    const wrapper = mount(Page, {\n      props: {\n        title: 'Test Title',\n      },\n      slots: {\n        title: '<p>Title Slot Content</p>',\n      },\n    });\n\n    expect(wrapper.text()).toContain('Title Slot Content');\n    expect(wrapper.html()).not.toContain('Test Title');\n  });\n\n  it('does not render description slot if description prop is provided', () => {\n    const wrapper = mount(Page, {\n      props: {\n        description: 'Test Description',\n      },\n      slots: {\n        description: '<p>Description Slot Content</p>',\n      },\n    });\n\n    expect(wrapper.text()).toContain('Description Slot Content');\n    expect(wrapper.html()).not.toContain('Test Description');\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/page/index.ts",
    "content": "export { default as Page } from './page.vue';\nexport * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/page/page.vue",
    "content": "<script setup lang=\"ts\">\nimport type { StyleValue } from 'vue';\n\nimport type { PageProps } from './types';\n\nimport { computed, nextTick, onMounted, ref, useTemplateRef } from 'vue';\n\nimport { CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT } from '@vben-core/shared/constants';\nimport { cn } from '@vben-core/shared/utils';\n\ndefineOptions({\n  name: 'Page',\n});\n\nconst { autoContentHeight = false, heightOffset = 0 } =\n  defineProps<PageProps>();\n\nconst headerHeight = ref(0);\nconst footerHeight = ref(0);\nconst shouldAutoHeight = ref(false);\n\nconst headerRef = useTemplateRef<HTMLDivElement>('headerRef');\nconst footerRef = useTemplateRef<HTMLDivElement>('footerRef');\n\nconst contentStyle = computed<StyleValue>(() => {\n  if (autoContentHeight) {\n    return {\n      height: `calc(var(${CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT}) - ${headerHeight.value}px - ${footerHeight.value}px - ${typeof heightOffset === 'number' ? `${heightOffset}px` : heightOffset})`,\n      overflowY: shouldAutoHeight.value ? 'auto' : 'unset',\n    };\n  }\n  return {};\n});\n\nasync function calcContentHeight() {\n  if (!autoContentHeight) {\n    return;\n  }\n  await nextTick();\n  headerHeight.value = headerRef.value?.offsetHeight || 0;\n  footerHeight.value = footerRef.value?.offsetHeight || 0;\n  setTimeout(() => {\n    shouldAutoHeight.value = true;\n  }, 30);\n}\n\nonMounted(() => {\n  calcContentHeight();\n});\n</script>\n\n<template>\n  <div class=\"relative flex min-h-full flex-col\">\n    <div\n      v-if=\"\n        description ||\n        $slots.description ||\n        title ||\n        $slots.title ||\n        $slots.extra\n      \"\n      ref=\"headerRef\"\n      :class=\"\n        cn(\n          'bg-card border-border relative flex items-end border-b px-6 py-4',\n          headerClass,\n        )\n      \"\n    >\n      <div class=\"flex-auto\">\n        <slot name=\"title\">\n          <div v-if=\"title\" class=\"mb-2 flex text-lg font-semibold\">\n            {{ title }}\n          </div>\n        </slot>\n\n        <slot name=\"description\">\n          <p v-if=\"description\" class=\"text-muted-foreground\">\n            {{ description }}\n          </p>\n        </slot>\n      </div>\n\n      <div v-if=\"$slots.extra\">\n        <slot name=\"extra\"></slot>\n      </div>\n    </div>\n\n    <div :class=\"cn('h-full p-4', contentClass)\" :style=\"contentStyle\">\n      <slot></slot>\n    </div>\n    <div\n      v-if=\"$slots.footer\"\n      ref=\"footerRef\"\n      :class=\"cn('bg-card align-center flex px-6 py-4', footerClass)\"\n    >\n      <slot name=\"footer\"></slot>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/page/types.ts",
    "content": "export interface PageProps {\n  title?: string;\n  description?: string;\n  contentClass?: string;\n  /**\n   * 根据content可见高度自适应\n   */\n  autoContentHeight?: boolean;\n  headerClass?: string;\n  footerClass?: string;\n  /**\n   * Custom height offset value (in pixels) to adjust content area sizing\n   * when used with autoContentHeight\n   * @default 0\n   */\n  heightOffset?: number;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/resize/index.ts",
    "content": "export { default as VResize } from './resize.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/resize/resize.vue",
    "content": "<script lang=\"ts\" setup>\n/**\n * This components is refactored from vue-drag-resize: https://github.com/kirillmurashov/vue-drag-resize\n */\n\nimport {\n  computed,\n  getCurrentInstance,\n  nextTick,\n  onBeforeUnmount,\n  onMounted,\n  ref,\n  toRefs,\n  watch,\n} from 'vue';\n\nconst props = defineProps({\n  stickSize: {\n    type: Number,\n    default: 8,\n  },\n  parentScaleX: {\n    type: Number,\n    default: 1,\n  },\n  parentScaleY: {\n    type: Number,\n    default: 1,\n  },\n  isActive: {\n    type: Boolean,\n    default: false,\n  },\n  preventActiveBehavior: {\n    type: Boolean,\n    default: false,\n  },\n  isDraggable: {\n    type: Boolean,\n    default: true,\n  },\n  isResizable: {\n    type: Boolean,\n    default: true,\n  },\n  aspectRatio: {\n    type: Boolean,\n    default: false,\n  },\n  parentLimitation: {\n    type: Boolean,\n    default: false,\n  },\n  snapToGrid: {\n    type: Boolean,\n    default: false,\n  },\n  gridX: {\n    type: Number,\n    default: 50,\n    validator(val: number) {\n      return val >= 0;\n    },\n  },\n  gridY: {\n    type: Number,\n    default: 50,\n    validator(val: number) {\n      return val >= 0;\n    },\n  },\n  parentW: {\n    type: Number,\n    default: 0,\n    validator(val: number) {\n      return val >= 0;\n    },\n  },\n  parentH: {\n    type: Number,\n    default: 0,\n    validator(val: number) {\n      return val >= 0;\n    },\n  },\n  w: {\n    type: [String, Number],\n    default: 200,\n    validator(val: number) {\n      return typeof val === 'string' ? val === 'auto' : val >= 0;\n    },\n  },\n  h: {\n    type: [String, Number],\n    default: 200,\n    validator(val: number) {\n      return typeof val === 'string' ? val === 'auto' : val >= 0;\n    },\n  },\n  minw: {\n    type: Number,\n    default: 50,\n    validator(val: number) {\n      return val >= 0;\n    },\n  },\n  minh: {\n    type: Number,\n    default: 50,\n    validator(val: number) {\n      return val >= 0;\n    },\n  },\n  x: {\n    type: Number,\n    default: 0,\n    validator(val: number) {\n      return typeof val === 'number';\n    },\n  },\n  y: {\n    type: Number,\n    default: 0,\n    validator(val: number) {\n      return typeof val === 'number';\n    },\n  },\n  z: {\n    type: [String, Number],\n    default: 'auto',\n    validator(val: number) {\n      return typeof val === 'string' ? val === 'auto' : val >= 0;\n    },\n  },\n  dragHandle: {\n    type: String,\n    default: null,\n  },\n  dragCancel: {\n    type: String,\n    default: null,\n  },\n  sticks: {\n    type: Array<'bl' | 'bm' | 'br' | 'ml' | 'mr' | 'tl' | 'tm' | 'tr'>,\n    default() {\n      return ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'];\n    },\n  },\n  axis: {\n    type: String,\n    default: 'both',\n    validator(val: string) {\n      return ['both', 'none', 'x', 'y'].includes(val);\n    },\n  },\n  contentClass: {\n    type: String,\n    required: false,\n    default: '',\n  },\n});\n\nconst emit = defineEmits([\n  'clicked',\n  'dragging',\n  'dragstop',\n  'resizing',\n  'resizestop',\n  'activated',\n  'deactivated',\n]);\n\nconst styleMapping = {\n  y: {\n    t: 'top',\n    m: 'marginTop',\n    b: 'bottom',\n  },\n  x: {\n    l: 'left',\n    m: 'marginLeft',\n    r: 'right',\n  },\n};\n\nfunction addEvents(events: Map<string, (...args: any[]) => void>) {\n  events.forEach((cb, eventName) => {\n    document.documentElement.addEventListener(eventName, cb);\n  });\n}\n\nfunction removeEvents(events: Map<string, (...args: any[]) => void>) {\n  events.forEach((cb, eventName) => {\n    document.documentElement.removeEventListener(eventName, cb);\n  });\n}\n\nconst {\n  stickSize,\n  parentScaleX,\n  parentScaleY,\n  isActive,\n  preventActiveBehavior,\n  isDraggable,\n  isResizable,\n  aspectRatio,\n  parentLimitation,\n  snapToGrid,\n  gridX,\n  gridY,\n  parentW,\n  parentH,\n  w,\n  h,\n  minw,\n  minh,\n  x,\n  y,\n  z,\n  dragHandle,\n  dragCancel,\n  sticks,\n  axis,\n  contentClass,\n} = toRefs(props);\n\n// states\nconst active = ref(false);\nconst zIndex = ref<null | number>(null);\nconst parentWidth = ref<null | number>(null);\nconst parentHeight = ref<null | number>(null);\nconst left = ref<null | number>(null);\nconst top = ref<null | number>(null);\nconst right = ref<null | number>(null);\nconst bottom = ref<null | number>(null);\n\nconst aspectFactor = ref<null | number>(null);\n\n// state end\n\nconst stickDrag = ref(false);\nconst bodyDrag = ref(false);\nconst dimensionsBeforeMove = ref({\n  pointerX: 0,\n  pointerY: 0,\n  x: 0,\n  y: 0,\n  w: 0,\n  h: 0,\n  top: 0,\n  right: 0,\n  bottom: 0,\n  left: 0,\n  width: 0,\n  height: 0,\n});\nconst limits = ref({\n  left: { min: null as null | number, max: null as null | number },\n  right: { min: null as null | number, max: null as null | number },\n  top: { min: null as null | number, max: null as null | number },\n  bottom: { min: null as null | number, max: null as null | number },\n});\nconst currentStick = ref<null | string>(null);\n\nconst parentElement = ref<HTMLElement | null>(null);\n\nconst width = computed(() => parentWidth.value! - left.value! - right.value!);\n\nconst height = computed(() => parentHeight.value! - top.value! - bottom.value!);\n\nconst rect = computed(() => ({\n  left: Math.round(left.value!),\n  top: Math.round(top.value!),\n  width: Math.round(width.value),\n  height: Math.round(height.value),\n}));\n\nconst saveDimensionsBeforeMove = ({\n  pointerX,\n  pointerY,\n}: {\n  pointerX: number;\n  pointerY: number;\n}) => {\n  dimensionsBeforeMove.value.pointerX = pointerX;\n  dimensionsBeforeMove.value.pointerY = pointerY;\n\n  dimensionsBeforeMove.value.left = left.value as number;\n  dimensionsBeforeMove.value.right = right.value as number;\n  dimensionsBeforeMove.value.top = top.value as number;\n  dimensionsBeforeMove.value.bottom = bottom.value as number;\n\n  dimensionsBeforeMove.value.width = width.value as number;\n  dimensionsBeforeMove.value.height = height.value as number;\n\n  aspectFactor.value = width.value / height.value;\n};\n\nconst sideCorrectionByLimit = (\n  limit: { max: number; min: number },\n  current: number,\n) => {\n  let value = current;\n\n  if (limit.min !== null && current < limit.min) {\n    value = limit.min;\n  } else if (limit.max !== null && limit.max < current) {\n    value = limit.max;\n  }\n\n  return value;\n};\n\nconst rectCorrectionByLimit = (rect: {\n  newBottom: number;\n  newLeft: number;\n  newRight: number;\n  newTop: number;\n}) => {\n  // const { limits } = this;\n  let { newRight, newLeft, newBottom, newTop } = rect;\n\n  type RectRange = {\n    max: number;\n    min: number;\n  };\n\n  newLeft = sideCorrectionByLimit(limits.value.left as RectRange, newLeft);\n  newRight = sideCorrectionByLimit(limits.value.right as RectRange, newRight);\n  newTop = sideCorrectionByLimit(limits.value.top as RectRange, newTop);\n  newBottom = sideCorrectionByLimit(\n    limits.value.bottom as RectRange,\n    newBottom,\n  );\n\n  return {\n    newLeft,\n    newRight,\n    newTop,\n    newBottom,\n  };\n};\n\nconst rectCorrectionByAspectRatio = (rect: {\n  newBottom: number;\n  newLeft: number;\n  newRight: number;\n  newTop: number;\n}) => {\n  let { newLeft, newRight, newTop, newBottom } = rect;\n  // const { parentWidth, parentHeight, currentStick, aspectFactor, dimensionsBeforeMove } = this;\n\n  let newWidth = parentWidth.value! - newLeft - newRight;\n  let newHeight = parentHeight.value! - newTop - newBottom;\n\n  if (currentStick.value![1] === 'm') {\n    const deltaHeight = newHeight - dimensionsBeforeMove.value.height;\n\n    newLeft -= (deltaHeight * aspectFactor.value!) / 2;\n    newRight -= (deltaHeight * aspectFactor.value!) / 2;\n  } else if (currentStick.value![0] === 'm') {\n    const deltaWidth = newWidth - dimensionsBeforeMove.value.width;\n\n    newTop -= deltaWidth / aspectFactor.value! / 2;\n    newBottom -= deltaWidth / aspectFactor.value! / 2;\n  } else if (newWidth / newHeight > aspectFactor.value!) {\n    newWidth = aspectFactor.value! * newHeight;\n\n    if (currentStick.value![1] === 'l') {\n      newLeft = parentWidth.value! - newRight - newWidth;\n    } else {\n      newRight = parentWidth.value! - newLeft - newWidth;\n    }\n  } else {\n    newHeight = newWidth / aspectFactor.value!;\n\n    if (currentStick.value![0] === 't') {\n      newTop = parentHeight.value! - newBottom - newHeight;\n    } else {\n      newBottom = parentHeight.value! - newTop - newHeight;\n    }\n  }\n\n  return { newLeft, newRight, newTop, newBottom };\n};\n\nconst stickMove = (delta: { x: number; y: number }) => {\n  let newTop = dimensionsBeforeMove.value.top;\n  let newBottom = dimensionsBeforeMove.value.bottom;\n  let newLeft = dimensionsBeforeMove.value.left;\n  let newRight = dimensionsBeforeMove.value.right;\n  switch (currentStick.value![0]) {\n    case 'b': {\n      newBottom = dimensionsBeforeMove.value.bottom + delta.y;\n\n      if (snapToGrid.value) {\n        newBottom =\n          (parentHeight.value as number) -\n          Math.round(\n            ((parentHeight.value as number) - newBottom) / gridY.value,\n          ) *\n            gridY.value;\n      }\n\n      break;\n    }\n\n    case 't': {\n      newTop = dimensionsBeforeMove.value.top - delta.y;\n\n      if (snapToGrid.value) {\n        newTop = Math.round(newTop / gridY.value) * gridY.value;\n      }\n\n      break;\n    }\n    default: {\n      break;\n    }\n  }\n\n  switch (currentStick.value![1]) {\n    case 'l': {\n      newLeft = dimensionsBeforeMove.value.left - delta.x;\n\n      if (snapToGrid.value) {\n        newLeft = Math.round(newLeft / gridX.value) * gridX.value;\n      }\n\n      break;\n    }\n\n    case 'r': {\n      newRight = dimensionsBeforeMove.value.right + delta.x;\n\n      if (snapToGrid.value) {\n        newRight =\n          (parentWidth.value as number) -\n          Math.round(((parentWidth.value as number) - newRight) / gridX.value) *\n            gridX.value;\n      }\n\n      break;\n    }\n    default: {\n      break;\n    }\n  }\n\n  ({ newLeft, newRight, newTop, newBottom } = rectCorrectionByLimit({\n    newLeft,\n    newRight,\n    newTop,\n    newBottom,\n  }));\n\n  if (aspectRatio.value) {\n    ({ newLeft, newRight, newTop, newBottom } = rectCorrectionByAspectRatio({\n      newLeft,\n      newRight,\n      newTop,\n      newBottom,\n    }));\n  }\n\n  left.value = newLeft;\n  right.value = newRight;\n  top.value = newTop;\n  bottom.value = newBottom;\n\n  emit('resizing', rect.value);\n};\n\nconst stickUp = () => {\n  stickDrag.value = false;\n  // dimensionsBeforeMove.value = {\n  //   pointerX: 0,\n  //   pointerY: 0,\n  //   x: 0,\n  //   y: 0,\n  //   w: 0,\n  //   h: 0,\n  // };\n\n  Object.assign(dimensionsBeforeMove.value, {\n    pointerX: 0,\n    pointerY: 0,\n    x: 0,\n    y: 0,\n    w: 0,\n    h: 0,\n  });\n\n  limits.value = {\n    left: { min: null, max: null },\n    right: { min: null, max: null },\n    top: { min: null, max: null },\n    bottom: { min: null, max: null },\n  };\n\n  emit('resizing', rect.value);\n  emit('resizestop', rect.value);\n};\n\nconst calcDragLimitation = () => {\n  return {\n    left: { min: 0, max: (parentWidth.value as number) - width.value },\n    right: { min: 0, max: (parentWidth.value as number) - width.value },\n    top: { min: 0, max: (parentHeight.value as number) - height.value },\n    bottom: { min: 0, max: (parentHeight.value as number) - height.value },\n  };\n};\n\nconst calcResizeLimits = () => {\n  // const { aspectFactor, width, height, bottom, top, left, right } = this;\n\n  const parentLim = parentLimitation.value ? 0 : null;\n\n  if (aspectRatio.value) {\n    if (minw.value / minh.value > (aspectFactor.value as number)) {\n      minh.value = minw.value / (aspectFactor.value as number);\n    } else {\n      minw.value = ((aspectFactor.value as number) * minh.value) as number;\n    }\n  }\n\n  const limits = {\n    left: {\n      min: parentLim,\n      max: (left.value as number) + (width.value - minw.value),\n    },\n    right: {\n      min: parentLim,\n      max: (right.value as number) + (width.value - minw.value),\n    },\n    top: {\n      min: parentLim,\n      max: (top.value as number) + (height.value - minh.value),\n    },\n    bottom: {\n      min: parentLim,\n      max: (bottom.value as number) + (height.value - minh.value),\n    },\n  };\n\n  if (aspectRatio.value) {\n    const aspectLimits = {\n      left: {\n        min:\n          left.value! -\n          Math.min(top.value!, bottom.value!) * aspectFactor.value! * 2,\n        max:\n          left.value! +\n          ((height.value - minh.value!) / 2) * aspectFactor.value! * 2,\n      },\n      right: {\n        min:\n          right.value! -\n          Math.min(top.value!, bottom.value!) * aspectFactor.value! * 2,\n        max:\n          right.value! +\n          ((height.value - minh.value!) / 2) * aspectFactor.value! * 2,\n      },\n      top: {\n        min:\n          top.value! -\n          (Math.min(left.value!, right.value!) / aspectFactor.value!) * 2,\n        max:\n          top.value! +\n          ((width.value - minw.value) / 2 / aspectFactor.value!) * 2,\n      },\n      bottom: {\n        min:\n          bottom.value! -\n          (Math.min(left.value!, right.value!) / aspectFactor.value!) * 2,\n        max:\n          bottom.value! +\n          ((width.value - minw.value) / 2 / aspectFactor.value!) * 2,\n      },\n    };\n\n    if (currentStick.value![0] === 'm') {\n      limits.left = {\n        min: Math.max(limits.left.min!, aspectLimits.left.min),\n        max: Math.min(limits.left.max, aspectLimits.left.max),\n      };\n      limits.right = {\n        min: Math.max(limits.right.min!, aspectLimits.right.min),\n        max: Math.min(limits.right.max, aspectLimits.right.max),\n      };\n    } else if (currentStick.value![1] === 'm') {\n      limits.top = {\n        min: Math.max(limits.top.min!, aspectLimits.top.min),\n        max: Math.min(limits.top.max, aspectLimits.top.max),\n      };\n      limits.bottom = {\n        min: Math.max(limits.bottom.min!, aspectLimits.bottom.min),\n        max: Math.min(limits.bottom.max, aspectLimits.bottom.max),\n      };\n    }\n  }\n\n  return limits;\n};\n\nconst positionStyle = computed(() => ({\n  top: `${top.value}px`,\n  left: `${left.value}px`,\n  zIndex: zIndex.value!,\n}));\n\nconst sizeStyle = computed(() => ({\n  width: w.value === 'auto' ? 'auto' : `${width.value}px`,\n  height: h.value === 'auto' ? 'auto' : `${height.value}px`,\n}));\n\nconst stickStyles = computed(() => (stick: string) => {\n  const stickStyle = {\n    width: `${stickSize.value / parentScaleX.value}px`,\n    height: `${stickSize.value / parentScaleY.value}px`,\n  };\n  stickStyle[\n    styleMapping.y[stick[0] as 'b' | 'm' | 't'] as 'height' | 'width'\n  ] = `${stickSize.value / parentScaleX.value / -2}px`;\n  stickStyle[\n    styleMapping.x[stick[1] as 'l' | 'm' | 'r'] as 'height' | 'width'\n  ] = `${stickSize.value / parentScaleX.value / -2}px`;\n  return stickStyle;\n});\n\nconst bodyMove = (delta: { x: number; y: number }) => {\n  let newTop = dimensionsBeforeMove.value.top - delta.y;\n  let newBottom = dimensionsBeforeMove.value.bottom + delta.y;\n  let newLeft = dimensionsBeforeMove.value.left - delta.x;\n  let newRight = dimensionsBeforeMove.value.right + delta.x;\n\n  if (snapToGrid.value) {\n    let alignTop = true;\n    let alignLeft = true;\n\n    let diffT = newTop - Math.floor(newTop / gridY.value) * gridY.value;\n    let diffB =\n      (parentHeight.value as number) -\n      newBottom -\n      Math.floor(((parentHeight.value as number) - newBottom) / gridY.value) *\n        gridY.value;\n    let diffL = newLeft - Math.floor(newLeft / gridX.value) * gridX.value;\n    let diffR =\n      (parentWidth.value as number) -\n      newRight -\n      Math.floor(((parentWidth.value as number) - newRight) / gridX.value) *\n        gridX.value;\n\n    if (diffT > gridY.value / 2) {\n      diffT -= gridY.value;\n    }\n    if (diffB > gridY.value / 2) {\n      diffB -= gridY.value;\n    }\n    if (diffL > gridX.value / 2) {\n      diffL -= gridX.value;\n    }\n    if (diffR > gridX.value / 2) {\n      diffR -= gridX.value;\n    }\n\n    if (Math.abs(diffB) < Math.abs(diffT)) {\n      alignTop = false;\n    }\n    if (Math.abs(diffR) < Math.abs(diffL)) {\n      alignLeft = false;\n    }\n\n    newTop -= alignTop ? diffT : diffB;\n    newBottom = (parentHeight.value as number) - height.value - newTop;\n    newLeft -= alignLeft ? diffL : diffR;\n    newRight = (parentWidth.value as number) - width.value - newLeft;\n  }\n\n  ({\n    newLeft: left.value,\n    newRight: right.value,\n    newTop: top.value,\n    newBottom: bottom.value,\n  } = rectCorrectionByLimit({ newLeft, newRight, newTop, newBottom }));\n\n  emit('dragging', rect.value);\n};\n\nconst bodyUp = () => {\n  bodyDrag.value = false;\n  emit('dragging', rect.value);\n  emit('dragstop', rect.value);\n\n  // dimensionsBeforeMove.value = { pointerX: 0, pointerY: 0, x: 0, y: 0, w: 0, h: 0 };\n  Object.assign(dimensionsBeforeMove.value, {\n    pointerX: 0,\n    pointerY: 0,\n    x: 0,\n    y: 0,\n    w: 0,\n    h: 0,\n  });\n\n  limits.value = {\n    left: { min: null, max: null },\n    right: { min: null, max: null },\n    top: { min: null, max: null },\n    bottom: { min: null, max: null },\n  };\n};\n\nconst stickDown = (\n  stick: string,\n  ev: { pageX: any; pageY: any; touches?: any },\n  force = false,\n) => {\n  if ((!isResizable.value || !active.value) && !force) {\n    return;\n  }\n\n  stickDrag.value = true;\n\n  const pointerX = ev.pageX === undefined ? ev.touches[0].pageX : ev.pageX;\n  const pointerY = ev.pageY === undefined ? ev.touches[0].pageY : ev.pageY;\n\n  saveDimensionsBeforeMove({ pointerX, pointerY });\n\n  currentStick.value = stick;\n\n  limits.value = calcResizeLimits();\n};\n\nconst move = (ev: MouseEvent & TouchEvent) => {\n  if (!stickDrag.value && !bodyDrag.value) {\n    return;\n  }\n\n  ev.stopPropagation();\n\n  // touches 兼容性代码\n  const pageX = ev.pageX === undefined ? ev.touches![0]!.pageX : ev.pageX;\n  const pageY = ev.pageY === undefined ? ev.touches![0]!.pageY : ev.pageY;\n\n  const delta = {\n    x: (dimensionsBeforeMove.value.pointerX - pageX) / parentScaleX.value,\n    y: (dimensionsBeforeMove.value.pointerY - pageY) / parentScaleY.value,\n  };\n\n  if (stickDrag.value) {\n    stickMove(delta);\n  }\n\n  if (bodyDrag.value) {\n    switch (axis.value) {\n      case 'none': {\n        return;\n      }\n      case 'x': {\n        delta.y = 0;\n\n        break;\n      }\n      case 'y': {\n        delta.x = 0;\n\n        break;\n      }\n      // No default\n    }\n    bodyMove(delta);\n  }\n};\n\nconst up = () => {\n  if (stickDrag.value) {\n    stickUp();\n  } else if (bodyDrag.value) {\n    bodyUp();\n  }\n};\n\nconst deselect = () => {\n  if (preventActiveBehavior.value) {\n    return;\n  }\n  active.value = false;\n};\n\nconst domEvents = ref(\n  new Map([\n    ['mousedown', deselect],\n    ['mouseleave', up],\n    ['mousemove', move],\n    ['mouseup', up],\n    ['touchcancel', up],\n    ['touchend', up],\n    ['touchmove', move],\n    ['touchstart', up],\n  ]),\n);\n\nconst container = ref<HTMLDivElement>();\n\nonMounted(() => {\n  const currentInstance = getCurrentInstance();\n  const $el = currentInstance?.vnode.el as HTMLElement;\n\n  parentElement.value = $el?.parentNode as HTMLElement;\n  parentWidth.value = parentW.value ?? parentElement.value?.clientWidth;\n  parentHeight.value = parentH.value ?? parentElement.value?.clientHeight;\n\n  left.value = x.value;\n  top.value = y.value;\n  right.value = (parentWidth.value -\n    (w.value === 'auto' ? container.value!.scrollWidth : (w.value as number)) -\n    left.value) as number;\n  bottom.value = (parentHeight.value -\n    (h.value === 'auto' ? container.value!.scrollHeight : (h.value as number)) -\n    top.value) as number;\n\n  addEvents(domEvents.value);\n\n  if (dragHandle.value) {\n    [...($el?.querySelectorAll(dragHandle.value) || [])].forEach(\n      (dragHandle) => {\n        (dragHandle as HTMLElement).dataset.dragHandle = String(\n          currentInstance?.uid,\n        );\n      },\n    );\n  }\n\n  if (dragCancel.value) {\n    [...($el?.querySelectorAll(dragCancel.value) || [])].forEach(\n      (cancelHandle) => {\n        (cancelHandle as HTMLElement).dataset.dragCancel = String(\n          currentInstance?.uid,\n        );\n      },\n    );\n  }\n});\n\nonBeforeUnmount(() => {\n  removeEvents(domEvents.value);\n});\n\nconst bodyDown = (ev: MouseEvent & TouchEvent) => {\n  const { target, button } = ev;\n\n  if (!preventActiveBehavior.value) {\n    active.value = true;\n  }\n\n  if (button && button !== 0) {\n    return;\n  }\n\n  emit('clicked', ev);\n\n  if (!active.value) {\n    return;\n  }\n\n  if (\n    dragHandle.value &&\n    (target! as HTMLElement).dataset.dragHandle !==\n      getCurrentInstance()?.uid.toString()\n  ) {\n    return;\n  }\n\n  if (\n    dragCancel.value &&\n    (target! as HTMLElement).dataset.dragCancel ===\n      getCurrentInstance()?.uid.toString()\n  ) {\n    return;\n  }\n\n  if (ev.stopPropagation !== undefined) {\n    ev.stopPropagation();\n  }\n\n  if (ev.preventDefault !== undefined) {\n    ev.preventDefault();\n  }\n\n  if (isDraggable.value) {\n    bodyDrag.value = true;\n  }\n\n  const pointerX = ev.pageX === undefined ? ev.touches[0]!.pageX : ev.pageX;\n  const pointerY = ev.pageY === undefined ? ev.touches[0]!.pageY : ev.pageY;\n\n  saveDimensionsBeforeMove({ pointerX, pointerY });\n\n  if (parentLimitation.value) {\n    limits.value = calcDragLimitation();\n  }\n};\n\nwatch(\n  () => active.value,\n  (isActive) => {\n    if (isActive) {\n      emit('activated');\n    } else {\n      emit('deactivated');\n    }\n  },\n);\n\nwatch(\n  () => isActive.value,\n  (val) => {\n    active.value = val;\n  },\n  { immediate: true },\n);\n\nwatch(\n  () => z.value,\n  (val) => {\n    if ((val as number) >= 0 || val === 'auto') {\n      zIndex.value = val as number;\n    }\n  },\n  { immediate: true },\n);\n\nwatch(\n  () => x.value,\n  (newVal, oldVal) => {\n    if (stickDrag.value || bodyDrag.value || newVal === left.value) {\n      return;\n    }\n\n    const delta = oldVal - newVal;\n\n    bodyDown({ pageX: left.value!, pageY: top.value! } as MouseEvent &\n      TouchEvent);\n    bodyMove({ x: delta, y: 0 });\n\n    nextTick(() => {\n      bodyUp();\n    });\n  },\n);\n\nwatch(\n  () => y.value,\n  (newVal, oldVal) => {\n    if (stickDrag.value || bodyDrag.value || newVal === top.value) {\n      return;\n    }\n\n    const delta = oldVal - newVal;\n\n    bodyDown({ pageX: left.value, pageY: top.value } as MouseEvent &\n      TouchEvent);\n    bodyMove({ x: 0, y: delta });\n\n    nextTick(() => {\n      bodyUp();\n    });\n  },\n);\n\nwatch(\n  () => w.value,\n  (newVal, oldVal) => {\n    if (stickDrag.value || bodyDrag.value || newVal === width.value) {\n      return;\n    }\n\n    const stick = 'mr';\n    const delta = (oldVal as number) - (newVal as number);\n\n    stickDown(\n      stick,\n      { pageX: right.value, pageY: top.value! + height.value / 2 },\n      true,\n    );\n    stickMove({ x: delta, y: 0 });\n\n    nextTick(() => {\n      stickUp();\n    });\n  },\n);\n\nwatch(\n  () => h.value,\n  (newVal, oldVal) => {\n    if (stickDrag.value || bodyDrag.value || newVal === height.value) {\n      return;\n    }\n\n    const stick = 'bm';\n    const delta = (oldVal as number) - (newVal as number);\n\n    stickDown(\n      stick,\n      { pageX: left.value! + width.value / 2, pageY: bottom.value },\n      true,\n    );\n    stickMove({ x: 0, y: delta });\n\n    nextTick(() => {\n      stickUp();\n    });\n  },\n);\n\nwatch(\n  () => parentW.value,\n  (val) => {\n    right.value = val - width.value - left.value!;\n    parentWidth.value = val;\n  },\n);\n\nwatch(\n  () => parentH.value,\n  (val) => {\n    bottom.value = val - height.value - top.value!;\n    parentHeight.value = val;\n  },\n);\n</script>\n\n<template>\n  <div\n    :class=\"`${active || isActive ? 'active' : 'inactive'} ${contentClass ? contentClass : ''}`\"\n    :style=\"positionStyle\"\n    class=\"resize\"\n    @mousedown=\"bodyDown($event as TouchEvent & MouseEvent)\"\n    @touchend=\"up\"\n    @touchstart=\"bodyDown($event as TouchEvent & MouseEvent)\"\n  >\n    <div ref=\"container\" :style=\"sizeStyle\" class=\"content-container\">\n      <slot></slot>\n    </div>\n    <div\n      v-for=\"(stick, index) of sticks\"\n      :key=\"index\"\n      :class=\"[`resize-stick-${stick}`, isResizable ? '' : 'not-resizable']\"\n      :style=\"stickStyles(stick)\"\n      class=\"resize-stick\"\n      @mousedown.stop.prevent=\"\n        stickDown(stick, $event as TouchEvent & MouseEvent)\n      \"\n      @touchstart.stop.prevent=\"\n        stickDown(stick, $event as TouchEvent & MouseEvent)\n      \"\n    ></div>\n  </div>\n</template>\n\n<style lang=\"css\" scoped>\n.resize {\n  position: absolute;\n  box-sizing: border-box;\n}\n\n.resize.active::before {\n  position: absolute;\n  top: 0;\n  left: 0;\n  box-sizing: border-box;\n  width: 100%;\n  height: 100%;\n  outline: 1px dashed #d6d6d6;\n  content: '';\n}\n\n.resize-stick {\n  position: absolute;\n  box-sizing: border-box;\n  font-size: 1px;\n  background: #fff;\n  border: 1px solid #6c6c6c;\n  box-shadow: 0 0 2px #bbb;\n}\n\n.inactive .resize-stick {\n  display: none;\n}\n\n.resize-stick-tl,\n.resize-stick-br {\n  cursor: nwse-resize;\n}\n\n.resize-stick-tm,\n.resize-stick-bm {\n  left: 50%;\n  cursor: ns-resize;\n}\n\n.resize-stick-tr,\n.resize-stick-bl {\n  cursor: nesw-resize;\n}\n\n.resize-stick-ml,\n.resize-stick-mr {\n  top: 50%;\n  cursor: ew-resize;\n}\n\n.resize-stick.not-resizable {\n  display: none;\n}\n\n.content-container {\n  position: relative;\n  display: block;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/tippy/directive.ts",
    "content": "import type { ComputedRef, Directive } from 'vue';\n\nimport { useTippy } from 'vue-tippy';\n\nexport default function useTippyDirective(isDark: ComputedRef<boolean>) {\n  const directive: Directive = {\n    mounted(el, binding, vnode) {\n      const opts =\n        typeof binding.value === 'string'\n          ? { content: binding.value }\n          : binding.value || {};\n\n      const modifiers = Object.keys(binding.modifiers || {});\n      const placement = modifiers.find((modifier) => modifier !== 'arrow');\n      const withArrow = modifiers.includes('arrow');\n\n      if (placement) {\n        opts.placement = opts.placement || placement;\n      }\n\n      if (withArrow) {\n        opts.arrow = opts.arrow === undefined ? true : opts.arrow;\n      }\n\n      if (vnode.props && vnode.props.onTippyShow) {\n        opts.onShow = function (...args: any[]) {\n          return vnode.props?.onTippyShow(...args);\n        };\n      }\n\n      if (vnode.props && vnode.props.onTippyShown) {\n        opts.onShown = function (...args: any[]) {\n          return vnode.props?.onTippyShown(...args);\n        };\n      }\n\n      if (vnode.props && vnode.props.onTippyHidden) {\n        opts.onHidden = function (...args: any[]) {\n          return vnode.props?.onTippyHidden(...args);\n        };\n      }\n\n      if (vnode.props && vnode.props.onTippyHide) {\n        opts.onHide = function (...args: any[]) {\n          return vnode.props?.onTippyHide(...args);\n        };\n      }\n\n      if (vnode.props && vnode.props.onTippyMount) {\n        opts.onMount = function (...args: any[]) {\n          return vnode.props?.onTippyMount(...args);\n        };\n      }\n\n      if (el.getAttribute('title') && !opts.content) {\n        opts.content = el.getAttribute('title');\n        el.removeAttribute('title');\n      }\n\n      if (el.getAttribute('content') && !opts.content) {\n        opts.content = el.getAttribute('content');\n      }\n\n      useTippy(el, opts);\n    },\n    unmounted(el) {\n      if (el.$tippy) {\n        el.$tippy.destroy();\n      } else if (el._tippy) {\n        el._tippy.destroy();\n      }\n    },\n\n    updated(el, binding) {\n      const opts =\n        typeof binding.value === 'string'\n          ? { content: binding.value, theme: isDark.value ? '' : 'light' }\n          : Object.assign(\n              { theme: isDark.value ? '' : 'light' },\n              binding.value,\n            );\n\n      if (el.getAttribute('title') && !opts.content) {\n        opts.content = el.getAttribute('title');\n        el.removeAttribute('title');\n      }\n\n      if (el.getAttribute('content') && !opts.content) {\n        opts.content = el.getAttribute('content');\n      }\n\n      if (el.$tippy) {\n        el.$tippy.setProps(opts || {});\n      } else if (el._tippy) {\n        el._tippy.setProps(opts || {});\n      }\n    },\n  };\n  return directive;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/tippy/index.ts",
    "content": "import type { DefaultProps, Props } from 'tippy.js';\n\nimport type { App, SetupContext } from 'vue';\n\nimport { h, watchEffect } from 'vue';\nimport { setDefaultProps, Tippy as TippyComponent } from 'vue-tippy';\n\nimport { usePreferences } from '@vben-core/preferences';\n\nimport useTippyDirective from './directive';\n\nimport 'tippy.js/dist/tippy.css';\nimport 'tippy.js/dist/backdrop.css';\nimport 'tippy.js/themes/light.css';\nimport 'tippy.js/animations/scale.css';\nimport 'tippy.js/animations/shift-toward.css';\nimport 'tippy.js/animations/shift-away.css';\nimport 'tippy.js/animations/perspective.css';\n\nconst { isDark } = usePreferences();\nexport type TippyProps = Partial<\n  Props & {\n    animation?:\n      | 'fade'\n      | 'perspective'\n      | 'scale'\n      | 'shift-away'\n      | 'shift-toward'\n      | boolean;\n    theme?: 'auto' | 'dark' | 'light';\n  }\n>;\n\nexport function initTippy(app: App<Element>, options?: DefaultProps) {\n  setDefaultProps({\n    allowHTML: true,\n    delay: [500, 200],\n    theme: isDark.value ? '' : 'light',\n    ...options,\n  });\n  if (!options || !Reflect.has(options, 'theme') || options.theme === 'auto') {\n    watchEffect(() => {\n      setDefaultProps({ theme: isDark.value ? '' : 'light' });\n    });\n  }\n\n  app.directive('tippy', useTippyDirective(isDark));\n}\n\nexport const Tippy = (props: any, { attrs, slots }: SetupContext) => {\n  let theme: string = (attrs.theme as string) ?? 'auto';\n  if (theme === 'auto') {\n    theme = isDark.value ? '' : 'light';\n  }\n  if (theme === 'dark') {\n    theme = '';\n  }\n  return h(\n    TippyComponent,\n    {\n      ...props,\n      ...attrs,\n      theme,\n    },\n    slots,\n  );\n};\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/tree/index.ts",
    "content": "export { default as Tree } from './tree.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/components/tree/tree.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TreeProps } from '@vben-core/shadcn-ui';\n\nimport { Inbox } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport { treePropsDefaults, VbenTree } from '@vben-core/shadcn-ui';\n\nconst props = withDefaults(defineProps<TreeProps>(), treePropsDefaults());\n</script>\n\n<template>\n  <VbenTree v-if=\"props.treeData?.length > 0\" v-bind=\"props\">\n    <template v-for=\"(_, key) in $slots\" :key=\"key\" #[key]=\"slotProps\">\n      <slot :name=\"key\" v-bind=\"slotProps\"> </slot>\n    </template>\n  </VbenTree>\n  <div\n    v-else\n    class=\"flex-col-center text-muted-foreground cursor-pointer rounded-lg border p-10 text-sm font-medium\"\n  >\n    <Inbox class=\"size-10\" />\n    <div class=\"mt-1\">{{ $t('common.noData') }}</div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/index.ts",
    "content": "export * from './components';\nexport * from './ui';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/about/about.ts",
    "content": "import type { Component } from 'vue';\n\ninterface AboutProps {\n  description?: string;\n  name?: string;\n  title?: string;\n}\n\ninterface DescriptionItem {\n  content: Component | string;\n  title: string;\n}\n\nexport type { AboutProps, DescriptionItem };\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/about/about.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AboutProps, DescriptionItem } from './about';\n\nimport { h } from 'vue';\n\nimport {\n  VBEN_DOC_URL,\n  VBEN_GITHUB_URL,\n  VBEN_PREVIEW_URL,\n} from '@vben/constants';\n\nimport { VbenRenderContent } from '@vben-core/shadcn-ui';\n\nimport { Page } from '../../components';\n\ninterface Props extends AboutProps {}\n\ndefineOptions({\n  name: 'AboutUI',\n});\n\nwithDefaults(defineProps<Props>(), {\n  description:\n    '是一个现代化开箱即用的中后台解决方案，采用最新的技术栈，包括 Vue 3.0、Vite、TailwindCSS 和 TypeScript 等前沿技术，代码规范严谨，提供丰富的配置选项，旨在为中大型项目的开发提供现成的开箱即用解决方案及丰富的示例，同时，它也是学习和深入前端技术的一个极佳示例。',\n  name: 'Vben Admin',\n  title: '关于项目',\n});\n\ndeclare global {\n  const __VBEN_ADMIN_METADATA__: {\n    authorEmail: string;\n    authorName: string;\n    authorUrl: string;\n    buildTime: string;\n    dependencies: Record<string, string>;\n    description: string;\n    devDependencies: Record<string, string>;\n    homepage: string;\n    license: string;\n    repositoryUrl: string;\n    version: string;\n  };\n}\n\nconst renderLink = (href: string, text: string) =>\n  h(\n    'a',\n    { href, target: '_blank', class: 'vben-link' },\n    { default: () => text },\n  );\n\nconst {\n  authorEmail,\n  authorName,\n  authorUrl,\n  buildTime,\n  dependencies = {},\n  devDependencies = {},\n  homepage,\n  license,\n  version,\n  // vite inject-metadata 插件注入的全局变量\n} = __VBEN_ADMIN_METADATA__ || {};\n\nconst vbenDescriptionItems: DescriptionItem[] = [\n  {\n    content: version,\n    title: '版本号',\n  },\n  {\n    content: license,\n    title: '开源许可协议',\n  },\n  {\n    content: buildTime,\n    title: '最后构建时间',\n  },\n  {\n    content: renderLink(homepage, '点击查看'),\n    title: '主页',\n  },\n  {\n    content: renderLink(VBEN_DOC_URL, '点击查看'),\n    title: '文档地址',\n  },\n  {\n    content: renderLink(VBEN_PREVIEW_URL, '点击查看'),\n    title: '预览地址',\n  },\n  {\n    content: renderLink(VBEN_GITHUB_URL, '点击查看'),\n    title: 'Github',\n  },\n  {\n    content: h('div', [\n      renderLink(authorUrl, `${authorName}  `),\n      renderLink(`mailto:${authorEmail}`, authorEmail),\n    ]),\n    title: '作者',\n  },\n];\n\nconst dependenciesItems = Object.keys(dependencies).map((key) => ({\n  content: dependencies[key],\n  title: key,\n}));\n\nconst devDependenciesItems = Object.keys(devDependencies).map((key) => ({\n  content: devDependencies[key],\n  title: key,\n}));\n</script>\n\n<template>\n  <Page :title=\"title\">\n    <template #description>\n      <p class=\"text-foreground mt-3 text-sm leading-6\">\n        <a :href=\"VBEN_GITHUB_URL\" class=\"vben-link\" target=\"_blank\">\n          {{ name }}\n        </a>\n        {{ description }}\n      </p>\n    </template>\n    <div class=\"card-box p-5\">\n      <div>\n        <h5 class=\"text-foreground text-lg\">基本信息</h5>\n      </div>\n      <div class=\"mt-4\">\n        <dl class=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4\">\n          <template v-for=\"item in vbenDescriptionItems\" :key=\"item.title\">\n            <div class=\"border-border border-t px-4 py-6 sm:col-span-1 sm:px-0\">\n              <dt class=\"text-foreground text-sm font-medium leading-6\">\n                {{ item.title }}\n              </dt>\n              <dd class=\"text-foreground mt-1 text-sm leading-6 sm:mt-2\">\n                <VbenRenderContent :content=\"item.content\" />\n              </dd>\n            </div>\n          </template>\n        </dl>\n      </div>\n    </div>\n\n    <div class=\"card-box mt-6 p-5\">\n      <div>\n        <h5 class=\"text-foreground text-lg\">生产环境依赖</h5>\n      </div>\n      <div class=\"mt-4\">\n        <dl class=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4\">\n          <template v-for=\"item in dependenciesItems\" :key=\"item.title\">\n            <div class=\"border-border border-t px-4 py-3 sm:col-span-1 sm:px-0\">\n              <dt class=\"text-foreground text-sm\">\n                {{ item.title }}\n              </dt>\n              <dd class=\"text-foreground/80 mt-1 text-sm sm:mt-2\">\n                <VbenRenderContent :content=\"item.content\" />\n              </dd>\n            </div>\n          </template>\n        </dl>\n      </div>\n    </div>\n    <div class=\"card-box mt-6 p-5\">\n      <div>\n        <h5 class=\"text-foreground text-lg\">开发环境依赖</h5>\n      </div>\n      <div class=\"mt-4\">\n        <dl class=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4\">\n          <template v-for=\"item in devDependenciesItems\" :key=\"item.title\">\n            <div class=\"border-border border-t px-4 py-3 sm:col-span-1 sm:px-0\">\n              <dt class=\"text-foreground text-sm\">\n                {{ item.title }}\n              </dt>\n              <dd class=\"text-foreground/80 mt-1 text-sm sm:mt-2\">\n                <VbenRenderContent :content=\"item.content\" />\n              </dd>\n            </div>\n          </template>\n        </dl>\n      </div>\n    </div>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/about/index.ts",
    "content": "export { default as About } from './about.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/auth-title.vue",
    "content": "<template>\n  <div class=\"mb-7 sm:mx-auto sm:w-full sm:max-w-md\">\n    <h2\n      class=\"text-foreground mb-3 text-3xl font-bold leading-9 tracking-tight lg:text-4xl\"\n    >\n      <slot></slot>\n    </h2>\n\n    <p class=\"text-muted-foreground lg:text-md text-sm\">\n      <slot name=\"desc\"></slot>\n    </p>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/code-login.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Recordable } from '@vben/types';\n\nimport type { VbenFormSchema } from '@vben-core/form-ui';\n\nimport { computed, reactive } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { $t } from '@vben/locales';\n\nimport { useVbenForm } from '@vben-core/form-ui';\nimport { VbenButton } from '@vben-core/shadcn-ui';\n\nimport Title from './auth-title.vue';\n\ninterface Props {\n  formSchema: VbenFormSchema[];\n  /**\n   * @zh_CN 是否处于加载处理状态\n   */\n  loading?: boolean;\n  /**\n   * @zh_CN 登录路径\n   */\n  loginPath?: string;\n  /**\n   * @zh_CN 标题\n   */\n  title?: string;\n  /**\n   * @zh_CN 描述\n   */\n  subTitle?: string;\n  /**\n   * @zh_CN 按钮文本\n   */\n  submitButtonText?: string;\n  /**\n   * @zh_CN 是否显示返回按钮\n   */\n  showBack?: boolean;\n}\n\ndefineOptions({\n  name: 'AuthenticationCodeLogin',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  loading: false,\n  showBack: true,\n  loginPath: '/auth/login',\n  submitButtonText: '',\n  subTitle: '',\n  title: '',\n});\n\nconst emit = defineEmits<{\n  submit: [Recordable<any>];\n}>();\n\nconst router = useRouter();\n\nconst [Form, formApi] = useVbenForm(\n  reactive({\n    commonConfig: {\n      hideLabel: true,\n      hideRequiredMark: true,\n    },\n    schema: computed(() => props.formSchema),\n    showDefaultActions: false,\n  }),\n);\n\nasync function handleSubmit() {\n  const { valid } = await formApi.validate();\n  const values = await formApi.getValues();\n  if (valid) {\n    emit('submit', values);\n  }\n}\n\nfunction goToLogin() {\n  router.push(props.loginPath);\n}\n\ndefineExpose({\n  getFormApi: () => formApi,\n});\n</script>\n\n<template>\n  <div>\n    <Title>\n      <slot name=\"title\">\n        {{ title || $t('authentication.welcomeBack') }} 📲\n      </slot>\n      <template #desc>\n        <span class=\"text-muted-foreground\">\n          <slot name=\"subTitle\">\n            {{ subTitle || $t('authentication.codeSubtitle') }}\n          </slot>\n        </span>\n      </template>\n    </Title>\n    <Form />\n    <VbenButton\n      :class=\"{\n        'cursor-wait': loading,\n      }\"\n      :loading=\"loading\"\n      class=\"w-full\"\n      @click=\"handleSubmit\"\n    >\n      <slot name=\"submitButtonText\">\n        {{ submitButtonText || $t('common.login') }}\n      </slot>\n    </VbenButton>\n    <VbenButton\n      v-if=\"showBack\"\n      class=\"mt-4 w-full\"\n      variant=\"outline\"\n      @click=\"goToLogin()\"\n    >\n      {{ $t('common.back') }}\n    </VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/dingding-login.vue",
    "content": "<script setup lang=\"ts\">\nimport { useRoute } from 'vue-router';\n\nimport { SvgDingDingIcon } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport { alert, useVbenModal } from '@vben-core/popup-ui';\nimport { VbenIconButton } from '@vben-core/shadcn-ui';\nimport { loadScript } from '@vben-core/shared/utils';\n\ninterface Props {\n  clientId: string;\n  corpId: string;\n  // 登录回调地址\n  redirectUri?: string;\n  // 是否内嵌二维码登录\n  isQrCode?: boolean;\n}\n\nconst props = defineProps<Props>();\n\nconst route = useRoute();\n\nconst [Modal, modalApi] = useVbenModal({\n  header: false,\n  footer: false,\n  fullscreenButton: false,\n  class: 'w-[302px] h-[302px] dingding-qrcode-login-modal',\n  onOpened() {\n    handleQrCodeLogin();\n  },\n});\n\nconst getRedirectUri = () => {\n  const { redirectUri } = props;\n  if (redirectUri) {\n    return redirectUri;\n  }\n  return window.location.origin + route.fullPath;\n};\n\n/**\n * 内嵌二维码登录\n */\nconst handleQrCodeLogin = async () => {\n  const { clientId, corpId } = props;\n  if (!(window as any).DTFrameLogin) {\n    // 二维码登录 加载资源\n    await loadScript(\n      'https://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js',\n    );\n  }\n  (window as any).DTFrameLogin(\n    {\n      id: 'dingding_qrcode_login_element',\n      width: 300,\n      height: 300,\n    },\n    {\n      // 注意：redirect_uri 需为完整URL，扫码后钉钉会带code跳转到这里\n      redirect_uri: encodeURIComponent(getRedirectUri()),\n      client_id: clientId,\n      scope: 'openid corpid',\n      response_type: 'code',\n      state: '1',\n      prompt: 'consent',\n      corpId,\n    },\n    (loginResult: any) => {\n      const { redirectUrl } = loginResult;\n      // 这里可以直接进行重定向\n      window.location.href = redirectUrl;\n    },\n    (errorMsg: string) => {\n      // 这里一般需要展示登录失败的具体原因\n      alert(`Login Error: ${errorMsg}`);\n    },\n  );\n};\n\nconst handleLogin = () => {\n  const { clientId, corpId, isQrCode } = props;\n  if (isQrCode) {\n    // 内嵌二维码登录\n    modalApi.open();\n  } else {\n    window.location.href = `https://login.dingtalk.com/oauth2/auth?redirect_uri=${encodeURIComponent(getRedirectUri())}&response_type=code&client_id=${clientId}&scope=openid&corpid=${corpId}&prompt=consent`;\n  }\n};\n</script>\n\n<template>\n  <div>\n    <VbenIconButton\n      @click=\"handleLogin\"\n      :tooltip=\"$t('authentication.dingdingLogin')\"\n      tooltip-side=\"top\"\n    >\n      <SvgDingDingIcon />\n    </VbenIconButton>\n    <Modal>\n      <div id=\"dingding_qrcode_login_element\"></div>\n    </Modal>\n  </div>\n</template>\n\n<style>\n.dingding-qrcode-login-modal {\n  .relative {\n    padding: 0 !important;\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/forget-password.vue",
    "content": "<script setup lang=\"ts\">\nimport type { VbenFormSchema } from '@vben-core/form-ui';\n\nimport { computed, reactive } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { $t } from '@vben/locales';\n\nimport { useVbenForm } from '@vben-core/form-ui';\nimport { VbenButton } from '@vben-core/shadcn-ui';\n\nimport Title from './auth-title.vue';\n\ninterface Props {\n  formSchema: VbenFormSchema[];\n  /**\n   * @zh_CN 是否处于加载处理状态\n   */\n  loading?: boolean;\n  /**\n   * @zh_CN 登录路径\n   */\n  loginPath?: string;\n  /**\n   * @zh_CN 标题\n   */\n  title?: string;\n  /**\n   * @zh_CN 描述\n   */\n  subTitle?: string;\n  /**\n   * @zh_CN 按钮文本\n   */\n  submitButtonText?: string;\n}\n\ndefineOptions({\n  name: 'ForgetPassword',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  loading: false,\n  loginPath: '/auth/login',\n  submitButtonText: '',\n  subTitle: '',\n  title: '',\n});\n\nconst emit = defineEmits<{\n  submit: [Record<string, any>];\n}>();\n\nconst [Form, formApi] = useVbenForm(\n  reactive({\n    commonConfig: {\n      hideLabel: true,\n      hideRequiredMark: true,\n    },\n    schema: computed(() => props.formSchema),\n    showDefaultActions: false,\n  }),\n);\n\nconst router = useRouter();\n\nasync function handleSubmit() {\n  const { valid } = await formApi.validate();\n  const values = await formApi.getValues();\n  if (valid) {\n    emit('submit', values);\n  }\n}\n\nfunction goToLogin() {\n  router.push(props.loginPath);\n}\n\ndefineExpose({\n  getFormApi: () => formApi,\n});\n</script>\n\n<template>\n  <div>\n    <Title>\n      <slot name=\"title\">\n        {{ title || $t('authentication.forgetPassword') }} 🤦🏻‍♂️\n      </slot>\n      <template #desc>\n        <slot name=\"subTitle\">\n          {{ subTitle || $t('authentication.forgetPasswordSubtitle') }}\n        </slot>\n      </template>\n    </Title>\n    <Form />\n\n    <div>\n      <VbenButton\n        :class=\"{\n          'cursor-wait': loading,\n        }\"\n        aria-label=\"submit\"\n        class=\"mt-2 w-full\"\n        @click=\"handleSubmit\"\n      >\n        <slot name=\"submitButtonText\">\n          {{ submitButtonText || $t('authentication.sendResetLink') }}\n        </slot>\n      </VbenButton>\n      <VbenButton class=\"mt-4 w-full\" variant=\"outline\" @click=\"goToLogin()\">\n        {{ $t('common.back') }}\n      </VbenButton>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/index.ts",
    "content": "export { default as AuthenticationCodeLogin } from './code-login.vue';\nexport { default as AuthenticationForgetPassword } from './forget-password.vue';\nexport { default as AuthenticationLoginExpiredModal } from './login-expired-modal.vue';\nexport { default as AuthenticationLogin } from './login.vue';\nexport { default as AuthenticationQrCodeLogin } from './qrcode-login.vue';\nexport { default as AuthenticationRegister } from './register.vue';\nexport type { AuthenticationProps } from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AuthenticationProps } from './types';\n\nimport { computed, watch } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport { useVbenModal } from '@vben-core/popup-ui';\nimport { Slot, VbenAvatar } from '@vben-core/shadcn-ui';\n\ninterface Props extends AuthenticationProps {\n  avatar?: string;\n  zIndex?: number;\n}\n\ndefineOptions({\n  name: 'LoginExpiredModal',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  avatar: '',\n  zIndex: 0,\n});\n\nconst open = defineModel<boolean>('open');\n\nconst [Modal, modalApi] = useVbenModal();\n\nwatch(\n  () => open.value,\n  (val) => {\n    modalApi.setState({ isOpen: val });\n  },\n);\n\nconst getZIndex = computed(() => {\n  return props.zIndex || calcZIndex();\n});\n\n/**\n * 排除ant-message和loading:9999的z-index\n */\nconst zIndexExcludeClass = ['ant-message', 'loading'];\nfunction isZIndexExcludeClass(element: Element) {\n  return zIndexExcludeClass.some((className) =>\n    element.classList.contains(className),\n  );\n}\n\n/**\n * 获取最大的zIndex值\n */\nfunction calcZIndex() {\n  let maxZ = 0;\n  const elements = document.querySelectorAll('*');\n  [...elements].forEach((element) => {\n    const style = window.getComputedStyle(element);\n    const zIndex = style.getPropertyValue('z-index');\n    if (\n      zIndex &&\n      !Number.isNaN(Number.parseInt(zIndex)) &&\n      !isZIndexExcludeClass(element)\n    ) {\n      maxZ = Math.max(maxZ, Number.parseInt(zIndex));\n    }\n  });\n  return maxZ + 1;\n}\n</script>\n\n<template>\n  <div>\n    <Modal\n      :closable=\"false\"\n      :close-on-click-modal=\"false\"\n      :close-on-press-escape=\"false\"\n      :footer=\"false\"\n      :fullscreen-button=\"false\"\n      :header=\"false\"\n      :z-index=\"getZIndex\"\n      class=\"border-none px-10 py-6 text-center shadow-xl sm:w-[600px] sm:rounded-2xl md:h-[unset]\"\n    >\n      <VbenAvatar :src=\"avatar\" class=\"mx-auto mb-6 size-20\" />\n      <Slot\n        :show-forget-password=\"false\"\n        :show-register=\"false\"\n        :show-remember-me=\"false\"\n        :sub-title=\"$t('authentication.loginAgainSubTitle')\"\n        :title=\"$t('authentication.loginAgainTitle')\"\n      >\n        <slot> </slot>\n      </Slot>\n    </Modal>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/login.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Recordable } from '@vben/types';\n\nimport type { VbenFormSchema } from '@vben-core/form-ui';\n\nimport type { AuthenticationProps } from './types';\n\nimport { computed, onMounted, reactive, ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { $t } from '@vben/locales';\n\nimport { useVbenForm } from '@vben-core/form-ui';\nimport { VbenButton, VbenCheckbox } from '@vben-core/shadcn-ui';\n\nimport Title from './auth-title.vue';\nimport ThirdPartyLogin from './third-party-login.vue';\n\ninterface Props extends AuthenticationProps {\n  formSchema?: VbenFormSchema[];\n}\n\ndefineOptions({\n  name: 'AuthenticationLogin',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  codeLoginPath: '/auth/code-login',\n  forgetPasswordPath: '/auth/forget-password',\n  formSchema: () => [],\n  loading: false,\n  qrCodeLoginPath: '/auth/qrcode-login',\n  registerPath: '/auth/register',\n  showCodeLogin: true,\n  showForgetPassword: true,\n  showQrcodeLogin: true,\n  showRegister: true,\n  showRememberMe: true,\n  showThirdPartyLogin: true,\n  submitButtonText: '',\n  subTitle: '',\n  title: '',\n});\n\nconst emit = defineEmits<{\n  submit: [Recordable<any>];\n}>();\n\nconst [Form, formApi] = useVbenForm(\n  reactive({\n    commonConfig: {\n      hideLabel: true,\n      hideRequiredMark: true,\n    },\n    schema: computed(() => props.formSchema),\n    showDefaultActions: false,\n  }),\n);\nconst router = useRouter();\n\nconst REMEMBER_ME_KEY = `REMEMBER_ME_USERNAME_${location.hostname}`;\n\nconst localUsername = localStorage.getItem(REMEMBER_ME_KEY) || '';\n\nconst rememberMe = ref(!!localUsername);\n\nasync function handleSubmit() {\n  const { valid } = await formApi.validate();\n  const values = await formApi.getValues();\n  if (valid) {\n    localStorage.setItem(\n      REMEMBER_ME_KEY,\n      rememberMe.value ? values?.username : '',\n    );\n    emit('submit', values);\n  }\n}\n\nfunction handleGo(path: string) {\n  router.push(path);\n}\n\nonMounted(() => {\n  if (localUsername) {\n    formApi.setFieldValue('username', localUsername);\n  }\n});\n\ndefineExpose({\n  getFormApi: () => formApi,\n});\n</script>\n\n<template>\n  <div @keydown.enter.prevent=\"handleSubmit\">\n    <slot name=\"title\">\n      <Title>\n        <slot name=\"title\">\n          {{ title || `${$t('authentication.welcomeBack')} 👋🏻` }}\n        </slot>\n        <template #desc>\n          <span class=\"text-muted-foreground\">\n            <slot name=\"subTitle\">\n              {{ subTitle || $t('authentication.loginSubtitle') }}\n            </slot>\n          </span>\n        </template>\n      </Title>\n    </slot>\n\n    <Form />\n\n    <div\n      v-if=\"showRememberMe || showForgetPassword\"\n      class=\"mb-6 flex justify-between\"\n    >\n      <div class=\"flex-center\">\n        <VbenCheckbox\n          v-if=\"showRememberMe\"\n          v-model:checked=\"rememberMe\"\n          name=\"rememberMe\"\n        >\n          {{ $t('authentication.rememberMe') }}\n        </VbenCheckbox>\n      </div>\n\n      <span\n        v-if=\"showForgetPassword\"\n        class=\"vben-link text-sm font-normal\"\n        @click=\"handleGo(forgetPasswordPath)\"\n      >\n        {{ $t('authentication.forgetPassword') }}\n      </span>\n    </div>\n    <VbenButton\n      :class=\"{\n        'cursor-wait': loading,\n      }\"\n      :loading=\"loading\"\n      aria-label=\"login\"\n      class=\"w-full\"\n      @click=\"handleSubmit\"\n    >\n      {{ submitButtonText || $t('common.login') }}\n    </VbenButton>\n\n    <div\n      v-if=\"showCodeLogin || showQrcodeLogin\"\n      class=\"mb-2 mt-4 flex items-center justify-between\"\n    >\n      <VbenButton\n        v-if=\"showCodeLogin\"\n        class=\"w-1/2\"\n        variant=\"outline\"\n        @click=\"handleGo(codeLoginPath)\"\n      >\n        {{ $t('authentication.mobileLogin') }}\n      </VbenButton>\n      <VbenButton\n        v-if=\"showQrcodeLogin\"\n        class=\"ml-4 w-1/2\"\n        variant=\"outline\"\n        @click=\"handleGo(qrCodeLoginPath)\"\n      >\n        {{ $t('authentication.qrcodeLogin') }}\n      </VbenButton>\n    </div>\n\n    <!-- 第三方登录 -->\n    <slot name=\"third-party-login\">\n      <ThirdPartyLogin v-if=\"showThirdPartyLogin\" />\n    </slot>\n\n    <slot name=\"to-register\">\n      <div v-if=\"showRegister\" class=\"mt-3 text-center text-sm\">\n        {{ $t('authentication.accountTip') }}\n        <span\n          class=\"vben-link text-sm font-normal\"\n          @click=\"handleGo(registerPath)\"\n        >\n          {{ $t('authentication.createAccount') }}\n        </span>\n      </div>\n    </slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { $t } from '@vben/locales';\n\nimport { VbenButton } from '@vben-core/shadcn-ui';\n\nimport { useQRCode } from '@vueuse/integrations/useQRCode';\n\nimport Title from './auth-title.vue';\n\ninterface Props {\n  /**\n   * @zh_CN 是否处于加载处理状态\n   */\n  loading?: boolean;\n  /**\n   * @zh_CN 登录路径\n   */\n  loginPath?: string;\n  /**\n   * @zh_CN 标题\n   */\n  title?: string;\n  /**\n   * @zh_CN 描述\n   */\n  subTitle?: string;\n  /**\n   * @zh_CN 按钮文本\n   */\n  submitButtonText?: string;\n  /**\n   * @zh_CN 描述\n   */\n  description?: string;\n  /**\n   * @zh_CN 是否显示返回按钮\n   */\n  showBack?: boolean;\n}\n\ndefineOptions({\n  name: 'AuthenticationQrCodeLogin',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  description: '',\n  loading: false,\n  showBack: true,\n  loginPath: '/auth/login',\n  submitButtonText: '',\n  subTitle: '',\n  title: '',\n});\n\nconst router = useRouter();\n\nconst text = ref('https://vben.vvbin.cn');\n\nconst qrcode = useQRCode(text, {\n  errorCorrectionLevel: 'H',\n  margin: 4,\n});\n\nfunction goToLogin() {\n  router.push(props.loginPath);\n}\n</script>\n\n<template>\n  <div>\n    <Title>\n      <slot name=\"title\">\n        {{ title || $t('authentication.welcomeBack') }} 📱\n      </slot>\n      <template #desc>\n        <span class=\"text-muted-foreground\">\n          <slot name=\"subTitle\">\n            {{ subTitle || $t('authentication.qrcodeSubtitle') }}\n          </slot>\n        </span>\n      </template>\n    </Title>\n\n    <div class=\"flex-col-center mt-6\">\n      <img :src=\"qrcode\" alt=\"qrcode\" class=\"w-1/2\" />\n      <p class=\"text-muted-foreground mt-4 text-sm\">\n        <slot name=\"description\">\n          {{ description || $t('authentication.qrcodePrompt') }}\n        </slot>\n      </p>\n    </div>\n\n    <VbenButton\n      v-if=\"showBack\"\n      class=\"mt-4 w-full\"\n      variant=\"outline\"\n      @click=\"goToLogin()\"\n    >\n      {{ $t('common.back') }}\n    </VbenButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/register.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Recordable } from '@vben/types';\n\nimport type { VbenFormSchema } from '@vben-core/form-ui';\n\nimport { computed, reactive } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { $t } from '@vben/locales';\n\nimport { useVbenForm } from '@vben-core/form-ui';\nimport { VbenButton } from '@vben-core/shadcn-ui';\n\nimport Title from './auth-title.vue';\n\ninterface Props {\n  formSchema?: VbenFormSchema[];\n  /**\n   * @zh_CN 是否处于加载处理状态\n   */\n  loading?: boolean;\n  /**\n   * @zh_CN 登录路径\n   */\n  loginPath?: string;\n  /**\n   * @zh_CN 标题\n   */\n  title?: string;\n  /**\n   * @zh_CN 描述\n   */\n  subTitle?: string;\n  /**\n   * @zh_CN 按钮文本\n   */\n  submitButtonText?: string;\n}\n\ndefineOptions({\n  name: 'RegisterForm',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  formSchema: () => [],\n  loading: false,\n  loginPath: '/auth/login',\n  submitButtonText: '',\n  subTitle: '',\n  title: '',\n});\n\nconst emit = defineEmits<{\n  submit: [Recordable<any>];\n}>();\n\nconst [Form, formApi] = useVbenForm(\n  reactive({\n    commonConfig: {\n      hideLabel: true,\n      hideRequiredMark: true,\n    },\n    schema: computed(() => props.formSchema),\n    showDefaultActions: false,\n  }),\n);\n\nconst router = useRouter();\n\nasync function handleSubmit() {\n  const { valid } = await formApi.validate();\n  const values = await formApi.getValues();\n  if (valid) {\n    emit('submit', values as { password: string; username: string });\n  }\n}\n\nfunction goToLogin() {\n  router.push(props.loginPath);\n}\n\ndefineExpose({\n  getFormApi: () => formApi,\n});\n</script>\n\n<template>\n  <div>\n    <Title>\n      <slot name=\"title\">\n        {{ title || $t('authentication.createAnAccount') }} 🚀\n      </slot>\n      <template #desc>\n        <slot name=\"subTitle\">\n          {{ subTitle || $t('authentication.signUpSubtitle') }}\n        </slot>\n      </template>\n    </Title>\n    <Form />\n\n    <VbenButton\n      :class=\"{\n        'cursor-wait': loading,\n      }\"\n      :loading=\"loading\"\n      aria-label=\"register\"\n      class=\"mt-2 w-full\"\n      @click=\"handleSubmit\"\n    >\n      <slot name=\"submitButtonText\">\n        {{ submitButtonText || $t('authentication.signUp') }}\n      </slot>\n    </VbenButton>\n    <div class=\"mt-4 text-center text-sm\">\n      {{ $t('authentication.alreadyHaveAccount') }}\n      <span class=\"vben-link text-sm font-normal\" @click=\"goToLogin()\">\n        {{ $t('authentication.goToLogin') }}\n      </span>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/third-party-login.vue",
    "content": "<script setup lang=\"ts\">\nimport { useAppConfig } from '@vben/hooks';\nimport {\n  SvgGithubIcon,\n  SvgGoogleIcon,\n  SvgQQChatIcon,\n  SvgWeChatIcon,\n} from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport { VbenIconButton } from '@vben-core/shadcn-ui';\n\nimport DingdingLogin from './dingding-login.vue';\n\ndefineOptions({\n  name: 'ThirdPartyLogin',\n});\n\nconst {\n  auth: { dingding: dingdingAuthConfig },\n} = useAppConfig(import.meta.env, import.meta.env.PROD);\n</script>\n\n<template>\n  <div class=\"w-full sm:mx-auto md:max-w-md\">\n    <div class=\"mt-4 flex items-center justify-between\">\n      <span class=\"border-input w-[35%] border-b dark:border-gray-600\"></span>\n      <span class=\"text-muted-foreground text-center text-xs uppercase\">\n        {{ $t('authentication.thirdPartyLogin') }}\n      </span>\n      <span class=\"border-input w-[35%] border-b dark:border-gray-600\"></span>\n    </div>\n\n    <div class=\"mt-4 flex flex-wrap justify-center\">\n      <VbenIconButton\n        :tooltip=\"$t('authentication.wechatLogin')\"\n        tooltip-side=\"top\"\n        class=\"mb-3\"\n      >\n        <SvgWeChatIcon />\n      </VbenIconButton>\n      <VbenIconButton\n        :tooltip=\"$t('authentication.qqLogin')\"\n        tooltip-side=\"top\"\n        class=\"mb-3\"\n      >\n        <SvgQQChatIcon />\n      </VbenIconButton>\n      <VbenIconButton\n        :tooltip=\"$t('authentication.githubLogin')\"\n        tooltip-side=\"top\"\n        class=\"mb-3\"\n      >\n        <SvgGithubIcon />\n      </VbenIconButton>\n      <VbenIconButton\n        :tooltip=\"$t('authentication.googleLogin')\"\n        tooltip-side=\"top\"\n        class=\"mb-3\"\n      >\n        <SvgGoogleIcon />\n      </VbenIconButton>\n      <DingdingLogin\n        v-if=\"dingdingAuthConfig\"\n        :corp-id=\"dingdingAuthConfig.corpId\"\n        :client-id=\"dingdingAuthConfig.clientId\"\n        class=\"mb-3\"\n      />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/authentication/types.ts",
    "content": "interface AuthenticationProps {\n  /**\n   * @zh_CN 验证码登录路径\n   */\n  codeLoginPath?: string;\n  /**\n   * @zh_CN 忘记密码路径\n   */\n  forgetPasswordPath?: string;\n\n  /**\n   * @zh_CN 是否处于加载处理状态\n   */\n  loading?: boolean;\n\n  /**\n   * @zh_CN 二维码登录路径\n   */\n  qrCodeLoginPath?: string;\n\n  /**\n   * @zh_CN 注册路径\n   */\n  registerPath?: string;\n\n  /**\n   * @zh_CN 是否显示验证码登录\n   */\n  showCodeLogin?: boolean;\n  /**\n   * @zh_CN 是否显示忘记密码\n   */\n  showForgetPassword?: boolean;\n\n  /**\n   * @zh_CN 是否显示二维码登录\n   */\n  showQrcodeLogin?: boolean;\n\n  /**\n   * @zh_CN 是否显示注册按钮\n   */\n  showRegister?: boolean;\n\n  /**\n   * @zh_CN 是否显示记住账号\n   */\n  showRememberMe?: boolean;\n\n  /**\n   * @zh_CN 是否显示第三方登录\n   */\n  showThirdPartyLogin?: boolean;\n\n  /**\n   * @zh_CN 登录框子标题\n   */\n  subTitle?: string;\n\n  /**\n   * @zh_CN 登录框标题\n   */\n  title?: string;\n  /**\n   * @zh_CN 提交按钮文本\n   */\n  submitButtonText?: string;\n}\n\nexport type { AuthenticationProps };\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue",
    "content": "<script setup lang=\"ts\">\nimport { Card, CardContent, CardHeader, CardTitle } from '@vben-core/shadcn-ui';\n\ninterface Props {\n  title: string;\n}\n\ndefineOptions({\n  name: 'AnalysisChartCard',\n});\n\nwithDefaults(defineProps<Props>(), {});\n</script>\n\n<template>\n  <Card>\n    <CardHeader>\n      <CardTitle class=\"text-xl\">{{ title }}</CardTitle>\n    </CardHeader>\n    <CardContent>\n      <slot></slot>\n    </CardContent>\n  </Card>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue",
    "content": "<script setup lang=\"ts\">\nimport type { TabOption } from '@vben/types';\n\nimport { computed } from 'vue';\n\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '@vben-core/shadcn-ui';\n\ninterface Props {\n  tabs?: TabOption[];\n}\n\ndefineOptions({\n  name: 'AnalysisChartsTabs',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  tabs: () => [],\n});\n\nconst defaultValue = computed(() => {\n  return props.tabs?.[0]?.value;\n});\n</script>\n\n<template>\n  <div class=\"card-box w-full px-4 pb-5 pt-3\">\n    <Tabs :default-value=\"defaultValue\">\n      <TabsList>\n        <template v-for=\"tab in tabs\" :key=\"tab.label\">\n          <TabsTrigger :value=\"tab.value\"> {{ tab.label }} </TabsTrigger>\n        </template>\n      </TabsList>\n      <template v-for=\"tab in tabs\" :key=\"tab.label\">\n        <TabsContent :value=\"tab.value\" class=\"pt-4\">\n          <slot :name=\"tab.value\"></slot>\n        </TabsContent>\n      </template>\n    </Tabs>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AnalysisOverviewItem } from '../typing';\n\nimport {\n  Card,\n  CardContent,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n  VbenCountToAnimator,\n  VbenIcon,\n} from '@vben-core/shadcn-ui';\n\ninterface Props {\n  items?: AnalysisOverviewItem[];\n}\n\ndefineOptions({\n  name: 'AnalysisOverview',\n});\n\nwithDefaults(defineProps<Props>(), {\n  items: () => [],\n});\n</script>\n\n<template>\n  <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4\">\n    <template v-for=\"item in items\" :key=\"item.title\">\n      <Card :title=\"item.title\" class=\"w-full\">\n        <CardHeader>\n          <CardTitle class=\"text-xl\">{{ item.title }}</CardTitle>\n        </CardHeader>\n\n        <CardContent class=\"flex items-center justify-between\">\n          <VbenCountToAnimator\n            :end-val=\"item.value\"\n            :start-val=\"1\"\n            class=\"text-xl\"\n            prefix=\"\"\n          />\n          <VbenIcon :icon=\"item.icon\" class=\"size-8 flex-shrink-0\" />\n        </CardContent>\n        <CardFooter class=\"justify-between\">\n          <span>{{ item.totalTitle }}</span>\n          <VbenCountToAnimator\n            :end-val=\"item.totalValue\"\n            :start-val=\"1\"\n            prefix=\"\"\n          />\n        </CardFooter>\n      </Card>\n    </template>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts",
    "content": "export { default as AnalysisChartCard } from './analysis-chart-card.vue';\nexport { default as AnalysisChartsTabs } from './analysis-charts-tabs.vue';\nexport { default as AnalysisOverview } from './analysis-overview.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/index.ts",
    "content": "export * from './analysis';\nexport type * from './typing';\nexport * from './workbench';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/typing.ts",
    "content": "import type { Component } from 'vue';\n\ninterface AnalysisOverviewItem {\n  icon: Component | string;\n  title: string;\n  totalTitle: string;\n  totalValue: number;\n  value: number;\n}\n\ninterface WorkbenchProjectItem {\n  color?: string;\n  content: string;\n  date: string;\n  group: string;\n  icon: Component | string;\n  title: string;\n  url?: string;\n}\n\ninterface WorkbenchTrendItem {\n  avatar: string;\n  content: string;\n  date: string;\n  title: string;\n}\n\ninterface WorkbenchTodoItem {\n  completed: boolean;\n  content: string;\n  date: string;\n  title: string;\n}\n\ninterface WorkbenchQuickNavItem {\n  color?: string;\n  icon: Component | string;\n  title: string;\n  url?: string;\n}\n\nexport type {\n  AnalysisOverviewItem,\n  WorkbenchProjectItem,\n  WorkbenchQuickNavItem,\n  WorkbenchTodoItem,\n  WorkbenchTrendItem,\n};\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts",
    "content": "export { default as WorkbenchHeader } from './workbench-header.vue';\nexport { default as WorkbenchProject } from './workbench-project.vue';\nexport { default as WorkbenchQuickNav } from './workbench-quick-nav.vue';\nexport { default as WorkbenchTodo } from './workbench-todo.vue';\nexport { default as WorkbenchTrends } from './workbench-trends.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue",
    "content": "<script lang=\"ts\" setup>\nimport { VbenAvatar } from '@vben-core/shadcn-ui';\n\ninterface Props {\n  avatar?: string;\n}\n\ndefineOptions({\n  name: 'WorkbenchHeader',\n});\n\nwithDefaults(defineProps<Props>(), {\n  avatar: '',\n});\n</script>\n<template>\n  <div class=\"card-box p-4 py-6 lg:flex\">\n    <VbenAvatar :src=\"avatar\" class=\"size-20\" />\n    <div\n      v-if=\"$slots.title || $slots.description\"\n      class=\"flex flex-col justify-center md:ml-6 md:mt-0\"\n    >\n      <h1 v-if=\"$slots.title\" class=\"text-md font-semibold md:text-xl\">\n        <slot name=\"title\"></slot>\n      </h1>\n      <span v-if=\"$slots.description\" class=\"text-foreground/80 mt-1\">\n        <slot name=\"description\"></slot>\n      </span>\n    </div>\n    <div class=\"mt-4 flex flex-1 justify-end md:mt-0\">\n      <div class=\"flex flex-col justify-center text-right\">\n        <span class=\"text-foreground/80\"> 待办 </span>\n        <span class=\"text-2xl\">2/10</span>\n      </div>\n\n      <div class=\"mx-12 flex flex-col justify-center text-right md:mx-16\">\n        <span class=\"text-foreground/80\"> 项目 </span>\n        <span class=\"text-2xl\">8</span>\n      </div>\n      <div class=\"mr-4 flex flex-col justify-center text-right md:mr-10\">\n        <span class=\"text-foreground/80\"> 团队 </span>\n        <span class=\"text-2xl\">300</span>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue",
    "content": "<script setup lang=\"ts\">\nimport type { WorkbenchProjectItem } from '../typing';\n\nimport {\n  Card,\n  CardContent,\n  CardHeader,\n  CardTitle,\n  VbenIcon,\n} from '@vben-core/shadcn-ui';\n\ninterface Props {\n  items?: WorkbenchProjectItem[];\n  title: string;\n}\n\ndefineOptions({\n  name: 'WorkbenchProject',\n});\n\nwithDefaults(defineProps<Props>(), {\n  items: () => [],\n});\n\ndefineEmits(['click']);\n</script>\n\n<template>\n  <Card>\n    <CardHeader class=\"py-4\">\n      <CardTitle class=\"text-lg\">{{ title }}</CardTitle>\n    </CardHeader>\n    <CardContent class=\"flex flex-wrap p-0\">\n      <template v-for=\"(item, index) in items\" :key=\"item.title\">\n        <div\n          :class=\"{\n            'border-r-0': index % 3 === 2,\n            'border-b-0': index < 3,\n            'pb-4': index > 2,\n            'rounded-bl-xl': index === items.length - 3,\n            'rounded-br-xl': index === items.length - 1,\n          }\"\n          class=\"border-border group w-full cursor-pointer border-r border-t p-4 transition-all hover:shadow-xl md:w-1/2 lg:w-1/3\"\n        >\n          <div class=\"flex items-center\">\n            <VbenIcon\n              :color=\"item.color\"\n              :icon=\"item.icon\"\n              class=\"size-8 transition-all duration-300 group-hover:scale-110\"\n              @click=\"$emit('click', item)\"\n            />\n            <span class=\"ml-4 text-lg font-medium\">{{ item.title }}</span>\n          </div>\n          <div class=\"text-foreground/80 mt-4 flex h-10\">\n            {{ item.content }}\n          </div>\n          <div class=\"text-foreground/80 flex justify-between\">\n            <span>{{ item.group }}</span>\n            <span>{{ item.date }}</span>\n          </div>\n        </div>\n      </template>\n    </CardContent>\n  </Card>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue",
    "content": "<script setup lang=\"ts\">\nimport type { WorkbenchQuickNavItem } from '../typing';\n\nimport {\n  Card,\n  CardContent,\n  CardHeader,\n  CardTitle,\n  VbenIcon,\n} from '@vben-core/shadcn-ui';\n\ninterface Props {\n  items?: WorkbenchQuickNavItem[];\n  title: string;\n}\n\ndefineOptions({\n  name: 'WorkbenchQuickNav',\n});\n\nwithDefaults(defineProps<Props>(), {\n  items: () => [],\n});\n\ndefineEmits(['click']);\n</script>\n\n<template>\n  <Card>\n    <CardHeader class=\"py-4\">\n      <CardTitle class=\"text-lg\">{{ title }}</CardTitle>\n    </CardHeader>\n    <CardContent class=\"flex flex-wrap p-0\">\n      <template v-for=\"(item, index) in items\" :key=\"item.title\">\n        <div\n          :class=\"{\n            'border-r-0': index % 3 === 2,\n            'border-b-0': index < 3,\n            'pb-4': index > 2,\n            'rounded-bl-xl': index === items.length - 3,\n            'rounded-br-xl': index === items.length - 1,\n          }\"\n          class=\"flex-col-center border-border group w-1/3 cursor-pointer border-r border-t py-8 hover:shadow-xl\"\n          @click=\"$emit('click', item)\"\n        >\n          <VbenIcon\n            :color=\"item.color\"\n            :icon=\"item.icon\"\n            class=\"size-7 transition-all duration-300 group-hover:scale-125\"\n          />\n          <span class=\"text-md mt-2 truncate\">{{ item.title }}</span>\n        </div>\n      </template>\n    </CardContent>\n  </Card>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue",
    "content": "<script setup lang=\"ts\">\nimport type { WorkbenchTodoItem } from '../typing';\n\nimport {\n  Card,\n  CardContent,\n  CardHeader,\n  CardTitle,\n  VbenCheckbox,\n} from '@vben-core/shadcn-ui';\n\ninterface Props {\n  items?: WorkbenchTodoItem[];\n  title: string;\n}\n\ndefineOptions({\n  name: 'WorkbenchTodo',\n});\n\nwithDefaults(defineProps<Props>(), {\n  items: () => [],\n});\n</script>\n\n<template>\n  <Card>\n    <CardHeader class=\"py-4\">\n      <CardTitle class=\"text-lg\">{{ title }}</CardTitle>\n    </CardHeader>\n    <CardContent class=\"flex flex-wrap p-5 pt-0\">\n      <ul class=\"divide-border w-full divide-y\" role=\"list\">\n        <li\n          v-for=\"item in items\"\n          :key=\"item.title\"\n          :class=\"{\n            'select-none line-through opacity-60': item.completed,\n          }\"\n          class=\"flex cursor-pointer justify-between gap-x-6 py-5\"\n        >\n          <div class=\"flex min-w-0 items-center gap-x-4\">\n            <VbenCheckbox v-model:checked=\"item.completed\" name=\"completed\" />\n            <div class=\"min-w-0 flex-auto\">\n              <p class=\"text-foreground text-sm font-semibold leading-6\">\n                {{ item.title }}\n              </p>\n              <!-- eslint-disable vue/no-v-html -->\n              <p\n                class=\"text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5\"\n                v-html=\"item.content\"\n              ></p>\n            </div>\n          </div>\n          <div class=\"hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end\">\n            <span class=\"text-foreground/80 mt-6 text-xs leading-6\">\n              {{ item.date }}\n            </span>\n          </div>\n        </li>\n      </ul>\n    </CardContent>\n  </Card>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue",
    "content": "<script setup lang=\"ts\">\nimport type { WorkbenchTrendItem } from '../typing';\n\nimport {\n  Card,\n  CardContent,\n  CardHeader,\n  CardTitle,\n  VbenIcon,\n} from '@vben-core/shadcn-ui';\n\ninterface Props {\n  items?: WorkbenchTrendItem[];\n  title: string;\n}\n\ndefineOptions({\n  name: 'WorkbenchTrends',\n});\n\nwithDefaults(defineProps<Props>(), {\n  items: () => [],\n});\n</script>\n\n<template>\n  <Card>\n    <CardHeader class=\"py-4\">\n      <CardTitle class=\"text-lg\">{{ title }}</CardTitle>\n    </CardHeader>\n    <CardContent class=\"flex flex-wrap p-5 pt-0\">\n      <ul class=\"divide-border w-full divide-y\" role=\"list\">\n        <li\n          v-for=\"item in items\"\n          :key=\"item.title\"\n          class=\"flex justify-between gap-x-6 py-5\"\n        >\n          <div class=\"flex min-w-0 items-center gap-x-4\">\n            <VbenIcon\n              :icon=\"item.avatar\"\n              alt=\"\"\n              class=\"size-10 flex-none rounded-full\"\n            />\n            <div class=\"min-w-0 flex-auto\">\n              <p class=\"text-foreground text-sm font-semibold leading-6\">\n                {{ item.title }}\n              </p>\n              <!-- eslint-disable vue/no-v-html -->\n              <p\n                class=\"text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5\"\n                v-html=\"item.content\"\n              ></p>\n            </div>\n          </div>\n          <div class=\"hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end\">\n            <span class=\"text-foreground/80 mt-6 text-xs leading-6\">\n              {{ item.date }}\n            </span>\n          </div>\n        </li>\n      </ul>\n    </CardContent>\n  </Card>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/fallback/fallback.ts",
    "content": "interface FallbackProps {\n  /**\n   * 描述\n   */\n  description?: string;\n  /**\n   *  @zh_CN 首页路由地址\n   *  @default /\n   */\n  homePath?: string;\n  /**\n   * @zh_CN 默认显示的图片\n   * @default pageNotFoundSvg\n   */\n  image?: string;\n  /**\n   *  @zh_CN 内置类型\n   */\n  status?: '403' | '404' | '500' | 'coming-soon' | 'offline';\n  /**\n   *  @zh_CN 页面提示语\n   */\n  title?: string;\n}\nexport type { FallbackProps };\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/fallback/fallback.vue",
    "content": "<script setup lang=\"ts\">\nimport type { FallbackProps } from './fallback';\n\nimport { computed, defineAsyncComponent } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { ArrowLeft, RotateCw } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport { VbenButton } from '@vben-core/shadcn-ui';\n\ninterface Props extends FallbackProps {}\n\ndefineOptions({\n  name: 'Fallback',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  description: '',\n  homePath: '/',\n  image: '',\n  showBack: true,\n  status: 'coming-soon',\n  title: '',\n});\n\nconst Icon403 = defineAsyncComponent(() => import('./icons/icon-403.vue'));\nconst Icon404 = defineAsyncComponent(() => import('./icons/icon-404.vue'));\nconst Icon500 = defineAsyncComponent(() => import('./icons/icon-500.vue'));\nconst IconHello = defineAsyncComponent(\n  () => import('./icons/icon-coming-soon.vue'),\n);\nconst IconOffline = defineAsyncComponent(\n  () => import('./icons/icon-offline.vue'),\n);\n\nconst titleText = computed(() => {\n  if (props.title) {\n    return props.title;\n  }\n\n  switch (props.status) {\n    case '403': {\n      return $t('ui.fallback.forbidden');\n    }\n    case '404': {\n      return $t('ui.fallback.pageNotFound');\n    }\n    case '500': {\n      return $t('ui.fallback.internalError');\n    }\n    case 'coming-soon': {\n      return $t('ui.fallback.comingSoon');\n    }\n    case 'offline': {\n      return $t('ui.fallback.offlineError');\n    }\n    default: {\n      return '';\n    }\n  }\n});\n\nconst descText = computed(() => {\n  if (props.description) {\n    return props.description;\n  }\n  switch (props.status) {\n    case '403': {\n      return $t('ui.fallback.forbiddenDesc');\n    }\n    case '404': {\n      return $t('ui.fallback.pageNotFoundDesc');\n    }\n    case '500': {\n      return $t('ui.fallback.internalErrorDesc');\n    }\n    case 'offline': {\n      return $t('ui.fallback.offlineErrorDesc');\n    }\n    default: {\n      return '';\n    }\n  }\n});\n\nconst fallbackIcon = computed(() => {\n  switch (props.status) {\n    case '403': {\n      return Icon403;\n    }\n    case '404': {\n      return Icon404;\n    }\n    case '500': {\n      return Icon500;\n    }\n    case 'coming-soon': {\n      return IconHello;\n    }\n    case 'offline': {\n      return IconOffline;\n    }\n    default: {\n      return null;\n    }\n  }\n});\n\nconst showBack = computed(() => {\n  return props.status === '403' || props.status === '404';\n});\n\nconst showRefresh = computed(() => {\n  return props.status === '500' || props.status === 'offline';\n});\n\nconst { push } = useRouter();\n\n// 返回首页\nfunction back() {\n  push(props.homePath);\n}\n\nfunction refresh() {\n  location.reload();\n}\n</script>\n\n<template>\n  <div class=\"flex size-full flex-col items-center justify-center duration-300\">\n    <img v-if=\"image\" :src=\"image\" class=\"md:1/3 w-1/2 lg:w-1/4\" />\n    <component\n      :is=\"fallbackIcon\"\n      v-else-if=\"fallbackIcon\"\n      class=\"md:1/3 h-1/3 w-1/2 lg:w-1/4\"\n    />\n    <div class=\"flex-col-center\">\n      <slot v-if=\"$slots.title\" name=\"title\"></slot>\n      <p\n        v-else-if=\"titleText\"\n        class=\"text-foreground mt-8 text-2xl md:text-3xl lg:text-4xl\"\n      >\n        {{ titleText }}\n      </p>\n      <slot v-if=\"$slots.describe\" name=\"describe\"></slot>\n      <p\n        v-else-if=\"descText\"\n        class=\"text-muted-foreground md:text-md my-4 lg:text-lg\"\n      >\n        {{ descText }}\n      </p>\n      <slot v-if=\"$slots.action\" name=\"action\"></slot>\n      <VbenButton v-else-if=\"showBack\" size=\"lg\" @click=\"back\">\n        <ArrowLeft class=\"mr-2 size-4\" />\n        {{ $t('common.backToHome') }}\n      </VbenButton>\n      <VbenButton v-else-if=\"showRefresh\" size=\"lg\" @click=\"refresh\">\n        <RotateCw class=\"mr-2 size-4\" />\n        {{ $t('common.refresh') }}\n      </VbenButton>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue",
    "content": "<template>\n  <svg\n    height=\"659.29778\"\n    viewBox=\"0 0 586 659.29778\"\n    width=\"586\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n  >\n    <circle cx=\"332.47856\" cy=\"254\" fill=\"#f2f2f2\" r=\"254.00001\" />\n    <path\n      d=\"M498.46363,113.58835H33.17063c-.99774-.02133-1.78931-.84746-1.76797-1.84521,.02069-.96771,.80026-1.74727,1.76797-1.76796H498.46363c.99774,.02133,1.78931,.84746,1.76794,1.84521-.02069,.96771-.80023,1.74727-1.76794,1.76796Z\"\n      fill=\"#cacaca\"\n    />\n    <rect\n      fill=\"#fff\"\n      height=\"34.98639\"\n      rx=\"17.49318\"\n      ry=\"17.49318\"\n      width=\"163.61147\"\n      x=\"193.77441\"\n      y=\"174.47256\"\n    />\n    <path\n      d=\"M128.17493,244.44534H422.98542c9.66122,0,17.49316,7.83197,17.49316,17.49319h0c0,9.66122-7.83194,17.49319-17.49316,17.49319H128.17493c-9.66122,0-17.49318-7.83197-17.49318-17.49319h0c0-9.66122,7.83196-17.49319,17.49318-17.49319Z\"\n      fill=\"#fff\"\n    />\n    <path\n      d=\"M128.17493,314.41812H422.98542c9.66122,0,17.49316,7.83197,17.49316,17.49319h0c0,9.66122-7.83194,17.49319-17.49316,17.49319H128.17493c-9.66122,0-17.49318-7.83197-17.49318-17.49319h0c0-9.66122,7.83196-17.49319,17.49318-17.49319Z\"\n      fill=\"#fff\"\n    />\n    <path\n      d=\"M91.64085,657.75932l-.69385-.06793c-23.54068-2.42871-44.82135-15.08929-58.18845-34.61835-3.66138-5.44159-6.62299-11.32251-8.815-17.50409l-.21069-.58966,.62375-.05048c7.44699-.59924,15.09732-1.86292,18.49585-2.46417l-21.91473-7.42511-.1355-.65033c-1.29926-6.10406,1.24612-12.38458,6.4285-15.86176,5.19641-3.64447,12.08731-3.76111,17.40405-.29449,2.38599,1.52399,4.88162,3.03339,7.29489,4.49359,8.29321,5.01636,16.8688,10.20337,23.29828,17.30121,9.74951,10.97778,14.02298,25.76984,11.63,40.25562l4.7829,17.47595Z\"\n      fill=\"#f2f2f2\"\n    />\n    <polygon\n      fill=\"#a0616a\"\n      points=\"171.30016 646.86102 182.10017 646.85999 187.23916 605.198 171.29716 605.19897 171.30016 646.86102\"\n    />\n    <path\n      d=\"M170.9192,658.12816l33.21436-.00122v-.41998c-.00049-7.13965-5.78833-12.92737-12.92798-12.92773h-.00079l-6.06702-4.60278-11.3197,4.60345-2.89941,.00012,.00055,13.34814Z\"\n      fill=\"#2f2e41\"\n    />\n    <polygon\n      fill=\"#a0616a\"\n      points=\"84.74116 616.94501 93.38016 623.42603 122.49316 593.185 109.74116 583.61902 84.74116 616.94501\"\n    />\n    <path\n      d=\"M77.67448,625.72966l26.569,19.93188,.25208-.336c4.2843-5.71136,3.12799-13.81433-2.58279-18.09937l-.00064-.00049-2.09079-7.32275-11.81735-3.11102-2.31931-1.73993-8.01019,10.67767Z\"\n      fill=\"#2f2e41\"\n    />\n    <path\n      d=\"M120.64463,451.35271s.59625,16.26422,1.3483,29.30737c.12335,2.13916-4.88821,4.46301-4.75842,6.7901,.08609,1.54395,1.02808,3.04486,1.1156,4.65472,.09235,1.69897-1.20822,3.20282-1.1156,4.95984,.09052,1.71667,1.57422,3.6853,1.66373,5.44244,.96317,18.9093,4.45459,41.54633,.9584,47.87439-1.72299,3.11871-23.68533,46.32446-23.68533,46.32446,0,0,12.23666,18.35498,15.73285,12.23663,4.61771-8.08099,40.20615-45.88745,40.20615-53.10712,0-7.21088,8.23346-61.25323,8.23346-61.25323l5.74103,31.98169,2.63239,6.33655-.82715,3.71997,1.70117,5.02045,.09192,4.96838,1.65619,9.22614s-4.98199,71.88159-2.17633,73.88312c2.81439,2.01038,16.44086,5.62018,18.04901,2.01038,1.59955-3.6098,12.0108-75.01947,12.0108-75.01947,0,0,1.6781-32.72424,3.49622-63.14111,.1048-1.76556,1.34607-3.89825,1.4422-5.63763,.11365-2.01898-.67297-4.64111-.56818-6.599,.11365-2.24628,1.11005-3.82831,1.20618-5.97852,.74292-16.6156-3.42761-36.84912-4.7561-38.84192-4.01202-6.01343-7.62177-10.82074-7.62177-10.82074,0,0-54.03558-17.75403-68.47485,.28625l-3.30185,25.37585Z\"\n      fill=\"#2f2e41\"\n    />\n    <path\n      d=\"M174.53779,284.10378l-21.4209-4.28418-9.9964,13.56656h0c-18.65262,18.34058-18.93359,34.52753-15.60379,60.47382v36.41553l-2.41,24.41187s-8.53156,17.84521,.26788,22.00006,66.59857,3.80066,72.117,2.14209,.73517-3.69482-.71399-11.4245c-2.72211-14.51929-.90131-7.51562-.71399-12.13849,2.68585-66.31363-3.57013-93.5379-4.20544-100.69376l-10.89398-19.75858-6.42639-10.71042Z\"\n      fill=\"#3f3d56\"\n    />\n    <path\n      d=\"M287.43909,337.57097c-2.23248,4.23007-7.47144,5.84943-11.70148,3.61694-.45099-.23804-.88013-.51541-1.28229-.82895l-46.26044,29.37308,.13336-15.9924,44.93842-26.07846c3.20093-3.58887,8.70514-3.90332,12.29401-.70239,3.00305,2.67844,3.7796,7.0657,1.87842,10.61218Z\"\n      fill=\"#a0616a\"\n    />\n    <path\n      d=\"M157.62488,302.62425l-5.26666-.55807c-4.86633-.50473-9.64093,1.57941-12.57947,5.491-1.12549,1.48346-1.9339,3.18253-2.37491,4.99164l-.00317,.01447c-1.32108,5.44534,.75095,11.15201,5.25803,14.48117l18.19031,13.41101c12.76544,17.24899,36.75653,28.69272,64.89832,37.98978l43.74274-27.16666-15.47186-18.73843-30.00336,16.0798-44.59833-34.52374-.0257-.02075-16.97424-10.936-4.79169-.5152Z\"\n      fill=\"#3f3d56\"\n    />\n    <circle cx=\"167.29993\" cy=\"248.60526\" fill=\"#a0616a\" r=\"24.9798\" />\n    <path\n      d=\"M167.8769,273.59047c-.20135,.00662-.4032,.01108-.6048,.01657-.0863,.22388-.17938,.44583-.2868,.66357l.8916-.68015Z\"\n      fill=\"#2f2e41\"\n    />\n    <path\n      d=\"M174.73243,249.29823c.03918,.24612,.09912,.48846,.17914,.72449-.03302-.24731-.09308-.49026-.17914-.72449Z\"\n      fill=\"#2f2e41\"\n    />\n    <path\n      d=\"M192.59852,224.6942c-1.0282,3.19272-1.94586-.85715-5.32825-.12869-4.06885,.87625-8.80377,.57532-12.13586-1.91879-4.96478-3.64273-11.39874-4.62335-17.22333-2.62509-5.70154,2.01706-15.25348,3.43933-16.73907,9.30179-.51642,2.03781-.7215,4.24933-1.97321,5.9382-1.09436,1.47662-2.82166,2.31854-4.26608,3.45499-4.87726,3.83743-1.14954,14.73981,1.15881,20.50046,2.30838,5.76065,7.60355,9.95721,13.42526,12.10678,5.63281,2.07977,11.7464,2.44662,17.75531,2.28317,1.04517-2.7106,.59363-5.84137-.26874-8.65134-.93359-3.04199-2.31592-5.97791-2.70593-9.13599s.46643-6.74527,3.11444-8.50986c2.4339-1.62192,6.39465-.63388,7.32062,1.98843-.54028-3.27841,2.7807-6.4509,6.20508-7.00882,3.67651-.599,7.35291,.72833,11.01886,1.38901s2.36475-14.77301,.64209-18.98425Z\"\n      fill=\"#2f2e41\"\n    />\n    <circle\n      cx=\"281.3585\"\n      cy=\"285.71051\"\n      fill=\"hsl(var(--primary))\"\n      r=\"51.12006\"\n      transform=\"translate(-26.58509 542.54478) rotate(-85.26884)\"\n    />\n    <path\n      d=\"M294.78675,264.41051l-13.42828,13.42828-13.42828-13.42828c-2.17371-2.17374-5.69806-2.17374-7.87177,0s-2.17371,5.69803,0,7.87177l13.42828,13.42828-13.42828,13.42828c-2.17169,2.17575-2.1684,5.70007,.00739,7.87177,2.17285,2.16879,5.69153,2.16879,7.86438-.00003l13.42828-13.42828,13.42828,13.42828c2.17578,2.17169,5.70007,2.1684,7.87177-.00735,2.16882-2.17288,2.16882-5.6915,0-7.86438l-13.42828-13.42828,13.42828-13.42828c2.17371-2.17374,2.17371-5.69803,0-7.87177s-5.69806-2.17374-7.87177,0h0Z\"\n      fill=\"#fff\"\n    />\n    <path\n      d=\"M261.21387,242.74385c1.5069,4.53946-.95154,9.44101-5.49097,10.94791-.48401,.16064-.9812,.27823-1.4859,.35141l-10.83051,53.71692-11.44788-11.16785,12.29266-50.48209c-.37366-4.7944,3.21008-8.98395,8.00452-9.3576,4.01166-.31265,7.71509,2.16425,8.95807,5.9913Z\"\n      fill=\"#a0616a\"\n    />\n    <path\n      d=\"M146.12519,312.22478l-4.04883,3.41412c-3.73322,3.16214-5.53476,8.05035-4.74649,12.87888,.29129,1.83917,.95773,3.59879,1.95786,5.16949l.00824,.0123c3.01477,4.72311,8.5672,7.17865,14.08978,6.23117l22.27075-3.84171c21.28461,2.72995,46.15155-6.65967,72.34302-20.53055l10.67969-50.37274-24.23297-1.80811-9.16821,32.78271-55.78815,8.28149-.03278,.00415-19.64294,4.67767-3.68896,3.1011Z\"\n      fill=\"#3f3d56\"\n    />\n    <path\n      d=\"M272.93684,658.99046l-271.75,.30731c-.65759-.00214-1.18896-.53693-1.18683-1.19452,.00211-.6546,.53223-1.18469,1.18683-1.18683l271.75-.30731c.65759,.00214,1.18896,.53693,1.18683,1.19452-.00208,.6546-.53223,1.18469-1.18683,1.18683Z\"\n      fill=\"#cacaca\"\n    />\n    <g>\n      <ellipse\n        cx=\"56.77685\"\n        cy=\"82.05834\"\n        fill=\"#3f3d56\"\n        rx=\"8.45661\"\n        ry=\"8.64507\"\n      />\n      <ellipse\n        cx=\"85.9906\"\n        cy=\"82.05834\"\n        fill=\"#3f3d56\"\n        rx=\"8.45661\"\n        ry=\"8.64507\"\n      />\n      <ellipse\n        cx=\"115.20435\"\n        cy=\"82.05834\"\n        fill=\"#3f3d56\"\n        rx=\"8.45661\"\n        ry=\"8.64507\"\n      />\n      <path\n        d=\"M148.51577,88.89113c-.25977,0-.51904-.10059-.71484-.30078l-5.70605-5.83301c-.38037-.38867-.38037-1.00977,0-1.39844l5.70605-5.83252c.38721-.39453,1.021-.40088,1.41406-.01562,.39502,.38623,.40186,1.01953,.01562,1.41406l-5.02197,5.1333,5.02197,5.13379c.38623,.39453,.37939,1.02783-.01562,1.41406-.19434,.19043-.44678,.28516-.69922,.28516Z\"\n        fill=\"#3f3d56\"\n      />\n      <path\n        d=\"M158.10415,88.89113c-.25244,0-.50488-.09473-.69922-.28516-.39502-.38623-.40186-1.01904-.01562-1.41406l5.02148-5.13379-5.02148-5.1333c-.38623-.39453-.37939-1.02783,.01562-1.41406,.39404-.38672,1.02783-.37939,1.41406,.01562l5.70557,5.83252c.38037,.38867,.38037,1.00977,0,1.39844l-5.70557,5.83301c-.1958,.2002-.45508,.30078-.71484,.30078Z\"\n        fill=\"#3f3d56\"\n      />\n      <path\n        d=\"M456.61398,74.41416h-10.60999c-1.21002,0-2.19,.97998-2.19,2.19v10.62c0,1.21002,.97998,2.19,2.19,2.19h10.60999c1.21002,0,2.20001-.97998,2.20001-2.19v-10.62c0-1.21002-.98999-2.19-2.20001-2.19Z\"\n        fill=\"#3f3d56\"\n      />\n      <path\n        d=\"M430.61398,74.41416h-10.60999c-1.21002,0-2.19,.97998-2.19,2.19v10.62c0,1.21002,.97998,2.19,2.19,2.19h10.60999c1.21002,0,2.20001-.97998,2.20001-2.19v-10.62c0-1.21002-.98999-2.19-2.20001-2.19Z\"\n        fill=\"#3f3d56\"\n      />\n      <path\n        d=\"M481.11398,74.91416h-10.60999c-1.21002,0-2.19,.97998-2.19,2.19v10.62c0,1.21002,.97998,2.19,2.19,2.19h10.60999c1.21002,0,2.20001-.97998,2.20001-2.19v-10.62c0-1.21002-.98999-2.19-2.20001-2.19Z\"\n        fill=\"#3f3d56\"\n      />\n      <path\n        d=\"M321.19229,78.95414h-84.81c-1.48004,0-2.67004,1.20001-2.67004,2.67004s1.19,2.66998,2.67004,2.66998h84.81c1.46997,0,2.66998-1.20001,2.66998-2.66998s-1.20001-2.67004-2.66998-2.67004Z\"\n        fill=\"#3f3d56\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue",
    "content": "<template>\n  <svg\n    height=\"571\"\n    viewBox=\"0 0 860 571\"\n    width=\"860\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n  >\n    <path\n      d=\"M605.66974,324.95306c-7.66934-12.68446-16.7572-26.22768-30.98954-30.36953-16.482-4.7965-33.4132,4.73193-47.77473,14.13453a1392.15692,1392.15692,0,0,0-123.89338,91.28311l.04331.49238q46.22556-3.1878,92.451-6.37554c22.26532-1.53546,45.29557-3.2827,64.97195-13.8156,7.46652-3.99683,14.74475-9.33579,23.20555-9.70782,10.51175-.46217,19.67733,6.87923,26.8802,14.54931,42.60731,45.371,54.937,114.75409,102.73817,154.61591A1516.99453,1516.99453,0,0,0,605.66974,324.95306Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M867.57068,709.78146c-4.71167-5.94958-6.6369-7.343-11.28457-13.34761q-56.7644-73.41638-106.70791-151.79237-33.92354-53.23-64.48275-108.50439-14.54864-26.2781-28.29961-52.96872-10.67044-20.6952-20.8646-41.63793c-1.94358-3.98782-3.8321-7.99393-5.71122-12.00922-4.42788-9.44232-8.77341-18.93047-13.43943-28.24449-5.31686-10.61572-11.789-21.74485-21.55259-28.877a29.40493,29.40493,0,0,0-15.31855-5.89458c-7.948-.51336-15.28184,2.76855-22.17568,6.35295-50.43859,26.301-97.65922,59.27589-140.3696,96.79771A730.77816,730.77816,0,0,0,303.32241,496.24719c-1.008,1.43927-3.39164.06417-2.37419-1.38422q6.00933-8.49818,12.25681-16.81288A734.817,734.817,0,0,1,500.80465,303.06436q18.24824-11.82581,37.18269-22.54245c6.36206-3.60275,12.75188-7.15967,19.25136-10.49653,6.37146-3.27274,13.13683-6.21547,20.41563-6.32547,24.7701-.385,37.59539,27.66695,46.40506,46.54248q4.15283,8.9106,8.40636,17.76626,16.0748,33.62106,33.38729,66.628,10.68453,20.379,21.83683,40.51955,34.7071,62.71816,73.77854,122.897c34.5059,53.1429,68.73651,100.08874,108.04585,149.78472C870.59617,709.21309,868.662,711.17491,867.57068,709.78146Z\"\n      fill=\"#e4e4e4\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M414.91613,355.804c-1.43911-1.60428-2.86927-3.20856-4.31777-4.81284-11.42244-12.63259-23.6788-25.11847-39.3644-32.36067a57.11025,57.11025,0,0,0-23.92679-5.54622c-8.56213.02753-16.93178,2.27348-24.84306,5.41792-3.74034,1.49427-7.39831,3.1902-11.00078,4.99614-4.11634,2.07182-8.15927,4.28118-12.1834,6.50883q-11.33112,6.27044-22.36816,13.09089-21.9606,13.57221-42.54566,29.21623-10.67111,8.11311-20.90174,16.75788-9.51557,8.03054-18.64618,16.492c-1.30169,1.20091-3.24527-.74255-1.94358-1.94347,1.60428-1.49428,3.22691-2.97938,4.84955-4.44613q6.87547-6.21546,13.9712-12.19257,12.93921-10.91827,26.54851-20.99312,21.16293-15.67614,43.78288-29.22541,11.30361-6.76545,22.91829-12.96259c2.33794-1.24675,4.70318-2.466,7.09572-3.6211a113.11578,113.11578,0,0,1,16.86777-6.86632,60.0063,60.0063,0,0,1,25.476-2.50265,66.32706,66.32706,0,0,1,23.50512,8.1314c15.40091,8.60812,27.34573,21.919,38.97,34.90915C418.03337,355.17141,416.09875,357.12405,414.91613,355.804Z\"\n      fill=\"#e4e4e4\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M730.47659,486.71092l36.90462-13.498,18.32327-6.70183c5.96758-2.18267,11.92082-4.66747,18.08988-6.23036a28.53871,28.53871,0,0,1,16.37356.20862,37.73753,37.73753,0,0,1,12.771,7.91666,103.63965,103.63965,0,0,1,10.47487,11.18643c3.98932,4.79426,7.91971,9.63877,11.86772,14.46706q24.44136,29.89094,48.56307,60.04134,24.12117,30.14991,47.91981,60.556,23.85681,30.48041,47.38548,61.21573,2.88229,3.76518,5.75966,7.53415c1.0598,1.38809,3.44949.01962,2.37472-1.38808Q983.582,650.9742,959.54931,620.184q-24.09177-30.86383-48.51647-61.46586-24.42421-30.60141-49.17853-60.93743-6.16706-7.55761-12.35445-15.09858c-3.47953-4.24073-6.91983-8.52718-10.73628-12.47427-7.00539-7.24516-15.75772-13.64794-26.23437-13.82166-6.15972-.10214-12.121,1.85248-17.844,3.92287-6.16968,2.232-12.32455,4.50571-18.48633,6.75941l-37.16269,13.59243-9.29067,3.3981c-1.64875.603-.93651,3.2619.73111,2.652Z\"\n      fill=\"#e4e4e4\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M366.37741,334.52609c-18.75411-9.63866-42.77137-7.75087-60.00508,4.29119a855.84708,855.84708,0,0,1,97.37056,22.72581C390.4603,353.75916,380.07013,341.5635,366.37741,334.52609Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M306.18775,338.7841l-3.61042,2.93462c1.22123-1.02713,2.4908-1.99013,3.795-2.90144C306.31073,338.80665,306.24935,338.79473,306.18775,338.7841Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M831.54929,486.84576c-3.6328-4.42207-7.56046-9.05222-12.99421-10.84836l-5.07308.20008A575.436,575.436,0,0,0,966.74929,651.418Q899.14929,569.13192,831.54929,486.84576Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M516.08388,450.36652A37.4811,37.4811,0,0,0,531.015,471.32518c2.82017,1.92011,6.15681,3.76209,7.12158,7.03463a8.37858,8.37858,0,0,1-.87362,6.1499,24.88351,24.88351,0,0,1-3.86126,5.04137l-.13667.512c-6.99843-4.14731-13.65641-9.3934-17.52227-16.55115s-4.40553-16.53895.34116-23.14544\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M749.08388,653.36652A37.4811,37.4811,0,0,0,764.015,674.32518c2.82017,1.92011,6.15681,3.76209,7.12158,7.03463a8.37858,8.37858,0,0,1-.87362,6.1499,24.88351,24.88351,0,0,1-3.86126,5.04137l-.13667.512c-6.99843-4.14731-13.65641-9.3934-17.52227-16.55115s-4.40553-16.53895.34116-23.14544\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M284.08388,639.36652A37.4811,37.4811,0,0,0,299.015,660.32518c2.82017,1.92011,6.15681,3.76209,7.12158,7.03463a8.37858,8.37858,0,0,1-.87362,6.1499,24.88351,24.88351,0,0,1-3.86126,5.04137l-.13667.512c-6.99843-4.14731-13.65641-9.3934-17.52227-16.55115s-4.40553-16.53895.34116-23.14544\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <circle cx=\"649.24878\" cy=\"51\" fill=\"hsl(var(--primary))\" r=\"51\" />\n    <path\n      d=\"M911.21851,176.29639c-24.7168-3.34094-52.93512,10.01868-59.34131,34.12353a21.59653,21.59653,0,0,0-41.09351,2.10871l2.82972,2.02667a372.27461,372.27461,0,0,0,160.65881-.72638C957.07935,195.76,935.93537,179.63727,911.21851,176.29639Z\"\n      fill=\"#f0f0f0\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M805.21851,244.29639c-24.7168-3.34094-52.93512,10.01868-59.34131,34.12353a21.59653,21.59653,0,0,0-41.09351,2.10871l2.82972,2.02667a372.27461,372.27461,0,0,0,160.65881-.72638C851.07935,263.76,829.93537,247.63727,805.21851,244.29639Z\"\n      fill=\"#f0f0f0\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M1020.94552,257.15423a.98189.98189,0,0,1-.30176-.04688C756.237,173.48919,523.19942,184.42376,374.26388,208.32122c-20.26856,3.251-40.59131,7.00586-60.40381,11.16113-5.05811,1.05957-10.30567,2.19532-15.59668,3.37793-6.31885,1.40723-12.55371,2.85645-18.53223,4.30567q-3.873.917-7.59472,1.84863c-3.75831.92773-7.57178,1.89453-11.65967,2.957-4.56787,1.17774-9.209,2.41309-13.79737,3.67188a.44239.44239,0,0,1-.05127.01465l.00049.001c-5.18261,1.415-10.33789,2.8711-15.32324,4.3252-2.69824.77929-5.30371,1.54785-7.79932,2.30664-.2788.07715-.52587.15136-.77636.22754l-.53614.16308c-.31054.09473-.61718.1875-.92382.27539l-.01953.00586.00048.001-.81152.252c-.96777.293-1.91211.5791-2.84082.86426-24.54492,7.56641-38.03809,12.94922-38.17139,13.00195a1,1,0,1,1-.74414-1.85644c.13428-.05274,13.69336-5.46289,38.32764-13.05762.93213-.28613,1.87891-.57226,2.84961-.86621l.7539-.23438c.02588-.00976.05176-.01757.07813-.02539.30518-.08691.60986-.17968.91943-.27343l.53711-.16309c.26758-.08105.53125-.16113.80127-.23535,2.47852-.75391,5.09278-1.52441,7.79785-2.30664,4.98731-1.45508,10.14746-2.91113,15.334-4.32813.01611-.00586.03271-.00976.04883-.01464v-.001c4.60449-1.2627,9.26269-2.50293,13.84521-3.68457,4.09424-1.06348,7.915-2.03223,11.67969-2.96192q3.73755-.93017,7.60937-1.85253c5.98536-1.45118,12.23291-2.90235,18.563-4.3125,5.29932-1.1836,10.55567-2.32227,15.62207-3.38282,19.84326-4.16211,40.19776-7.92285,60.49707-11.17871C523.09591,182.415,756.46749,171.46282,1021.2463,255.2011a.99974.99974,0,0,1-.30078,1.95313Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M432.92309,584.266a6.72948,6.72948,0,0,0-1.7-2.67,6.42983,6.42983,0,0,0-.92-.71c-2.61-1.74-6.51-2.13-8.99,0a5.81012,5.81012,0,0,0-.69.71q-1.11,1.365-2.28,2.67c-1.28,1.46-2.59,2.87-3.96,4.24-.39.38-.78.77-1.18,1.15-.23.23-.46.45-.69.67-.88.84-1.78,1.65-2.69,2.45-.48.43-.96.85-1.45,1.26-.73.61-1.46,1.22-2.2,1.81-.07.05-.14.1-.21.16-.02.01-.03.03-.05.04-.01,0-.02,0-.03.02a.17861.17861,0,0,0-.07.05c-.22.15-.37.25-.48.34.04-.01995.08-.05.12-.07-.18.14-.37.28-.55.42-1.75,1.29-3.54,2.53-5.37,3.69a99.21022,99.21022,0,0,1-14.22,7.55c-.33.13-.67.27-1.01.4a85.96993,85.96993,0,0,1-40.85,6.02q-2.13008-.165-4.26-.45c-1.64-.24-3.27-.53-4.89-.86a97.93186,97.93186,0,0,1-18.02-5.44,118.65185,118.65185,0,0,1-20.66-12.12c-1-.71-2.01-1.42-3.02-2.11,1.15-2.82,2.28-5.64,3.38-8.48.55-1.37,1.08-2.74,1.6-4.12,4.09-10.63,7.93-21.36,11.61-32.13q5.58-16.365,10.53-32.92.51-1.68.99-3.36,2.595-8.745,4.98-17.53c.15-.56994.31-1.12994.45-1.7q.68994-2.52,1.35-5.04c1-3.79-1.26-8.32-5.24-9.23a7.63441,7.63441,0,0,0-9.22,5.24c-.43,1.62-.86,3.23-1.3,4.85q-3.165,11.74494-6.66,23.41-.51,1.68-1.02,3.36-7.71,25.41-16.93,50.31-1.11,3.015-2.25,6.01c-.37.98-.74,1.96-1.12,2.94-.73,1.93-1.48,3.86-2.23,5.79-.43006,1.13-.87006,2.26-1.31,3.38-.29.71-.57,1.42-.85,2.12a41.80941,41.80941,0,0,0-8.81-2.12l-.48-.06a27.397,27.397,0,0,0-7.01.06,23.91419,23.91419,0,0,0-17.24,10.66c-4.77,7.51-4.71,18.25,1.98,24.63,6.89,6.57,17.32,6.52,25.43,2.41a28.35124,28.35124,0,0,0,10.52-9.86,50.56939,50.56939,0,0,0,2.74-4.65c.21.14.42.28.63.43.8.56,1.6,1.13,2.39,1.69a111.73777,111.73777,0,0,0,14.51,8.91,108.35887,108.35887,0,0,0,34.62,10.47c.27.03.53.07.8.1,1.33.17,2.67.3,4.01.41a103.78229,103.78229,0,0,0,55.58-11.36q2.175-1.125,4.31-2.36,3.315-1.92,6.48-4.08c1.15-.78,2.27-1.57,3.38-2.4a101.04244,101.04244,0,0,0,13.51-11.95q2.35491-2.475,4.51-5.11005a8.0612,8.0612,0,0,0,2.2-5.3A7.5644,7.5644,0,0,0,432.92309,584.266Zm-165.59,23.82c.21-.15.42-.31.62-.47C267.89312,607.766,267.60308,607.936,267.33312,608.086Zm3.21-3.23c-.23.26-.44.52-.67.78a23.36609,23.36609,0,0,1-2.25,2.2c-.11.1-.23.2-.35.29a.00976.00976,0,0,0-.01.01,3.80417,3.80417,0,0,0-.42005.22q-.645.39-1.31994.72a17.00459,17.00459,0,0,1-2.71.75,16.79925,16.79925,0,0,1-2.13.02h-.02a14.82252,14.82252,0,0,1-1.45-.4c-.24-.12-.47-.25994-.7-.4-.09-.08-.17005-.16-.22-.21a2.44015,2.44015,0,0,1-.26995-.29.0098.0098,0,0,0-.01-.01c-.11005-.2-.23005-.4-.34-.6a.031.031,0,0,1-.01-.02c-.08-.25-.15-.51-.21-.77a12.51066,12.51066,0,0,1,.01-1.37,13.4675,13.4675,0,0,1,.54-1.88,11.06776,11.06776,0,0,1,.69-1.26c.02-.04.12-.2.23-.38.01-.01.01-.01.01-.02.15-.17.3-.35.46-.51.27-.3.56-.56.85-.83a18.02212,18.02212,0,0,1,1.75-1.01,19.48061,19.48061,0,0,1,2.93-.79,24.98945,24.98945,0,0,1,4.41.04,30.30134,30.30134,0,0,1,4.1,1.01,36.94452,36.94452,0,0,1-2.77,4.54C270.6231,604.746,270.58312,604.806,270.54308,604.856Zm-11.12-3.29a2.18029,2.18029,0,0,1-.31.38995A1.40868,1.40868,0,0,1,259.42309,601.566Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M402.86309,482.136q-.13494,4.71-.27,9.42-.285,10.455-.59,20.92-.315,11.775-.66,23.54-.165,6.07507-.34,12.15-.465,16.365-.92,32.72c-.03,1.13-.07,2.25-.1,3.38q-.225,8.11506-.45,16.23-.255,8.805-.5,17.61-.18,6.59994-.37,13.21-1.34994,47.895-2.7,95.79a7.64844,7.64844,0,0,1-7.5,7.5,7.56114,7.56114,0,0,1-7.5-7.5q.75-26.94,1.52-53.88.675-24.36,1.37-48.72.225-8.025.45-16.06.345-12.09.68-24.18c.03-1.13.07-2.25.1-3.38.02-.99.05-1.97.08-2.96q.66-23.475,1.32-46.96.27-9.24.52-18.49.3-10.545.6-21.08c.09-3.09.17005-6.17.26-9.26a7.64844,7.64844,0,0,1,7.5-7.5A7.56116,7.56116,0,0,1,402.86309,482.136Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M814.29118,484.2172a893.23753,893.23753,0,0,1-28.16112,87.94127c-3.007,7.94641-6.08319,15.877-9.3715,23.71185l.75606-1.7916a54.58274,54.58274,0,0,1-5.58953,10.61184q-.22935.32119-.46685.63642,1.16559-1.49043.4428-.589c-.25405.30065-.5049.60219-.7676.89546a23.66436,23.66436,0,0,1-2.2489,2.20318q-.30139.25767-.61188.5043l.93783-.729c-.10884.25668-.87275.59747-1.11067.74287a18.25362,18.25362,0,0,1-2.40479,1.21853l1.7916-.75606a19.0859,19.0859,0,0,1-4.23122,1.16069l1.9938-.26791a17.02055,17.02055,0,0,1-4.29785.046l1.99379.2679a14.0022,14.0022,0,0,1-3.40493-.917l1.79159.75606a12.01175,12.01175,0,0,1-1.67882-.89614c-.27135-.17688-1.10526-.80852-.01487.02461,1.13336.86595.14562.07434-.08763-.15584-.19427-.19171-.36962-.4-.55974-.595-.88208-.90454.99637,1.55662.39689.49858a18.18179,18.18179,0,0,1-.87827-1.63672l.75606,1.7916a11.92493,11.92493,0,0,1-.728-2.65143l.26791,1.9938a13.65147,13.65147,0,0,1-.00316-3.40491l-.2679,1.9938a15.96371,15.96371,0,0,1,.99486-3.68011l-.75606,1.7916a16.72914,16.72914,0,0,1,1.17794-2.29848,6.72934,6.72934,0,0,1,.72851-1.0714c.04915.01594-1.26865,1.51278-.56937.757.1829-.19767.354-.40592.539-.602.29617-.31382.61354-.60082.92561-.89791,1.04458-.99442-1.46188.966-.25652.17907a19.0489,19.0489,0,0,1,2.74925-1.49923l-1.79159.75606a20.31136,20.31136,0,0,1,4.99523-1.33984l-1.9938.2679a25.62828,25.62828,0,0,1,6.46062.07647l-1.9938-.2679a33.21056,33.21056,0,0,1,7.89178,2.2199l-1.7916-.75606c5.38965,2.31383,10.16308,5.74926,14.928,9.118a111.94962,111.94962,0,0,0,14.50615,8.9065,108.38849,108.38849,0,0,0,34.62226,10.47371,103.93268,103.93268,0,0,0,92.58557-36.75192,8.07773,8.07773,0,0,0,2.1967-5.3033,7.63232,7.63232,0,0,0-2.1967-5.3033c-2.75154-2.52586-7.94926-3.239-10.6066,0a95.63575,95.63575,0,0,1-8.10664,8.72692q-2.01736,1.914-4.14232,3.70983-1.21364,1.02588-2.46086,2.01121c-.3934.31081-1.61863,1.13807.26309-.19744-.43135.30614-.845.64036-1.27058.95478a99.26881,99.26881,0,0,1-20.33215,11.56478l1.79159-.75606a96.8364,96.8364,0,0,1-24.17119,6.62249l1.99379-.2679a97.64308,97.64308,0,0,1-25.75362-.03807l1.99379.2679a99.79982,99.79982,0,0,1-24.857-6.77027l1.7916.75607a116.02515,116.02515,0,0,1-21.7364-12.59112,86.87725,86.87725,0,0,0-11.113-6.99417,42.8238,42.8238,0,0,0-14.43784-4.38851c-9.43884-1.11076-19.0571,2.56562-24.24624,10.72035-4.77557,7.50482-4.71394,18.24362,1.97369,24.62519,6.8877,6.5725,17.31846,6.51693,25.43556,2.40567,7.81741-3.95946,12.51288-12.18539,15.815-19.94186,7.43109-17.45514,14.01023-35.31364,20.1399-53.263q9.09651-26.63712,16.49855-53.81332.91661-3.36581,1.80683-6.73869c1.001-3.78869-1.26094-8.32-5.23829-9.22589a7.63317,7.63317,0,0,0-9.22589,5.23829Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M889.12382,482.13557l-2.69954,95.79311-2.68548,95.29418-1.5185,53.88362a7.56465,7.56465,0,0,0,7.5,7.5,7.64923,7.64923,0,0,0,7.5-7.5l2.69955-95.79311,2.68548-95.29418,1.51849-53.88362a7.56465,7.56465,0,0,0-7.5-7.5,7.64923,7.64923,0,0,0-7.5,7.5Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M629.52566,700.36106h2.32885V594.31942h54.32863v-2.32291H631.85451V547.25214H673.8102q-.92256-1.17339-1.89893-2.31694H631.85451V515.38231c-.7703-.32846-1.54659-.64493-2.32885-.9435V544.9352h-45.652V507.07c-.78227.03583-1.55258.08959-2.3289.15527v37.71h-36.4201V516.68409c-.78227.34636-1.55258.71061-2.31694,1.0928V544.9352h-30.6158v2.31694h30.6158v44.74437h-30.6158v2.32291h30.6158V700.36106h2.31694V594.31942a36.41283,36.41283,0,0,1,36.4201,36.42007v69.62157h2.3289V594.31942h45.652Zm-84.401-108.36455V547.25214h36.4201v44.74437Zm38.749,0V547.25214h.91362a44.74135,44.74135,0,0,1,44.73842,44.74437Z\"\n      opacity=\"0.2\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M615.30309,668.566a63.05854,63.05854,0,0,1-20.05,33.7c-.74.64-1.48,1.26-2.25,1.87q-2.805.25506-5.57.52c-1.53.14-3.04.29-4.54.43l-.27.03-.19-1.64-.76-6.64a37.623,37.623,0,0,1-3.3-32.44c2.64-7.12,7.42-13.41,12.12-19.65,6.49-8.62,12.8-17.14,13.03-27.65a60.54415,60.54415,0,0,1,7.9,13.33,16.432,16.432,0,0,0-5.12,3.76995c-.41.45-.82,1.08-.54,1.62006.24.46.84.57,1.36.62994,1.25.13,2.51.26,3.76.39,1,.11,2,.21,3,.32a63.99025,63.99025,0,0,1,2.45,12.18A61.18851,61.18851,0,0,1,615.30309,668.566Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M648.50311,642.356c-5.9,4.29-9.35,10.46-12.03,17.26a16.62776,16.62776,0,0,0-7.17,4.58c-.41.45-.82,1.08-.54,1.62006.24.46.84.57,1.36.62994,1.25.13,2.51.26,3.76.39-2.68,8.04-5.14,16.36-9.88,23.15a36.98942,36.98942,0,0,1-12.03,10.91,38.49166,38.49166,0,0,1-4.02,1.99q-7.62.585-14.95,1.25-2.805.25506-5.57.52c-1.53.14-3.04.29-4.54.43q-.015-.825,0-1.65a63.30382,63.30382,0,0,1,15.25-39.86c.45-.52.91-1.03,1.38-1.54a61.7925,61.7925,0,0,1,16.81-12.7A62.65425,62.65425,0,0,1,648.50311,642.356Z\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M589.16308,699.526l-1.15,3.4-.58,1.73c-1.53.14-3.04.29-4.54.43l-.27.03c-1.66.17-3.31.34-4.96.51-.43-.5-.86-1.01-1.28-1.53a62.03045,62.03045,0,0,1,8.07-87.11c-1.32,6.91.22,13.53,2.75,20.1-.27.11-.53.22-.78.34a16.432,16.432,0,0,0-5.12,3.76995c-.41.45-.82,1.08-.54,1.62006.24.46.84.57,1.36.62994,1.25.13,2.51.26,3.76.39,1,.11,2,.21,3,.32q.705.075,1.41.15c.07.15.13.29.2.44,2.85,6.18,5.92,12.39,7.65,18.83a43.66591,43.66591,0,0,1,1.02,4.91A37.604,37.604,0,0,1,589.16308,699.526Z\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M689.82123,554.48655c-8.60876-16.79219-21.94605-30.92088-37.63219-41.30357a114.2374,114.2374,0,0,0-52.5626-18.37992q-3.69043-.33535-7.399-.39281c-2.92141-.04371-46.866,12.63176-61.58712,22.98214a114.29462,114.29462,0,0,0-35.333,39.527,102.49972,102.49972,0,0,0-12.12557,51.6334,113.56387,113.56387,0,0,0,14.70268,51.47577,110.47507,110.47507,0,0,0,36.44425,38.74592C549.66655,708.561,565.07375,734.51,583.1831,735.426c18.24576.923,39.05418-23.55495,55.6951-30.98707a104.42533,104.42533,0,0,0,41.72554-34.005,110.24964,110.24964,0,0,0,19.599-48.94777c2.57368-18.08313,1.37415-36.73271-4.80123-54.01627a111.85969,111.85969,0,0,0-5.58024-12.9833c-1.77961-3.50519-6.996-4.7959-10.26142-2.69063a7.67979,7.67979,0,0,0-2.69064,10.26142q1.56766,3.08773,2.91536,6.27758l-.75606-1.7916a101.15088,101.15088,0,0,1,6.87641,25.53816l-.26791-1.99379a109.2286,109.2286,0,0,1-.06613,28.68252l.26791-1.9938a109.73379,109.73379,0,0,1-7.55462,27.67419l.75606-1.79159a104.212,104.212,0,0,1-6.67151,13.09835q-1.92308,3.18563-4.08062,6.22159c-.63172.8881-1.28287,1.761-1.939,2.63114-.85625,1.13555,1.16691-1.48321.28228-.36941-.15068.18972-.30049.3801-.45182.5693q-.68121.85165-1.3818,1.68765a93.61337,93.61337,0,0,1-10.17647,10.38359q-1.36615,1.19232-2.77786,2.33115c-.46871.37832-.932.77269-1.42079,1.12472.01861-.0134,1.57956-1.19945.65556-.511-.2905.21644-.57851.43619-.86961.65184q-2.90994,2.1558-5.97433,4.092a103.48509,103.48509,0,0,1-14.75565,7.7131l1.7916-.75606a109.21493,109.21493,0,0,1-27.59663,7.55154l1.9938-.26791a108.15361,108.15361,0,0,1-28.58907.0506l1.99379.2679a99.835,99.835,0,0,1-25.09531-6.78448l1.79159.75607a93.64314,93.64314,0,0,1-13.41605-6.99094q-3.17437-2-6.18358-4.24743c-.2862-.21359-.56992-.43038-.855-.64549-.9155-.69088.65765.50965.67021.51787a19.16864,19.16864,0,0,1-1.535-1.22469q-1.45353-1.18358-2.86136-2.4218a101.98931,101.98931,0,0,1-10.49319-10.70945q-1.21308-1.43379-2.37407-2.91054c-.33524-.4263-.9465-1.29026.40424.5289-.17775-.23939-.36206-.47414-.54159-.71223q-.64657-.85751-1.27568-1.72793-2.203-3.048-4.18787-6.24586a109.29037,109.29037,0,0,1-7.8054-15.10831l.75606,1.7916a106.58753,106.58753,0,0,1-7.34039-26.837l.26791,1.9938a97.86589,97.86589,0,0,1-.04843-25.63587l-.2679,1.9938A94.673,94.673,0,0,1,505.27587,570.55l-.75606,1.7916a101.55725,101.55725,0,0,1,7.19519-13.85624q2.0655-3.32328,4.37767-6.4847.52528-.71832,1.06244-1.42786c.324-.4279,1.215-1.49333-.30537.38842.14906-.18449.29252-.37428.43942-.56041q1.26882-1.60756,2.59959-3.1649A107.40164,107.40164,0,0,1,530.772,536.21508q1.47408-1.29171,2.99464-2.52906.6909-.56218,1.39108-1.11284c.18664-.14673.37574-.29073.56152-.43858-1.99743,1.58953-.555.43261-.10157.09288q3.13393-2.34833,6.43534-4.46134a103.64393,103.64393,0,0,1,15.38655-8.10791l-1.7916.75606c7.76008-3.25839,42.14086-10.9492,48.394-10.10973l-1.99379-.26791A106.22471,106.22471,0,0,1,628.768,517.419l-1.7916-.75606a110.31334,110.31334,0,0,1,12.6002,6.32922q3.04344,1.78405,5.96742,3.76252,1.38351.93658,2.73809,1.915.677.48917,1.34626.98885c.24789.185.49386.37253.74135.558,1.03924.779-1.43148-1.1281-.34209-.26655a110.84261,110.84261,0,0,1,10.36783,9.2532q2.401,2.445,4.63686,5.04515,1.14659,1.33419,2.24643,2.70757c.36436.45495,1.60506,2.101.08448.08457.37165.49285.74744.98239,1.11436,1.47884a97.97718,97.97718,0,0,1,8.39161,13.53807c1.79317,3.49775,6.98675,4.80186,10.26142,2.69064A7.67666,7.67666,0,0,0,689.82123,554.48655Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M602.43116,676.88167a3.77983,3.77983,0,0,1-2.73939-6.55137c.09531-.37882.16368-.65085.259-1.02968q-.05115-.12366-.1029-.24717c-3.47987-8.29769-25.685,14.83336-26.645,22.63179a30.029,30.029,0,0,0,.52714,10.32752A120.39223,120.39223,0,0,1,562.77838,652.01a116.20247,116.20247,0,0,1,.72078-12.96332q.59712-5.293,1.65679-10.51055a121.78667,121.78667,0,0,1,24.1515-51.61646c6.87378.38364,12.898-.66348,13.47967-13.98532.10346-2.36972,1.86113-4.42156,2.24841-6.756-.65621.08607-1.32321.13985-1.97941.18285-.20444.0107-.41958.02149-.624.03228l-.07709.00346a3.745,3.745,0,0,1-3.07566-6.10115q.425-.52305.85054-1.04557c.43036-.53793.87143-1.06507,1.30171-1.60292a1.865,1.865,0,0,0,.13986-.16144c.49494-.61322.98971-1.21564,1.48465-1.82885a10.82911,10.82911,0,0,0-3.55014-3.43169c-4.95941-2.90463-11.80146-.89293-15.38389,3.59313-3.59313,4.486-4.27083,10.77947-3.023,16.3843a43.39764,43.39764,0,0,0,6.003,13.3828c-.269.34429-.54872.67779-.81765,1.02209a122.57366,122.57366,0,0,0-12.79359,20.2681c1.0163-7.93863-11.41159-36.60795-16.21776-42.68052-5.773-7.29409-17.61108-4.11077-18.62815,5.13562q-.01476.13428-.02884.26849,1.07082.60411,2.0964,1.28237a5.12707,5.12707,0,0,1-2.06713,9.33031l-.10452.01613c-9.55573,13.64367,21.07745,49.1547,28.74518,41.18139a125.11045,125.11045,0,0,0-6.73449,31.69282,118.66429,118.66429,0,0,0,.08607,19.15986l-.03231-.22593C558.90163,648.154,529.674,627.51374,521.139,629.233c-4.91675.99041-9.75952.76525-9.01293,5.72484q.01788.11874.03635.2375a34.4418,34.4418,0,0,1,3.862,1.86105q1.07082.60423,2.09639,1.28237a5.12712,5.12712,0,0,1-2.06712,9.33039l-.10464.01606c-.07528.01079-.13987.02157-.21507.03237-4.34967,14.96631,27.90735,39.12,47.5177,31.43461h.01081a125.07484,125.07484,0,0,0,8.402,24.52806H601.679c.10765-.3335.20443-.67779.3013-1.01129a34.102,34.102,0,0,1-8.30521-.49477c2.22693-2.73257,4.45377-5.48664,6.6807-8.21913a1.86122,1.86122,0,0,0,.13986-.16135c1.12956-1.39849,2.26992-2.78627,3.39948-4.18476l.00061-.00173a49.95232,49.95232,0,0,0-1.46367-12.72495Zm-34.37066-67.613.0158-.02133-.0158.04282Zm-6.64832,59.93237-.25822-.58084c.01079-.41957.01079-.83914,0-1.26942,0-.11845-.0215-.23672-.0215-.35508.09678.74228.18285,1.48464.29042,2.22692Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <circle cx=\"95.24878\" cy=\"439\" fill=\"hsl(var(--foreground))\" r=\"11\" />\n    <circle cx=\"227.24878\" cy=\"559\" fill=\"hsl(var(--foreground))\" r=\"11\" />\n    <circle cx=\"728.24878\" cy=\"559\" fill=\"hsl(var(--foreground))\" r=\"11\" />\n    <circle cx=\"755.24878\" cy=\"419\" fill=\"hsl(var(--foreground))\" r=\"11\" />\n    <circle cx=\"723.24878\" cy=\"317\" fill=\"hsl(var(--foreground))\" r=\"11\" />\n    <path\n      d=\"M434.1831,583.426a10.949,10.949,0,1,1-.21-2.16A10.9921,10.9921,0,0,1,434.1831,583.426Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <circle cx=\"484.24878\" cy=\"349\" fill=\"hsl(var(--foreground))\" r=\"11\" />\n    <path\n      d=\"M545.1831,513.426a10.949,10.949,0,1,1-.21-2.16A10.9921,10.9921,0,0,1,545.1831,513.426Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <path\n      d=\"M403.1831,481.426a10.949,10.949,0,1,1-.21-2.16A10.9921,10.9921,0,0,1,403.1831,481.426Z\"\n      fill=\"hsl(var(--foreground))\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n    <circle cx=\"599.24878\" cy=\"443\" fill=\"hsl(var(--foreground))\" r=\"11\" />\n    <circle cx=\"426.24878\" cy=\"338\" fill=\"hsl(var(--foreground))\" r=\"16\" />\n    <path\n      d=\"M1028.875,735.26666l-857.75.30733a1.19068,1.19068,0,1,1,0-2.38136l857.75-.30734a1.19069,1.19069,0,0,1,0,2.38137Z\"\n      fill=\"#cacaca\"\n      transform=\"translate(-169.93432 -164.42601)\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue",
    "content": "<template>\n  <svg\n    height=\"699\"\n    viewBox=\"0 0 1119 699\"\n    width=\"1119\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n  >\n    <title>server down</title>\n    <circle cx=\"292.60911\" cy=\"213\" fill=\"#f2f2f2\" r=\"213\" />\n    <path\n      d=\"M31.39089,151.64237c0,77.49789,48.6181,140.20819,108.70073,140.20819\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M140.09162,291.85056c0-78.36865,54.255-141.78356,121.30372-141.78356\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M70.77521,158.66768c0,73.61476,31.00285,133.18288,69.31641,133.18288\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M140.09162,291.85056c0-100.13772,62.7103-181.16788,140.20819-181.16788\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M117.22379,292.83905s15.41555-.47479,20.06141-3.783,23.713-7.2585,24.86553-1.95278,23.16671,26.38821,5.76263,26.5286-40.43935-2.711-45.07627-5.53549S117.22379,292.83905,117.22379,292.83905Z\"\n      fill=\"#a8a8a8\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M168.224,311.78489c-17.40408.14042-40.43933-2.71094-45.07626-5.53548-3.53126-2.151-4.93843-9.86945-5.40926-13.43043-.32607.014-.51463.02-.51463.02s.97638,12.43276,5.61331,15.2573,27.67217,5.67589,45.07626,5.53547c5.02386-.04052,6.7592-1.82793,6.66391-4.47526C173.87935,310.756,171.96329,311.75474,168.224,311.78489Z\"\n      opacity=\"0.2\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <ellipse cx=\"198.60911\" cy=\"424.5\" fill=\"#3f3d56\" rx=\"187\" ry=\"25.43993\" />\n    <ellipse cx=\"198.60911\" cy=\"424.5\" opacity=\"0.1\" rx=\"157\" ry=\"21.35866\" />\n    <ellipse cx=\"836.60911\" cy=\"660.5\" fill=\"#3f3d56\" rx=\"283\" ry=\"38.5\" />\n    <ellipse cx=\"310.60911\" cy=\"645.5\" fill=\"#3f3d56\" rx=\"170\" ry=\"23.12721\" />\n    <path\n      d=\"M494,726.5c90,23,263-30,282-90\"\n      fill=\"none\"\n      stroke=\"#2f2e41\"\n      stroke-miterlimit=\"10\"\n      stroke-width=\"2\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M341,359.5s130-36,138,80-107,149-17,172\"\n      fill=\"none\"\n      stroke=\"#2f2e41\"\n      stroke-miterlimit=\"10\"\n      stroke-width=\"2\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M215.40233,637.78332s39.0723-10.82,41.47675,24.04449-32.15951,44.78287-5.10946,51.69566\"\n      fill=\"none\"\n      stroke=\"#2f2e41\"\n      stroke-miterlimit=\"10\"\n      stroke-width=\"2\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M810.09554,663.73988,802.218,714.03505s-38.78182,20.60284-11.51335,21.20881,155.73324,0,155.73324,0,24.84461,0-14.54318-21.81478l-7.87756-52.719Z\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M785.21906,734.69812c6.193-5.51039,16.9989-11.252,16.9989-11.252l7.87756-50.2952,113.9216.10717,7.87756,49.582c9.185,5.08711,14.8749,8.987,18.20362,11.97818,5.05882-1.15422,10.58716-5.44353-18.20362-21.38921l-7.87756-52.719-113.9216,3.02983L802.218,714.03506S769.62985,731.34968,785.21906,734.69812Z\"\n      opacity=\"0.1\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <rect\n      fill=\"#2f2e41\"\n      height=\"357.51989\"\n      rx=\"18.04568\"\n      width=\"513.25314\"\n      x=\"578.43291\"\n      y=\"212.68859\"\n    />\n    <rect\n      fill=\"#3f3d56\"\n      height=\"267.83694\"\n      width=\"478.71308\"\n      x=\"595.70294\"\n      y=\"231.77652\"\n    />\n    <circle cx=\"835.05948\" cy=\"223.29299\" fill=\"#f2f2f2\" r=\"3.02983\" />\n    <path\n      d=\"M1123.07694,621.32226V652.6628a18.04341,18.04341,0,0,1-18.04568,18.04568H627.86949A18.04341,18.04341,0,0,1,609.8238,652.6628V621.32226Z\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <polygon\n      fill=\"#2f2e41\"\n      points=\"968.978 667.466 968.978 673.526 642.968 673.526 642.968 668.678 643.417 667.466 651.452 645.651 962.312 645.651 968.978 667.466\"\n    />\n    <path\n      d=\"M1125.828,762.03359c-.59383,2.539-2.83591,5.21743-7.90178,7.75032-18.179,9.08949-55.1429-2.42386-55.1429-2.42386s-28.4804-4.84773-28.4804-17.573a22.72457,22.72457,0,0,1,2.49658-1.48459c7.64294-4.04351,32.98449-14.02122,77.9177.42248a18.73921,18.73921,0,0,1,8.54106,5.59715C1125.07908,756.45353,1126.50669,759.15715,1125.828,762.03359Z\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <path\n      d=\"M1125.828,762.03359c-22.251,8.526-42.0843,9.1622-62.43871-4.975-10.26507-7.12617-19.59089-8.88955-26.58979-8.75618,7.64294-4.04351,32.98449-14.02122,77.9177.42248a18.73921,18.73921,0,0,1,8.54106,5.59715C1125.07908,756.45353,1126.50669,759.15715,1125.828,762.03359Z\"\n      opacity=\"0.1\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <ellipse\n      cx=\"1066.53846\"\n      cy=\"654.13477\"\n      fill=\"#f2f2f2\"\n      rx=\"7.87756\"\n      ry=\"2.42386\"\n    />\n    <circle cx=\"835.05948\" cy=\"545.66686\" fill=\"#f2f2f2\" r=\"11.51335\" />\n    <polygon\n      opacity=\"0.1\"\n      points=\"968.978 667.466 968.978 673.526 642.968 673.526 642.968 668.678 643.417 667.466 968.978 667.466\"\n    />\n    <rect fill=\"#2f2e41\" height=\"242\" width=\"208\" x=\"108.60911\" y=\"159\" />\n    <rect fill=\"#3f3d56\" height=\"86\" width=\"250\" x=\"87.60911\" y=\"135\" />\n    <rect fill=\"#3f3d56\" height=\"86\" width=\"250\" x=\"87.60911\" y=\"237\" />\n    <rect fill=\"#3f3d56\" height=\"86\" width=\"250\" x=\"87.60911\" y=\"339\" />\n    <rect\n      fill=\"#6c63ff\"\n      height=\"16\"\n      opacity=\"0.4\"\n      width=\"16\"\n      x=\"271.60911\"\n      y=\"150\"\n    />\n    <rect\n      fill=\"#6c63ff\"\n      height=\"16\"\n      opacity=\"0.8\"\n      width=\"16\"\n      x=\"294.60911\"\n      y=\"150\"\n    />\n    <rect fill=\"#6c63ff\" height=\"16\" width=\"16\" x=\"317.60911\" y=\"150\" />\n    <rect\n      fill=\"#6c63ff\"\n      height=\"16\"\n      opacity=\"0.4\"\n      width=\"16\"\n      x=\"271.60911\"\n      y=\"251\"\n    />\n    <rect\n      fill=\"#6c63ff\"\n      height=\"16\"\n      opacity=\"0.8\"\n      width=\"16\"\n      x=\"294.60911\"\n      y=\"251\"\n    />\n    <rect fill=\"#6c63ff\" height=\"16\" width=\"16\" x=\"317.60911\" y=\"251\" />\n    <rect\n      fill=\"#6c63ff\"\n      height=\"16\"\n      opacity=\"0.4\"\n      width=\"16\"\n      x=\"271.60911\"\n      y=\"352\"\n    />\n    <rect\n      fill=\"#6c63ff\"\n      height=\"16\"\n      opacity=\"0.8\"\n      width=\"16\"\n      x=\"294.60911\"\n      y=\"352\"\n    />\n    <rect fill=\"#6c63ff\" height=\"16\" width=\"16\" x=\"317.60911\" y=\"352\" />\n    <circle cx=\"316.60911\" cy=\"538\" fill=\"#2f2e41\" r=\"79\" />\n    <rect fill=\"#2f2e41\" height=\"43\" width=\"24\" x=\"280.60911\" y=\"600\" />\n    <rect fill=\"#2f2e41\" height=\"43\" width=\"24\" x=\"328.60911\" y=\"600\" />\n    <ellipse cx=\"300.60911\" cy=\"643.5\" fill=\"#2f2e41\" rx=\"20\" ry=\"7.5\" />\n    <ellipse cx=\"348.60911\" cy=\"642.5\" fill=\"#2f2e41\" rx=\"20\" ry=\"7.5\" />\n    <circle cx=\"318.60911\" cy=\"518\" fill=\"#fff\" r=\"27\" />\n    <circle cx=\"318.60911\" cy=\"518\" fill=\"#3f3d56\" r=\"9\" />\n    <path\n      d=\"M271.36733,565.03228c-6.37889-28.56758,14.01185-57.43392,45.544-64.47477s62.2651,10.41,68.644,38.9776-14.51861,39.10379-46.05075,46.14464S277.74622,593.59986,271.36733,565.03228Z\"\n      fill=\"#6c63ff\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n    <ellipse\n      cx=\"417.21511\"\n      cy=\"611.34365\"\n      fill=\"#2f2e41\"\n      rx=\"39.5\"\n      ry=\"12.40027\"\n      transform=\"translate(-238.28665 112.98044) rotate(-23.17116)\"\n    />\n    <ellipse\n      cx=\"269.21511\"\n      cy=\"664.34365\"\n      fill=\"#2f2e41\"\n      rx=\"39.5\"\n      ry=\"12.40027\"\n      transform=\"translate(-271.07969 59.02084) rotate(-23.17116)\"\n    />\n    <path\n      d=\"M394,661.5c0,7.732-19.90861,23-42,23s-43-14.268-43-22,20.90861-6,43-6S394,653.768,394,661.5Z\"\n      fill=\"#fff\"\n      transform=\"translate(-31.39089 -100.5)\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue",
    "content": "<template>\n  <svg\n    data-name=\"Layer 1\"\n    height=\"424.8366\"\n    viewBox=\"0 0 979.32677 424.8366\"\n    width=\"979.32677\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n  >\n    <path\n      d=\"M993.71816,412.83936H419.142a9.19888,9.19888,0,0,0,0,18.39776H435.417V651.3026a9.19888,9.19888,0,0,0,18.39776,0l.1398-220.06548h461.1557l42.52,220.06548a9.19887,9.19887,0,1,0,18.39775,0l2.67633-220.06548h15.01383a9.19888,9.19888,0,0,0,0-18.39776Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M518.73716,371.85047v38.9547H421.141a19.48915,19.48915,0,1,1-1.35523-38.95474q.67739-.02358,1.35523,0Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M521.13449,410.50552a1.49881,1.49881,0,0,1-1.49822,1.49822H419.40273a20.52615,20.52615,0,0,1,0-41.05229H519.63627a1.49827,1.49827,0,1,1,0,2.99653H419.40273a17.52964,17.52964,0,0,0,0,35.05924H519.63627A1.49883,1.49883,0,0,1,521.13449,410.50552Z\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M518.73716,380.84H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M518.73716,388.03169H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M518.73716,395.22332H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M518.73716,402.41487H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M500.33941,330.80932v38.95474H402.74324a19.48915,19.48915,0,0,1-1.35522-38.95474q.67737-.02358,1.35522,0Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M502.73673,369.46442a1.49885,1.49885,0,0,1-1.49822,1.49826H401.005a20.52614,20.52614,0,0,1,0-41.05229H501.23851a1.49826,1.49826,0,1,1,0,2.99652H401.005a17.52964,17.52964,0,0,0,0,35.05928H501.23851A1.49884,1.49884,0,0,1,502.73673,369.46442Z\"\n      fill=\"#3f3d56\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M500.33941,339.79886H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M500.33941,346.99054H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M500.33941,354.18217H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M500.33941,361.37376H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M613.87355,550.68347V516.71838a5.661,5.661,0,0,0-5.66085-5.66085H479.4284a5.661,5.661,0,0,0-5.66084,5.66085v33.96509Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <rect\n      fill=\"#ccc\"\n      height=\"43.87158\"\n      width=\"140.10602\"\n      x=\"363.43092\"\n      y=\"325.83868\"\n    />\n    <path\n      d=\"M473.76756,620.02887V653.994a5.661,5.661,0,0,0,5.66084,5.66084H608.2127a5.661,5.661,0,0,0,5.66085-5.66084V620.02887Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <circle cx=\"432.77633\" cy=\"294.70402\" fill=\"#fff\" r=\"4.24564\" />\n    <circle cx=\"432.77633\" cy=\"351.3125\" fill=\"#fff\" r=\"4.24564\" />\n    <circle cx=\"433.00385\" cy=\"406.72228\" fill=\"#fff\" r=\"4.24564\" />\n    <path\n      d=\"M597.989,472.33053v38.9547H500.39287a19.48916,19.48916,0,0,1-1.35647-38.9547q.678-.02358,1.35647,0Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M600.38637,510.98558a1.49881,1.49881,0,0,1-1.49822,1.49822H498.65461a20.52615,20.52615,0,0,1-.0247-41.05229H598.88815a1.49827,1.49827,0,1,1,0,2.99653H498.65461a17.52963,17.52963,0,0,0,0,35.05923H598.88815A1.49885,1.49885,0,0,1,600.38637,510.98558Z\"\n      fill=\"#3f3d56\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M597.989,481.32H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M597.989,488.51175H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M597.989,495.70338H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M597.989,502.89493H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M483.36747,317.81415H438.90162a2.74745,2.74745,0,0,0-1.21689.28306l-11.22288,5.61835a2.0452,2.0452,0,0,0,0,3.76443l11.22288,5.61835a2.74718,2.74718,0,0,0,1.21689.28306h44.46585a2.33381,2.33381,0,0,0,2.4628-2.16532v-11.2367A2.3338,2.3338,0,0,0,483.36747,317.81415Z\"\n      fill=\"#3f3d56\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M485.83027,319.97947v11.2367a2.33383,2.33383,0,0,1-2.4628,2.16532h-8.8589V317.81415h8.8589A2.33383,2.33383,0,0,1,485.83027,319.97947Z\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M216.78083,537.99332a35.33951,35.33951,0,0,0,34.12552-6.01134c11.95262-10.03214,15.70013-26.56,18.74934-41.864q4.50949-22.63308,9.019-45.26617l-18.88217,13.00153c-13.57891,9.34993-27.46375,18.99939-36.86572,32.54233S209.42082,522.42587,216.975,537.08\"\n      fill=\"#e6e6e6\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M218.39489,592.79741c-1.91113-13.92071-3.87625-28.0202-2.53572-42.09016,1.19057-12.4956,5.00277-24.70032,12.764-34.70734a57.73582,57.73582,0,0,1,14.81307-13.42309c1.48131-.935,2.84468,1.41257,1.36983,2.34348a54.88844,54.88844,0,0,0-21.71125,26.19626c-4.72684,12.02273-5.48591,25.12848-4.67135,37.90006.4926,7.72345,1.53656,15.39627,2.58859,23.05926a1.40615,1.40615,0,0,1-.94781,1.66928,1.3653,1.3653,0,0,1-1.6693-.94781Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M236.80246,568.16434a26.01425,26.01425,0,0,0,22.6665,11.69871c11.47417-.54466,21.04-8.55293,29.651-16.15584l25.46969-22.48783-16.85671-.80672c-12.12234-.58011-24.55745-1.12124-36.10356,2.617s-22.19457,12.73508-24.30583,24.68624\"\n      fill=\"#e6e6e6\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M212.99392,600.79976c9.19853-16.27621,19.86805-34.36538,38.93262-40.14695A43.445,43.445,0,0,1,268.3022,558.962c1.73863.14991,1.30448,2.82994-.431,2.6803a40.36111,40.36111,0,0,0-26.133,6.91386c-7.36852,5.01554-13.10573,11.98848-17.96161,19.383-2.97439,4.52936-5.63867,9.25082-8.30346,13.966-.85161,1.50687-3.34078.41915-2.47922-1.10534Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M198.25523,617.93168a19.69836,19.69836,0,0,1,12.0709-16.49847v-9.40956h15.782v9.70608a19.68812,19.68812,0,0,1,11.41362,16.202l3.711,43.13835H194.54417Z\"\n      fill=\"#f2f2f2\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M734.973,411.955l-4.69488-1.97685-3.22067-23.53551h-42.889l-3.491,23.43936-4.20031,2.10013a.99744.99744,0,0,0,.44611,1.88955h57.66283A.99739.99739,0,0,0,734.973,411.955Z\"\n      fill=\"#e6e6e6\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M811.1898,389.574H600.50692a4.174,4.174,0,0,1-4.16467-4.174V355.69092H815.35446V385.4A4.17408,4.17408,0,0,1,811.1898,389.574Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M815.57469,369.73213H596.15V242.61337a5.0375,5.0375,0,0,1,5.03186-5.03167h209.361a5.03755,5.03755,0,0,1,5.03191,5.03167Z\"\n      fill=\"#3f3d56\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M802.46932,360.50584h-193.214a3.88344,3.88344,0,0,1-3.87919-3.87908V250.68707a3.88365,3.88365,0,0,1,3.87919-3.87932h193.214a3.88366,3.88366,0,0,1,3.8792,3.87932V356.62676A3.88345,3.88345,0,0,1,802.46932,360.50584Z\"\n      fill=\"#fff\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M751.57964,397.88662a11.6159,11.6159,0,0,1,17.666,2.27241l26.13446-4.64642,6.69716,15.19317-36.99908,6.04328a11.67883,11.67883,0,0,1-13.49855-18.86244Z\"\n      fill=\"#ffb6b6\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M775.77611,417.286l27.24571-.33963,3.44882-.04668,55.43253-.69843s15.05312-14.3609,28.16068-29.1465l-1.83719-13.28833A54.29159,54.29159,0,0,0,870.023,340.1519C851.24988,352.696,840.363,377.52559,840.363,377.52559l-34.37018,8.22071-3.43848.82227-21.35608,5.10326Z\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M915.25011,498.96167H864.39249c0,2.17915-55.59414,3.94772-55.59414,3.94772a20.30858,20.30858,0,0,0-3.33166,3.15818,19.59694,19.59694,0,0,0-4.58,12.63271v3.15818a19.74588,19.74588,0,0,0,19.73861,19.73861h94.62478a19.75579,19.75579,0,0,0,19.73862-19.73861v-3.15818A19.76607,19.76607,0,0,0,915.25011,498.96167Z\"\n      fill=\"#e4e4e4\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <rect\n      fill=\"#e4e4e4\"\n      height=\"118.48951\"\n      width=\"20.52816\"\n      x=\"747.4019\"\n      y=\"303.23122\"\n    />\n    <path\n      d=\"M799.31222,658.58132c0,2.218,31.10721.858,69.47992.858s69.47991,1.36012,69.47991-.858-31.1072-19.807-69.47991-19.807S799.31222,656.36323,799.31222,658.58132Z\"\n      fill=\"#e4e4e4\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <polygon\n      fill=\"#ffb6b6\"\n      points=\"675.186 407.461 659.908 407.46 652.64 348.531 675.188 348.532 675.186 407.461\"\n    />\n    <path\n      d=\"M789.41863,659.852l-49.2623-.00183v-.62309a19.17528,19.17528,0,0,1,19.17426-19.17395h.00122l30.08773.00122Z\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <polygon\n      fill=\"#ffb6b6\"\n      points=\"630.031 407.461 614.753 407.46 607.485 348.531 630.033 348.532 630.031 407.461\"\n    />\n    <path\n      d=\"M744.2636,659.852l-49.2623-.00183v-.62309a19.1753,19.1753,0,0,1,19.17426-19.17395h.00122l30.08773.00122Z\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <circle cx=\"766.88656\" cy=\"41.63615\" fill=\"#ffb6b6\" r=\"26.56401\" />\n    <path\n      d=\"M920.21655,461.22417s8.91308,47.1307-24.99958,53.13247-82.86639,10.21993-82.86639,10.21993L790.36706,627.14324l-29.53443-2.63675s3.928-123.46737,13.5876-133.127,70.71212-38.58282,70.71212-38.58282Z\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M853.98286,441.47135,839.151,456.35062s-107.0941,17.25-111.22553,41.9852c-6.23747,37.34427-13.60493,118.552-13.60493,118.552l32.1988-2.41491,12.62647-92.31123,51.5182-11.71874L869.27729,478.5Z\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M902.78526,263.36115c-2.6223-4.94751-5.95413-14.80785-11.24679-16.63657a42.07731,42.07731,0,0,0-9.05841-1.92972l-8.99618,3.46009,4.89616-3.808q-1.42988-.08519-2.85817-.13928l-6.0699,2.33453,3.10542-2.41532c-5.65883-.05808-11.5.53031-15.88468,3.9752-3.73817,2.93677-7.44169,14.06185-8.04057,18.77753a35.9171,35.9171,0,0,0,.6603,13.53055l1.53716,1.46166a18.85936,18.85936,0,0,0,1.206-3.83883,18.18056,18.18056,0,0,1,8.70263-11.80641l.08368-.0472c2.5782-1.451,5.7065-1.3841,8.66308-1.27769l14.04158.50527c3.37829.12158,7.01608.33533,9.64978,2.45443a15.888,15.888,0,0,1,3.85826,5.58929c1.30868,2.6414,3.8661,12.60418,3.8661,12.60418s1.44689-1.88062,2.1404-.48092a48.39766,48.39766,0,0,0,2.01437-11.23347A22.00877,22.00877,0,0,0,902.78526,263.36115Z\"\n      fill=\"#2f2e41\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M995.69426,290.88349A11.61582,11.61582,0,0,0,985.181,305.26136l-21.3614,15.75722,6.40951,15.31674,29.8539-22.67594a11.67883,11.67883,0,0,0-4.38876-22.77589Z\"\n      fill=\"#ffb6b6\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M992.25627,323.052l-53.551,59.4744s-25.60913-8.19816-45.41466-17.08624l-8.8977-27.32787a54.34329,54.34329,0,0,1-2.60112-19.66442c27.45606-7.306,59.391,19.87863,59.391,19.87863l40.08517-31.39877Z\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M867.301,465.6169c-9.554-3.30029-19.43312-6.71277-30.08912-7.99385l-.45773-.05533.12632-.443c11.03073-38.7308,8.27761-63.50657,2.87195-100.72306a37.59072,37.59072,0,0,1,21.5483-39.50121l.06542-.02958,30.43436-1.93391.06935-.00423,22.13437,6.50989a15.18313,15.18313,0,0,1,10.86724,14.83111c-.23987,12.23937.26868,25.9043.80711,40.37114,1.20787,32.45569,2.45686,66.01647-4.63045,87.79166l-.03718.11412-.09462.07416a36.09883,36.09883,0,0,1-23.08086,8.10758C887.90057,472.73235,877.76186,469.23034,867.301,465.6169Z\"\n      fill=\"hsl(var(--primary))\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n    <path\n      d=\"M1088.24817,662.4183H111.75183a1.41521,1.41521,0,1,1,0-2.83042h976.49634a1.41521,1.41521,0,1,1,0,2.83042Z\"\n      fill=\"#ccc\"\n      transform=\"translate(-110.33661 -237.5817)\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue",
    "content": "<template>\n  <svg\n    height=\"458.68642\"\n    viewBox=\"0 0 656 458.68642\"\n    width=\"656\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n  >\n    <rect fill=\"#3f3d56\" height=\"2\" width=\"656\" y=\"434.34322\" />\n    <g>\n      <path\n        d=\"M471.97092,210.81397c-6.0733-36.41747-37.72842-64.16942-75.86423-64.16942H240.14931c-38.12099,0-69.76869,27.72972-75.86421,64.12497-.70358,4.16241-1.06653,8.44331-1.06653,12.80573v135.88599c0,4.36237,.36295,8.63589,1.06653,12.79831,4.85126,28.99625,25.92996,52.49686,53.58563,60.84393,7.05095,2.13306,14.53143,3.28104,22.27859,3.28104h155.9574c7.74716,0,15.22763-1.14798,22.27859-3.28104,27.66309-8.35449,48.74921-31.86993,53.58563-60.88837,.6962-4.14758,1.05911-8.40628,1.05911-12.75388V223.57525c0-4.34758-.36292-8.61369-1.05911-12.76128h-.00003Zm-62.66592,222.28954c-4.2883,.76285-8.69516,1.16281-13.19827,1.16281H240.14931c-4.50313,0-8.90997-.39999-13.19829-1.16281-35.01768-6.22885-61.60677-36.83228-61.60677-73.64224v-45.10526c0-127.45004,103.31242-165.58582,230.76244-165.58582,41.31314,0,74.80505,33.49194,74.80505,74.80505v135.88599c-100.29059,13.42047-26.58911,67.41339-61.60678,73.64224l.00003,.00003Z\"\n        fill=\"#3f3d56\"\n      />\n      <polygon\n        fill=\"hsl(var(--primary))\"\n        points=\"349.16196 249.18644 355.16196 288.18642 443.16196 276.18642 434.66196 230.6195 349.16196 249.18644\"\n      />\n      <rect\n        fill=\"#2f2e41\"\n        height=\"37.66125\"\n        width=\"36.38461\"\n        x=\"381.84177\"\n        y=\"30.34218\"\n      />\n      <polygon\n        fill=\"#ffb6b6\"\n        points=\"385.16196 70.18643 394.16196 43.18643 411.70447 43.18643 412.62653 70.18643 385.16196 70.18643\"\n      />\n      <polygon\n        isolation=\"isolate\"\n        opacity=\".1\"\n        points=\"385.16196 70.18643 394.16196 43.18643 411.70447 43.18643 412.62653 70.18643 385.16196 70.18643\"\n      />\n      <path\n        d=\"M394.66196,310.68642l-1,104-1,8v11.48425l15,1.51575,1-23s16-45,12-80-2-25-2-25l-24,3Z\"\n        fill=\"#ffb6b6\"\n      />\n      <path\n        d=\"M404.18408,318.85363l-36.90134,97.23831-1.97873,7.81567-4.1777,10.69742-14.52368-4.04477,7.43539-21.78796s1.46619-47.7373,17.92432-78.88422,10.9574-22.5596,10.9574-22.5596l21.26434,11.52512v.00003Z\"\n        fill=\"#ffb6b6\"\n      />\n      <path\n        d=\"M385.16196,67.18643l-27,12,17.23959,89.01208-2.72385,127.75565-18,38s-3.01575,21.73227,27.98425,7.73227,66-18,66-18l-8.5-58.5-7.5-153.5,1-34-22-14s-26.5,3.5-26.5,3.50001Z\"\n        fill=\"#2f2e41\"\n      />\n      <path\n        d=\"M370.1243,335.34322l-29.96231-50.15677,34.23959-116.98792-16.23959-89.01208,28.49045-12.19685s14.74915,14.36248,14.74915,26.20894-31.27728,242.1447-31.27728,242.1447v-.00003Z\"\n        fill=\"#e6e6e6\"\n      />\n      <path\n        d=\"M435.1243,325.34322l-27.19693-233.62811c-.34341-2.94999,.16013-5.93678,1.45178-8.6111l7.78284-16.11441,30.5,8.69685-12.26041,95.51208,32.76041,93.98792-33.03769,60.15677Z\"\n        fill=\"#e6e6e6\"\n      />\n      <path\n        d=\"M410.66196,433.68642s-19-11-21-5-3,11-3,11c0,0-5,19,10,19s14-8.64172,14-8.64172v-16.35828Z\"\n        fill=\"#2f2e41\"\n      />\n      <path\n        d=\"M344.53574,427.60598s21.69977-3.33459,21.3801,2.9819c-.3197,6.31647-1.20709,11.33768-1.20709,11.33768,0,0-2.25433,19.51712-16.22662,14.06046s-9.89713-13.14252-9.89713-13.14252l5.95078-15.23749-.00003-.00003Z\"\n        fill=\"#2f2e41\"\n      />\n      <circle cx=\"404.10297\" cy=\"33.02146\" fill=\"#ffb6b6\" r=\"24.85993\" />\n      <path\n        d=\"M423.96469,10.86766c-1.15707-6.12936-7.44913-10.27514-13.66504-10.79501s-12.30453,1.82726-17.90228,4.57921c-3.79456,1.86548-7.53061,3.96811-10.60425,6.87182s-5.46063,6.69692-6.01202,10.88913c-.19507,1.48324-.1698,3.03289-.77692,4.40016-.75845,1.708-2.38654,2.86795-3.36917,4.4576-1.76227,2.85096-.95267,6.99858,1.75238,8.97753-3.40024,1.44912-6.89398,2.96069-9.48602,5.59563s-4.08878,6.70308-2.66644,10.11462c.50323,1.20699,1.33481,2.26349,1.76489,3.49843,.81668,2.34499,.03943,5.00909-1.40924,7.02585s-3.49316,3.51228-5.50174,4.97226c5.16196,1.01177,10.43097,1.80015,15.66992,1.32811s10.49707-2.30805,14.29086-5.95176c3.79379-3.64371,5.88083-9.26437,4.51974-14.34539-1.04269-3.89231-3.95898-7.30301-3.95712-11.33256,.00143-3.09747,1.7431-5.89158,3.4249-8.49271,3.67291-5.68066,7.34579-11.36132,11.01868-17.04197,.66068-1.02183,1.35739-2.07924,2.4014-2.70425,1.77606-1.06326,4.0798-.59568,5.95227,.28683,1.87244,.88252,3.58304,2.14867,5.57941,2.69585,4.07452,1.11677,8.80106-1.44789,10.08575-5.47261\"\n        fill=\"#2f2e41\"\n      />\n      <path\n        d=\"M409.27951,61.42523c-2.07159,2.0061-5.05701,2.65225-7.82379,3.46516s-5.70978,2.09141-6.95499,4.69243c-1.22101,2.55043-.33459,5.78793,1.68692,7.76505s4.95816,2.80999,7.78555,2.77077c2.82736-.03922,5.58282-.86796,8.24176-1.8301,7.27054-2.63087,14.15665-6.32148,20.37314-10.919-4.02679-1.11411-6.66107-5.81614-5.50836-9.83205,.93768-3.26677,3.80499-5.54528,5.75616-8.32809,3.35959-4.79151,3.91925-11.10753,2.80676-16.85277-1.11246-5.74524-3.73163-11.07097-6.32358-16.3176-.81934-1.65853-1.65805-3.34513-2.93619-4.68245-1.27814-1.33731-3.08783-2.29539-4.92776-2.10379-3.05334,.31795-5.00302,3.66989-5.02377,6.7397s1.32593,5.95491,2.34732,8.84988c1.05231,2.98259,1.78381,6.14409,1.50146,9.29425-.2366,2.63989-1.19669,5.21132-2.74811,7.36029-1.19809,1.65954-2.72479,3.05223-4.0275,4.63097-1.00714,1.22055-1.90009,2.60309-2.16486,4.16321-.48181,2.83914,1.18356,5.71186,.72714,8.55519-.48248,3.0056-3.6452,5.3067-6.65341,4.84085\"\n        fill=\"#2f2e41\"\n      />\n      <g>\n        <circle\n          cx=\"333.2486\"\n          cy=\"323.64455\"\n          fill=\"hsl(var(--primary))\"\n          r=\"85\"\n        />\n        <g>\n          <path\n            d=\"M384.17838,316.82296h-10.56668c-1.64377-9.68713-6.7168-18.46011-14.2923-24.71729-17.43427-14.39993-43.24109-11.94022-57.64099,5.49411-.04913,.05563-.09644,.11282-.14169,.17151-1.15063,1.49146-.87427,3.63333,.61716,4.784,1.49118,1.1507,3.63306,.87448,4.78394-.61697,6.25537-7.5788,15.72369-12.40167,26.31064-12.40167,16.20853,.00195,30.17899,11.40631,33.42572,27.28629h-9.31805c-.3988,.00012-.78458,.13992-1.09082,.39502-.72375,.60281-.82175,1.6781-.21915,2.40186l13.41125,16.09894c.06577,.07889,.13855,.1517,.21759,.21747,.72324,.60327,1.79871,.50583,2.40186-.21747l13.41125-16.09894c.25504-.30624,.3949-.69223,.39514-1.09082,.00027-.94186-.763-1.70566-1.70486-1.70605v.00003Z\"\n            fill=\"#fff\"\n          />\n          <path\n            d=\"M364.34329,344.7337c-1.49146-1.15063-3.63333-.87433-4.78394,.6171-4.96201,6.00781-11.83066,10.13629-19.46436,11.69922-18.46167,3.77988-36.49231-8.12213-40.27225-26.58392h9.3183c.94186-.0004,1.70514-.76419,1.70486-1.70605-.00027-.39853-.14011-.78452-.39514-1.09082l-13.41125-16.09888c-.60312-.72336-1.67862-.8208-2.40186-.21753-.07904,.06577-.15182,.13855-.21759,.21753l-13.41125,16.09888c-.6026,.72375-.50461,1.7991,.21915,2.40186,.30624,.25516,.69205,.3949,1.09082,.39502h10.56641c1.64404,9.68723,6.7168,18.46011,14.29254,24.71729,17.43427,14.39999,43.24109,11.94022,57.64099-5.49405,.04913-.05569,.09619-.11295,.14142-.17163,1.15088-1.49146,.87454-3.63327-.61691-4.784h.00006Z\"\n            fill=\"#fff\"\n          />\n        </g>\n      </g>\n      <path\n        id=\"uuid-da16df1e-5659-4232-96f6-61e8c639a9ec-574\"\n        d=\"M356.98148,237.19363c-1.02939,7.36621-5.66458,12.80598-10.35239,12.15012-4.68781-.65588-7.65225-7.15837-6.62149-14.52707,.37137-2.94914,1.4436-5.76646,3.12701-8.21626l4.75577-31.15587,14.57297,2.54338-6.23553,30.44414c.94736,2.81844,1.20581,5.82278,.75369,8.76157h-.00003Z\"\n        fill=\"#ffb6b6\"\n      />\n      <path\n        d=\"M369.66196,77.68643s-15-5-17,13-4,39.99999-4,39.99999c0,0-9,21-5,32s11,3.3307,4,12.66534-6.02478,40.04724-6.02478,40.04724l22.52478-1.13387s12.5-82.57875,12.5-84.57875-7-52-7-52v.00004Z\"\n        fill=\"#e6e6e6\"\n      />\n      <g>\n        <path\n          id=\"uuid-6bf35aa9-e432-4b51-af77-8f4eb19e6e42-575\"\n          d=\"M467.16132,233.84998c.27881,7.43257-3.33017,13.60114-8.06033,13.7778s-8.78937-5.70491-9.06732-13.14017c-.15176-2.96857,.40961-5.93028,1.63712-8.63741l-.78369-31.507,14.79315-.05261-.798,31.0659c1.42709,2.60854,2.20859,5.52095,2.27905,8.49347l.00003,.00002Z\"\n          fill=\"#ffb6b6\"\n        />\n        <path\n          d=\"M444.06961,77.34876s15.08694-4.73121,16.76505,13.30165,3.28473,51.06508,3.28473,51.06508c0,0,8.62338,21.15744,4.42749,32.08421s-11.05774,3.13365-4.22565,12.59187c6.83212,9.45822,4.37997,36.13126,4.37997,36.13126l-22.50095-1.53612s-10.09427-78.77167-10.05853-80.77133,7.92792-62.86664,7.92792-62.86664l-.00003,.00002Z\"\n          fill=\"#e6e6e6\"\n        />\n      </g>\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/fallback/index.ts",
    "content": "export type * from './fallback';\nexport { default as Fallback } from './fallback.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/src/ui/index.ts",
    "content": "export * from './about';\nexport * from './authentication';\nexport * from './dashboard';\nexport * from './fallback';\n"
  },
  {
    "path": "hiauth-front/packages/effects/common-ui/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/README.md",
    "content": "# @vben/hooks\n\n用于多个 `app` 公用的 hook，继承了 `@vben/hooks` 的所有能力。业务上有通用 hooks 可以放在这里。\n\n## 用法\n\n### 添加依赖\n\n```bash\n# 进入目标应用目录，例如 apps/xxxx-app\n# cd apps/xxxx-app\npnpm add @vben/hooks\n```\n\n### 使用\n\n```ts\nimport { useNamespace } from '@vben/hooks';\n```\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/package.json",
    "content": "{\n  \"name\": \"@vben/hooks\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/effects/hooks\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/composables\": \"workspace:*\",\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/stores\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\",\n    \"watermark-js-plus\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/index.ts",
    "content": "export * from './use-app-config';\nexport * from './use-content-maximize';\nexport * from './use-design-tokens';\nexport * from './use-hover-toggle';\nexport * from './use-pagination';\nexport * from './use-refresh';\nexport * from './use-tabs';\nexport * from './use-watermark';\nexport * from '@vben-core/composables';\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/use-app-config.ts",
    "content": "import type {\n  ApplicationConfig,\n  VbenAdminProAppConfigRaw,\n} from '@vben/types/global';\n\n/**\n * 由 vite-inject-app-config 注入的全局配置\n */\nexport function useAppConfig(\n  env: Record<string, any>,\n  isProduction: boolean,\n): ApplicationConfig {\n  // 生产环境下，直接使用 window._VBEN_ADMIN_PRO_APP_CONF_ 全局变量\n  const config = isProduction\n    ? window._VBEN_ADMIN_PRO_APP_CONF_\n    : (env as VbenAdminProAppConfigRaw);\n\n  const {\n    VITE_GLOB_API_URL,\n    VITE_GLOB_AUTH_DINGDING_CORP_ID,\n    VITE_GLOB_AUTH_DINGDING_CLIENT_ID,\n  } = config;\n\n  const applicationConfig: ApplicationConfig = {\n    apiURL: VITE_GLOB_API_URL,\n    auth: {},\n  };\n  if (VITE_GLOB_AUTH_DINGDING_CORP_ID && VITE_GLOB_AUTH_DINGDING_CLIENT_ID) {\n    applicationConfig.auth.dingding = {\n      clientId: VITE_GLOB_AUTH_DINGDING_CLIENT_ID,\n      corpId: VITE_GLOB_AUTH_DINGDING_CORP_ID,\n    };\n  }\n\n  return applicationConfig;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/use-content-maximize.ts",
    "content": "import { updatePreferences, usePreferences } from '@vben/preferences';\n/**\n * 主体区域最大化\n */\nexport function useContentMaximize() {\n  const { contentIsMaximize } = usePreferences();\n\n  function toggleMaximize() {\n    const isMaximize = contentIsMaximize.value;\n\n    updatePreferences({\n      header: {\n        hidden: !isMaximize,\n      },\n      sidebar: {\n        hidden: !isMaximize,\n      },\n    });\n  }\n  return {\n    contentIsMaximize,\n    toggleMaximize,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/use-design-tokens.ts",
    "content": "import { reactive, watch } from 'vue';\n\nimport { preferences, usePreferences } from '@vben/preferences';\nimport { convertToRgb, updateCSSVariables } from '@vben/utils';\n\n/**\n * 用于适配各个框架的设计系统\n */\n\nexport function useAntdDesignTokens() {\n  const rootStyles = getComputedStyle(document.documentElement);\n\n  const tokens = reactive({\n    borderRadius: '' as any,\n    colorBgBase: '',\n    colorBgContainer: '',\n    colorBgElevated: '',\n    colorBgLayout: '',\n    colorBgMask: '',\n    colorBorder: '',\n    colorBorderSecondary: '',\n    colorError: '',\n    colorInfo: '',\n    colorPrimary: '',\n    colorSuccess: '',\n    colorTextBase: '',\n    colorWarning: '',\n    zIndexPopupBase: 2000, // 调整基础弹层层级，避免下拉等组件被弹窗或者最大化状态下的表格遮挡\n  });\n\n  const getCssVariableValue = (variable: string, isColor: boolean = true) => {\n    const value = rootStyles.getPropertyValue(variable);\n    return isColor ? `hsl(${value})` : value;\n  };\n\n  watch(\n    () => preferences.theme,\n    () => {\n      tokens.colorPrimary = getCssVariableValue('--primary');\n\n      tokens.colorInfo = getCssVariableValue('--primary');\n\n      tokens.colorError = getCssVariableValue('--destructive');\n\n      tokens.colorWarning = getCssVariableValue('--warning');\n\n      tokens.colorSuccess = getCssVariableValue('--success');\n\n      tokens.colorTextBase = getCssVariableValue('--foreground');\n\n      getCssVariableValue('--primary-foreground');\n\n      tokens.colorBorderSecondary = tokens.colorBorder =\n        getCssVariableValue('--border');\n\n      tokens.colorBgElevated = getCssVariableValue('--popover');\n\n      tokens.colorBgContainer = getCssVariableValue('--card');\n\n      tokens.colorBgBase = getCssVariableValue('--background');\n\n      const radius = Number.parseFloat(getCssVariableValue('--radius', false));\n      // 1rem = 16px\n      tokens.borderRadius = radius * 16;\n\n      tokens.colorBgLayout = getCssVariableValue('--background-deep');\n      tokens.colorBgMask = getCssVariableValue('--overlay');\n    },\n    { immediate: true },\n  );\n\n  return {\n    tokens,\n  };\n}\n\nexport function useNaiveDesignTokens() {\n  const rootStyles = getComputedStyle(document.documentElement);\n\n  const commonTokens = reactive({\n    baseColor: '',\n    bodyColor: '',\n    borderColor: '',\n    borderRadius: '',\n    cardColor: '',\n    dividerColor: '',\n    errorColor: '',\n    errorColorHover: '',\n    errorColorPressed: '',\n    errorColorSuppl: '',\n    invertedColor: '',\n    modalColor: '',\n    popoverColor: '',\n    primaryColor: '',\n    primaryColorHover: '',\n    primaryColorPressed: '',\n    primaryColorSuppl: '',\n    successColor: '',\n    successColorHover: '',\n    successColorPressed: '',\n    successColorSuppl: '',\n    tableColor: '',\n    textColorBase: '',\n    warningColor: '',\n    warningColorHover: '',\n    warningColorPressed: '',\n    warningColorSuppl: '',\n  });\n\n  const getCssVariableValue = (variable: string, isColor: boolean = true) => {\n    const value = rootStyles.getPropertyValue(variable);\n    return isColor ? convertToRgb(`hsl(${value})`) : value;\n  };\n\n  watch(\n    () => preferences.theme,\n    () => {\n      commonTokens.primaryColor = getCssVariableValue('--primary');\n      commonTokens.primaryColorHover = getCssVariableValue('--primary-600');\n      commonTokens.primaryColorPressed = getCssVariableValue('--primary-700');\n      commonTokens.primaryColorSuppl = getCssVariableValue('--primary-800');\n\n      commonTokens.errorColor = getCssVariableValue('--destructive');\n      commonTokens.errorColorHover = getCssVariableValue('--destructive-600');\n      commonTokens.errorColorPressed = getCssVariableValue('--destructive-700');\n      commonTokens.errorColorSuppl = getCssVariableValue('--destructive-800');\n\n      commonTokens.warningColor = getCssVariableValue('--warning');\n      commonTokens.warningColorHover = getCssVariableValue('--warning-600');\n      commonTokens.warningColorPressed = getCssVariableValue('--warning-700');\n      commonTokens.warningColorSuppl = getCssVariableValue('--warning-800');\n\n      commonTokens.successColor = getCssVariableValue('--success');\n      commonTokens.successColorHover = getCssVariableValue('--success-600');\n      commonTokens.successColorPressed = getCssVariableValue('--success-700');\n      commonTokens.successColorSuppl = getCssVariableValue('--success-800');\n\n      commonTokens.textColorBase = getCssVariableValue('--foreground');\n\n      commonTokens.baseColor = getCssVariableValue('--primary-foreground');\n\n      commonTokens.dividerColor = commonTokens.borderColor =\n        getCssVariableValue('--border');\n\n      commonTokens.modalColor = commonTokens.popoverColor =\n        getCssVariableValue('--popover');\n\n      commonTokens.tableColor = commonTokens.cardColor =\n        getCssVariableValue('--card');\n\n      commonTokens.bodyColor = getCssVariableValue('--background');\n      commonTokens.invertedColor = getCssVariableValue('--background-deep');\n\n      commonTokens.borderRadius = getCssVariableValue('--radius', false);\n    },\n    { immediate: true },\n  );\n  return {\n    commonTokens,\n  };\n}\n\nexport function useElementPlusDesignTokens() {\n  const { isDark } = usePreferences();\n  const rootStyles = getComputedStyle(document.documentElement);\n\n  const getCssVariableValueRaw = (variable: string) => {\n    return rootStyles.getPropertyValue(variable);\n  };\n\n  const getCssVariableValue = (variable: string, isColor: boolean = true) => {\n    const value = getCssVariableValueRaw(variable);\n    return isColor ? convertToRgb(`hsl(${value})`) : value;\n  };\n\n  watch(\n    () => preferences.theme,\n    () => {\n      const background = getCssVariableValue('--background');\n      const border = getCssVariableValue('--border');\n      const accent = getCssVariableValue('--accent');\n\n      const variables: Record<string, string> = {\n        '--el-bg-color': background,\n        '--el-bg-color-overlay': getCssVariableValue('--popover'),\n        '--el-bg-color-page': getCssVariableValue('--background-deep'),\n        '--el-border-color': border,\n        '--el-border-color-dark': border,\n        '--el-border-color-extra-light': border,\n        '--el-border-color-hover': accent,\n        '--el-border-color-light': border,\n        '--el-border-color-lighter': border,\n\n        '--el-border-radius-base': getCssVariableValue('--radius', false),\n        '--el-color-danger': getCssVariableValue('--destructive-500'),\n        '--el-color-danger-dark-2': isDark.value\n          ? getCssVariableValue('--destructive-400')\n          : getCssVariableValue('--destructive-600'),\n        '--el-color-danger-light-3': isDark.value\n          ? getCssVariableValue('--destructive-600')\n          : getCssVariableValue('--destructive-400'),\n        '--el-color-danger-light-5': isDark.value\n          ? getCssVariableValue('--destructive-700')\n          : getCssVariableValue('--destructive-300'),\n        '--el-color-danger-light-7': isDark.value\n          ? getCssVariableValue('--destructive-800')\n          : getCssVariableValue('--destructive-200'),\n        '--el-color-danger-light-8': isDark.value\n          ? getCssVariableValue('--destructive-900')\n          : getCssVariableValue('--destructive-100'),\n        '--el-color-danger-light-9': isDark.value\n          ? getCssVariableValue('--destructive-950')\n          : getCssVariableValue('--destructive-50'),\n\n        '--el-color-error': getCssVariableValue('--destructive-500'),\n        '--el-color-error-dark-2': isDark.value\n          ? getCssVariableValue('--destructive-400')\n          : getCssVariableValue('--destructive-600'),\n        '--el-color-error-light-3': isDark.value\n          ? getCssVariableValue('--destructive-600')\n          : getCssVariableValue('--destructive-400'),\n        '--el-color-error-light-5': isDark.value\n          ? getCssVariableValue('--destructive-700')\n          : getCssVariableValue('--destructive-300'),\n        '--el-color-error-light-7': isDark.value\n          ? getCssVariableValue('--destructive-800')\n          : getCssVariableValue('--destructive-200'),\n        '--el-color-error-light-8': isDark.value\n          ? getCssVariableValue('--destructive-900')\n          : getCssVariableValue('--destructive-100'),\n        '--el-color-error-light-9': isDark.value\n          ? getCssVariableValue('--destructive-950')\n          : getCssVariableValue('--destructive-50'),\n\n        '--el-color-info-light-5': border,\n        '--el-color-info-light-8': border,\n        '--el-color-info-light-9': getCssVariableValue('--info'), // getCssVariableValue('--secondary'),\n\n        '--el-color-primary': getCssVariableValue('--primary-500'),\n        '--el-color-primary-dark-2': isDark.value\n          ? getCssVariableValue('--primary-400')\n          : getCssVariableValue('--primary-600'),\n        '--el-color-primary-light-3': isDark.value\n          ? getCssVariableValue('--primary-600')\n          : getCssVariableValue('--primary-400'),\n        '--el-color-primary-light-5': isDark.value\n          ? getCssVariableValue('--primary-700')\n          : getCssVariableValue('--primary-300'),\n        '--el-color-primary-light-7': isDark.value\n          ? getCssVariableValue('--primary-800')\n          : getCssVariableValue('--primary-200'),\n        '--el-color-primary-light-8': isDark.value\n          ? getCssVariableValue('--primary-900')\n          : getCssVariableValue('--primary-100'),\n        '--el-color-primary-light-9': isDark.value\n          ? getCssVariableValue('--primary-950')\n          : getCssVariableValue('--primary-50'),\n\n        '--el-color-success': getCssVariableValue('--success-500'),\n        '--el-color-success-dark-2': isDark.value\n          ? getCssVariableValue('--success-400')\n          : getCssVariableValue('--success-600'),\n        '--el-color-success-light-3': isDark.value\n          ? getCssVariableValue('--success-600')\n          : getCssVariableValue('--success-400'),\n        '--el-color-success-light-5': isDark.value\n          ? getCssVariableValue('--success-700')\n          : getCssVariableValue('--success-300'),\n        '--el-color-success-light-7': isDark.value\n          ? getCssVariableValue('--success-800')\n          : getCssVariableValue('--success-200'),\n        '--el-color-success-light-8': isDark.value\n          ? getCssVariableValue('--success-900')\n          : getCssVariableValue('--success-100'),\n        '--el-color-success-light-9': isDark.value\n          ? getCssVariableValue('--success-950')\n          : getCssVariableValue('--success-50'),\n\n        '--el-color-warning': getCssVariableValue('--warning-500'),\n        '--el-color-warning-dark-2': isDark.value\n          ? getCssVariableValue('--warning-400')\n          : getCssVariableValue('--warning-600'),\n        '--el-color-warning-light-3': isDark.value\n          ? getCssVariableValue('--warning-600')\n          : getCssVariableValue('--warning-400'),\n        '--el-color-warning-light-5': isDark.value\n          ? getCssVariableValue('--warning-700')\n          : getCssVariableValue('--warning-300'),\n        '--el-color-warning-light-7': isDark.value\n          ? getCssVariableValue('--warning-800')\n          : getCssVariableValue('--warning-200'),\n        '--el-color-warning-light-8': isDark.value\n          ? getCssVariableValue('--warning-900')\n          : getCssVariableValue('--warning-100'),\n        '--el-color-warning-light-9': isDark.value\n          ? getCssVariableValue('--warning-950')\n          : getCssVariableValue('--warning-50'),\n\n        '--el-fill-color': getCssVariableValue('--accent'),\n        '--el-fill-color-blank': background,\n        '--el-fill-color-light': getCssVariableValue('--accent'),\n        '--el-fill-color-lighter': getCssVariableValue('--accent-lighter'),\n\n        '--el-fill-color-dark': getCssVariableValue('--accent-dark'),\n        '--el-fill-color-darker': getCssVariableValue('--accent-darker'),\n\n        // 解决ElLoading背景色问题\n        '--el-mask-color': isDark.value\n          ? 'rgba(0,0,0,.8)'\n          : 'rgba(255,255,255,.9)',\n\n        '--el-text-color-primary': getCssVariableValue('--foreground'),\n\n        '--el-text-color-regular': getCssVariableValue('--foreground'),\n      };\n\n      updateCSSVariables(variables, `__vben_design_styles__`);\n    },\n    { immediate: true },\n  );\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/use-hover-toggle.ts",
    "content": "import type { Arrayable, MaybeElementRef } from '@vueuse/core';\n\nimport type { Ref } from 'vue';\n\nimport { computed, effectScope, onUnmounted, ref, unref, watch } from 'vue';\n\nimport { isFunction } from '@vben/utils';\n\nimport { useElementHover } from '@vueuse/core';\n\ninterface HoverDelayOptions {\n  /** 鼠标进入延迟时间 */\n  enterDelay?: (() => number) | number;\n  /** 鼠标离开延迟时间 */\n  leaveDelay?: (() => number) | number;\n}\n\nconst DEFAULT_LEAVE_DELAY = 500; // 鼠标离开延迟时间，默认为 500ms\nconst DEFAULT_ENTER_DELAY = 0; // 鼠标进入延迟时间，默认为 0（立即响应）\n\n/**\n * 监测鼠标是否在元素内部，如果在元素内部则返回 true，否则返回 false\n * @param refElement 所有需要检测的元素。支持单个元素、元素数组或响应式引用的元素数组。如果鼠标在任何一个元素内部都会返回 true\n * @param delay 延迟更新状态的时间，可以是数字或包含进入/离开延迟的配置对象\n * @returns 返回一个数组，第一个元素是一个 ref，表示鼠标是否在元素内部，第二个元素是一个控制器，可以通过 enable 和 disable 方法来控制监听器的启用和禁用\n */\nexport function useHoverToggle(\n  refElement: Arrayable<MaybeElementRef> | Ref<HTMLElement[] | null>,\n  delay: (() => number) | HoverDelayOptions | number = DEFAULT_LEAVE_DELAY,\n) {\n  // 兼容旧版本API\n  const normalizedOptions: HoverDelayOptions =\n    typeof delay === 'number' || isFunction(delay)\n      ? { enterDelay: DEFAULT_ENTER_DELAY, leaveDelay: delay }\n      : {\n          enterDelay: DEFAULT_ENTER_DELAY,\n          leaveDelay: DEFAULT_LEAVE_DELAY,\n          ...delay,\n        };\n\n  const value = ref(false);\n  const enterTimer = ref<ReturnType<typeof setTimeout> | undefined>();\n  const leaveTimer = ref<ReturnType<typeof setTimeout> | undefined>();\n  const hoverScopes = ref<ReturnType<typeof effectScope>[]>([]);\n\n  // 使用计算属性包装 refElement，使其响应式变化\n  const refs = computed(() => {\n    const raw = unref(refElement);\n    if (raw === null) return [];\n    return Array.isArray(raw) ? raw : [raw];\n  });\n  // 存储所有 hover 状态\n  const isHovers = ref<Array<Ref<boolean>>>([]);\n\n  // 更新 hover 监听的函数\n  function updateHovers() {\n    // 停止并清理之前的作用域\n    hoverScopes.value.forEach((scope) => scope.stop());\n    hoverScopes.value = [];\n\n    isHovers.value = refs.value.map((refEle) => {\n      if (!refEle) {\n        return ref(false);\n      }\n      const eleRef = computed(() => {\n        const ele = unref(refEle);\n        return ele instanceof Element ? ele : (ele?.$el as Element);\n      });\n\n      // 为每个元素创建独立的作用域\n      const scope = effectScope();\n      const hoverRef = scope.run(() => useElementHover(eleRef)) || ref(false);\n      hoverScopes.value.push(scope);\n\n      return hoverRef;\n    });\n  }\n\n  // 监听元素数量变化，避免过度执行\n  const elementsCount = computed(() => {\n    const raw = unref(refElement);\n    if (raw === null) return 0;\n    return Array.isArray(raw) ? raw.length : 1;\n  });\n\n  // 初始设置\n  updateHovers();\n\n  // 只在元素数量变化时重新设置监听器\n  const stopWatcher = watch(elementsCount, updateHovers, { deep: false });\n\n  const isOutsideAll = computed(() => isHovers.value.every((v) => !v.value));\n\n  function clearTimers() {\n    if (enterTimer.value) {\n      clearTimeout(enterTimer.value);\n      enterTimer.value = undefined;\n    }\n    if (leaveTimer.value) {\n      clearTimeout(leaveTimer.value);\n      leaveTimer.value = undefined;\n    }\n  }\n\n  function setValueDelay(val: boolean) {\n    clearTimers();\n\n    if (val) {\n      // 鼠标进入\n      const enterDelay = normalizedOptions.enterDelay ?? DEFAULT_ENTER_DELAY;\n      const delayTime = isFunction(enterDelay) ? enterDelay() : enterDelay;\n\n      if (delayTime <= 0) {\n        value.value = true;\n      } else {\n        enterTimer.value = setTimeout(() => {\n          value.value = true;\n          enterTimer.value = undefined;\n        }, delayTime);\n      }\n    } else {\n      // 鼠标离开\n      const leaveDelay = normalizedOptions.leaveDelay ?? DEFAULT_LEAVE_DELAY;\n      const delayTime = isFunction(leaveDelay) ? leaveDelay() : leaveDelay;\n\n      if (delayTime <= 0) {\n        value.value = false;\n      } else {\n        leaveTimer.value = setTimeout(() => {\n          value.value = false;\n          leaveTimer.value = undefined;\n        }, delayTime);\n      }\n    }\n  }\n\n  const hoverWatcher = watch(\n    isOutsideAll,\n    (val) => {\n      setValueDelay(!val);\n    },\n    { immediate: true },\n  );\n\n  const controller = {\n    enable() {\n      hoverWatcher.resume();\n    },\n    disable() {\n      hoverWatcher.pause();\n    },\n  };\n\n  onUnmounted(() => {\n    clearTimers();\n    // 停止监听器\n    stopWatcher();\n    // 停止所有剩余的作用域\n    hoverScopes.value.forEach((scope) => scope.stop());\n  });\n\n  return [value, controller] as [typeof value, typeof controller];\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/use-pagination.ts",
    "content": "import type { Ref } from 'vue';\n\nimport { computed, ref, unref } from 'vue';\n\n/**\n * Paginates an array of items\n * @param list The array to paginate\n * @param pageNo The current page number (1-based)\n * @param pageSize Number of items per page\n * @returns Paginated array slice\n * @throws {Error} If pageNo or pageSize are invalid\n */\nfunction pagination<T = any>(list: T[], pageNo: number, pageSize: number): T[] {\n  if (pageNo < 1) throw new Error('Page number must be positive');\n  if (pageSize < 1) throw new Error('Page size must be positive');\n\n  const offset = (pageNo - 1) * Number(pageSize);\n  const ret =\n    offset + pageSize >= list.length\n      ? list.slice(offset)\n      : list.slice(offset, offset + pageSize);\n  return ret;\n}\n\nexport function usePagination<T = any>(list: Ref<T[]>, pageSize: number) {\n  const currentPage = ref(1);\n  const pageSizeRef = ref(pageSize);\n\n  const totalPages = computed(() =>\n    Math.ceil(unref(list).length / unref(pageSizeRef)),\n  );\n\n  const paginationList = computed(() => {\n    return pagination(unref(list), unref(currentPage), unref(pageSizeRef));\n  });\n\n  const total = computed(() => {\n    return unref(list).length;\n  });\n\n  function setCurrentPage(page: number) {\n    if (page < 1 || page > unref(totalPages)) {\n      throw new Error('Invalid page number');\n    }\n    currentPage.value = page;\n  }\n\n  function setPageSize(pageSize: number) {\n    if (pageSize < 1) {\n      throw new Error('Page size must be positive');\n    }\n    pageSizeRef.value = pageSize;\n    // Reset to first page to prevent invalid state\n    currentPage.value = 1;\n  }\n\n  return { setCurrentPage, total, setPageSize, paginationList };\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/use-refresh.ts",
    "content": "import { useRouter } from 'vue-router';\n\nimport { useTabbarStore } from '@vben/stores';\n\nexport function useRefresh() {\n  const router = useRouter();\n  const tabbarStore = useTabbarStore();\n\n  async function refresh() {\n    await tabbarStore.refresh(router);\n  }\n\n  return {\n    refresh,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/use-tabs.ts",
    "content": "import type { ComputedRef } from 'vue';\nimport type { RouteLocationNormalized } from 'vue-router';\n\nimport { useRoute, useRouter } from 'vue-router';\n\nimport { useTabbarStore } from '@vben/stores';\n\nexport function useTabs() {\n  const router = useRouter();\n  const route = useRoute();\n  const tabbarStore = useTabbarStore();\n\n  async function closeLeftTabs(tab?: RouteLocationNormalized) {\n    await tabbarStore.closeLeftTabs(tab || route);\n  }\n\n  async function closeAllTabs() {\n    await tabbarStore.closeAllTabs(router);\n  }\n\n  async function closeRightTabs(tab?: RouteLocationNormalized) {\n    await tabbarStore.closeRightTabs(tab || route);\n  }\n\n  async function closeOtherTabs(tab?: RouteLocationNormalized) {\n    await tabbarStore.closeOtherTabs(tab || route);\n  }\n\n  async function closeCurrentTab(tab?: RouteLocationNormalized) {\n    await tabbarStore.closeTab(tab || route, router);\n  }\n\n  async function pinTab(tab?: RouteLocationNormalized) {\n    await tabbarStore.pinTab(tab || route);\n  }\n\n  async function unpinTab(tab?: RouteLocationNormalized) {\n    await tabbarStore.unpinTab(tab || route);\n  }\n\n  async function toggleTabPin(tab?: RouteLocationNormalized) {\n    await tabbarStore.toggleTabPin(tab || route);\n  }\n\n  async function refreshTab(name?: string) {\n    await tabbarStore.refresh(name || router);\n  }\n\n  async function openTabInNewWindow(tab?: RouteLocationNormalized) {\n    await tabbarStore.openTabInNewWindow(tab || route);\n  }\n\n  async function closeTabByKey(key: string) {\n    await tabbarStore.closeTabByKey(key, router);\n  }\n\n  /**\n   * 设置当前标签页的标题\n   *\n   * @description 支持设置静态标题字符串或动态计算标题\n   * @description 动态标题会在每次渲染时重新计算,适用于多语言或状态相关的标题\n   *\n   * @param title - 标题内容\n   *   - 静态标题: 直接传入字符串\n   *   - 动态标题: 传入 ComputedRef\n   *\n   * @example\n   * // 静态标题\n   * setTabTitle('标签页')\n   *\n   * // 动态标题(多语言)\n   * setTabTitle(computed(() => t('page.title')))\n   */\n  async function setTabTitle(title: ComputedRef<string> | string) {\n    tabbarStore.setUpdateTime();\n    await tabbarStore.setTabTitle(route, title);\n  }\n\n  async function resetTabTitle() {\n    tabbarStore.setUpdateTime();\n    await tabbarStore.resetTabTitle(route);\n  }\n\n  /**\n   * 获取操作是否禁用\n   * @param tab\n   */\n  function getTabDisableState(tab: RouteLocationNormalized = route) {\n    const tabs = tabbarStore.getTabs;\n    const affixTabs = tabbarStore.affixTabs;\n    const index = tabs.findIndex((item) => item.path === tab.path);\n\n    const disabled = tabs.length <= 1;\n\n    const { meta } = tab;\n    const affixTab = meta?.affixTab ?? false;\n    const isCurrentTab = route.path === tab.path;\n\n    // 当前处于最左侧或者减去固定标签页的数量等于0\n    const disabledCloseLeft =\n      index === 0 || index - affixTabs.length <= 0 || !isCurrentTab;\n\n    const disabledCloseRight = !isCurrentTab || index === tabs.length - 1;\n\n    const disabledCloseOther =\n      disabled || !isCurrentTab || tabs.length - affixTabs.length <= 1;\n    return {\n      disabledCloseAll: disabled,\n      disabledCloseCurrent: !!affixTab || disabled,\n      disabledCloseLeft,\n      disabledCloseOther,\n      disabledCloseRight,\n      disabledRefresh: !isCurrentTab,\n    };\n  }\n\n  return {\n    closeAllTabs,\n    closeCurrentTab,\n    closeLeftTabs,\n    closeOtherTabs,\n    closeRightTabs,\n    closeTabByKey,\n    getTabDisableState,\n    openTabInNewWindow,\n    pinTab,\n    refreshTab,\n    resetTabTitle,\n    setTabTitle,\n    toggleTabPin,\n    unpinTab,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/src/use-watermark.ts",
    "content": "import type { Watermark, WatermarkOptions } from 'watermark-js-plus';\n\nimport { nextTick, onUnmounted, readonly, ref } from 'vue';\n\nconst watermark = ref<Watermark>();\nconst unmountedHooked = ref<boolean>(false);\nconst cachedOptions = ref<Partial<WatermarkOptions>>({\n  advancedStyle: {\n    colorStops: [\n      {\n        color: 'gray',\n        offset: 0,\n      },\n      {\n        color: 'gray',\n        offset: 1,\n      },\n    ],\n    type: 'linear',\n  },\n  // fontSize: '20px',\n  content: '',\n  contentType: 'multi-line-text',\n  globalAlpha: 0.25,\n  gridLayoutOptions: {\n    cols: 2,\n    gap: [20, 20],\n    matrix: [\n      [1, 0],\n      [0, 1],\n    ],\n    rows: 2,\n  },\n  height: 200,\n  layout: 'grid',\n  rotate: 30,\n  width: 160,\n});\n\nexport function useWatermark() {\n  async function initWatermark(options: Partial<WatermarkOptions>) {\n    const { Watermark } = await import('watermark-js-plus');\n\n    cachedOptions.value = {\n      ...cachedOptions.value,\n      ...options,\n    };\n    watermark.value = new Watermark(cachedOptions.value);\n    await watermark.value?.create();\n  }\n\n  async function updateWatermark(options: Partial<WatermarkOptions>) {\n    if (watermark.value) {\n      await nextTick();\n      await watermark.value?.changeOptions({\n        ...cachedOptions.value,\n        ...options,\n      });\n    } else {\n      await initWatermark(options);\n    }\n  }\n\n  function destroyWatermark() {\n    if (watermark.value) {\n      watermark.value.destroy();\n      watermark.value = undefined;\n    }\n  }\n\n  // 只在第一次调用时注册卸载钩子，防止重复注册以致于在路由切换时销毁了水印\n  if (!unmountedHooked.value) {\n    unmountedHooked.value = true;\n    onUnmounted(() => {\n      destroyWatermark();\n    });\n  }\n\n  return {\n    destroyWatermark,\n    updateWatermark,\n    watermark: readonly(watermark),\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/hooks/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"compilerOptions\": {\n    \"types\": [\"vite/client\", \"@vben/types/global\"]\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/package.json",
    "content": "{\n  \"name\": \"@vben/layouts\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/effects/layouts\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/composables\": \"workspace:*\",\n    \"@vben-core/form-ui\": \"workspace:*\",\n    \"@vben-core/layout-ui\": \"workspace:*\",\n    \"@vben-core/menu-ui\": \"workspace:*\",\n    \"@vben-core/popup-ui\": \"workspace:*\",\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/tabs-ui\": \"workspace:*\",\n    \"@vben/constants\": \"workspace:*\",\n    \"@vben/hooks\": \"workspace:*\",\n    \"@vben/icons\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/stores\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/authentication/authentication.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ToolbarType } from './types';\n\nimport { preferences, usePreferences } from '@vben/preferences';\n\nimport { Copyright } from '../basic/copyright';\nimport AuthenticationFormView from './form.vue';\nimport SloganIcon from './icons/slogan.vue';\nimport Toolbar from './toolbar.vue';\n\ninterface Props {\n  appName?: string;\n  logo?: string;\n  pageTitle?: string;\n  pageDescription?: string;\n  sloganImage?: string;\n  toolbar?: boolean;\n  copyright?: boolean;\n  toolbarList?: ToolbarType[];\n  clickLogo?: () => void;\n}\n\nwithDefaults(defineProps<Props>(), {\n  appName: '',\n  copyright: true,\n  logo: '',\n  pageDescription: '',\n  pageTitle: '',\n  sloganImage: '',\n  toolbar: true,\n  toolbarList: () => ['color', 'language', 'layout', 'theme'],\n  clickLogo: () => {},\n});\n\nconst { authPanelCenter, authPanelLeft, authPanelRight, isDark } =\n  usePreferences();\n</script>\n\n<template>\n  <div\n    :class=\"[isDark ? 'dark' : '']\"\n    class=\"flex min-h-full flex-1 select-none overflow-x-hidden\"\n  >\n    <template v-if=\"toolbar\">\n      <slot name=\"toolbar\">\n        <Toolbar :toolbar-list=\"toolbarList\" />\n      </slot>\n    </template>\n    <!-- 左侧认证面板 -->\n    <AuthenticationFormView\n      v-if=\"authPanelLeft\"\n      class=\"min-h-full w-2/5 flex-1\"\n      transition-name=\"slide-left\"\n    >\n      <template v-if=\"copyright\" #copyright>\n        <slot name=\"copyright\">\n          <Copyright\n            v-if=\"preferences.copyright.enable\"\n            v-bind=\"preferences.copyright\"\n          />\n        </slot>\n      </template>\n    </AuthenticationFormView>\n\n    <slot name=\"logo\">\n      <!-- 头部 Logo 和应用名称 -->\n      <div\n        v-if=\"logo || appName\"\n        class=\"absolute left-0 top-0 z-10 flex flex-1\"\n        @click=\"clickLogo\"\n      >\n        <div\n          class=\"text-foreground lg:text-foreground ml-4 mt-4 flex flex-1 items-center sm:left-6 sm:top-6\"\n        >\n          <img v-if=\"logo\" :alt=\"appName\" :src=\"logo\" class=\"mr-2\" width=\"42\" />\n          <p v-if=\"appName\" class=\"m-0 text-xl font-medium\">\n            {{ appName }}\n          </p>\n        </div>\n      </div>\n    </slot>\n\n    <!-- 系统介绍 -->\n    <div v-if=\"!authPanelCenter\" class=\"relative hidden w-0 flex-1 lg:block\">\n      <div\n        class=\"bg-background-deep absolute inset-0 h-full w-full dark:bg-[#070709]\"\n      >\n        <div class=\"login-background absolute left-0 top-0 size-full\"></div>\n        <div class=\"flex-col-center -enter-x mr-20 h-full\">\n          <template v-if=\"sloganImage\">\n            <img\n              :alt=\"appName\"\n              :src=\"sloganImage\"\n              class=\"animate-float h-64 w-2/5\"\n            />\n          </template>\n          <SloganIcon v-else :alt=\"appName\" class=\"animate-float h-64 w-2/5\" />\n          <div class=\"text-1xl text-foreground mt-6 font-sans lg:text-2xl\">\n            {{ pageTitle }}\n          </div>\n          <div class=\"dark:text-muted-foreground mt-2\">\n            {{ pageDescription }}\n          </div>\n        </div>\n      </div>\n    </div>\n\n    <!-- 中心认证面板 -->\n    <div v-if=\"authPanelCenter\" class=\"flex-center relative w-full\">\n      <div class=\"login-background absolute left-0 top-0 size-full\"></div>\n      <AuthenticationFormView\n        class=\"md:bg-background shadow-primary/5 shadow-float w-full rounded-3xl pb-20 md:w-2/3 lg:w-1/2 xl:w-[36%]\"\n      >\n        <template v-if=\"copyright\" #copyright>\n          <slot name=\"copyright\">\n            <Copyright\n              v-if=\"preferences.copyright.enable\"\n              v-bind=\"preferences.copyright\"\n            />\n          </slot>\n        </template>\n      </AuthenticationFormView>\n    </div>\n\n    <!-- 右侧认证面板 -->\n    <AuthenticationFormView\n      v-if=\"authPanelRight\"\n      class=\"min-h-full w-[34%] flex-1\"\n    >\n      <template v-if=\"copyright\" #copyright>\n        <slot name=\"copyright\">\n          <Copyright\n            v-if=\"preferences.copyright.enable\"\n            v-bind=\"preferences.copyright\"\n          />\n        </slot>\n      </template>\n    </AuthenticationFormView>\n  </div>\n</template>\n\n<style scoped>\n.login-background {\n  background: linear-gradient(\n    154deg,\n    #07070915 30%,\n    hsl(var(--primary) / 30%) 48%,\n    #07070915 64%\n  );\n  filter: blur(100px);\n}\n\n.dark {\n  .login-background {\n    background: linear-gradient(\n      154deg,\n      #07070915 30%,\n      hsl(var(--primary) / 20%) 48%,\n      #07070915 64%\n    );\n    filter: blur(100px);\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/authentication/form.vue",
    "content": "<script setup lang=\"ts\">\ndefineOptions({\n  name: 'AuthenticationFormView',\n});\n</script>\n\n<template>\n  <div\n    class=\"flex-col-center dark:bg-background-deep bg-background relative px-6 py-10 lg:flex-initial lg:px-8\"\n  >\n    <slot></slot>\n    <!-- Router View with Transition and KeepAlive -->\n    <RouterView v-slot=\"{ Component, route }\">\n      <Transition appear mode=\"out-in\" name=\"slide-right\">\n        <KeepAlive :include=\"['Login']\">\n          <component\n            :is=\"Component\"\n            :key=\"route.fullPath\"\n            class=\"enter-x mt-6 w-full sm:mx-auto md:max-w-md\"\n          />\n        </KeepAlive>\n      </Transition>\n    </RouterView>\n\n    <!-- Footer Copyright -->\n\n    <div\n      class=\"text-muted-foreground absolute bottom-3 flex text-center text-xs\"\n    >\n      <slot name=\"copyright\"> </slot>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/authentication/icons/slogan.vue",
    "content": "<template>\n  <svg\n    enable-background=\"new 0 0 800 800\"\n    version=\"1.1\"\n    viewBox=\"0 0 800 800\"\n    x=\"0px\"\n    xml:space=\"preserve\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n    y=\"0px\"\n  >\n    <filter\n      id=\"filter-95\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"124.9%\"\n      width=\"114.5%\"\n      x=\"-7.3%\"\n      y=\"-12.5%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"4.21434086\" />\n    </filter>\n    <filter\n      id=\"filter-79\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"101.4%\"\n      width=\"100.8%\"\n      x=\"-0.4%\"\n      y=\"-0.7%\"\n    >\n      <feOffset dx=\"0\" dy=\"-1\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-71\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"142.5%\"\n      width=\"120.1%\"\n      x=\"-10.1%\"\n      y=\"-21.3%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"4.21434086\" />\n    </filter>\n    <filter\n      id=\"filter-59\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"181.0%\"\n      width=\"133.4%\"\n      x=\"-16.7%\"\n      y=\"-40.5%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"4.85695311\" />\n    </filter>\n    <filter\n      id=\"filter-56\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"181.0%\"\n      width=\"133.4%\"\n      x=\"-16.7%\"\n      y=\"-40.5%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"2.91417187\" />\n    </filter>\n    <filter\n      id=\"filter-53\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"100.9%\"\n      width=\"100.5%\"\n      x=\"-0.2%\"\n      y=\"-0.4%\"\n    >\n      <feOffset dx=\"0\" dy=\"-1\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-50\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"241.5%\"\n      width=\"643.8%\"\n      x=\"-271.9%\"\n      y=\"-70.7%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"16.2954513\" />\n    </filter>\n    <filter\n      id=\"filter-5\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"100.8%\"\n      width=\"100.4%\"\n      x=\"-0.2%\"\n      y=\"-0.4%\"\n    >\n      <feOffset dx=\"0\" dy=\"-3\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-46\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"100.7%\"\n      width=\"100.4%\"\n      x=\"-0.2%\"\n      y=\"-0.3%\"\n    >\n      <feOffset dx=\"0\" dy=\"-1\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-43\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"241.5%\"\n      width=\"643.8%\"\n      x=\"-271.9%\"\n      y=\"-70.7%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"20.3693141\" />\n    </filter>\n    <filter\n      id=\"filter-39\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"113.3%\"\n      width=\"107.0%\"\n      x=\"-3.5%\"\n      y=\"-6.7%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"3.51195071\" />\n    </filter>\n    <filter\n      id=\"filter-34\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"103.6%\"\n      width=\"102.1%\"\n      x=\"-1.1%\"\n      y=\"-1.8%\"\n    >\n      <feOffset dx=\"0\" dy=\"-1\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-29\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"103.6%\"\n      width=\"102.1%\"\n      x=\"-1.1%\"\n      y=\"-1.8%\"\n    >\n      <feOffset dx=\"0\" dy=\"-1\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-24\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"103.6%\"\n      width=\"102.1%\"\n      x=\"-1.1%\"\n      y=\"-1.8%\"\n    >\n      <feOffset dx=\"0\" dy=\"-1\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-20\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"102.3%\"\n      width=\"101.3%\"\n      x=\"-0.7%\"\n      y=\"-1.1%\"\n    >\n      <feOffset dx=\"0\" dy=\"-3\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-14\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"103.6%\"\n      width=\"102.1%\"\n      x=\"-1.0%\"\n      y=\"-1.8%\"\n    >\n      <feOffset dx=\"0\" dy=\"-1\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-109\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"102.5%\"\n      width=\"101.4%\"\n      x=\"-0.7%\"\n      y=\"-1.2%\"\n    >\n      <feOffset dx=\"0\" dy=\"-1\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0\"\n      />\n    </filter>\n    <filter\n      id=\"filter-106\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"149.1%\"\n      width=\"128.6%\"\n      x=\"-14.3%\"\n      y=\"-24.5%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"4.71559623\" />\n    </filter>\n    <filter\n      id=\"filter-100\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"133.5%\"\n      width=\"119.4%\"\n      x=\"-9.7%\"\n      y=\"-16.8%\"\n    >\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"4.21434086\" />\n    </filter>\n    <filter\n      id=\"filter-10\"\n      filterUnits=\"objectBoundingBox\"\n      height=\"100.7%\"\n      width=\"100.4%\"\n      x=\"-0.2%\"\n      y=\"-0.3%\"\n    >\n      <feOffset dx=\"0\" dy=\"-3\" in=\"SourceAlpha\" result=\"shadowOffsetInner1\" />\n      <feComposite\n        in=\"shadowOffsetInner1\"\n        in2=\"SourceAlpha\"\n        k2=\"-1\"\n        k3=\"1\"\n        operator=\"arithmetic\"\n        result=\"shadowInnerInner1\"\n      />\n      <feColorMatrix\n        in=\"shadowInnerInner1\"\n        type=\"matrix\"\n        values=\"0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0\"\n      />\n    </filter>\n    <title>87667-SVG8</title>\n    <g>\n      <g id=\"Group备份\" transform=\"translate(40.000000, 350.000000)\">\n        <linearGradient\n          id=\"Shape_1_\"\n          gradientTransform=\"matrix(352.3498 0 0 -229.3688 -21376.5684 335815.1875)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"62.7934\"\n          x2=\"61.7099\"\n          y1=\"1462.9332\"\n          y2=\"1462.535\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #0043fb\" />\n          <stop offset=\"1\" style=\"stop-color: #3684ff\" />\n        </linearGradient>\n        <path\n          id=\"Shape\"\n          d=\"M368,428.9c1.4,0.8,3.2,0.8,4.6,0l344.4-198.3c2.8-1.6,3.4-5.4,1.2-7.8l-16.3-22.7\n\t\t\tL370.3,395.7v31.6l-3.2,1L368,428.9z\"\n          fill=\"url(#Shape_1_)\"\n        />\n\n        <linearGradient\n          id=\"SVGID_1_\"\n          gradientTransform=\"matrix(369.5781 0 0 -241.7468 -22811.1367 353968.8438)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"63.31\"\n          x2=\"61.5984\"\n          y1=\"1462.5217\"\n          y2=\"1463.1935\"\n        >\n          <stop offset=\"5.400000e-03\" style=\"stop-color: #00c6fb\" />\n          <stop offset=\"1\" style=\"stop-color: #005bea\" />\n        </linearGradient>\n        <path\n          d=\"M370.3,427.3c0,1.3-1.4,2.1-2.5,1.4L3.2,217.3c-2.8-1.6-3.4-5.4-1.2-7.8l17.8-22.3l350.5,208.4\n\t\t\tV427.3L370.3,427.3z\"\n          fill=\"url(#SVGID_1_)\"\n        />\n        <g>\n          <g>\n            <linearGradient\n              id=\"path-4_1_\"\n              gradientTransform=\"matrix(689.8593 0 0 -397.2563 -42654.3008 582014.8125)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"62.5423\"\n              x2=\"62.1013\"\n              y1=\"1464.4305\"\n              y2=\"1464.7888\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n              <stop offset=\"1\" style=\"stop-color: #00209e\" />\n            </linearGradient>\n            <path\n              id=\"path-4\"\n              clip-rule=\"evenodd\"\n              d=\"M355.7,393.8L18,198.7\n\t\t\t\t\tc-4-2.3-4-8.1,0-10.4L337.8,3.6c7.4-4.3,16.5-4.3,24,0l340.1,196.5c4,2.3,4,8.1,0,10.4L384.4,393.8\n\t\t\t\t\tC375.5,398.9,364.6,398.9,355.7,393.8z\"\n              fill=\"url(#path-4_1_)\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n          <g filter=\"url(#filter-5)\">\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M355.7,393.8L18,198.7c-4-2.3-4-8.1,0-10.4L337.8,3.6c7.4-4.3,16.5-4.3,24,0\n\t\t\t\t\tl340.1,196.5c4,2.3,4,8.1,0,10.4L384.4,393.8C375.5,398.9,364.6,398.9,355.7,393.8z\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n        </g>\n        <path\n          id=\"Shape备份\"\n          d=\"M356.1,376L49.6,199c-3.6-2.1-3.6-7.4,0-9.5\n\t\t\tL339.8,21.9c6.7-3.9,15-3.9,21.7,0l308.6,178.3c3.6,2.1,3.6,7.4,0,9.5L382.1,376C374.1,380.7,364.1,380.7,356.1,376z\"\n          fill=\"none\"\n          stroke=\"#FFFFFF\"\n          stroke-width=\"0.9511\"\n        />\n      </g>\n      <g id=\"Group\" transform=\"translate(0.000000, 259.000000)\">\n        <linearGradient\n          id=\"SVGID_2_\"\n          gradientTransform=\"matrix(391.4998 0 0 -254.8542 -39423.0664 396432.7188)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"102.8224\"\n          x2=\"101.7388\"\n          y1=\"1554.3767\"\n          y2=\"1553.9784\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #0043fb\" />\n          <stop offset=\"1\" style=\"stop-color: #3684ff\" />\n        </linearGradient>\n        <path\n          d=\"M408.9,476.5c1.6,0.9,3.5,0.9,5.1,0l382.6-220.3c3.1-1.8,3.8-6,1.3-8.7l-18.1-25.2L411.4,439.6\n\t\t\tv35.2l-3.5,1.1L408.9,476.5z\"\n          fill=\"url(#SVGID_2_)\"\n        />\n\n        <linearGradient\n          id=\"SVGID_3_\"\n          gradientTransform=\"matrix(410.6423 0 0 -268.6075 -41782.7344 417855)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"103.3376\"\n          x2=\"101.626\"\n          y1=\"1553.9424\"\n          y2=\"1554.6141\"\n        >\n          <stop offset=\"5.400000e-03\" style=\"stop-color: #00c6fb\" />\n          <stop offset=\"1\" style=\"stop-color: #005bea\" />\n        </linearGradient>\n        <path\n          d=\"M411.4,474.8c0,1.4-1.5,2.3-2.8,1.6L3.6,241.5c-3.1-1.8-3.8-6-1.3-8.7L22,208l389.4,231.6V474.8\n\t\t\tL411.4,474.8z\"\n          fill=\"url(#SVGID_3_)\"\n        />\n        <g>\n          <g>\n            <linearGradient\n              id=\"path-9_1_\"\n              gradientTransform=\"matrix(766.5103 0 0 -441.3958 -78065.4141 686963.125)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"102.5571\"\n              x2=\"102.1161\"\n              y1=\"1555.6865\"\n              y2=\"1556.0448\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n              <stop offset=\"1\" style=\"stop-color: #00209e\" />\n            </linearGradient>\n            <path\n              id=\"path-9\"\n              clip-rule=\"evenodd\"\n              d=\"M395.2,437.6L20,220.8\n\t\t\t\t\tc-4.5-2.6-4.5-9,0-11.6L375.3,4c8.2-4.8,18.4-4.8,26.6,0l377.9,218.3c4.5,2.6,4.5,9,0,11.6L427.1,437.6\n\t\t\t\t\tC417.2,443.3,405.1,443.3,395.2,437.6z\"\n              fill=\"url(#path-9_1_)\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n          <g filter=\"url(#filter-10)\">\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M395.2,437.6L20,220.8c-4.5-2.6-4.5-9,0-11.6L375.3,4c8.2-4.8,18.4-4.8,26.6,0\n\t\t\t\t\tl377.9,218.3c4.5,2.6,4.5,9,0,11.6L427.1,437.6C417.2,443.3,405.1,443.3,395.2,437.6z\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n        </g>\n        <path\n          d=\"M395.6,417.8L55.2,221.1c-4.1-2.3-4.1-8.2,0-10.5L377.6,24.4\n\t\t\tc7.5-4.3,16.7-4.3,24.2,0l342.9,198.1c4.1,2.3,4.1,8.2,0,10.5L424.6,417.8C415.6,423,404.6,423,395.6,417.8z\"\n          fill=\"none\"\n          stroke=\"#FFFFFF\"\n          stroke-width=\"1.0568\"\n        />\n      </g>\n      <g id=\"编组备份-4\" transform=\"translate(386.000000, 561.000000)\">\n        <g id=\"编组备份-3\" transform=\"translate(0.000000, 69.529529)\">\n          <g id=\"Stroke-1\">\n            <g>\n              <linearGradient\n                id=\"path-13_1_\"\n                gradientTransform=\"matrix(47.9924 0 0 -27.7074 13731.9688 31874.9453)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"-285.6253\"\n                x2=\"-285.6253\"\n                y1=\"1149.4111\"\n                y2=\"1150.4111\"\n              >\n                <stop offset=\"0\" style=\"stop-color: #3a3aff\" />\n                <stop offset=\"1\" style=\"stop-color: #0707d6\" />\n              </linearGradient>\n              <polygon\n                id=\"path-13\"\n                clip-rule=\"evenodd\"\n                fill=\"url(#path-13_1_)\"\n                fill-rule=\"evenodd\"\n                points=\"0.1,13.9 24.1,27.8 48.1,13.9\n\t\t\t\t\t\t24.1,0.1 \t\t\t\t\t\"\n              />\n            </g>\n            <g>\n              <linearGradient\n                id=\"SVGID_4_\"\n                gradientTransform=\"matrix(47.9924 0 0 -27.7074 13731.9688 31874.9453)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"-285.6253\"\n                x2=\"-285.6253\"\n                y1=\"1149.4111\"\n                y2=\"1150.4294\"\n              >\n                <stop\n                  offset=\"0\"\n                  style=\"stop-color: #8fa0ff; stop-opacity: 0.467\"\n                />\n                <stop\n                  offset=\"1\"\n                  style=\"stop-color: #0f0f0f; stop-opacity: 0.06\"\n                />\n                <stop offset=\"1\" style=\"stop-color: #2f59e1; stop-opacity: 0\" />\n              </linearGradient>\n              <polygon\n                clip-rule=\"evenodd\"\n                fill=\"url(#SVGID_4_)\"\n                fill-rule=\"evenodd\"\n                points=\"0.1,13.9 24.1,27.8 48.1,13.9 24.1,0.1\n\t\t\t\t\t\t\"\n              />\n            </g>\n            <g filter=\"url(#filter-14)\">\n              <polygon\n                clip-rule=\"evenodd\"\n                fill-rule=\"evenodd\"\n                points=\"0.1,13.9 24.1,27.8 48.1,13.9 24.1,0.1 \t\t\t\t\t\"\n              />\n            </g>\n          </g>\n\n          <linearGradient\n            id=\"Stroke-3_1_\"\n            gradientTransform=\"matrix(23.9962 0 0 -41.5628 6916.9932 48336.7578)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-287.7007\"\n            x2=\"-287.815\"\n            y1=\"1162.8857\"\n            y2=\"1161.1971\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #4f3eff\" />\n            <stop offset=\"1\" style=\"stop-color: #060071\" />\n          </linearGradient>\n          <polygon\n            id=\"Stroke-3\"\n            clip-rule=\"evenodd\"\n            fill=\"url(#Stroke-3_1_)\"\n            fill-rule=\"evenodd\"\n            points=\"24.1,55.5 24.1,27.8 0.1,13.9\n\t\t\t\t0.1,41.6 \t\t\t\"\n          />\n\n          <linearGradient\n            id=\"Stroke-5_1_\"\n            gradientTransform=\"matrix(23.9962 0 0 -41.5628 6941.0435 48336.7578)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-287.7007\"\n            x2=\"-287.815\"\n            y1=\"1162.8857\"\n            y2=\"1161.1971\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #1200ca\" />\n            <stop offset=\"1\" style=\"stop-color: #060071\" />\n          </linearGradient>\n          <polygon\n            id=\"Stroke-5\"\n            clip-rule=\"evenodd\"\n            fill=\"url(#Stroke-5_1_)\"\n            fill-rule=\"evenodd\"\n            points=\"24.1,55.5 24.1,27.8\n\t\t\t\t48.1,13.9 48.1,41.6 \t\t\t\"\n          />\n        </g>\n\n        <linearGradient\n          id=\"矩形_1_\"\n          gradientTransform=\"matrix(48.245 0 0 -97.3101 13803.5742 121267.3516)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-285.6142\"\n          x2=\"-285.6142\"\n          y1=\"1246.0574\"\n          y2=\"1244.9515\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff; stop-opacity: 0\" />\n          <stop offset=\"1\" style=\"stop-color: #fff\" />\n        </linearGradient>\n\n        <polygon\n          id=\"矩形\"\n          clip-rule=\"evenodd\"\n          enable-background=\"new    \"\n          fill=\"url(#矩形_1_)\"\n          fill-rule=\"evenodd\"\n          opacity=\"0.1977\"\n          points=\"\n\t\t\t0,0 48.2,0 48.2,83.7 24.1,97.3 0,83.7 \t\t\"\n        />\n      </g>\n      <g id=\"编组-4\" transform=\"translate(71.000000, 199.000000)\">\n        <g id=\"Shape备份-2\">\n          <g>\n            <linearGradient\n              id=\"path-19_1_\"\n              gradientTransform=\"matrix(228.3947 0 0 -131.5657 -6978.2363 212124.2031)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"31.2434\"\n              x2=\"30.8024\"\n              y1=\"1610.2603\"\n              y2=\"1610.6188\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n              <stop offset=\"1\" style=\"stop-color: #00209e\" />\n            </linearGradient>\n            <path\n              id=\"path-19\"\n              clip-rule=\"evenodd\"\n              d=\"M63.4,312.7l-62-35.9\n\t\t\t\t\tc-1.9-1.1-1.9-3.8,0-4.9l151.1-87.4c3.5-2,7.8-2,11.3,0l63.1,36.6c1.9,1.1,1.9,3.8,0,4.9L77,312.7\n\t\t\t\t\tC72.8,315.2,67.6,315.2,63.4,312.7z\"\n              fill=\"url(#path-19_1_)\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n          <g filter=\"url(#filter-20)\">\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M63.4,312.7l-62-35.9c-1.9-1.1-1.9-3.8,0-4.9l151.1-87.4c3.5-2,7.8-2,11.3,0\n\t\t\t\t\tl63.1,36.6c1.9,1.1,1.9,3.8,0,4.9L77,312.7C72.8,315.2,67.6,315.2,63.4,312.7z\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n        </g>\n        <g id=\"编组-13\" transform=\"translate(45.000000, 0.000000)\">\n          <g id=\"编组备份-17\" transform=\"translate(90.066225, 54.000000)\">\n            <g>\n              <g>\n                <linearGradient\n                  id=\"path-23_1_\"\n                  gradientTransform=\"matrix(47.5983 0 0 -27.4798 5055.4995 41979.2891)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-105.7092\"\n                  x2=\"-105.7092\"\n                  y1=\"1526.6367\"\n                  y2=\"1527.6367\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #3a3aff\" />\n                  <stop offset=\"1\" style=\"stop-color: #0707d6\" />\n                </linearGradient>\n                <polygon\n                  id=\"path-23\"\n                  clip-rule=\"evenodd\"\n                  fill=\"url(#path-23_1_)\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,13.8 23.9,27.6\n\t\t\t\t\t\t\t47.7,13.8 23.9,0.1 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g>\n                <linearGradient\n                  id=\"SVGID_5_\"\n                  gradientTransform=\"matrix(47.5983 0 0 -27.4798 5055.4995 41979.2891)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-105.7092\"\n                  x2=\"-105.7092\"\n                  y1=\"1526.6367\"\n                  y2=\"1527.655\"\n                >\n                  <stop\n                    offset=\"0\"\n                    style=\"stop-color: #8fa0ff; stop-opacity: 0.467\"\n                  />\n                  <stop\n                    offset=\"1\"\n                    style=\"stop-color: #0f0f0f; stop-opacity: 0.06\"\n                  />\n                  <stop\n                    offset=\"1\"\n                    style=\"stop-color: #2f59e1; stop-opacity: 0\"\n                  />\n                </linearGradient>\n                <polygon\n                  clip-rule=\"evenodd\"\n                  fill=\"url(#SVGID_5_)\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,13.8 23.9,27.6 47.7,13.8 23.9,0.1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                />\n              </g>\n              <g filter=\"url(#filter-24)\">\n                <polygon\n                  clip-rule=\"evenodd\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,13.8 23.9,27.6 47.7,13.8 23.9,0.1 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n\n            <linearGradient\n              id=\"SVGID_6_\"\n              gradientTransform=\"matrix(23.7991 0 0 -168.4388 2578.7588 262543.8125)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-107.8491\"\n              x2=\"-107.8559\"\n              y1=\"1558.8499\"\n              y2=\"1557.1613\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4f3eff\" />\n              <stop offset=\"1\" style=\"stop-color: #060071\" />\n            </linearGradient>\n            <polygon\n              clip-rule=\"evenodd\"\n              fill=\"url(#SVGID_6_)\"\n              fill-rule=\"evenodd\"\n              points=\"23.9,182.3 23.9,27.6 0.1,13.8 0.1,168.5\n\t\t\t\t\t\"\n            />\n\n            <linearGradient\n              id=\"SVGID_7_\"\n              gradientTransform=\"matrix(23.7991 0 0 -168.4388 2602.6116 262543.8125)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-107.8491\"\n              x2=\"-107.8559\"\n              y1=\"1558.8499\"\n              y2=\"1557.1613\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #1200ca\" />\n              <stop offset=\"1\" style=\"stop-color: #060071\" />\n            </linearGradient>\n            <polygon\n              clip-rule=\"evenodd\"\n              fill=\"url(#SVGID_7_)\"\n              fill-rule=\"evenodd\"\n              points=\"23.9,182.3 23.9,27.6 47.7,13.8 47.7,168.5\n\t\t\t\t\t\t\t\t\t\"\n            />\n          </g>\n          <g id=\"编组备份-16\" transform=\"translate(45.562914, 134.529801)\">\n            <g>\n              <g>\n                <linearGradient\n                  id=\"path-28_1_\"\n                  gradientTransform=\"matrix(47.5983 0 0 -27.4798 2937.218 39766.3438)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-61.7058\"\n                  x2=\"-60.7058\"\n                  y1=\"1446.6069\"\n                  y2=\"1446.6069\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #bda0e5\" />\n                  <stop offset=\"1\" style=\"stop-color: #5f3abd\" />\n                </linearGradient>\n                <polygon\n                  id=\"path-28\"\n                  clip-rule=\"evenodd\"\n                  fill=\"url(#path-28_1_)\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,13.8 23.9,27.6\n\t\t\t\t\t\t\t47.7,13.8 23.9,0.1 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g>\n                <linearGradient\n                  id=\"SVGID_8_\"\n                  gradientTransform=\"matrix(47.5983 0 0 -27.4798 2937.218 39766.3438)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-61.2058\"\n                  x2=\"-61.2058\"\n                  y1=\"1446.1069\"\n                  y2=\"1447.1252\"\n                >\n                  <stop\n                    offset=\"0\"\n                    style=\"stop-color: #8fa0ff; stop-opacity: 0.467\"\n                  />\n                  <stop\n                    offset=\"1\"\n                    style=\"stop-color: #0f0f0f; stop-opacity: 0.06\"\n                  />\n                  <stop\n                    offset=\"1\"\n                    style=\"stop-color: #2f59e1; stop-opacity: 0\"\n                  />\n                </linearGradient>\n                <polygon\n                  clip-rule=\"evenodd\"\n                  fill=\"url(#SVGID_8_)\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,13.8 23.9,27.6 47.7,13.8 23.9,0.1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                />\n              </g>\n              <g filter=\"url(#filter-29)\">\n                <polygon\n                  clip-rule=\"evenodd\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,13.8 23.9,27.6 47.7,13.8 23.9,0.1 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n\n            <linearGradient\n              id=\"SVGID_9_\"\n              gradientTransform=\"matrix(23.7991 0 0 -114.399 1519.618 168778.2344)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-63.3488\"\n              x2=\"-63.3488\"\n              y1=\"1475.4679\"\n              y2=\"1474.0222\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4f3eff\" />\n              <stop offset=\"1\" style=\"stop-color: #f77\" />\n            </linearGradient>\n            <polygon\n              clip-rule=\"evenodd\"\n              fill=\"url(#SVGID_9_)\"\n              fill-rule=\"evenodd\"\n              points=\"23.9,128.2 23.9,27.6 0.1,13.8 0.1,114.5\n\t\t\t\t\t\"\n            />\n\n            <linearGradient\n              id=\"SVGID_10_\"\n              gradientTransform=\"matrix(23.7991 0 0 -114.399 1543.4708 168778.2344)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-63.3488\"\n              x2=\"-63.3488\"\n              y1=\"1475.4679\"\n              y2=\"1474.0222\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4f3eff\" />\n              <stop offset=\"1\" style=\"stop-color: #d73838\" />\n            </linearGradient>\n            <polygon\n              clip-rule=\"evenodd\"\n              fill=\"url(#SVGID_10_)\"\n              fill-rule=\"evenodd\"\n              points=\"23.9,128.2 23.9,27.6 47.7,13.8 47.7,114.5\n\t\t\t\t\t\t\t\t\t\"\n            />\n          </g>\n          <g id=\"编组备份-18\" transform=\"translate(0.000000, 0.271523)\">\n            <g>\n              <g>\n                <linearGradient\n                  id=\"path-33_1_\"\n                  gradientTransform=\"matrix(47.5983 0 0 -27.4798 768.5011 43638.7383)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-16.1429\"\n                  x2=\"-15.1429\"\n                  y1=\"1580.8652\"\n                  y2=\"1580.8652\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #8afffc\" />\n                  <stop offset=\"1\" style=\"stop-color: #003dde\" />\n                </linearGradient>\n                <polygon\n                  id=\"path-33\"\n                  clip-rule=\"evenodd\"\n                  fill=\"url(#path-33_1_)\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,196.8 23.9,210.6\n\t\t\t\t\t\t\t47.7,196.8 23.9,183.1 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g>\n                <linearGradient\n                  id=\"SVGID_11_\"\n                  gradientTransform=\"matrix(47.5983 0 0 -27.4798 768.5011 43638.7383)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-15.6429\"\n                  x2=\"-15.6429\"\n                  y1=\"1580.3652\"\n                  y2=\"1581.3835\"\n                >\n                  <stop\n                    offset=\"0\"\n                    style=\"stop-color: #8fa0ff; stop-opacity: 0.467\"\n                  />\n                  <stop\n                    offset=\"1\"\n                    style=\"stop-color: #0f0f0f; stop-opacity: 0.06\"\n                  />\n                  <stop\n                    offset=\"1\"\n                    style=\"stop-color: #2f59e1; stop-opacity: 0\"\n                  />\n                </linearGradient>\n                <polygon\n                  clip-rule=\"evenodd\"\n                  fill=\"url(#SVGID_11_)\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,196.8 23.9,210.6 47.7,196.8\n\t\t\t\t\t\t\t23.9,183.1 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g filter=\"url(#filter-34)\">\n                <polygon\n                  clip-rule=\"evenodd\"\n                  fill-rule=\"evenodd\"\n                  points=\"0.1,196.8 23.9,210.6 47.7,196.8 23.9,183.1 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n\n            <linearGradient\n              id=\"SVGID_12_\"\n              gradientTransform=\"matrix(48 0 0 -80.5525 774 129477.0156)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-15.625\"\n              x2=\"-15.625\"\n              y1=\"1604.7488\"\n              y2=\"1605.7488\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #45efed\" />\n              <stop offset=\"1\" style=\"stop-color: #d0ffed; stop-opacity: 0\" />\n            </linearGradient>\n            <polygon\n              clip-rule=\"evenodd\"\n              enable-background=\"new    \"\n              fill=\"url(#SVGID_12_)\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.3\"\n              points=\"\n\t\t\t\t\t0,130 48,130 48,196.7 24,210.6 0,196.7 \t\t\t\t\"\n            />\n\n            <linearGradient\n              id=\"矩形备份_1_\"\n              gradientTransform=\"matrix(48 0 0 -80.5525 820 129428.7578)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-15.625\"\n              x2=\"-15.625\"\n              y1=\"1604.7488\"\n              y2=\"1605.7488\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #45efed\" />\n              <stop offset=\"1\" style=\"stop-color: #d0ffed; stop-opacity: 0\" />\n            </linearGradient>\n\n            <polygon\n              id=\"矩形备份\"\n              clip-rule=\"evenodd\"\n              enable-background=\"new    \"\n              fill=\"url(#矩形备份_1_)\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.3\"\n              points=\"\n\t\t\t\t\t46,81.7 94,81.7 94,148.5 70,162.3 46,148.5 \t\t\t\t\"\n            />\n\n            <linearGradient\n              id=\"矩形备份-4_1_\"\n              gradientTransform=\"matrix(48 0 0 -80.5525 863 129347.75)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-15.625\"\n              x2=\"-15.625\"\n              y1=\"1604.7488\"\n              y2=\"1605.7488\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #45efed\" />\n              <stop offset=\"1\" style=\"stop-color: #d0ffed; stop-opacity: 0\" />\n            </linearGradient>\n\n            <polygon\n              id=\"矩形备份-4\"\n              clip-rule=\"evenodd\"\n              enable-background=\"new    \"\n              fill=\"url(#矩形备份-4_1_)\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.3\"\n              points=\"\n\t\t\t\t\t89,0.7 137,0.7 137,67.5 113,81.3 89,67.5 \t\t\t\t\"\n            />\n\n            <linearGradient\n              id=\"SVGID_13_\"\n              gradientTransform=\"matrix(23.7991 0 0 -93.207 435.2595 150023.5938)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-17.8122\"\n              x2=\"-17.7572\"\n              y1=\"1607.5193\"\n              y2=\"1606.3573\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #68dfff\" />\n              <stop offset=\"1\" style=\"stop-color: #004a8b\" />\n            </linearGradient>\n            <polygon\n              clip-rule=\"evenodd\"\n              fill=\"url(#SVGID_13_)\"\n              fill-rule=\"evenodd\"\n              points=\"23.9,290 23.9,210.6 0.1,196.8 0.1,276.3\n\t\t\t\t\t\"\n            />\n\n            <linearGradient\n              id=\"SVGID_14_\"\n              gradientTransform=\"matrix(23.7991 0 0 -93.207 459.1122 150023.5938)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-17.8038\"\n              x2=\"-17.7678\"\n              y1=\"1607.3881\"\n              y2=\"1606.5361\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #0567de\" />\n              <stop offset=\"1\" style=\"stop-color: #00048b\" />\n            </linearGradient>\n            <polygon\n              clip-rule=\"evenodd\"\n              fill=\"url(#SVGID_14_)\"\n              fill-rule=\"evenodd\"\n              points=\"23.9,290 23.9,210.6 47.7,196.8 47.7,276.3\n\t\t\t\t\t\t\t\t\t\"\n            />\n          </g>\n        </g>\n      </g>\n      <g id=\"编组-9\" transform=\"translate(286.000000, 26.000000)\">\n        <g id=\"编组-3\" transform=\"translate(0.000000, 326.797996)\">\n          <g id=\"椭圆形\" filter=\"url(#filter-39)\">\n            <linearGradient\n              id=\"SVGID_15_\"\n              gradientTransform=\"matrix(298.9761 -31.4237 -16.5194 -157.172 79324.2969 223473.4688)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-183.6863\"\n              x2=\"-184.3618\"\n              y1=\"1458.1069\"\n              y2=\"1457.9841\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #1b0f9c; stop-opacity: 0\" />\n              <stop offset=\"1\" style=\"stop-color: #060071\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M161.7,23.6c82.6-8.7,153.2,19.5,157.7,62.9\n\t\t\t\t\tc4.6,43.4-58.7,85.6-141.2,94.3C95.7,189.5,25,161.3,20.5,117.9S79.1,32.3,161.7,23.6z\"\n              fill=\"url(#SVGID_15_)\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n          <g transform=\"translate(0.000000, 32.309947)\">\n            <g id=\"形状结合\">\n              <linearGradient\n                id=\"SVGID_16_\"\n                gradientTransform=\"matrix(252.8605 0 0 -153.121 46628.3242 218334.6719)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"-184.3435\"\n                x2=\"-183.4387\"\n                y1=\"1425.4349\"\n                y2=\"1425.3547\"\n              >\n                <stop offset=\"0\" style=\"stop-color: #3b76df\" />\n                <stop offset=\"1\" style=\"stop-color: #0c2ea7\" />\n              </linearGradient>\n              <path\n                clip-rule=\"evenodd\"\n                d=\"M36.9,21.3c49.2-28.4,129.8-28.4,179,0\n\t\t\t\t\t\tc9.7,5.6,17.5,12.2,23.4,19.4l13.5,0v39.3l-0.1,0c-1.3,19.3-13.6,38.3-36.8,51.7c-49.2,28.4-129.8,28.4-179,0\n\t\t\t\t\t\tC13.7,118.4,1.4,99.4,0.1,80.1l-0.1,0V40.7l13.5,0C19.4,33.5,27.2,26.9,36.9,21.3z\"\n                fill=\"url(#SVGID_16_)\"\n                fill-rule=\"evenodd\"\n              />\n            </g>\n            <defs>\n              <filter\n                id=\"Adobe_OpacityMaskFilter\"\n                filterUnits=\"userSpaceOnUse\"\n                height=\"86.4\"\n                width=\"22.5\"\n                x=\"18.3\"\n                y=\"59.7\"\n              >\n                <feColorMatrix\n                  type=\"matrix\"\n                  values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                />\n              </filter>\n            </defs>\n            <mask\n              id=\"mask-42_1_\"\n              height=\"86.4\"\n              maskUnits=\"userSpaceOnUse\"\n              width=\"22.5\"\n              x=\"18.3\"\n              y=\"59.7\"\n            >\n              <g filter=\"url(#Adobe_OpacityMaskFilter)\">\n                <path\n                  id=\"path-41_1_\"\n                  clip-rule=\"evenodd\"\n                  d=\"M36.9,21.3c49.2-28.4,129.8-28.4,179,0\n\t\t\t\t\t\t\tc9.7,5.6,17.5,12.2,23.4,19.4l13.5,0v39.3l-0.1,0c-1.3,19.3-13.6,38.3-36.8,51.7c-49.2,28.4-129.8,28.4-179,0\n\t\t\t\t\t\t\tC13.7,118.4,1.4,99.4,0.1,80.1l-0.1,0V40.7l13.5,0C19.4,33.5,27.2,26.9,36.9,21.3z\"\n                  fill=\"#FFFFFF\"\n                  fill-rule=\"evenodd\"\n                />\n              </g>\n            </mask>\n            <g filter=\"url(#filter-43)\" mask=\"url(#mask-42_1_)\">\n              <rect\n                clip-rule=\"evenodd\"\n                fill=\"#FFFFFF\"\n                fill-rule=\"evenodd\"\n                height=\"86.4\"\n                width=\"22.5\"\n                x=\"18.3\"\n                y=\"59.7\"\n              />\n            </g>\n          </g>\n          <g id=\"Stroke-1备份\">\n            <g>\n              <linearGradient\n                id=\"path-45_1_\"\n                gradientTransform=\"matrix(252.8604 0 0 -146.0971 46628.3203 212993.0469)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"-183.7127\"\n                x2=\"-184.1537\"\n                y1=\"1457.2306\"\n                y2=\"1457.5913\"\n              >\n                <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n                <stop offset=\"1\" style=\"stop-color: #00209e\" />\n              </linearGradient>\n              <path\n                id=\"path-45\"\n                clip-rule=\"evenodd\"\n                d=\"M36.9,21.3c-49.2,28.4-49.2,75,0,103.4\n\t\t\t\t\t\tc49.2,28.4,129.8,28.4,179,0c49.2-28.4,49.2-75,0-103.4C166.7-7.1,86.2-7.1,36.9,21.3z\"\n                fill=\"url(#path-45_1_)\"\n                fill-rule=\"evenodd\"\n              />\n            </g>\n            <g filter=\"url(#filter-46)\">\n              <path\n                clip-rule=\"evenodd\"\n                d=\"M36.9,21.3c-49.2,28.4-49.2,75,0,103.4c49.2,28.4,129.8,28.4,179,0\n\t\t\t\t\t\tc49.2-28.4,49.2-75,0-103.4C166.7-7.1,86.2-7.1,36.9,21.3z\"\n                fill-rule=\"evenodd\"\n              />\n            </g>\n          </g>\n        </g>\n        <g id=\"编组-3备份\" transform=\"translate(24.286045, 0.000000)\">\n          <g transform=\"translate(1.000000, 323.847957)\">\n            <g>\n              <linearGradient\n                id=\"SVGID_17_\"\n                gradientTransform=\"matrix(202.2884 0 0 -122.4968 42438.1328 178783.5781)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"-209.8152\"\n                x2=\"-208.7883\"\n                y1=\"1459.0104\"\n                y2=\"1458.9812\"\n              >\n                <stop offset=\"0\" style=\"stop-color: #8dcbff\" />\n                <stop offset=\"0.1196\" style=\"stop-color: #cafbff\" />\n                <stop offset=\"0.768\" style=\"stop-color: #7feeff\" />\n                <stop offset=\"1\" style=\"stop-color: #adcbff\" />\n              </linearGradient>\n              <path\n                clip-rule=\"evenodd\"\n                d=\"M29.5,17.1c39.4-22.8,103.8-22.8,143.2,0\n\t\t\t\t\t\tc7.8,4.5,14,9.8,18.7,15.5l10.8,0v31.5l-0.1,0c-1.1,15.5-10.9,30.6-29.4,41.4c-39.4,22.8-103.8,22.8-143.2,0\n\t\t\t\t\t\tC11,94.7,1.2,79.5,0.1,64.1l-0.1,0V32.6l10.8,0C15.5,26.8,21.8,21.6,29.5,17.1z\"\n                fill=\"url(#SVGID_17_)\"\n                fill-rule=\"evenodd\"\n              />\n            </g>\n            <defs>\n              <filter\n                id=\"Adobe_OpacityMaskFilter_1_\"\n                filterUnits=\"userSpaceOnUse\"\n                height=\"69.1\"\n                width=\"18\"\n                x=\"14.6\"\n                y=\"47.8\"\n              >\n                <feColorMatrix\n                  type=\"matrix\"\n                  values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                />\n              </filter>\n            </defs>\n            <mask\n              id=\"mask-49_1_\"\n              height=\"69.1\"\n              maskUnits=\"userSpaceOnUse\"\n              width=\"18\"\n              x=\"14.6\"\n              y=\"47.8\"\n            >\n              <g filter=\"url(#Adobe_OpacityMaskFilter_1_)\">\n                <path\n                  id=\"path-48_1_\"\n                  clip-rule=\"evenodd\"\n                  d=\"M29.5,17.1c39.4-22.8,103.8-22.8,143.2,0\n\t\t\t\t\t\t\tc7.8,4.5,14,9.8,18.7,15.5l10.8,0v31.5l-0.1,0c-1.1,15.5-10.9,30.6-29.4,41.4c-39.4,22.8-103.8,22.8-143.2,0\n\t\t\t\t\t\t\tC11,94.7,1.2,79.5,0.1,64.1l-0.1,0V32.6l10.8,0C15.5,26.8,21.8,21.6,29.5,17.1z\"\n                  fill=\"#FFFFFF\"\n                  fill-rule=\"evenodd\"\n                />\n              </g>\n            </mask>\n            <g filter=\"url(#filter-50)\" mask=\"url(#mask-49_1_)\">\n              <rect\n                clip-rule=\"evenodd\"\n                fill=\"#FFFFFF\"\n                fill-rule=\"evenodd\"\n                height=\"69.1\"\n                width=\"18\"\n                x=\"14.6\"\n                y=\"47.8\"\n              />\n            </g>\n          </g>\n          <g>\n            <g>\n              <linearGradient\n                id=\"path-52_1_\"\n                gradientTransform=\"matrix(202.2884 0 0 -116.8777 42236.8438 208684.4531)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"-208.0996\"\n                x2=\"-208.5406\"\n                y1=\"1782.2883\"\n                y2=\"1782.6489\"\n              >\n                <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n                <stop offset=\"1\" style=\"stop-color: #00209e\" />\n              </linearGradient>\n              <path\n                id=\"path-52\"\n                clip-rule=\"evenodd\"\n                d=\"M30.5,315.1c-39.4,22.8-39.4,60,0,82.7\n\t\t\t\t\t\tc39.4,22.8,103.8,22.8,143.2,0c39.4-22.8,39.4-60,0-82.7C134.4,292.3,69.9,292.3,30.5,315.1z\"\n                fill=\"url(#path-52_1_)\"\n                fill-rule=\"evenodd\"\n              />\n            </g>\n            <g filter=\"url(#filter-53)\">\n              <path\n                clip-rule=\"evenodd\"\n                d=\"M30.5,315.1c-39.4,22.8-39.4,60,0,82.7c39.4,22.8,103.8,22.8,143.2,0\n\t\t\t\t\t\tc39.4-22.8,39.4-60,0-82.7C134.4,292.3,69.9,292.3,30.5,315.1z\"\n                fill-rule=\"evenodd\"\n              />\n            </g>\n          </g>\n\n          <linearGradient\n            id=\"SVGID_18_\"\n            gradientTransform=\"matrix(202.5744 0 0 -414.8777 42296.1367 742296.8125)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-208.2896\"\n            x2=\"-208.2896\"\n            y1=\"1788.1943\"\n            y2=\"1789.1943\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #45efed\" />\n            <stop offset=\"1\" style=\"stop-color: #d0ffed; stop-opacity: 0\" />\n          </linearGradient>\n          <path\n            clip-rule=\"evenodd\"\n            d=\"M202.7,0\n\t\t\t\tl0,350.2c3.1,17-6.5,34.7-29,47.6c-39.4,22.8-103.8,22.8-143.2,0C12,387.1,2.2,373.1,1.1,359l-0.4,0V0H202.7z\"\n            enable-background=\"new    \"\n            fill=\"url(#SVGID_18_)\"\n            fill-rule=\"evenodd\"\n            opacity=\"0.3\"\n          />\n        </g>\n      </g>\n      <g id=\"编组-11备份\" transform=\"translate(329.000000, 539.000000)\">\n        <g id=\"编组-6备份\" transform=\"translate(0.000000, 4.148936)\">\n          <g filter=\"url(#filter-56)\">\n            <linearGradient\n              id=\"SVGID_19_\"\n              gradientTransform=\"matrix(52.2766 0 0 -21.5745 11984.5537 26508.6328)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-227.9383\"\n              x2=\"-228.6138\"\n              y1=\"1226.9152\"\n              y2=\"1226.8395\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #1b0f9c; stop-opacity: 0\" />\n              <stop offset=\"1\" style=\"stop-color: #060071\" />\n            </linearGradient>\n            <ellipse\n              clip-rule=\"evenodd\"\n              cx=\"41.9\"\n              cy=\"39.8\"\n              fill=\"url(#SVGID_19_)\"\n              fill-rule=\"evenodd\"\n              rx=\"26.1\"\n              ry=\"10.8\"\n            />\n          </g>\n\n          <radialGradient\n            id=\"SVGID_20_\"\n            cx=\"-228.8779\"\n            cy=\"1253.5115\"\n            gradientTransform=\"matrix(48.9574 0 0 -48.9574 11215.3408 61379.1055)\"\n            gradientUnits=\"userSpaceOnUse\"\n            r=\"0.9018\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #dedbff\" />\n            <stop offset=\"0.3987\" style=\"stop-color: #4165fc\" />\n            <stop offset=\"1\" style=\"stop-color: #0a00c2\" />\n          </radialGradient>\n          <circle\n            clip-rule=\"evenodd\"\n            cx=\"24.5\"\n            cy=\"24.5\"\n            fill=\"url(#SVGID_20_)\"\n            fill-rule=\"evenodd\"\n            r=\"24.5\"\n          />\n        </g>\n        <g id=\"编组-6\" transform=\"translate(23.510638, 0.000000)\">\n          <g filter=\"url(#filter-59)\">\n            <linearGradient\n              id=\"SVGID_21_\"\n              gradientTransform=\"matrix(87.1277 0 0 -35.9574 21954.6836 45008.2383)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-250.6685\"\n              x2=\"-251.344\"\n              y1=\"1249.9197\"\n              y2=\"1249.844\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #1b0f9c; stop-opacity: 0\" />\n              <stop offset=\"1\" style=\"stop-color: #060071\" />\n            </linearGradient>\n            <ellipse\n              clip-rule=\"evenodd\"\n              cx=\"69.8\"\n              cy=\"66.4\"\n              fill=\"url(#SVGID_21_)\"\n              fill-rule=\"evenodd\"\n              rx=\"43.6\"\n              ry=\"18\"\n            />\n          </g>\n\n          <radialGradient\n            id=\"SVGID_22_\"\n            cx=\"-251.5552\"\n            cy=\"1265.9697\"\n            gradientTransform=\"matrix(81.5957 0 0 -81.5957 20542.6016 103315.0391)\"\n            gradientUnits=\"userSpaceOnUse\"\n            r=\"0.9018\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #dedbff\" />\n            <stop offset=\"0.3987\" style=\"stop-color: #4165fc\" />\n            <stop offset=\"1\" style=\"stop-color: #0a00c2\" />\n          </radialGradient>\n          <circle\n            clip-rule=\"evenodd\"\n            cx=\"40.8\"\n            cy=\"40.8\"\n            fill=\"url(#SVGID_22_)\"\n            fill-rule=\"evenodd\"\n            r=\"40.8\"\n          />\n        </g>\n      </g>\n\n      <g\n        id=\"编组备份-9\"\n        opacity=\"0.5\"\n        transform=\"translate(488.000000, 172.000000) scale(-1, 1) translate(-488.000000, -172.000000) translate(449.000000, 122.000000)\"\n      >\n        <linearGradient\n          id=\"SVGID_23_\"\n          gradientTransform=\"matrix(-75.8604 0 0 -99.5101 32139.0957 167716.875)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"423.6246\"\n          x2=\"424.2521\"\n          y1=\"1683.8809\"\n          y2=\"1685.3489\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #00c6fb\" />\n        </linearGradient>\n        <path\n          d=\"M72.5,0l3.8,2.1L75.1,4l-1.6,0.6l-0.7,49.2c0,1.6-0.9,3.4-2.1,4.2l-0.2,0.1L5.7,95.5l0,0l-0.7,4\n\t\t\tl-3.7-2.1c-0.1,0-0.1-0.1-0.2-0.1l0,0c-0.4-0.3-0.7-0.9-0.7-1.8l0,0l0.8-51.8c0-1.7,1-3.6,2.3-4.3l0,0L71.2,0.3\n\t\t\tC71.7,0,72.1-0.1,72.5,0L72.5,0z\"\n          fill=\"url(#SVGID_23_)\"\n        />\n\n        <linearGradient\n          id=\"SVGID_24_\"\n          gradientTransform=\"matrix(-73.087 0 0 -97.5101 30963.9746 164327.5781)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"423.5395\"\n          x2=\"424.1461\"\n          y1=\"1683.6631\"\n          y2=\"1685.1311\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #005bea\" />\n          <stop offset=\"1\" style=\"stop-color: #00c6fb\" />\n        </linearGradient>\n        <path\n          d=\"M6.3,99.2l67.8-39.1c1.2-0.7,2.3-2.7,2.3-4.3L77.1,4c0-1.7-1-2.4-2.3-1.7L7,41.4\n\t\t\tc-1.2,0.7-2.3,2.7-2.3,4.3L4,97.5C4,99.2,5,100,6.3,99.2z\"\n          fill=\"url(#SVGID_24_)\"\n        />\n        <g\n          id=\"XMLID_902_\"\n          opacity=\"0.3\"\n          transform=\"translate(51.463000, 21.500000)\"\n        >\n          <path\n            id=\"XMLID_905_\"\n            d=\"M17.9,4.7L1.7,14.1c-0.5,0.3-1.2,0.1-1.5-0.4C0.1,13.5,0,13.3,0,13.1\n\t\t\t\tc0-1.2,0.6-2.2,1.6-2.8l16.3-9.4c0.5-0.3,1.2-0.1,1.5,0.4c0.1,0.2,0.1,0.4,0.1,0.5C19.5,3,18.9,4.1,17.9,4.7z\"\n            fill=\"#FFFFFF\"\n          />\n          <path\n            id=\"XMLID_905_备份\"\n            d=\"M18.2,14.6L5.5,21.9c-0.4,0.2-0.9,0.1-1.1-0.3c-0.1-0.1-0.1-0.3-0.1-0.4\n\t\t\t\tc0-0.9,0.5-1.7,1.3-2.2l12.6-7.3c0.4-0.2,0.9-0.1,1.1,0.3c0.1,0.1,0.1,0.3,0.1,0.4C19.4,13.3,18.9,14.2,18.2,14.6z\"\n            fill=\"#FFFFFF\"\n          />\n          <path\n            id=\"XMLID_905_备份-2\"\n            d=\"M18.2,22.3L5.5,29.6c-0.4,0.2-0.9,0.1-1.1-0.3c-0.1-0.1-0.1-0.3-0.1-0.4\n\t\t\t\tc0-0.9,0.5-1.7,1.3-2.2l12.6-7.3c0.4-0.2,0.9-0.1,1.1,0.3c0.1,0.1,0.1,0.3,0.1,0.4C19.4,21,18.9,21.8,18.2,22.3z\"\n            fill=\"#FFFFFF\"\n          />\n          <path\n            id=\"XMLID_905_备份-3\"\n            d=\"M18.2,29.9L5.5,37.2c-0.4,0.2-0.9,0.1-1.1-0.3c-0.1-0.1-0.1-0.3-0.1-0.4\n\t\t\t\tc0-0.9,0.5-1.7,1.3-2.2L18.2,27c0.4-0.2,0.9-0.1,1.1,0.3c0.1,0.1,0.1,0.3,0.1,0.4C19.4,28.7,18.9,29.5,18.2,29.9z\"\n            fill=\"#FFFFFF\"\n          />\n        </g>\n\n        <linearGradient\n          id=\"SVGID_25_\"\n          gradientTransform=\"matrix(-43.8881 0 0 -83.0886 18579.1777 139875)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"422.0028\"\n          x2=\"421.7111\"\n          y1=\"1683.5527\"\n          y2=\"1682.4626\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n        </linearGradient>\n        <polygon\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_25_)\"\n          opacity=\"0.4\"\n          points=\"50,16.6 28.7,86.3 51,73.4 72.6,3.2 \t\t\"\n        />\n\n        <linearGradient\n          id=\"XMLID_22_\"\n          gradientTransform=\"matrix(-6.6055 0 0 -25.864 2720.3372 42898.332)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"408.911\"\n          x2=\"408.7796\"\n          y1=\"1654.5455\"\n          y2=\"1655.6864\"\n        >\n          <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n          <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n          <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n          <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n          <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n          <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n        </linearGradient>\n\n        <linearGradient\n          id=\"XMLID_23_\"\n          gradientTransform=\"matrix(-6.6055 0 0 -25.864 2720.3372 42898.332)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"409.0583\"\n          x2=\"409.0583\"\n          y1=\"1656.3246\"\n          y2=\"1655.3246\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n        </linearGradient>\n        <polygon\n          id=\"XMLID_875_\"\n          fill=\"url(#XMLID_22_)\"\n          points=\"21.6,81.2 15,85 15,63\n\t\t\t21.6,59.2 \t\t\"\n          stroke=\"url(#XMLID_23_)\"\n          stroke-width=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"XMLID_24_\"\n          gradientTransform=\"matrix(-6.6055 0 0 -32.7555 2732.1479 54570.1641)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"409.0159\"\n          x2=\"408.9963\"\n          y1=\"1663.0452\"\n          y2=\"1663.531\"\n        >\n          <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n          <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n          <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n          <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n          <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n          <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n        </linearGradient>\n\n        <linearGradient\n          id=\"XMLID_25_\"\n          gradientTransform=\"matrix(-6.6055 0 0 -32.7555 2732.1479 54570.1641)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"409.0583\"\n          x2=\"409.0583\"\n          y1=\"1664.5974\"\n          y2=\"1663.5974\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n        </linearGradient>\n        <polygon\n          id=\"XMLID_874_\"\n          fill=\"url(#XMLID_24_)\"\n          points=\"33.4,74.4 26.8,78.2\n\t\t\t26.8,49.3 33.4,45.4 \t\t\"\n          stroke=\"url(#XMLID_25_)\"\n          stroke-width=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"XMLID_26_\"\n          gradientTransform=\"matrix(-6.6055 0 0 -39.6465 2744.3577 66240.9141)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"408.98\"\n          x2=\"408.9241\"\n          y1=\"1668.4514\"\n          y2=\"1669.1958\"\n        >\n          <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n          <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n          <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n          <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n          <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n          <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n        </linearGradient>\n\n        <linearGradient\n          id=\"XMLID_27_\"\n          gradientTransform=\"matrix(-6.6055 0 0 -39.6465 2744.3577 66240.9141)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"409.0583\"\n          x2=\"409.0583\"\n          y1=\"1669.994\"\n          y2=\"1668.994\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n        </linearGradient>\n        <polygon\n          id=\"XMLID_873_\"\n          fill=\"url(#XMLID_26_)\"\n          points=\"45.6,67.3 39,71.1 39,35.3\n\t\t\t45.6,31.5 \t\t\"\n          stroke=\"url(#XMLID_27_)\"\n          stroke-width=\"0.5\"\n        />\n      </g>\n      <g id=\"人备份\" transform=\"translate(364.000000, 134.000000)\">\n        <path\n          id=\"Path\"\n          clip-rule=\"evenodd\"\n          d=\"M78,41.6c0,0,6.5-5.1,7.6-5.4c7.2-2.4,8-1,9.4,0.7\n\t\t\tc1.4,1.6-4,4.2-5.4,5.7c-0.7,0.8,4.5-1,3.9,1c-0.5,1.5-4.9,2.2-5.6,2.9s-5.3,3.8-5.3,3.8L78,41.6z\"\n          fill=\"#F7C19C\"\n          fill-rule=\"evenodd\"\n        />\n\n        <linearGradient\n          id=\"SVGID_26_\"\n          gradientTransform=\"matrix(66.553 0 0 -42.1921 17559.9336 70059.375)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-263.0341\"\n          x2=\"-263.2938\"\n          y1=\"1659.3563\"\n          y2=\"1659.0363\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #3158d3\" />\n          <stop offset=\"1\" style=\"stop-color: #306ef3\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M53,81.7c5.3-2,34.6-33.6,34.6-33.6\n\t\t\tc-3.3-7.5-9.4-7.6-9.4-7.6L50.5,61.6c0,0-24.3-19.7-28.7-21.7s12.7,33,12.7,33S47.8,83.7,53,81.7z\"\n          fill=\"url(#SVGID_26_)\"\n          fill-rule=\"evenodd\"\n        />\n        <g\n          id=\"Oval\"\n          enable-background=\"new    \"\n          filter=\"url(#filter-71)\"\n          opacity=\"0.5267\"\n        >\n          <linearGradient\n            id=\"SVGID_27_\"\n            gradientTransform=\"matrix(125.5104 0 0 -59.4816 33000.125 99355.7422)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-261.8036\"\n            x2=\"-262.479\"\n            y1=\"1666.1232\"\n            y2=\"1666.0233\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #1b0f9c; stop-opacity: 0\" />\n            <stop offset=\"1\" style=\"stop-color: #060071\" />\n          </linearGradient>\n          <ellipse\n            clip-rule=\"evenodd\"\n            cx=\"77.2\"\n            cy=\"256.5\"\n            fill=\"url(#SVGID_27_)\"\n            fill-rule=\"evenodd\"\n            rx=\"62.8\"\n            ry=\"29.7\"\n          />\n        </g>\n\n        <linearGradient\n          id=\"SVGID_28_\"\n          gradientTransform=\"matrix(37.5807 0 0 -16.9728 9948.6885 27801.6328)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-264.5023\"\n          x2=\"-262.5973\"\n          y1=\"1623.2751\"\n          y2=\"1622.7434\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #434343\" />\n          <stop offset=\"1\" style=\"stop-color: #122142\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M6.3,242.5c-1.9,1.4-7.6,6.1-5.2,12.6\n\t\t\tc2.4,6.5,8.7,4.1,12.8,2.9c4.1-1.2,9.3-4.2,15.3-5.1c6-0.9,12.9-5.5,5.8-8.6C30.3,242.2,6.3,242.5,6.3,242.5z\"\n          fill=\"url(#SVGID_28_)\"\n          fill-rule=\"evenodd\"\n        />\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M51.7,252.1l-2.2,9.5c0,0-5.1,0.3-8.5-1.4\n\t\t\tc-1.1-0.5-2-1.3-2.5-2.3l2.8-13.2l10.3-65.3l-9.3-33.8L16.9,246.6c0,0-3.1,1.6-6.5,0.4c-0.7-0.3-3.6-2-4.1-2.9l29.2-106.8l20,4.8\n\t\t\tl8.5,45L51.7,252.1z\"\n          fill=\"#EFAD81\"\n          fill-rule=\"evenodd\"\n        />\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M34.8,39.4l1.4-8.4c0,0-2-21.1,3.8-23.2s18.3-0.3,18.4,10\n\t\t\tc0.1,10.4-0.1,19.3-4.6,19.1c-4.5-0.2-5.3-1-5.3-1l0.1,8.1L34.8,39.4z\"\n          fill=\"#F7C19C\"\n          fill-rule=\"evenodd\"\n        />\n\n        <linearGradient\n          id=\"SVGID_29_\"\n          gradientTransform=\"matrix(65.856 0 0 -139.1891 17361.0918 233445.5938)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-263.1151\"\n          x2=\"-263.0032\"\n          y1=\"1676.3293\"\n          y2=\"1675.5613\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #021814\" />\n          <stop offset=\"1\" style=\"stop-color: #424fec\" />\n        </linearGradient>\n        <path\n          d=\"M17.5,117.5l1.9,57.1L4.8,238c0,0,3.3,5.5,18.1,4.1c0,0,16.4-56.8,18-59.2\n\t\t\tc1.6-2.4,4.4-21.7,4.4-21.7s2.5,29.8,1.7,32.9c-0.8,3.2-8.4,56.9-8.4,56.9s3.1,7.4,17,5.2c0,0,15-62,15-67.8v-62.1L17.5,117.5z\"\n          fill=\"url(#SVGID_29_)\"\n        />\n\n        <linearGradient\n          id=\"SVGID_30_\"\n          gradientTransform=\"matrix(38.3908 0 0 -17.2271 10193.9805 28243.3203)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-264.4597\"\n          x2=\"-262.5546\"\n          y1=\"1624.1052\"\n          y2=\"1623.5803\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #434343\" />\n          <stop offset=\"1\" style=\"stop-color: #122142\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M50.9,258.4c0,0-2.9,1.7-6.7,0.7c-3.8-1-4.4-3-5.6-3.1\n\t\t\tc-1.2-0.1-5,6.2-5,11.4c0,3.4,4.2,6.7,13.4,5.6c10.7-1.3,9.7,1,19-1c9.3-1.9,6.1-7.6,0.7-8.2c-5.4-0.6-10.7-1.5-12.7-3\n\t\t\tC52.1,259.4,50.9,258.4,50.9,258.4z\"\n          fill=\"url(#SVGID_30_)\"\n          fill-rule=\"evenodd\"\n        />\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M129.6,67.3c-0.6,0.2-1.7,0.5-2.9,0.8c-0.6-0.4-1.4-2.4-2-2.7\n\t\t\tc-1.2-0.5-3.1,3.8-3.9,4.9l-4.9,2.6l-0.9,9.2c2.5,0.1,5-1.1,7.5-1.4c1.4-0.3,13.7-6.6,15.5-10.8C139,67.4,133.6,65.7,129.6,67.3z\"\n          fill=\"#F7C19C\"\n          fill-rule=\"evenodd\"\n        />\n\n        <linearGradient\n          id=\"SVGID_31_\"\n          gradientTransform=\"matrix(107.5405 0 0 -93.2162 28291.4941 155960.2031)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-261.9086\"\n          x2=\"-262.8504\"\n          y1=\"1672.3391\"\n          y2=\"1672.2106\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #77f7e1\" />\n          <stop offset=\"1\" style=\"stop-color: #424fec\" />\n        </linearGradient>\n        <path\n          d=\"M76.5,100.3c5.7,0.2,44.9-17.6,44.9-17.6c-0.2-8.2-5.8-10.7-5.8-10.7l-33.7,8.6\n\t\t\tc0,0-14.7-27.5-18-31.1C60.7,46,49.1,40,49.1,40S39,43.3,34.6,35c0,0-3.2-0.8-8.7-0.8S12.3,46,14.1,69.2s2,53,2,53\n\t\t\ts16.7,7.8,54.5,4.2l-7.9-41.5C62.8,84.9,70.9,100.2,76.5,100.3z\"\n          fill=\"url(#SVGID_31_)\"\n        />\n\n        <linearGradient\n          id=\"SVGID_32_\"\n          gradientTransform=\"matrix(33.4128 0 0 -34.3382 8885.7266 56796.8203)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-264.4242\"\n          x2=\"-265.0254\"\n          y1=\"1653.8715\"\n          y2=\"1653.0199\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #253c6f\" />\n          <stop offset=\"1\" style=\"stop-color: #3068e8\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M53,18.9c0,0,10.3,1.5,10-5.4c-0.2-6.9-4.7-3.6-5.9-9.4\n\t\t\tc-1.4-7-11-2.3-22.3,0c-14.1,2.8,4.7,43.2,4.6,26.7s1.7-4.4,7.1-5.3c0.8-0.6-1.1-2.6,0-3.9C48.3,19.9,53,18.9,53,18.9z\"\n          fill=\"url(#SVGID_32_)\"\n          fill-rule=\"evenodd\"\n        />\n      </g>\n      <g id=\"Stroke-1备份-3\" opacity=\"0.2645\">\n        <g filter=\"url(#filter-79)\">\n          <path\n            id=\"path-78_1_\"\n            clip-rule=\"evenodd\"\n            d=\"M322.9,141.3c-49.2,28.4-49.2,75,0,103.4\n\t\t\t\tc49.2,28.4,129.8,28.4,179,0c49.2-28.4,49.2-75,0-103.4C452.7,112.9,372.2,112.9,322.9,141.3z\"\n            fill-rule=\"evenodd\"\n          />\n        </g>\n        <g>\n          <linearGradient\n            id=\"SVGID_33_\"\n            gradientTransform=\"matrix(252.8604 0 0 -146.0971 -25403.7617 264655.8438)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"102.0966\"\n            x2=\"102.0966\"\n            y1=\"1810.3647\"\n            y2=\"1809.6846\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #fff; stop-opacity: 0\" />\n            <stop offset=\"1\" style=\"stop-color: #fff\" />\n          </linearGradient>\n          <path\n            d=\"M322.9,141.3c-49.2,28.4-49.2,75,0,103.4c49.2,28.4,129.8,28.4,179,0\n\t\t\t\tc49.2-28.4,49.2-75,0-103.4C452.7,112.9,372.2,112.9,322.9,141.3z\"\n            fill=\"none\"\n            stroke=\"url(#SVGID_33_)\"\n          />\n        </g>\n      </g>\n\n      <linearGradient\n        id=\"Stroke-1备份-4_1_\"\n        gradientTransform=\"matrix(224 0 0 -130 -22445.5664 235373.9844)\"\n        gradientUnits=\"userSpaceOnUse\"\n        x1=\"102.0446\"\n        x2=\"102.0446\"\n        y1=\"1809.8226\"\n        y2=\"1809.215\"\n      >\n        <stop offset=\"0\" style=\"stop-color: #fff\" />\n        <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n      </linearGradient>\n      <path\n        id=\"Stroke-1备份-4\"\n        d=\"\n\t\tM333.1,116c-43.6,25.3-43.6,66.7,0,92c43.6,25.3,115,25.3,158.6,0c43.6-25.3,43.6-66.7,0-92C448.1,90.7,376.8,90.7,333.1,116z\"\n        enable-background=\"new    \"\n        fill=\"none\"\n        opacity=\"0.2645\"\n        stroke=\"url(#Stroke-1备份-4_1_)\"\n      />\n\n      <linearGradient\n        id=\"Stroke-1备份-5_1_\"\n        gradientTransform=\"matrix(224 0 0 -130 -22445.5664 235434.9375)\"\n        gradientUnits=\"userSpaceOnUse\"\n        x1=\"102.0446\"\n        x2=\"102.0446\"\n        y1=\"1809.8226\"\n        y2=\"1809.215\"\n      >\n        <stop offset=\"0\" style=\"stop-color: #fff\" />\n        <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n      </linearGradient>\n\n      <path\n        id=\"Stroke-1备份-5\"\n        d=\"\n\t\tM333.1,177c-43.6,25.3-43.6,66.7,0,92c43.6,25.3,115,25.3,158.6,0c43.6-25.3,43.6-66.7,0-92C448.1,151.7,376.8,151.7,333.1,177z\"\n        enable-background=\"new    \"\n        fill=\"none\"\n        opacity=\"7.956659e-02\"\n        stroke=\"url(#Stroke-1备份-5_1_)\"\n      />\n      <g id=\"编组-15\" transform=\"translate(286.000000, 69.000000)\">\n        <linearGradient\n          id=\"SVGID_34_\"\n          gradientTransform=\"matrix(84.647 0 0 -130.0737 15677.0488 226435.8125)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-184.6048\"\n          x2=\"-184.7916\"\n          y1=\"1739.7522\"\n          y2=\"1740.8326\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n          <stop offset=\"1\" style=\"stop-color: #00209e\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M84.6,54\n\t\t\tv71.1c0,3.8-2.9,5.8-6.4,4.6c-14-5-27.2-11.1-39.4-18.1C25.4,103.8,14,95.3,4.7,86.3C2.1,83.6,0,78.4,0,74.6V3.5\n\t\t\tc0-3.8,2.1-4.6,4.7-1.9c9.3,9,20.6,17.6,34.1,25.3C51,33.9,64.2,39.9,78.2,45C81.8,46.2,84.6,50.2,84.6,54z\"\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_34_)\"\n          fill-rule=\"evenodd\"\n          opacity=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"SVGID_35_\"\n          gradientTransform=\"matrix(42.8864 0 0 -55.1569 8005.1216 95474.0859)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-186.8636\"\n          x2=\"-185.8636\"\n          y1=\"1729.7074\"\n          y2=\"1729.7074\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <path\n          d=\"M33.5,44.1c11.8,6.8,21.4,23.4,21.4,37\n\t\t\tc0,13.6-9.7,19.1-21.5,12.3C21.6,86.6,12,70,12,56.4C12.1,42.8,21.7,37.3,33.5,44.1z M33.4,85.5c8,4.6,14.6,0.9,14.6-8.3\n\t\t\tc0-9.2-6.5-20.5-14.5-25.1c-8-4.6-14.6-0.9-14.6,8.3C18.9,69.6,25.4,80.9,33.4,85.5L33.4,85.5z\"\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_35_)\"\n          opacity=\"0.4\"\n        />\n\n        <linearGradient\n          id=\"SVGID_36_\"\n          gradientTransform=\"matrix(21.3932 0 0 -37.017 4071.8147 63756.6836)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-189.5823\"\n          x2=\"-188.5823\"\n          y1=\"1720.6718\"\n          y2=\"1720.6718\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M33.5,44.1c11.8,6.8,21.4,23.4,21.4,37l-6.9-4\n\t\t\tc0-9.2-6.5-20.5-14.5-25.1L33.5,44.1z\"\n          fill=\"url(#SVGID_36_)\"\n          fill-rule=\"evenodd\"\n        />\n      </g>\n\n      <g\n        id=\"编组-15备份\"\n        transform=\"translate(524.500000, 179.500000) scale(-1, 1) translate(-524.500000, -179.500000) translate(482.000000, 114.000000)\"\n      >\n        <linearGradient\n          id=\"SVGID_37_\"\n          gradientTransform=\"matrix(-84.647 0 0 -130.0737 39258.8555 220582.5)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"463.1948\"\n          x2=\"463.008\"\n          y1=\"1694.7522\"\n          y2=\"1695.8326\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n          <stop offset=\"1\" style=\"stop-color: #00209e\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M84.6,54\n\t\t\tv71.1c0,3.8-2.9,5.8-6.4,4.6c-14-5-27.2-11.1-39.4-18.1C25.4,103.8,14,95.3,4.7,86.3C2.1,83.6,0,78.4,0,74.6V3.5\n\t\t\tc0-3.8,2.1-4.6,4.7-1.9c9.3,9,20.6,17.6,34.1,25.3C51,33.9,64.2,39.9,78.2,45C81.8,46.2,84.6,50.2,84.6,54z\"\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_37_)\"\n          fill-rule=\"evenodd\"\n          opacity=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"SVGID_38_\"\n          gradientTransform=\"matrix(-42.8864 0 0 -55.1569 19852.209 92992.0234)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"462.6216\"\n          x2=\"463.1363\"\n          y1=\"1684.7074\"\n          y2=\"1684.7074\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #ccff70\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <path\n          d=\"M33.5,44.1c11.8,6.8,21.4,23.4,21.4,37\n\t\t\tc0,13.6-9.7,19.1-21.5,12.3C21.6,86.6,12,70,12,56.4C12.1,42.8,21.7,37.3,33.5,44.1z M33.4,85.5c8,4.6,14.6,0.9,14.6-8.3\n\t\t\tc0-9.2-6.5-20.5-14.5-25.1c-8-4.6-14.6-0.9-14.6,8.3C18.9,69.6,25.4,80.9,33.4,85.5L33.4,85.5z\"\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_38_)\"\n          opacity=\"0.4\"\n        />\n\n        <linearGradient\n          id=\"SVGID_39_\"\n          gradientTransform=\"matrix(-21.3932 0 0 -37.017 9879.3115 62090.918)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"461.0466\"\n          x2=\"462.0466\"\n          y1=\"1675.6718\"\n          y2=\"1675.6718\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afa91\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M33.5,44.1c11.8,6.8,21.4,23.4,21.4,37l-6.9-4\n\t\t\tc0-9.2-6.5-20.5-14.5-25.1L33.5,44.1z\"\n          fill=\"url(#SVGID_39_)\"\n          fill-rule=\"evenodd\"\n        />\n      </g>\n      <g id=\"编组\" transform=\"translate(457.000000, 235.000000)\">\n        <linearGradient\n          id=\"SVGID_40_\"\n          gradientTransform=\"matrix(94.2244 0 0 -135.8154 33551.6523 213971.6875)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-355.4666\"\n          x2=\"-355.6789\"\n          y1=\"1574.0848\"\n          y2=\"1575.1653\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n          <stop offset=\"1\" style=\"stop-color: #00209e\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M36.3,166.1\n\t\t\tc-9.3,4.2-19.3,7.7-29.7,10.5c-3.6,1-6.6-1.4-6.6-5.1v-44.7c0-3.8,3-7.5,6.6-8.4C17,115.5,27,112,36.3,107.8\n\t\t\tc4.8-2.2,9.5-4.6,13.9-7.2c28.4-16.5,43.1-38,44-59.6v54.4c0.8,23-13.8,46-44,63.6C45.8,161.5,41.1,163.9,36.3,166.1z\"\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_40_)\"\n          fill-rule=\"evenodd\"\n          opacity=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"SVGID_41_\"\n          gradientTransform=\"matrix(19.3679 0 0 -68.3208 7052.4458 107110.6953)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-359.7519\"\n          x2=\"-359.7874\"\n          y1=\"1566.6797\"\n          y2=\"1567.7601\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n          <stop offset=\"1\" style=\"stop-color: #00209e\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M79.4,59.9\n\t\t\tc-2.4-2.9-4.6-8.1-4.6-11.8V3.5c0-3.8,2.2-4.6,4.6-1.8c17.4,20.9,19.5,45,6.1,66.6C83.7,65.5,81.7,62.7,79.4,59.9z\"\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_41_)\"\n          fill-rule=\"evenodd\"\n          opacity=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"SVGID_42_\"\n          gradientTransform=\"matrix(5.707 0 0 -15.38 2179.3494 23459.5469)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-372.3728\"\n          x2=\"-372.3728\"\n          y1=\"1517.4354\"\n          y2=\"1516.2238\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <polygon\n          clip-rule=\"evenodd\"\n          fill=\"url(#SVGID_42_)\"\n          fill-rule=\"evenodd\"\n          points=\"57.1,146.8 57,135.5 51.4,138.7 51.4,150.9\n\t\t\t\"\n        />\n\n        <linearGradient\n          id=\"Path备份_1_\"\n          gradientTransform=\"matrix(5.707 0 0 -15.38 2199.9822 23445.7344)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-372.3728\"\n          x2=\"-372.3728\"\n          y1=\"1517.4354\"\n          y2=\"1516.2238\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <polygon\n          id=\"Path备份\"\n          clip-rule=\"evenodd\"\n          fill=\"url(#Path备份_1_)\"\n          fill-rule=\"evenodd\"\n          points=\"77.7,133 77.7,121.7\n\t\t\t72,124.9 72,137 \t\t\"\n        />\n\n        <linearGradient\n          id=\"SVGID_43_\"\n          gradientTransform=\"matrix(5.791 0 0 -44.69 2175.166 69834.2344)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-372.1319\"\n          x2=\"-372.1109\"\n          y1=\"1562.8905\"\n          y2=\"1558.8889\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M23.2,165.4c-1.9,0.7-3.8,1.4-5.7,2.1l-0.1-42.8\n\t\t\tc1.9-0.6,3.8-1.3,5.7-1.9L23.2,165.4z\"\n          fill=\"url(#SVGID_43_)\"\n          fill-rule=\"evenodd\"\n        />\n\n        <linearGradient\n          id=\"SVGID_44_\"\n          gradientTransform=\"matrix(5.754 0 0 -21.635 2173.4099 33364.9844)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-372.2268\"\n          x2=\"-372.2268\"\n          y1=\"1536.7212\"\n          y2=\"1535.3361\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M34.5,160.5c-1,0.5-2,1-3.1,1.4\n\t\t\tc-0.8,0.4-1.7,0.8-2.6,1.1L28.7,144c0,0,0.1,0,0.1,0c0.9-0.4,1.7-0.8,2.6-1.1c1-0.5,2-0.9,3-1.4L34.5,160.5z\"\n          fill=\"url(#SVGID_44_)\"\n          fill-rule=\"evenodd\"\n        />\n\n        <linearGradient\n          id=\"SVGID_45_\"\n          gradientTransform=\"matrix(5.78 0 0 -42.615 2194.2666 66542.2656)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-372.1471\"\n          x2=\"-372.1471\"\n          y1=\"1559.7903\"\n          y2=\"1558.4763\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M46.1,154.2c-0.6,0.4-1.2,0.7-1.9,1.1\n\t\t\tc-1.2,0.7-2.5,1.4-3.8,2.1l-0.1-39.3l5.7-3.3L46.1,154.2z\"\n          fill=\"url(#SVGID_45_)\"\n          fill-rule=\"evenodd\"\n        />\n\n        <linearGradient\n          id=\"Path备份-2_1_\"\n          gradientTransform=\"matrix(5.78 0 0 -28.2102 2214.8997 43745.1641)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"-372.1471\"\n          x2=\"-372.1471\"\n          y1=\"1547.6044\"\n          y2=\"1546.2904\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4c83ff\" />\n          <stop offset=\"1\" style=\"stop-color: #2afadf\" />\n        </linearGradient>\n        <path\n          id=\"Path备份-2\"\n          clip-rule=\"evenodd\"\n          d=\"M66.8,140.4\n\t\t\tc-0.6,0.4-1.2,0.7-1.9,1.1c-1.2,0.7-2.5,1.4-3.8,2.1L61,118.7l5.7-3.3L66.8,140.4z\"\n          fill=\"url(#Path备份-2_1_)\"\n          fill-rule=\"evenodd\"\n        />\n      </g>\n\n      <g\n        id=\"编组备份\"\n        transform=\"translate(316.500000, 268.500000) scale(-1, 1) translate(-316.500000, -268.500000) translate(269.000000, 180.000000)\"\n      >\n        <linearGradient\n          id=\"SVGID_46_\"\n          gradientTransform=\"matrix(-94.2244 0 0 -135.8154 24584.7852 221441.5469)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"260.3016\"\n          x2=\"260.0893\"\n          y1=\"1629.0848\"\n          y2=\"1630.1653\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n          <stop offset=\"1\" style=\"stop-color: #00209e\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M36.3,166.1\n\t\t\tc-9.3,4.2-19.3,7.7-29.7,10.5c-3.6,1-6.6-1.4-6.6-5.1v-44.7c0-3.8,3-7.5,6.6-8.4C17,115.5,27,112,36.3,107.8\n\t\t\tc4.8-2.2,9.5-4.6,13.9-7.2c28.4-16.5,43.1-38,44-59.6v54.4c0.8,23-13.8,46-44,63.6C45.8,161.5,41.1,163.9,36.3,166.1z\"\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_46_)\"\n          fill-rule=\"evenodd\"\n          opacity=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"SVGID_47_\"\n          gradientTransform=\"matrix(-19.3679 0 0 -68.3208 5047.2349 110868.3359)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"256.219\"\n          x2=\"256.1836\"\n          y1=\"1621.6797\"\n          y2=\"1622.7601\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #4587ef\" />\n          <stop offset=\"1\" style=\"stop-color: #00209e\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M79.4,59.9\n\t\t\tc-2.4-2.9-4.6-8.1-4.6-11.8V3.5c0-3.8,2.2-4.6,4.6-1.8c17.4,20.9,19.5,45,6.1,66.6C83.7,65.5,81.7,62.7,79.4,59.9z\"\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_47_)\"\n          fill-rule=\"evenodd\"\n          opacity=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"路径_1_\"\n          gradientTransform=\"matrix(-65.0245 0 0 -44.112 16953.9395 71322.6641)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"259.3418\"\n          x2=\"258.6121\"\n          y1=\"1614.2808\"\n          y2=\"1614.0671\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #f8ff24\" />\n          <stop offset=\"1\" style=\"stop-color: #fff\" />\n        </linearGradient>\n\n        <path\n          id=\"路径\"\n          d=\"\n\t\t\tM84.5,110.9c-11.6-15.5-17.4-14.7-17.4,2.4c0,25.7-11.4,29.9-19.6,17.1c-8.2-12.9-23.3-14.6-28,13.6\"\n          enable-background=\"new    \"\n          fill=\"none\"\n          opacity=\"0.6\"\n          stroke=\"url(#路径_1_)\"\n          stroke-linecap=\"round\"\n          stroke-width=\"3.5247\"\n        />\n      </g>\n      <g id=\"编组-11\" transform=\"translate(558.000000, 306.000000)\">\n        <g id=\"product3\" transform=\"translate(11.447727, 0.000000)\">\n          <g filter=\"url(#filter-95)\">\n            <linearGradient\n              id=\"SVGID_48_\"\n              gradientTransform=\"matrix(174.1648 0 0 -101.4708 81515.7969 152491.3594)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-467.0351\"\n              x2=\"-467.7105\"\n              y1=\"1501.2344\"\n              y2=\"1501.0835\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #1b0f9c; stop-opacity: 0\" />\n              <stop offset=\"1\" style=\"stop-color: #060071\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M171.8,157.9c4.3,2.5,4.3,6.5,0,8.9L81.2,220\n\t\t\t\t\tc-4.8,2.5-10.6,2.5-15.4,0L4.1,184.4c-4.3-2.5-4.3-6.5,0-8.9l90.5-53.2c4.8-2.5,10.6-2.5,15.4,0L171.8,157.9z\"\n              fill=\"url(#SVGID_48_)\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n          <g id=\"编组-2\" transform=\"translate(0.862170, 124.812382)\">\n            <linearGradient\n              id=\"SVGID_49_\"\n              gradientTransform=\"matrix(145.0025 0 0 -83.8574 68008.0859 115279.1875)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-469.0133\"\n              x2=\"-468.0133\"\n              y1=\"1374.2056\"\n              y2=\"1374.2056\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #6ecaf9\" />\n              <stop offset=\"0.35\" style=\"stop-color: #a1ddfb\" />\n              <stop offset=\"1\" style=\"stop-color: #fff\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M141.8,37.5c4.3,2.5,4.3,6.5,0,8.9L80.4,82\n\t\t\t\t\tc-4.8,2.5-10.6,2.5-15.4,0L3.2,46.4c-4.3-2.5-4.3-6.5,0-8.9L64.6,1.8c4.8-2.5,10.6-2.5,15.4,0L141.8,37.5z\"\n              fill=\"url(#SVGID_49_)\"\n              fill-rule=\"evenodd\"\n            />\n\n            <linearGradient\n              id=\"SVGID_50_\"\n              gradientTransform=\"matrix(132.2205 0 0 -73.006 62028.5859 100235.5703)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-469.0813\"\n              x2=\"-468.0813\"\n              y1=\"1372.403\"\n              y2=\"1372.403\"\n            >\n              <stop offset=\"0.12\" style=\"stop-color: #5c90fe\" />\n              <stop offset=\"0.56\" style=\"stop-color: #466cf5\" />\n              <stop offset=\"0.69\" style=\"stop-color: #4265f3\" />\n              <stop offset=\"0.87\" style=\"stop-color: #3853ef\" />\n              <stop offset=\"1\" style=\"stop-color: #2e42eb\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M72.8,78.5c-1.7,0.1-3.4-0.3-5-1.1L6.4,42L67.3,6.5\n\t\t\t\t\tc1.5-0.8,3.2-1.1,5-1.1c1.7-0.1,3.4,0.3,5,1.1L138.6,42L77.7,77.3C76.2,78.1,74.5,78.5,72.8,78.5z\"\n              fill=\"url(#SVGID_50_)\"\n              fill-rule=\"evenodd\"\n            />\n\n            <linearGradient\n              id=\"SVGID_51_\"\n              gradientTransform=\"matrix(144.9687 0 0 -54.9245 67992.2734 75196.0781)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-469.0135\"\n              x2=\"-468.0135\"\n              y1=\"1367.8169\"\n              y2=\"1367.8169\"\n            >\n              <stop offset=\"0.12\" style=\"stop-color: #5c90fe\" />\n              <stop offset=\"0.56\" style=\"stop-color: #466cf5\" />\n              <stop offset=\"0.69\" style=\"stop-color: #4265f3\" />\n              <stop offset=\"0.87\" style=\"stop-color: #3853ef\" />\n              <stop offset=\"1\" style=\"stop-color: #2e42eb\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M145,42c0,0.1,0,0.2,0,0.3s0,0.2,0,0.3s0,0.2-0.1,0.3\n\t\t\t\t\tc-0.1,0.1-0.1,0.2-0.1,0.3s-0.1,0.2-0.1,0.3c0,0.1-0.1,0.2-0.2,0.3l-0.2,0.2c-0.1,0.1-0.2,0.3-0.3,0.4l-0.2,0.2\n\t\t\t\t\tc-0.1,0.2-0.3,0.3-0.5,0.5l-0.2,0.2l-0.3,0.3l-0.3,0.2l-0.4,0.3l-0.4,0.3L80.5,82c-0.4,0.2-0.7,0.4-1.1,0.5l-0.3,0.1\n\t\t\t\t\tc-0.3,0.1-0.6,0.2-0.9,0.3l-0.3,0.1l-0.6,0.2l-0.4,0.1l-0.6,0.1l-0.4,0.1c-0.4,0.1-0.8,0.1-1.2,0.2h-0.4h-0.7H72h-0.6h-0.5\n\t\t\t\t\tl-0.6,0l-0.5-0.1l-0.6-0.1l-0.5-0.1l-0.7-0.2l-0.4-0.1c-0.4-0.1-0.8-0.2-1.2-0.4l-0.2-0.1c-0.5-0.2-1-0.4-1.5-0.7L3.2,46.5\n\t\t\t\t\tC1.1,45.2,0,43.6,0,42v13.3c0,1.6,1.1,3.2,3.2,4.5L65,95.4c0.5,0.3,1,0.5,1.5,0.7h0.1h0.1c0.4,0.2,0.8,0.3,1.2,0.4h0.1l0.3,0.1\n\t\t\t\t\tl0.7,0.2h0.2h0.3l0.6,0.1h0.2h0.3l0.5,0.1h0.3h0.3H72h1.6h0.7h0.3h0.1c0.4,0,0.8-0.1,1.2-0.2H76l0.4-0.1l0.5,0.1l0.4-0.1\n\t\t\t\t\tl0.6-0.2H78l0.2-0.1c0.3-0.1,0.6-0.2,0.9-0.3l0.3-0.1c0.4-0.2,0.7-0.3,1.1-0.5l61.4-35.6l0.1-0.1l0.3-0.2l0.4-0.3l0.3-0.2\n\t\t\t\t\tl0.3-0.3l0.1-0.1l0.1-0.1c0.2-0.2,0.3-0.3,0.5-0.5L144,58l0.1-0.1c0.1-0.1,0.2-0.2,0.3-0.4l0.1-0.2v-0.1\n\t\t\t\t\tc0.1-0.1,0.1-0.2,0.2-0.3s0.1-0.1,0.1-0.2v-0.1c0-0.1,0.1-0.2,0.1-0.3c0-0.1,0-0.2,0.1-0.2c0.1-0.1,0,0,0-0.1s0-0.2,0-0.3\n\t\t\t\t\ts0-0.2,0-0.2c0-0.1,0-0.1,0-0.1l0,0L145,42z\"\n              fill=\"url(#SVGID_51_)\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n          <g id=\"编组-2备份\" transform=\"translate(8.400000, 103.200000)\">\n            <g\n              id=\"Path备份-3\"\n              enable-background=\"new    \"\n              filter=\"url(#filter-100)\"\n              opacity=\"0.6817\"\n            >\n              <linearGradient\n                id=\"SVGID_52_\"\n                gradientTransform=\"matrix(130.5022 0 0 -75.4716 62201.1797 105298.6953)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"-475.6305\"\n                x2=\"-476.3059\"\n                y1=\"1394.5802\"\n                y2=\"1394.4315\"\n              >\n                <stop offset=\"0\" style=\"stop-color: #1b0f9c; stop-opacity: 0\" />\n                <stop offset=\"1\" style=\"stop-color: #060071\" />\n              </linearGradient>\n              <path\n                clip-rule=\"evenodd\"\n                d=\"M127.6,51.7c3.9,2.2,3.9,5.8,0,8L72.3,91.8\n\t\t\t\t\t\tc-4.4,2.2-9.5,2.2-13.9,0L2.9,59.7c-3.8-2.2-3.9-5.8,0-8l55.2-32.1c4.4-2.2,9.5-2.2,13.9,0L127.6,51.7z\"\n                fill=\"url(#SVGID_52_)\"\n                fill-rule=\"evenodd\"\n              />\n            </g>\n\n            <linearGradient\n              id=\"SVGID_53_\"\n              gradientTransform=\"matrix(130.5022 0 0 -75.4716 62201.1797 105280.6953)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-476.6293\"\n              x2=\"-475.6293\"\n              y1=\"1394.4705\"\n              y2=\"1394.4705\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #6ecaf9\" />\n              <stop offset=\"0.35\" style=\"stop-color: #a1ddfb\" />\n              <stop offset=\"1\" style=\"stop-color: #fff\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M127.6,33.7c3.9,2.2,3.9,5.8,0,8L72.3,73.8\n\t\t\t\t\tc-4.4,2.2-9.5,2.2-13.9,0L2.9,41.7c-3.8-2.2-3.9-5.8,0-8L58.1,1.7c4.4-2.2,9.5-2.2,13.9,0L127.6,33.7z\"\n              fill=\"url(#SVGID_53_)\"\n              fill-rule=\"evenodd\"\n            />\n\n            <linearGradient\n              id=\"SVGID_54_\"\n              gradientTransform=\"matrix(118.9985 0 0 -65.7054 56732.918 91530.375)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-476.7049\"\n              x2=\"-475.7049\"\n              y1=\"1392.4675\"\n              y2=\"1392.4675\"\n            >\n              <stop offset=\"0.12\" style=\"stop-color: #5c90fe\" />\n              <stop offset=\"0.56\" style=\"stop-color: #466cf5\" />\n              <stop offset=\"0.69\" style=\"stop-color: #4265f3\" />\n              <stop offset=\"0.87\" style=\"stop-color: #3853ef\" />\n              <stop offset=\"1\" style=\"stop-color: #2e42eb\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M65.5,70.6c-1.6,0.1-3.1-0.3-4.5-1L5.8,37.8L60.6,5.9\n\t\t\t\t\tc1.4-0.7,2.9-1,4.5-1c1.6,0,3.1,0.3,4.5,1l55.2,31.9L69.9,69.6C68.6,70.3,67,70.6,65.5,70.6z\"\n              fill=\"url(#SVGID_54_)\"\n              fill-rule=\"evenodd\"\n            />\n\n            <linearGradient\n              id=\"SVGID_55_\"\n              gradientTransform=\"matrix(130.4718 0 0 -49.432 62186.7266 68643.1094)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-476.6295\"\n              x2=\"-475.6295\"\n              y1=\"1387.3719\"\n              y2=\"1387.3719\"\n            >\n              <stop offset=\"0.12\" style=\"stop-color: #5c90fe\" />\n              <stop offset=\"0.56\" style=\"stop-color: #466cf5\" />\n              <stop offset=\"0.69\" style=\"stop-color: #4265f3\" />\n              <stop offset=\"0.87\" style=\"stop-color: #3853ef\" />\n              <stop offset=\"1\" style=\"stop-color: #2e42eb\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M130.5,37.8c0,0.1,0,0.2,0,0.3c0,0.1,0,0.2,0,0.3\n\t\t\t\t\ts0,0.2-0.1,0.3c-0.1,0.1,0,0.2-0.1,0.3s-0.1,0.2-0.1,0.2c0,0.1-0.1,0.2-0.1,0.3l-0.1,0.2c-0.1,0.1-0.1,0.2-0.2,0.3l-0.2,0.2\n\t\t\t\t\tc-0.1,0.2-0.3,0.3-0.4,0.4l-0.2,0.2l-0.3,0.3l-0.3,0.2l-0.3,0.2l-0.4,0.2L72.4,73.8c-0.3,0.2-0.6,0.3-1,0.5l-0.3,0.1\n\t\t\t\t\tc-0.3,0.1-0.5,0.2-0.8,0.3l-0.3,0.1l-0.5,0.1L69.2,75l-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.1-1.1,0.2h-0.3h-0.7h-1.4h-0.5h-0.5\n\t\t\t\t\tl-0.5,0l-0.4-0.1l-0.5-0.1L62,75.2L61.4,75L61,74.9c-0.4-0.1-0.7-0.2-1-0.4l-0.1-0.1c-0.5-0.2-0.9-0.4-1.3-0.6L2.9,41.8\n\t\t\t\t\tC1,40.7,0,39.3,0,37.8v12c0,1.5,1,2.9,2.9,4l55.6,32.1c0.4,0.2,0.9,0.5,1.3,0.6h0.1H60c0.3,0.1,0.7,0.3,1,0.3h0.1l0.3,0.1\n\t\t\t\t\tl0.6,0.1h0.2h0.2l0.5,0.1h0.2h0.2l0.5,0.1h0.2h0.3h0.5h1.4h0.7h0.3h0.1c0.4,0,0.7-0.1,1.1-0.2h0.1l0.3-0.1l0.4,0.1l0.4-0.1\n\t\t\t\t\tl0.5-0.1h0.1l0.2-0.1c0.3-0.1,0.5-0.2,0.8-0.3l0.3-0.1c0.3-0.1,0.7-0.3,1-0.5l55.2-32.1l0.1-0.1l0.3-0.2l0.3-0.2l0.3-0.2\n\t\t\t\t\tl0.3-0.3l0.1,0l0.1-0.1c0.1-0.1,0.3-0.3,0.4-0.4l0.1-0.1l0.1-0.1c0.1-0.1,0.2-0.2,0.2-0.3l0.1-0.1v-0.1c0.1-0.1,0.1-0.2,0.1-0.3\n\t\t\t\t\tc0-0.1,0.1-0.1,0.1-0.2V51c0-0.1,0.1-0.2,0.1-0.3s0-0.1,0.1-0.2c0.1-0.1,0,0,0,0s0-0.2,0-0.3c0-0.1,0-0.1,0-0.2s0-0.1,0-0.1l0,0\n\t\t\t\t\tL130.5,37.8z\"\n              fill=\"url(#SVGID_55_)\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n          <path\n            clip-rule=\"evenodd\"\n            d=\"M63.9,130.7l0.1,0.4\n\t\t\t\tL63.9,130.7z\"\n            fill=\"#666666\"\n            fill-rule=\"evenodd\"\n            stroke=\"#000000\"\n            stroke-width=\"0.6\"\n          />\n          <path\n            clip-rule=\"evenodd\"\n            d=\"M63.8,130l0.1,0.4\n\t\t\t\tL63.8,130z\"\n            fill=\"#666666\"\n            fill-rule=\"evenodd\"\n            stroke=\"#000000\"\n            stroke-width=\"0.6\"\n          />\n\n          <linearGradient\n            id=\"SVGID_56_\"\n            gradientTransform=\"matrix(132.2205 0 0 -178.9849 61915.457 269544.7812)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-467.7177\"\n            x2=\"-467.7209\"\n            y1=\"1504.9636\"\n            y2=\"1506.2531\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #00dcf3\" />\n            <stop\n              offset=\"1.000000e-02\"\n              style=\"stop-color: #00dbf3; stop-opacity: 0.97\"\n            />\n            <stop\n              offset=\"8.000000e-02\"\n              style=\"stop-color: #00d0ef; stop-opacity: 0.77\"\n            />\n            <stop\n              offset=\"0.16\"\n              style=\"stop-color: #00c7ec; stop-opacity: 0.59\"\n            />\n            <stop\n              offset=\"0.24\"\n              style=\"stop-color: #00beea; stop-opacity: 0.43\"\n            />\n            <stop\n              offset=\"0.32\"\n              style=\"stop-color: #00b7e8; stop-opacity: 0.3\"\n            />\n            <stop\n              offset=\"0.42\"\n              style=\"stop-color: #00b2e6; stop-opacity: 0.19\"\n            />\n            <stop\n              offset=\"0.52\"\n              style=\"stop-color: #00ade5; stop-opacity: 0.1\"\n            />\n            <stop\n              offset=\"0.63\"\n              style=\"stop-color: #00aae4; stop-opacity: 4e-2\"\n            />\n            <stop\n              offset=\"0.77\"\n              style=\"stop-color: #00a9e3; stop-opacity: 1e-2\"\n            />\n            <stop offset=\"1\" style=\"stop-color: #00a8e3; stop-opacity: 0\" />\n          </linearGradient>\n          <path\n            clip-rule=\"evenodd\"\n            d=\"M7.3,0.1v142.4l61.4,35.4c1.5,0.8,3.3,1.1,5,1.1\n\t\t\t\tc1.7,0.1,3.4-0.3,5-1.1l60.9-35.4V0L7.3,0.1z\"\n            fill=\"url(#SVGID_56_)\"\n            fill-rule=\"evenodd\"\n          />\n        </g>\n        <g id=\"编组备份-8\" transform=\"translate(47.447727, 63.600000)\">\n          <g\n            enable-background=\"new    \"\n            filter=\"url(#filter-106)\"\n            opacity=\"0.3003\"\n          >\n            <linearGradient\n              id=\"SVGID_57_\"\n              gradientTransform=\"matrix(99.0186 0 0 -57.6674 49956.1875 82510.0469)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-503.4795\"\n              x2=\"-504.155\"\n              y1=\"1430.0212\"\n              y2=\"1429.8705\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #1b0f9c; stop-opacity: 0\" />\n              <stop offset=\"1\" style=\"stop-color: #060071\" />\n            </linearGradient>\n            <polygon\n              clip-rule=\"evenodd\"\n              fill=\"url(#SVGID_57_)\"\n              fill-rule=\"evenodd\"\n              points=\"3.5,59.5 38.6,79.7 102.5,42.3 67.4,22.1\n\t\t\t\t\t\"\n            />\n          </g>\n          <g>\n            <g>\n              <linearGradient\n                id=\"path-108_1_\"\n                gradientTransform=\"matrix(70.176 0 0 -40.5146 35432.1289 57650.0859)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"-504.9012\"\n                x2=\"-503.9012\"\n                y1=\"1422.4436\"\n                y2=\"1422.4436\"\n              >\n                <stop offset=\"0\" style=\"stop-color: #fff\" />\n                <stop offset=\"1\" style=\"stop-color: #00a2ff\" />\n              </linearGradient>\n              <polygon\n                id=\"path-108\"\n                clip-rule=\"evenodd\"\n                fill=\"url(#path-108_1_)\"\n                fill-rule=\"evenodd\"\n                points=\"0.2,20.4 35.3,40.6\n\t\t\t\t\t\t70.4,20.4 35.3,0.1 \t\t\t\t\t\"\n              />\n            </g>\n            <g filter=\"url(#filter-109)\">\n              <polygon\n                clip-rule=\"evenodd\"\n                fill-rule=\"evenodd\"\n                points=\"0.2,20.4 35.3,40.6 70.4,20.4 35.3,0.1 \t\t\t\t\t\"\n              />\n            </g>\n          </g>\n\n          <linearGradient\n            id=\"SVGID_58_\"\n            gradientTransform=\"matrix(35.088 0 0 -60.7744 17767.0781 87007.4453)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-505.8155\"\n            x2=\"-505.9297\"\n            y1=\"1431.3086\"\n            y2=\"1429.8619\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #7bedff\" />\n            <stop offset=\"1\" style=\"stop-color: #060071\" />\n          </linearGradient>\n          <polygon\n            clip-rule=\"evenodd\"\n            fill=\"url(#SVGID_58_)\"\n            fill-rule=\"evenodd\"\n            points=\"35.2,81.1 35.2,40.6 0.1,20.4 0.1,60.9 \t\t\t\"\n          />\n          <g id=\"编组-10\" transform=\"translate(4.431004, 28.063025)\">\n            <g id=\"编组-8\">\n              <g id=\"Shape备份-3\" transform=\"translate(0.000000, -0.000000)\">\n                <g id=\"蒙版\">\n                  <linearGradient\n                    id=\"SVGID_59_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3322.1904 14513.207)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-523.204\"\n                    x2=\"-524.0609\"\n                    y1=\"1326.9464\"\n                    y2=\"1325.4684\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #fb6583\" />\n                    <stop offset=\"0.1302\" style=\"stop-color: #fc7688\" />\n                    <stop offset=\"0.5277\" style=\"stop-color: #fda797\" />\n                    <stop offset=\"0.8302\" style=\"stop-color: #ffc6a0\" />\n                    <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_59_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_2_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-113_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_2_)\">\n                    <polygon\n                      id=\"path-112_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_60_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3111.8501 14516.8223)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-491.1827\"\n                  x2=\"-491.4043\"\n                  y1=\"1326.7101\"\n                  y2=\"1326.2715\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #fb6583\" />\n                  <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_60_)\"\n                  mask=\"url(#mask-113_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g id=\"Shape备份-4\" transform=\"translate(9.630049, 5.468450)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_61_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3383.2495 14453.3994)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-532.7115\"\n                    x2=\"-533.1328\"\n                    y1=\"1319.3007\"\n                    y2=\"1321.1917\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_61_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_3_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-117_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_3_)\">\n                    <polygon\n                      id=\"path-116_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_62_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3172.9092 14457.0146)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-500.7126\"\n                  x2=\"-501.1153\"\n                  y1=\"1321.2085\"\n                  y2=\"1320.8575\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_62_)\"\n                  mask=\"url(#mask-117_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g id=\"Shape备份-5\" transform=\"translate(19.201017, 11.077510)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_63_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3443.9341 14392.0537)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-542.2824\"\n                    x2=\"-542.7037\"\n                    y1=\"1313.6917\"\n                    y2=\"1315.5826\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_63_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_4_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-120_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_4_)\">\n                    <polygon\n                      id=\"path-119_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_64_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3233.5935 14395.6689)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-510.2835\"\n                  x2=\"-510.6862\"\n                  y1=\"1315.5994\"\n                  y2=\"1315.2484\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_64_)\"\n                  mask=\"url(#mask-120_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n            <g id=\"编组-8备份\" transform=\"translate(0.000000, 11.077510)\">\n              <g transform=\"translate(0.000000, -0.000000)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_65_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3322.1904 14392.0537)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-523.204\"\n                    x2=\"-524.0609\"\n                    y1=\"1315.8689\"\n                    y2=\"1314.3909\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #fb6583\" />\n                    <stop offset=\"0.1302\" style=\"stop-color: #fc7688\" />\n                    <stop offset=\"0.5277\" style=\"stop-color: #fda797\" />\n                    <stop offset=\"0.8302\" style=\"stop-color: #ffc6a0\" />\n                    <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_65_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_5_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-122_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_5_)\">\n                    <polygon\n                      id=\"path-121_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_66_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3111.8501 14395.6689)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-491.1827\"\n                  x2=\"-491.4043\"\n                  y1=\"1315.6326\"\n                  y2=\"1315.194\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #fb6583\" />\n                  <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_66_)\"\n                  mask=\"url(#mask-122_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(9.630049, 5.468450)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_67_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3383.2495 14332.2451)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-532.7115\"\n                    x2=\"-533.1328\"\n                    y1=\"1308.2231\"\n                    y2=\"1310.1143\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_67_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_6_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-124_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_6_)\">\n                    <polygon\n                      id=\"path-123_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_68_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3172.9092 14335.8613)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-500.7126\"\n                  x2=\"-501.1153\"\n                  y1=\"1310.131\"\n                  y2=\"1309.78\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_68_)\"\n                  mask=\"url(#mask-124_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(19.201017, 11.077510)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_69_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3443.9341 14270.8994)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-542.2824\"\n                    x2=\"-542.7037\"\n                    y1=\"1302.6141\"\n                    y2=\"1304.5051\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_69_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_7_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-126_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_7_)\">\n                    <polygon\n                      id=\"path-125_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_70_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3233.5935 14274.5156)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-510.2835\"\n                  x2=\"-510.6862\"\n                  y1=\"1304.5219\"\n                  y2=\"1304.1709\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_70_)\"\n                  mask=\"url(#mask-126_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n            <g id=\"编组-8备份-2\" transform=\"translate(0.000000, 22.155020)\">\n              <g transform=\"translate(0.000000, -0.000000)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_71_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3322.1904 14270.8994)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-523.204\"\n                    x2=\"-524.0609\"\n                    y1=\"1304.7914\"\n                    y2=\"1303.3134\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #fb6583\" />\n                    <stop offset=\"0.1302\" style=\"stop-color: #fc7688\" />\n                    <stop offset=\"0.5277\" style=\"stop-color: #fda797\" />\n                    <stop offset=\"0.8302\" style=\"stop-color: #ffc6a0\" />\n                    <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_71_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_8_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-128_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_8_)\">\n                    <polygon\n                      id=\"path-127_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_72_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3111.8501 14274.5156)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-491.1827\"\n                  x2=\"-491.4043\"\n                  y1=\"1304.5552\"\n                  y2=\"1304.1165\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #fb6583\" />\n                  <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_72_)\"\n                  mask=\"url(#mask-128_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(9.630049, 5.468450)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_73_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3383.2495 14211.0918)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-532.7115\"\n                    x2=\"-533.1328\"\n                    y1=\"1297.1456\"\n                    y2=\"1299.0367\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_73_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_9_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-130_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_9_)\">\n                    <polygon\n                      id=\"path-129_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_74_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3172.9092 14214.708)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-500.7126\"\n                  x2=\"-501.1153\"\n                  y1=\"1299.0535\"\n                  y2=\"1298.7025\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_74_)\"\n                  mask=\"url(#mask-130_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(19.201017, 11.077510)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_75_\"\n                    gradientTransform=\"matrix(6.3405 0 0 -10.9369 3443.9341 14149.7461)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"-542.2824\"\n                    x2=\"-542.7037\"\n                    y1=\"1291.5366\"\n                    y2=\"1293.4276\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_75_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_10_\"\n                    filterUnits=\"userSpaceOnUse\"\n                    height=\"10.9\"\n                    width=\"6.3\"\n                    x=\"0\"\n                    y=\"3.6\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask\n                  id=\"mask-132_1_\"\n                  height=\"10.9\"\n                  maskUnits=\"userSpaceOnUse\"\n                  width=\"6.3\"\n                  x=\"0\"\n                  y=\"3.6\"\n                >\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_10_)\">\n                    <polygon\n                      id=\"path-131_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_76_\"\n                  gradientTransform=\"matrix(-6.3405 0 0 -10.9369 -3233.5935 14153.3623)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"-510.2835\"\n                  x2=\"-510.6862\"\n                  y1=\"1293.4443\"\n                  y2=\"1293.0934\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_76_)\"\n                  mask=\"url(#mask-132_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n          </g>\n\n          <linearGradient\n            id=\"SVGID_77_\"\n            gradientTransform=\"matrix(35.088 0 0 -60.7744 17802.2441 87007.4453)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-505.8547\"\n            x2=\"-505.8547\"\n            y1=\"1431.6647\"\n            y2=\"1430.4622\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #7bedff\" />\n            <stop offset=\"1\" style=\"stop-color: #060071\" />\n          </linearGradient>\n          <polygon\n            clip-rule=\"evenodd\"\n            fill=\"url(#SVGID_77_)\"\n            fill-rule=\"evenodd\"\n            points=\"35.3,81.1 35.3,40.6 70.4,20.4 70.4,60.9\n\t\t\t\t\"\n          />\n\n          <g\n            id=\"编组-10备份-4\"\n            transform=\"translate(53.703560, 51.063025) scale(-1, 1) translate(-53.703560, -51.063025) translate(40.203560, 28.063025)\"\n          >\n            <g>\n              <g transform=\"translate(0.000000, -0.000000)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_78_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3516.198 14513.207)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"553.8022\"\n                    x2=\"552.9454\"\n                    y1=\"1326.9464\"\n                    y2=\"1325.4684\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #fb6583\" />\n                    <stop offset=\"0.1302\" style=\"stop-color: #fc7688\" />\n                    <stop offset=\"0.5277\" style=\"stop-color: #fda797\" />\n                    <stop offset=\"0.8302\" style=\"stop-color: #ffc6a0\" />\n                    <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_78_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_11_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-135_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_11_)\">\n                    <polygon\n                      id=\"path-134_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_79_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3713.8577 14516.8223)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"586.1296\"\n                  x2=\"585.908\"\n                  y1=\"1326.7101\"\n                  y2=\"1326.2715\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #fb6583\" />\n                  <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_79_)\"\n                  mask=\"url(#mask-135_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(9.630049, 5.468450)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_80_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3455.1392 14453.3994)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"544.0497\"\n                    x2=\"543.6284\"\n                    y1=\"1319.3007\"\n                    y2=\"1321.1917\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_80_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_12_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-137_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_12_)\">\n                    <polygon\n                      id=\"path-136_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_81_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3652.7986 14457.0146)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"576.3993\"\n                  x2=\"575.9966\"\n                  y1=\"1321.2085\"\n                  y2=\"1320.8575\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_81_)\"\n                  mask=\"url(#mask-137_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(19.201017, 11.077510)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_82_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3394.4546 14392.0537)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"534.4787\"\n                    x2=\"534.0574\"\n                    y1=\"1313.6917\"\n                    y2=\"1315.5826\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_82_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_13_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-139_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_13_)\">\n                    <polygon\n                      id=\"path-138_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_83_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3592.114 14395.6689)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"566.8283\"\n                  x2=\"566.4257\"\n                  y1=\"1315.5994\"\n                  y2=\"1315.2484\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_83_)\"\n                  mask=\"url(#mask-139_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n            <g transform=\"translate(0.000000, 11.077510)\">\n              <g transform=\"translate(0.000000, -0.000000)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_84_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3516.198 14392.0537)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"553.8022\"\n                    x2=\"552.9454\"\n                    y1=\"1315.8689\"\n                    y2=\"1314.3909\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #fb6583\" />\n                    <stop offset=\"0.1302\" style=\"stop-color: #fc7688\" />\n                    <stop offset=\"0.5277\" style=\"stop-color: #fda797\" />\n                    <stop offset=\"0.8302\" style=\"stop-color: #ffc6a0\" />\n                    <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_84_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_14_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-141_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_14_)\">\n                    <polygon\n                      id=\"path-140_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_85_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3713.8577 14395.6689)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"586.1296\"\n                  x2=\"585.908\"\n                  y1=\"1315.6326\"\n                  y2=\"1315.194\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #fb6583\" />\n                  <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_85_)\"\n                  mask=\"url(#mask-141_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(9.630049, 5.468450)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_86_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3455.1392 14332.2451)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"544.0497\"\n                    x2=\"543.6284\"\n                    y1=\"1308.2231\"\n                    y2=\"1310.1143\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_86_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_15_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-143_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_15_)\">\n                    <polygon\n                      id=\"path-142_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_87_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3652.7986 14335.8613)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"576.3993\"\n                  x2=\"575.9966\"\n                  y1=\"1310.131\"\n                  y2=\"1309.78\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_87_)\"\n                  mask=\"url(#mask-143_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(19.201017, 11.077510)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_88_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3394.4546 14270.8994)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"534.4787\"\n                    x2=\"534.0574\"\n                    y1=\"1302.6141\"\n                    y2=\"1304.5051\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_88_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_16_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-145_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_16_)\">\n                    <polygon\n                      id=\"path-144_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_89_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3592.114 14274.5156)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"566.8283\"\n                  x2=\"566.4257\"\n                  y1=\"1304.5219\"\n                  y2=\"1304.1709\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_89_)\"\n                  mask=\"url(#mask-145_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n            <g transform=\"translate(0.000000, 22.155020)\">\n              <g transform=\"translate(0.000000, -0.000000)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_90_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3516.198 14270.8994)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"553.8022\"\n                    x2=\"552.9454\"\n                    y1=\"1304.7914\"\n                    y2=\"1303.3134\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #fb6583\" />\n                    <stop offset=\"0.1302\" style=\"stop-color: #fc7688\" />\n                    <stop offset=\"0.5277\" style=\"stop-color: #fda797\" />\n                    <stop offset=\"0.8302\" style=\"stop-color: #ffc6a0\" />\n                    <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_90_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_17_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-147_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_17_)\">\n                    <polygon\n                      id=\"path-146_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_91_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3713.8577 14274.5156)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"586.1296\"\n                  x2=\"585.908\"\n                  y1=\"1304.5552\"\n                  y2=\"1304.1165\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #fb6583\" />\n                  <stop offset=\"1\" style=\"stop-color: #ffd1a3\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_91_)\"\n                  mask=\"url(#mask-147_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(9.630049, 5.468450)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_92_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3455.1392 14211.0918)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"544.0497\"\n                    x2=\"543.6284\"\n                    y1=\"1297.1456\"\n                    y2=\"1299.0367\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_92_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_18_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-149_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_18_)\">\n                    <polygon\n                      id=\"path-148_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_93_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3652.7986 14214.708)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"576.3993\"\n                  x2=\"575.9966\"\n                  y1=\"1299.0535\"\n                  y2=\"1298.7025\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_93_)\"\n                  mask=\"url(#mask-149_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n              <g transform=\"translate(19.201017, 11.077510)\">\n                <g>\n                  <linearGradient\n                    id=\"SVGID_94_\"\n                    gradientTransform=\"matrix(-6.3405 0 0 -10.9369 3394.4546 14149.7461)\"\n                    gradientUnits=\"userSpaceOnUse\"\n                    x1=\"534.4787\"\n                    x2=\"534.0574\"\n                    y1=\"1291.5366\"\n                    y2=\"1293.4276\"\n                  >\n                    <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n                    <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n                    <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n                    <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n                    <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n                    <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                  </linearGradient>\n                  <polygon\n                    fill=\"url(#SVGID_94_)\"\n                    points=\"0,7.3 6.3,10.9 6.3,3.7 0,0 \t\t\t\t\t\t\t\"\n                  />\n                </g>\n                <defs>\n                  <filter\n                    id=\"Adobe_OpacityMaskFilter_19_\"\n                    filterUnits=\"userSpaceOnUse\"\n                  >\n                    <feColorMatrix\n                      type=\"matrix\"\n                      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                    />\n                  </filter>\n                </defs>\n                <mask id=\"mask-151_1_\" maskUnits=\"userSpaceOnUse\">\n                  <g filter=\"url(#Adobe_OpacityMaskFilter_19_)\">\n                    <polygon\n                      id=\"path-150_1_\"\n                      clip-rule=\"evenodd\"\n                      fill=\"#FFFFFF\"\n                      fill-rule=\"evenodd\"\n                      points=\"0,7.3 6.3,10.9 6.3,3.7 0,0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"\n                    />\n                  </g>\n                </mask>\n\n                <linearGradient\n                  id=\"SVGID_95_\"\n                  gradientTransform=\"matrix(6.3405 0 0 -10.9369 -3592.114 14153.3623)\"\n                  gradientUnits=\"userSpaceOnUse\"\n                  x1=\"566.8283\"\n                  x2=\"566.4257\"\n                  y1=\"1293.4443\"\n                  y2=\"1293.0934\"\n                >\n                  <stop offset=\"0\" style=\"stop-color: #00c4ba\" />\n                  <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n                </linearGradient>\n                <polygon\n                  fill=\"url(#SVGID_95_)\"\n                  mask=\"url(#mask-151_1_)\"\n                  points=\"6.3,10.9 0,14.6 0,7.3 6.3,3.6 \t\t\t\t\t\t\"\n                />\n              </g>\n            </g>\n          </g>\n        </g>\n\n        <g\n          id=\"椭圆\"\n          transform=\"translate(83.218192, 86.783330) rotate(5.000000) translate(-83.218192, -86.783330) translate(7.218192, 10.783330)\"\n        >\n          <g id=\"编组-5\" transform=\"translate(8.161827, 36.521835)\">\n            <linearGradient\n              id=\"SVGID_96_\"\n              gradientTransform=\"matrix(124.0018 47.351 0.1479 -31.3606 42600.2344 62547.3867)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-344.7103\"\n              x2=\"-344.7103\"\n              y1=\"1473.182\"\n              y2=\"1472.182\"\n            >\n              <stop\n                offset=\"0\"\n                style=\"stop-color: #5cd7e8; stop-opacity: 0.1893\"\n              />\n              <stop offset=\"1\" style=\"stop-color: #fff\" />\n            </linearGradient>\n\n            <ellipse\n              cx=\"68\"\n              cy=\"38.7\"\n              fill=\"none\"\n              rx=\"14.6\"\n              ry=\"66.6\"\n              stroke=\"url(#SVGID_96_)\"\n              stroke-width=\"0.6\"\n              transform=\"matrix(-0.3746 0.9272 -0.9272 -0.3746 129.3914 -9.7912)\"\n            />\n\n            <ellipse\n              clip-rule=\"evenodd\"\n              cx=\"60.3\"\n              cy=\"51.5\"\n              fill=\"#FFFFFF\"\n              fill-rule=\"evenodd\"\n              rx=\"1.7\"\n              ry=\"1.7\"\n              transform=\"matrix(2.765398e-06 1 -1 2.765398e-06 111.8035 -8.8797)\"\n            />\n\n            <ellipse\n              id=\"椭圆形备份\"\n              clip-rule=\"evenodd\"\n              cx=\"86\"\n              cy=\"30.8\"\n              enable-background=\"new    \"\n              fill=\"#FFFFFF\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.2662\"\n              rx=\"1.1\"\n              ry=\"1\"\n              transform=\"matrix(2.765396e-06 1 -1 2.765396e-06 116.7571 -55.2401)\"\n            />\n          </g>\n\n          <g\n            transform=\"translate(76.180160, 76.074544) rotate(-45.000000) translate(-76.180160, -76.074544) translate(8.680160, 37.074544)\"\n          >\n            <linearGradient\n              id=\"SVGID_97_\"\n              gradientTransform=\"matrix(87.4224 55.5937 87.656 11.2551 42330.7227 60598.5664)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"-1242.9404\"\n              x2=\"-1242.9404\"\n              y1=\"757.5463\"\n              y2=\"756.5463\"\n            >\n              <stop\n                offset=\"0\"\n                style=\"stop-color: #5cd7e8; stop-opacity: 0.1893\"\n              />\n              <stop offset=\"1\" style=\"stop-color: #fff\" />\n            </linearGradient>\n\n            <ellipse\n              cx=\"67.9\"\n              cy=\"38.7\"\n              fill=\"none\"\n              rx=\"66.5\"\n              ry=\"14.6\"\n              stroke=\"url(#SVGID_97_)\"\n              stroke-width=\"0.6\"\n              transform=\"matrix(-0.9272 -0.3746 0.3746 -0.9272 116.2823 100.0875)\"\n            />\n\n            <ellipse\n              clip-rule=\"evenodd\"\n              cx=\"31.9\"\n              cy=\"37\"\n              fill=\"#FFFFFF\"\n              fill-rule=\"evenodd\"\n              rx=\"1.7\"\n              ry=\"1.7\"\n              transform=\"matrix(-1 -5.213811e-07 5.213811e-07 -1 63.8725 74.0324)\"\n            />\n\n            <ellipse\n              clip-rule=\"evenodd\"\n              cx=\"85.8\"\n              cy=\"30.8\"\n              enable-background=\"new    \"\n              fill=\"#FFFFFF\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.2662\"\n              rx=\"1\"\n              ry=\"1.1\"\n              transform=\"matrix(-1 2.765399e-06 -2.765399e-06 -1 171.6696 61.5172)\"\n            />\n          </g>\n        </g>\n      </g>\n\n      <g\n        id=\"编组备份-11\"\n        transform=\"translate(694.000000, 158.500000) scale(-1, 1) translate(-694.000000, -158.500000) translate(622.000000, 65.000000)\"\n      >\n        <linearGradient\n          id=\"SVGID_98_\"\n          gradientTransform=\"matrix(-142.0107 0 0 -186.2829 94193.1797 325470.9375)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"663.2509\"\n          x2=\"663.8784\"\n          y1=\"1745.6415\"\n          y2=\"1747.1095\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #00c6fb\" />\n        </linearGradient>\n        <path\n          d=\"M134.9,0l7.1,4l-2.2,3.6l-3,1.2l-1.4,92c0,3-1.8,6.5-4,8l-0.2,0.1L10,178.8l0,0l-1.2,7.5l-7-3.9\n\t\t\tc-0.1-0.1-0.3-0.1-0.4-0.2l0,0c-0.8-0.6-1.3-1.7-1.3-3.3l0,0l1.4-97.1c0-3.1,1.9-6.7,4.2-8.1l0,0L132.6,0.5\n\t\t\tC133.5,0,134.3-0.1,134.9,0L134.9,0z\"\n          fill=\"url(#SVGID_98_)\"\n        />\n\n        <linearGradient\n          id=\"SVGID_99_\"\n          gradientTransform=\"matrix(-136.8189 0 0 -182.5389 90752.4922 318912.7812)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"662.8271\"\n          x2=\"662.9656\"\n          y1=\"1746.7982\"\n          y2=\"1746.3707\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #276cfc\" />\n          <stop offset=\"1\" style=\"stop-color: #84ffd1\" />\n        </linearGradient>\n        <path\n          clip-rule=\"evenodd\"\n          d=\"M11,185.8l126.9-73.2c2.3-1.4,4.2-5,4.2-8.1l1.4-97.1\n\t\t\tc0-3.1-1.9-4.6-4.2-3.2L12.4,77.4c-2.3,1.4-4.2,5-4.2,8.1l-1.4,97.1C6.8,185.7,8.7,187.1,11,185.8z\"\n          fill=\"url(#SVGID_99_)\"\n          fill-rule=\"evenodd\"\n        />\n        <g opacity=\"0.3\" transform=\"translate(95.618736, 40.248000)\">\n          <path\n            d=\"M33.5,8.7L3.1,26.3c-1,0.6-2.2,0.2-2.8-0.7\n\t\t\t\tc-0.2-0.3-0.3-0.7-0.3-1c0-2.2,1.2-4.2,3-5.2L33.5,1.7c1-0.6,2.2-0.2,2.8,0.7c0.2,0.3,0.3,0.7,0.3,1C36.6,5.7,35.4,7.7,33.5,8.7z\n\t\t\t\t\"\n            enable-background=\"new    \"\n            fill=\"#FFFFFF\"\n            opacity=\"0.3007\"\n          />\n          <path\n            d=\"M34,27.4L10.3,41c-0.8,0.4-1.7,0.2-2.1-0.6\n\t\t\t\tC8,40.2,8,40,8,39.7c0-1.7,0.9-3.2,2.4-4.1L34,22c0.8-0.4,1.7-0.2,2.1,0.6c0.1,0.2,0.2,0.5,0.2,0.8C36.3,25,35.4,26.5,34,27.4z\"\n            enable-background=\"new    \"\n            fill=\"#FFFFFF\"\n            opacity=\"0.3007\"\n          />\n          <path\n            d=\"M34,41.7L10.3,55.4c-0.8,0.4-1.7,0.2-2.1-0.6\n\t\t\t\tC8,54.6,8,54.3,8,54c0-1.7,0.9-3.2,2.4-4.1L34,36.3c0.8-0.4,1.7-0.2,2.1,0.6c0.1,0.2,0.2,0.5,0.2,0.8\n\t\t\t\tC36.3,39.3,35.4,40.9,34,41.7z\"\n            enable-background=\"new    \"\n            fill=\"#FFFFFF\"\n            opacity=\"0.3007\"\n          />\n          <path\n            d=\"M34,56L10.3,69.7c-0.8,0.4-1.7,0.2-2.1-0.6\n\t\t\t\tC8,68.9,8,68.6,8,68.3c0-1.7,0.9-3.2,2.4-4.1L34,50.6c0.8-0.4,1.7-0.2,2.1,0.6c0.1,0.2,0.2,0.5,0.2,0.8\n\t\t\t\tC36.3,53.6,35.4,55.2,34,56z\"\n            enable-background=\"new    \"\n            fill=\"#FFFFFF\"\n            opacity=\"0.3007\"\n          />\n        </g>\n\n        <linearGradient\n          id=\"SVGID_100_\"\n          gradientTransform=\"matrix(-82.1586 0 0 -155.5418 54504.3555 271598.7188)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"662.0853\"\n          x2=\"661.7936\"\n          y1=\"1746.2543\"\n          y2=\"1745.1642\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n        </linearGradient>\n        <polygon\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_100_)\"\n          opacity=\"0.4\"\n          points=\"93,31 53,161.5 94.8,137.4 135.2,6 \t\t\"\n        />\n\n        <linearGradient\n          id=\"SVGID_101_\"\n          gradientTransform=\"matrix(-12.3655 0 0 -48.4174 8136.0479 83952.2812)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"655.1039\"\n          x2=\"654.9725\"\n          y1=\"1729.8617\"\n          y2=\"1731.0027\"\n        >\n          <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n          <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n          <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n          <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n          <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n          <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n        </linearGradient>\n\n        <linearGradient\n          id=\"SVGID_102_\"\n          gradientTransform=\"matrix(-12.3655 0 0 -48.4174 8136.0479 83952.2812)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"655.2512\"\n          x2=\"655.2512\"\n          y1=\"1731.6409\"\n          y2=\"1730.6409\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n        </linearGradient>\n\n        <polygon\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_101_)\"\n          opacity=\"0.3007\"\n          points=\"\n\t\t\t39.7,152 27.4,159.1 27.4,117.9 39.7,110.7 \t\t\"\n          stroke=\"url(#SVGID_102_)\"\n          stroke-width=\"0.5\"\n        />\n\n        <g\n          transform=\"translate(72.980000, 101.800000) scale(-1, 1) translate(-72.980000, -101.800000) translate(13.480000, 28.800000)\"\n        >\n          <linearGradient\n            id=\"SVGID_103_\"\n            gradientTransform=\"matrix(116.289 0 0 -102.7515 61913.2812 176111.3281)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-531.9647\"\n            x2=\"-531.5446\"\n            y1=\"1713.5308\"\n            y2=\"1713.0157\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #fff\" />\n            <stop offset=\"1\" style=\"stop-color: #fff\" />\n          </linearGradient>\n\n          <linearGradient\n            id=\"SVGID_104_\"\n            gradientTransform=\"matrix(116.289 0 0 -102.7515 61913.2812 176111.3281)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-531.3857\"\n            x2=\"-532.1153\"\n            y1=\"1713.6992\"\n            y2=\"1713.3367\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #f8ff24\" />\n            <stop offset=\"1\" style=\"stop-color: #fff\" />\n          </linearGradient>\n          <path\n            clip-rule=\"evenodd\"\n            d=\"\n\t\t\t\tM117.6,103.3c-6-3.4-9-14.2-11.9-24.6c-2.9-10.2-5.7-20.7-11.4-24c-5.7-3.3-8.6,3.9-11.4,10.8c-2.9,7.1-5.9,14.4-11.9,10.9\n\t\t\t\tc-6-3.5-9-14.2-11.8-24.6c-2.9-10.2-5.8-20.7-11.4-24s-8.6,3.9-11.4,10.8c-2.9,7.1-5.9,14.4-11.9,10.9c-6-3.4-9-14.2-11.8-24.6\n\t\t\t\tC9.9,14.9,7,4.3,1.3,1.1V0.5c6,3.4,9,14.2,11.9,24.6c2.8,10.2,5.7,20.7,11.4,24c5.7,3.3,8.6-3.9,11.4-10.8\n\t\t\t\tc2.9-7.1,5.9-14.4,11.8-10.9s9,14.2,11.9,24.6c2.9,10.2,5.7,20.7,11.4,24c5.7,3.2,8.6-3.9,11.4-10.8c2.9-7.1,5.9-14.4,11.8-10.9\n\t\t\t\tc6,3.5,9,14.2,11.9,24.6c2.9,10.2,5.8,20.7,11.4,24V103.3z\"\n            fill=\"url(#SVGID_103_)\"\n            fill-rule=\"evenodd\"\n            stroke=\"url(#SVGID_104_)\"\n            stroke-width=\"1.4256\"\n          />\n\n          <linearGradient\n            id=\"路径-2_1_\"\n            gradientTransform=\"matrix(117.4617 0 0 -144.8008 62535.8438 248597.6562)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"-531.8884\"\n            x2=\"-531.8884\"\n            y1=\"1716.8223\"\n            y2=\"1715.8223\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #fff\" />\n            <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n          </linearGradient>\n          <path\n            id=\"路径-2\"\n            clip-rule=\"evenodd\"\n            d=\"M0.6,0.5v77.2l117,67.6l0.5-42\n\t\t\t\tc-3.3-3.2-5.5-5.6-6.5-7.3c-4.4-7.6-5.6-14.4-6.1-18.2c-1.1-7.7-9.1-26.4-15.2-23.3c-6.1,3.1-10.8,27.4-17.9,23.3\n\t\t\t\tc-7-4-15.5-32-17.3-39.4S46,22.8,41.4,29.7c-1,1.5-4.9,9.1-6,11.5c-7.7,15.9-13.7,7.5-19.1-5C14.1,31.1,9.8,15.4,6.2,6.8\n\t\t\t\tC5,3.9,3.2,1.8,0.6,0.5z\"\n            fill=\"url(#路径-2_1_)\"\n            fill-rule=\"evenodd\"\n          />\n          <g id=\"编组-7\" transform=\"translate(41.723113, 19.522022)\">\n            <path\n              id=\"Fill-11\"\n              clip-rule=\"evenodd\"\n              d=\"\n\t\t\t\t\tM5.4,0.8c3,1.9,5.4,6.4,5.4,10.1c0,3.7-2.4,5.2-5.4,3.4C2.4,12.4,0,7.9,0,4.2C0,0.4,2.4-1.1,5.4,0.8\"\n              enable-background=\"new    \"\n              fill=\"#AA69FF\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.6\"\n            />\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M9.7,10.7\n\t\t\t\t\tc0,3.2-2,4.5-4.3,2.9C3,12,1.1,8.1,1.1,4.9c0-3.2,2-4.5,4.3-2.9S9.7,7.5,9.7,10.7z\"\n              enable-background=\"new    \"\n              fill=\"#7005FF\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.6\"\n            />\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M7.4,9c0,1.6-1,2.2-2.2,1.4C4.1,9.6,3.1,7.6,3.1,6\n\t\t\t\t\tc0-1.6,1-2.2,2.2-1.4S7.4,7.4,7.4,9z\"\n              fill=\"#E7C769\"\n              fill-rule=\"evenodd\"\n            />\n          </g>\n        </g>\n\n        <linearGradient\n          id=\"SVGID_105_\"\n          gradientTransform=\"matrix(-12.3655 0 0 -61.3183 8158.1587 106537.3281)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"655.2088\"\n          x2=\"655.1892\"\n          y1=\"1734.5078\"\n          y2=\"1734.9935\"\n        >\n          <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n          <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n          <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n          <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n          <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n          <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n        </linearGradient>\n\n        <linearGradient\n          id=\"SVGID_106_\"\n          gradientTransform=\"matrix(-12.3655 0 0 -61.3183 8158.1587 106537.3281)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"655.2512\"\n          x2=\"655.2512\"\n          y1=\"1736.0601\"\n          y2=\"1735.0601\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n        </linearGradient>\n\n        <polygon\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_105_)\"\n          opacity=\"0.3007\"\n          points=\"\n\t\t\t61.8,139.2 49.5,146.4 49.5,92.2 61.8,85.1 \t\t\"\n          stroke=\"url(#SVGID_106_)\"\n          stroke-width=\"0.5\"\n        />\n\n        <linearGradient\n          id=\"SVGID_107_\"\n          gradientTransform=\"matrix(-12.3655 0 0 -74.2182 8181.0142 129120.2578)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"655.1729\"\n          x2=\"655.117\"\n          y1=\"1737.4004\"\n          y2=\"1738.1447\"\n        >\n          <stop offset=\"5.400000e-03\" style=\"stop-color: #130cb5\" />\n          <stop offset=\"0.2823\" style=\"stop-color: #285ecb\" />\n          <stop offset=\"0.538\" style=\"stop-color: #3aa3dd\" />\n          <stop offset=\"0.75\" style=\"stop-color: #47d5eb\" />\n          <stop offset=\"0.9102\" style=\"stop-color: #4ff4f3\" />\n          <stop offset=\"1\" style=\"stop-color: #52fff6\" />\n        </linearGradient>\n\n        <linearGradient\n          id=\"SVGID_108_\"\n          gradientTransform=\"matrix(-12.3655 0 0 -74.2182 8181.0142 129120.2578)\"\n          gradientUnits=\"userSpaceOnUse\"\n          x1=\"655.2512\"\n          x2=\"655.2512\"\n          y1=\"1738.9429\"\n          y2=\"1737.9429\"\n        >\n          <stop offset=\"0\" style=\"stop-color: #fff\" />\n          <stop offset=\"1\" style=\"stop-color: #fff; stop-opacity: 0\" />\n        </linearGradient>\n\n        <polygon\n          enable-background=\"new    \"\n          fill=\"url(#SVGID_107_)\"\n          opacity=\"0.3007\"\n          points=\"\n\t\t\t84.7,126 72.3,133.2 72.3,66.1 84.7,59 \t\t\"\n          stroke=\"url(#SVGID_108_)\"\n          stroke-width=\"0.5\"\n        />\n      </g>\n      <g id=\"编组-16\" transform=\"translate(51.000000, 152.000000)\">\n        <g id=\"云\">\n          <g transform=\"translate(0.000000, 0.000000)\">\n            <g>\n              <linearGradient\n                id=\"SVGID_109_\"\n                gradientTransform=\"matrix(100.2748 0 0 -95.0757 -5012.0137 157345.375)\"\n                gradientUnits=\"userSpaceOnUse\"\n                x1=\"49.8504\"\n                x2=\"50.8986\"\n                y1=\"1654.3923\"\n                y2=\"1654.5082\"\n              >\n                <stop offset=\"0\" style=\"stop-color: #544cde\" />\n                <stop offset=\"0.5868\" style=\"stop-color: #a7a0ff\" />\n                <stop offset=\"1\" style=\"stop-color: #7b74ff\" />\n              </linearGradient>\n              <path\n                clip-rule=\"evenodd\"\n                d=\"M70.3,14.7c0,0.3,0,0.5,0,0.7\n\t\t\t\t\t\tc1.5-1.4,3.2-2.6,4.8-3.5c5.6-3.2,10.6-3.3,14-0.8l11.1,6.6l-7.1,11c-2.1,10-8.9,20.5-17.2,25.7L23.9,84.6L18,95.1L6.2,88l0,0\n\t\t\t\t\t\tC2.4,85.8,0,81.2,0,74.5c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33\n\t\t\t\t\t\tC61-3.8,70.3,1.6,70.3,14.7z\"\n                fill=\"url(#SVGID_109_)\"\n                fill-rule=\"evenodd\"\n              />\n            </g>\n            <defs>\n              <filter\n                id=\"Adobe_OpacityMaskFilter_20_\"\n                filterUnits=\"userSpaceOnUse\"\n                height=\"67.1\"\n                width=\"76.3\"\n                x=\"58.3\"\n                y=\"-13.8\"\n              >\n                <feColorMatrix\n                  type=\"matrix\"\n                  values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                />\n              </filter>\n            </defs>\n            <mask\n              id=\"mask-168_1_\"\n              height=\"67.1\"\n              maskUnits=\"userSpaceOnUse\"\n              width=\"76.3\"\n              x=\"58.3\"\n              y=\"-13.8\"\n            >\n              <g filter=\"url(#Adobe_OpacityMaskFilter_20_)\">\n                <path\n                  id=\"path-167_1_\"\n                  clip-rule=\"evenodd\"\n                  d=\"M70.3,14.7c0,0.3,0,0.5,0,0.7\n\t\t\t\t\t\t\tc1.5-1.4,3.2-2.6,4.8-3.5c5.6-3.2,10.6-3.3,14-0.8l11.1,6.6l-7.1,11c-2.1,10-8.9,20.5-17.2,25.7L23.9,84.6L18,95.1L6.2,88l0,0\n\t\t\t\t\t\t\tC2.4,85.8,0,81.2,0,74.5c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33\n\t\t\t\t\t\t\tC61-3.8,70.3,1.6,70.3,14.7z\"\n                  fill=\"#FFFFFF\"\n                  fill-rule=\"evenodd\"\n                />\n              </g>\n            </mask>\n\n            <linearGradient\n              id=\"矩形备份-3_1_\"\n              gradientTransform=\"matrix(76.2914 0 0 -67.1042 -3730.5828 110741.1094)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"49.8816\"\n              x2=\"50.4973\"\n              y1=\"1649.8344\"\n              y2=\"1650.4406\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4f3eff\" />\n              <stop offset=\"0.4096\" style=\"stop-color: #9c92ff\" />\n              <stop offset=\"0.7979\" style=\"stop-color: #2519da\" />\n              <stop offset=\"1\" style=\"stop-color: #0d04ab\" />\n            </linearGradient>\n\n            <path\n              id=\"矩形备份-3\"\n              clip-rule=\"evenodd\"\n              d=\"\n\t\t\t\t\tM100.1-13.4l29.3,15.6l5.2,15.3C112,43,96.4,54.9,87.8,53.2S69.3,34.5,58.3,2.2c10.3-7,18.4-11.6,24.2-13.7\n\t\t\t\t\tS94.1-14.3,100.1-13.4z\"\n              fill=\"url(#矩形备份-3_1_)\"\n              fill-rule=\"evenodd\"\n              mask=\"url(#mask-168_1_)\"\n            />\n            <defs>\n              <filter\n                id=\"Adobe_OpacityMaskFilter_21_\"\n                filterUnits=\"userSpaceOnUse\"\n                height=\"67.1\"\n                width=\"76.3\"\n                x=\"0\"\n                y=\"-13.8\"\n              >\n                <feColorMatrix\n                  type=\"matrix\"\n                  values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                />\n              </filter>\n            </defs>\n            <mask\n              id=\"mask-168_2_\"\n              height=\"67.1\"\n              maskUnits=\"userSpaceOnUse\"\n              width=\"76.3\"\n              x=\"0\"\n              y=\"-13.8\"\n            >\n              <g filter=\"url(#Adobe_OpacityMaskFilter_21_)\">\n                <path\n                  id=\"path-167_2_\"\n                  clip-rule=\"evenodd\"\n                  d=\"M70.3,14.7c0,0.3,0,0.5,0,0.7\n\t\t\t\t\t\t\tc1.5-1.4,3.2-2.6,4.8-3.5c5.6-3.2,10.6-3.3,14-0.8l11.1,6.6l-7.1,11c-2.1,10-8.9,20.5-17.2,25.7L23.9,84.6L18,95.1L6.2,88l0,0\n\t\t\t\t\t\t\tC2.4,85.8,0,81.2,0,74.5c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33\n\t\t\t\t\t\t\tC61-3.8,70.3,1.6,70.3,14.7z\"\n                  fill=\"#FFFFFF\"\n                  fill-rule=\"evenodd\"\n                />\n              </g>\n            </mask>\n\n            <linearGradient\n              id=\"矩形备份-2_1_\"\n              gradientTransform=\"matrix(76.2914 0 0 -67.1042 -3788.8608 110741.1094)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"49.8816\"\n              x2=\"50.4973\"\n              y1=\"1649.8344\"\n              y2=\"1650.4406\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4f3eff\" />\n              <stop offset=\"0.4096\" style=\"stop-color: #9c92ff\" />\n              <stop offset=\"0.7979\" style=\"stop-color: #2519da\" />\n              <stop offset=\"1\" style=\"stop-color: #0d04ab\" />\n            </linearGradient>\n\n            <path\n              id=\"矩形备份-2\"\n              clip-rule=\"evenodd\"\n              d=\"\n\t\t\t\t\tM41.8-13.4L71.1,2.2l5.2,15.3C53.7,43,38.1,54.9,29.5,53.2S11,34.5,0,2.2c10.3-7,18.4-11.6,24.2-13.7S35.8-14.3,41.8-13.4z\"\n              fill=\"url(#矩形备份-2_1_)\"\n              fill-rule=\"evenodd\"\n              mask=\"url(#mask-168_2_)\"\n            />\n            <defs>\n              <filter\n                id=\"Adobe_OpacityMaskFilter_22_\"\n                filterUnits=\"userSpaceOnUse\"\n                height=\"67.1\"\n                width=\"76.3\"\n                x=\"-12.7\"\n                y=\"35.5\"\n              >\n                <feColorMatrix\n                  type=\"matrix\"\n                  values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"\n                />\n              </filter>\n            </defs>\n            <mask\n              id=\"mask-168_3_\"\n              height=\"67.1\"\n              maskUnits=\"userSpaceOnUse\"\n              width=\"76.3\"\n              x=\"-12.7\"\n              y=\"35.5\"\n            >\n              <g filter=\"url(#Adobe_OpacityMaskFilter_22_)\">\n                <path\n                  id=\"path-167_3_\"\n                  clip-rule=\"evenodd\"\n                  d=\"M70.3,14.7c0,0.3,0,0.5,0,0.7\n\t\t\t\t\t\t\tc1.5-1.4,3.2-2.6,4.8-3.5c5.6-3.2,10.6-3.3,14-0.8l11.1,6.6l-7.1,11c-2.1,10-8.9,20.5-17.2,25.7L23.9,84.6L18,95.1L6.2,88l0,0\n\t\t\t\t\t\t\tC2.4,85.8,0,81.2,0,74.5c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33\n\t\t\t\t\t\t\tC61-3.8,70.3,1.6,70.3,14.7z\"\n                  fill=\"#FFFFFF\"\n                  fill-rule=\"evenodd\"\n                />\n              </g>\n            </mask>\n\n            <linearGradient\n              id=\"SVGID_110_\"\n              gradientTransform=\"matrix(76.2914 0 0 -67.1042 -3801.5762 110790.3594)\"\n              gradientUnits=\"userSpaceOnUse\"\n              x1=\"49.8816\"\n              x2=\"50.4973\"\n              y1=\"1649.8344\"\n              y2=\"1650.4406\"\n            >\n              <stop offset=\"0\" style=\"stop-color: #4f3eff\" />\n              <stop offset=\"0.4096\" style=\"stop-color: #9c92ff\" />\n              <stop offset=\"0.7979\" style=\"stop-color: #2519da\" />\n              <stop offset=\"1\" style=\"stop-color: #0d04ab\" />\n            </linearGradient>\n            <path\n              clip-rule=\"evenodd\"\n              d=\"M29.1,35.9l29.3,15.6\n\t\t\t\t\tl5.2,15.3C41,92.3,25.4,104.1,16.8,102.4c-8.7-1.7-18.5-18.7-29.5-50.9c10.3-7,18.4-11.6,24.2-13.7S23.1,35,29.1,35.9z\"\n              fill=\"url(#SVGID_110_)\"\n              fill-rule=\"evenodd\"\n              mask=\"url(#mask-168_3_)\"\n            />\n          </g>\n\n          <linearGradient\n            id=\"Fill-1备份_1_\"\n            gradientTransform=\"matrix(93.8386 0 0 -89.2609 -4672.3262 147666.9375)\"\n            gradientUnits=\"userSpaceOnUse\"\n            x1=\"50.6106\"\n            x2=\"50.1002\"\n            y1=\"1654.2188\"\n            y2=\"1652.9083\"\n          >\n            <stop offset=\"0\" style=\"stop-color: #5e51e4\" />\n            <stop offset=\"1\" style=\"stop-color: #060071\" />\n          </linearGradient>\n          <path\n            id=\"Fill-1备份\"\n            clip-rule=\"evenodd\"\n            d=\"M86.6,18.8\n\t\t\t\tc10.3-6,18.6-1.1,18.7,10.7c0,11.6-7.9,25.6-17.9,31.8l-55.2,32l-0.4,0.2c-11.3,6.3-20.3,0.9-20.4-12.1\n\t\t\t\tc0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33c11.4-6.6,20.7-1.3,20.8,11.9c0,0.3,0,0.5,0,0.7\n\t\t\t\tC83.3,21,84.9,19.7,86.6,18.8\"\n            fill=\"url(#Fill-1备份_1_)\"\n            fill-rule=\"evenodd\"\n          />\n        </g>\n      </g>\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/authentication/index.ts",
    "content": "export { default as AuthPageLayout } from './authentication.vue';\nexport * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/authentication/toolbar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { ToolbarType } from './types';\n\nimport { computed } from 'vue';\n\nimport { preferences } from '@vben/preferences';\n\nimport {\n  AuthenticationColorToggle,\n  AuthenticationLayoutToggle,\n  LanguageToggle,\n  ThemeToggle,\n} from '../widgets';\n\ninterface Props {\n  toolbarList?: ToolbarType[];\n}\n\ndefineOptions({\n  name: 'AuthenticationToolbar',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  toolbarList: () => ['color', 'language', 'layout', 'theme'],\n});\n\nconst showColor = computed(() => props.toolbarList.includes('color'));\nconst showLayout = computed(() => props.toolbarList.includes('layout'));\nconst showLanguage = computed(() => props.toolbarList.includes('language'));\nconst showTheme = computed(() => props.toolbarList.includes('theme'));\n</script>\n\n<template>\n  <div\n    :class=\"{\n      'bg-accent rounded-3xl px-3 py-1': toolbarList.length > 1,\n    }\"\n    class=\"flex-center absolute right-2 top-4 z-10\"\n  >\n    <!-- Only show on medium and larger screens -->\n    <div class=\"hidden md:flex\">\n      <AuthenticationColorToggle v-if=\"showColor\" />\n      <AuthenticationLayoutToggle v-if=\"showLayout\" />\n    </div>\n    <!-- Always show Language and Theme toggles -->\n    <LanguageToggle v-if=\"showLanguage && preferences.widget.languageToggle\" />\n    <ThemeToggle v-if=\"showTheme && preferences.widget.themeToggle\" />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/authentication/types.ts",
    "content": "export type ToolbarType = 'color' | 'language' | 'layout' | 'theme';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/README.md",
    "content": "## layout\n\n### header\n\n- 支持N个自定义插槽，命名方式：header-right-n，header-left-n\n- header-left-n ，排序方式：0-19 ,breadcrumb 21-x\n- header-right-n ，排序方式：0-49，global-search，51-59，theme-toggle，61-69，language-toggle，71-79，fullscreen，81-89，notification，91-149，user-dropdown，151-x\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/content/content-spinner.vue",
    "content": "<script lang=\"ts\" setup>\nimport { VbenSpinner } from '@vben-core/shadcn-ui';\n\nimport { useContentSpinner } from './use-content-spinner';\n\ndefineOptions({ name: 'LayoutContentSpinner' });\n\nconst { spinning } = useContentSpinner();\n</script>\n<template>\n  <VbenSpinner :spinning=\"spinning\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/content/content.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VNode } from 'vue';\nimport type {\n  RouteLocationNormalizedLoaded,\n  RouteLocationNormalizedLoadedGeneric,\n} from 'vue-router';\n\nimport { computed } from 'vue';\nimport { RouterView } from 'vue-router';\n\nimport { preferences, usePreferences } from '@vben/preferences';\nimport { getTabKey, storeToRefs, useTabbarStore } from '@vben/stores';\n\nimport { IFrameRouterView } from '../../iframe';\n\ndefineOptions({ name: 'LayoutContent' });\n\nconst tabbarStore = useTabbarStore();\nconst { keepAlive } = usePreferences();\n\nconst { getCachedTabs, getExcludeCachedTabs, renderRouteView } =\n  storeToRefs(tabbarStore);\n\n/**\n * 是否使用动画\n */\nconst getEnabledTransition = computed(() => {\n  const { transition } = preferences;\n  const transitionName = transition.name;\n  return transitionName && transition.enable;\n});\n\n// 页面切换动画\nfunction getTransitionName(_route: RouteLocationNormalizedLoaded) {\n  // 如果偏好设置未设置，则不使用动画\n  const { tabbar, transition } = preferences;\n  const transitionName = transition.name;\n  if (!transitionName || !transition.enable) {\n    return;\n  }\n\n  // 标签页未启用或者未开启缓存，则使用全局配置动画\n  if (!tabbar.enable || !keepAlive) {\n    return transitionName;\n  }\n\n  // 如果页面已经加载过，则不使用动画\n  // if (route.meta.loaded) {\n  //   return;\n  // }\n  // 已经打开且已经加载过的页面不使用动画\n  // const inTabs = getCachedTabs.value.includes(route.name as string);\n\n  // return inTabs && route.meta.loaded ? undefined : transitionName;\n  return transitionName;\n}\n\n/**\n * 转换组件，自动添加 name\n * @param component\n */\nfunction transformComponent(\n  component: VNode,\n  route: RouteLocationNormalizedLoadedGeneric,\n) {\n  // 组件视图未找到，如果有设置后备视图，则返回后备视图，如果没有，则抛出错误\n  if (!component) {\n    console.error(\n      'Component view not found，please check the route configuration',\n    );\n    return undefined;\n  }\n\n  const routeName = route.name as string;\n  // 如果组件没有 name，则直接返回\n  if (!routeName) {\n    return component;\n  }\n  const componentName = (component?.type as any)?.name;\n\n  // 已经设置过 name，则直接返回\n  if (componentName) {\n    return component;\n  }\n\n  // componentName 与 routeName 一致，则直接返回\n  if (componentName === routeName) {\n    return component;\n  }\n\n  // 设置 name\n  component.type ||= {};\n  (component.type as any).name = routeName;\n\n  return component;\n}\n</script>\n\n<template>\n  <div class=\"relative h-full\">\n    <IFrameRouterView />\n    <RouterView v-slot=\"{ Component, route }\">\n      <Transition\n        v-if=\"getEnabledTransition\"\n        :name=\"getTransitionName(route)\"\n        appear\n        mode=\"out-in\"\n      >\n        <KeepAlive\n          v-if=\"keepAlive\"\n          :exclude=\"getExcludeCachedTabs\"\n          :include=\"getCachedTabs\"\n        >\n          <component\n            :is=\"transformComponent(Component, route)\"\n            v-if=\"renderRouteView\"\n            v-show=\"!route.meta.iframeSrc\"\n            :key=\"getTabKey(route)\"\n          />\n        </KeepAlive>\n        <component\n          :is=\"Component\"\n          v-else-if=\"renderRouteView\"\n          :key=\"getTabKey(route)\"\n        />\n      </Transition>\n      <template v-else>\n        <KeepAlive\n          v-if=\"keepAlive\"\n          :exclude=\"getExcludeCachedTabs\"\n          :include=\"getCachedTabs\"\n        >\n          <component\n            :is=\"transformComponent(Component, route)\"\n            v-if=\"renderRouteView\"\n            v-show=\"!route.meta.iframeSrc\"\n            :key=\"getTabKey(route)\"\n          />\n        </KeepAlive>\n        <component\n          :is=\"Component\"\n          v-else-if=\"renderRouteView\"\n          :key=\"getTabKey(route)\"\n        />\n      </template>\n    </RouterView>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/content/index.ts",
    "content": "export { default as LayoutContentSpinner } from './content-spinner.vue';\nexport { default as LayoutContent } from './content.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/content/use-content-spinner.ts",
    "content": "import { computed, ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { preferences } from '@vben/preferences';\n\nfunction useContentSpinner() {\n  const spinning = ref(false);\n  const startTime = ref(0);\n  const router = useRouter();\n  const minShowTime = 500; // 最小显示时间\n  const enableLoading = computed(() => preferences.transition.loading);\n\n  // 结束加载动画\n  const onEnd = () => {\n    if (!enableLoading.value) {\n      return;\n    }\n    const processTime = performance.now() - startTime.value;\n    if (processTime < minShowTime) {\n      setTimeout(() => {\n        spinning.value = false;\n      }, minShowTime - processTime);\n    } else {\n      spinning.value = false;\n    }\n  };\n\n  // 路由前置守卫\n  router.beforeEach((to) => {\n    if (to.meta.loaded || !enableLoading.value || to.meta.iframeSrc) {\n      return true;\n    }\n    startTime.value = performance.now();\n    spinning.value = true;\n    return true;\n  });\n\n  // 路由后置守卫\n  router.afterEach((to) => {\n    if (to.meta.loaded || !enableLoading.value || to.meta.iframeSrc) {\n      return true;\n    }\n    onEnd();\n    return true;\n  });\n\n  return { spinning };\n}\n\nexport { useContentSpinner };\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/copyright/copyright.vue",
    "content": "<script lang=\"ts\" setup>\ninterface Props {\n  companyName?: string;\n  companySiteLink?: string;\n  date?: string;\n  icp?: string;\n  icpLink?: string;\n}\n\ndefineOptions({\n  name: 'Copyright',\n});\n\nwithDefaults(defineProps<Props>(), {\n  companyName: 'Vben Admin',\n  companySiteLink: '',\n  date: '2024',\n  icp: '',\n  icpLink: '',\n});\n</script>\n\n<template>\n  <div class=\"text-md flex-center\">\n    <!-- ICP Link -->\n    <a\n      v-if=\"icp\"\n      :href=\"icpLink || 'javascript:void(0)'\"\n      class=\"hover:text-primary-hover mx-1\"\n      target=\"_blank\"\n    >\n      {{ icp }}\n    </a>\n\n    <!-- Copyright Text -->\n    Copyright © {{ date }}\n\n    <!-- Company Link -->\n    <a\n      v-if=\"companyName\"\n      :href=\"companySiteLink || 'javascript:void(0)'\"\n      class=\"hover:text-primary-hover mx-1\"\n      target=\"_blank\"\n    >\n      {{ companyName }}\n    </a>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/copyright/index.ts",
    "content": "export { default as Copyright } from './copyright.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/footer/footer.vue",
    "content": "<script lang=\"ts\" setup>\ndefineOptions({\n  name: 'LayoutFooter',\n});\n</script>\n\n<template>\n  <div class=\"flex-center text-muted-foreground relative h-full w-full text-xs\">\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/footer/index.ts",
    "content": "export { default as LayoutFooter } from './footer.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/header/header.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed, useSlots } from 'vue';\n\nimport { useRefresh } from '@vben/hooks';\nimport { RotateCw } from '@vben/icons';\nimport { preferences, usePreferences } from '@vben/preferences';\nimport { useAccessStore } from '@vben/stores';\n\nimport { VbenFullScreen, VbenIconButton } from '@vben-core/shadcn-ui';\n\nimport {\n  GlobalSearch,\n  LanguageToggle,\n  PreferencesButton,\n  ThemeToggle,\n} from '../../widgets';\n\ninterface Props {\n  /**\n   * Logo 主题\n   */\n  theme?: string;\n}\n\ndefineOptions({\n  name: 'LayoutHeader',\n});\n\nwithDefaults(defineProps<Props>(), {\n  theme: 'light',\n});\n\nconst emit = defineEmits<{ clearPreferencesAndLogout: [] }>();\n\nconst REFERENCE_VALUE = 50;\n\nconst accessStore = useAccessStore();\nconst { globalSearchShortcutKey, preferencesButtonPosition } = usePreferences();\nconst slots = useSlots();\nconst { refresh } = useRefresh();\n\nconst rightSlots = computed(() => {\n  const list = [{ index: REFERENCE_VALUE + 100, name: 'user-dropdown' }];\n  if (preferences.widget.globalSearch) {\n    list.push({\n      index: REFERENCE_VALUE,\n      name: 'global-search',\n    });\n  }\n\n  if (preferencesButtonPosition.value.header) {\n    list.push({\n      index: REFERENCE_VALUE + 10,\n      name: 'preferences',\n    });\n  }\n  if (preferences.widget.themeToggle) {\n    list.push({\n      index: REFERENCE_VALUE + 20,\n      name: 'theme-toggle',\n    });\n  }\n  if (preferences.widget.languageToggle) {\n    list.push({\n      index: REFERENCE_VALUE + 30,\n      name: 'language-toggle',\n    });\n  }\n  if (preferences.widget.fullscreen) {\n    list.push({\n      index: REFERENCE_VALUE + 40,\n      name: 'fullscreen',\n    });\n  }\n  if (preferences.widget.notification) {\n    list.push({\n      index: REFERENCE_VALUE + 50,\n      name: 'notification',\n    });\n  }\n\n  Object.keys(slots).forEach((key) => {\n    const name = key.split('-');\n    if (key.startsWith('header-right')) {\n      list.push({ index: Number(name[2]), name: key });\n    }\n  });\n  return list.sort((a, b) => a.index - b.index);\n});\n\nconst leftSlots = computed(() => {\n  const list: Array<{ index: number; name: string }> = [];\n\n  if (preferences.widget.refresh) {\n    list.push({\n      index: 0,\n      name: 'refresh',\n    });\n  }\n\n  Object.keys(slots).forEach((key) => {\n    const name = key.split('-');\n    if (key.startsWith('header-left')) {\n      list.push({ index: Number(name[2]), name: key });\n    }\n  });\n  return list.sort((a, b) => a.index - b.index);\n});\n\nfunction clearPreferencesAndLogout() {\n  emit('clearPreferencesAndLogout');\n}\n</script>\n\n<template>\n  <template\n    v-for=\"slot in leftSlots.filter((item) => item.index < REFERENCE_VALUE)\"\n    :key=\"slot.name\"\n  >\n    <slot :name=\"slot.name\">\n      <template v-if=\"slot.name === 'refresh'\">\n        <VbenIconButton class=\"my-0 mr-1 rounded-md\" @click=\"refresh\">\n          <RotateCw class=\"size-4\" />\n        </VbenIconButton>\n      </template>\n    </slot>\n  </template>\n  <div class=\"flex-center hidden lg:block\">\n    <slot name=\"breadcrumb\"></slot>\n  </div>\n  <template\n    v-for=\"slot in leftSlots.filter((item) => item.index > REFERENCE_VALUE)\"\n    :key=\"slot.name\"\n  >\n    <slot :name=\"slot.name\"></slot>\n  </template>\n  <div\n    :class=\"`menu-align-${preferences.header.menuAlign}`\"\n    class=\"flex h-full min-w-0 flex-1 items-center\"\n  >\n    <slot name=\"menu\"></slot>\n  </div>\n  <div class=\"flex h-full min-w-0 flex-shrink-0 items-center\">\n    <template v-for=\"slot in rightSlots\" :key=\"slot.name\">\n      <slot :name=\"slot.name\">\n        <template v-if=\"slot.name === 'global-search'\">\n          <GlobalSearch\n            :enable-shortcut-key=\"globalSearchShortcutKey\"\n            :menus=\"accessStore.accessMenus\"\n            class=\"mr-1 sm:mr-4\"\n          />\n        </template>\n\n        <template v-else-if=\"slot.name === 'preferences'\">\n          <PreferencesButton\n            class=\"mr-1\"\n            @clear-preferences-and-logout=\"clearPreferencesAndLogout\"\n          />\n        </template>\n        <template v-else-if=\"slot.name === 'theme-toggle'\">\n          <ThemeToggle class=\"mr-1 mt-[2px]\" />\n        </template>\n        <template v-else-if=\"slot.name === 'language-toggle'\">\n          <LanguageToggle class=\"mr-1\" />\n        </template>\n        <template v-else-if=\"slot.name === 'fullscreen'\">\n          <VbenFullScreen class=\"mr-1\" />\n        </template>\n      </slot>\n    </template>\n  </div>\n</template>\n<style lang=\"scss\" scoped>\n.menu-align-start {\n  --menu-align: start;\n}\n\n.menu-align-center {\n  --menu-align: center;\n}\n\n.menu-align-end {\n  --menu-align: end;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/header/index.ts",
    "content": "export { default as LayoutHeader } from './header.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/index.ts",
    "content": "export { default as BasicLayout } from './layout.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/layout.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { SetupContext } from 'vue';\nimport type { RouteLocationNormalizedLoaded } from 'vue-router';\n\nimport type { MenuRecordRaw } from '@vben/types';\n\nimport { computed, onMounted, useSlots, watch } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { useRefresh } from '@vben/hooks';\nimport { $t, i18n } from '@vben/locales';\nimport {\n  preferences,\n  updatePreferences,\n  usePreferences,\n} from '@vben/preferences';\nimport { useAccessStore } from '@vben/stores';\nimport { cloneDeep, mapTree } from '@vben/utils';\n\nimport { VbenAdminLayout } from '@vben-core/layout-ui';\nimport { VbenBackTop, VbenLogo } from '@vben-core/shadcn-ui';\n\nimport { Breadcrumb, CheckUpdates, Preferences } from '../widgets';\nimport { LayoutContent, LayoutContentSpinner } from './content';\nimport { Copyright } from './copyright';\nimport { LayoutFooter } from './footer';\nimport { LayoutHeader } from './header';\nimport {\n  LayoutExtraMenu,\n  LayoutMenu,\n  LayoutMixedMenu,\n  useExtraMenu,\n  useMixedMenu,\n} from './menu';\nimport { LayoutTabbar } from './tabbar';\n\ndefineOptions({ name: 'BasicLayout' });\n\nconst emit = defineEmits<{ clearPreferencesAndLogout: []; clickLogo: [] }>();\n\nconst {\n  isDark,\n  isHeaderNav,\n  isMixedNav,\n  isMobile,\n  isSideMixedNav,\n  isHeaderMixedNav,\n  isHeaderSidebarNav,\n  layout,\n  preferencesButtonPosition,\n  sidebarCollapsed,\n  theme,\n} = usePreferences();\nconst accessStore = useAccessStore();\nconst { refresh } = useRefresh();\n\nconst sidebarTheme = computed(() => {\n  const dark = isDark.value || preferences.theme.semiDarkSidebar;\n  return dark ? 'dark' : 'light';\n});\n\nconst headerTheme = computed(() => {\n  const dark = isDark.value || preferences.theme.semiDarkHeader;\n  return dark ? 'dark' : 'light';\n});\n\nconst logoClass = computed(() => {\n  const { collapsedShowTitle } = preferences.sidebar;\n  const classes: string[] = [];\n\n  if (collapsedShowTitle && sidebarCollapsed.value && !isMixedNav.value) {\n    classes.push('mx-auto');\n  }\n\n  if (isSideMixedNav.value) {\n    classes.push('flex-center');\n  }\n\n  return classes.join(' ');\n});\n\nconst isMenuRounded = computed(() => {\n  return preferences.navigation.styleType === 'rounded';\n});\n\nconst logoCollapsed = computed(() => {\n  if (isMobile.value && sidebarCollapsed.value) {\n    return true;\n  }\n  if (isHeaderNav.value || isMixedNav.value || isHeaderSidebarNav.value) {\n    return false;\n  }\n  return (\n    sidebarCollapsed.value || isSideMixedNav.value || isHeaderMixedNav.value\n  );\n});\n\nconst showHeaderNav = computed(() => {\n  return (\n    !isMobile.value &&\n    (isHeaderNav.value || isMixedNav.value || isHeaderMixedNav.value)\n  );\n});\n\nconst {\n  handleMenuSelect,\n  handleMenuOpen,\n  headerActive,\n  headerMenus,\n  sidebarActive,\n  sidebarMenus,\n  mixHeaderMenus,\n  sidebarVisible,\n} = useMixedMenu();\n\n// 侧边多列菜单\nconst {\n  extraActiveMenu,\n  extraMenus,\n  handleDefaultSelect,\n  handleMenuMouseEnter,\n  handleMixedMenuSelect,\n  handleSideMouseLeave,\n  sidebarExtraVisible,\n} = useExtraMenu(mixHeaderMenus);\n\n/**\n * 包装菜单，翻译菜单名称\n * @param menus 原始菜单数据\n * @param deep 是否深度包装。对于双列布局，只需要包装第一层，因为更深层的数据会在扩展菜单中重新包装\n */\nfunction wrapperMenus(menus: MenuRecordRaw[], deep: boolean = true) {\n  return deep\n    ? mapTree(menus, (item) => {\n        return { ...cloneDeep(item), name: $t(item.name) };\n      })\n    : menus.map((item) => {\n        return { ...cloneDeep(item), name: $t(item.name) };\n      });\n}\n\nfunction toggleSidebar() {\n  updatePreferences({\n    sidebar: {\n      hidden: !preferences.sidebar.hidden,\n    },\n  });\n}\n\nfunction clearPreferencesAndLogout() {\n  emit('clearPreferencesAndLogout');\n}\n\nfunction clickLogo() {\n  emit('clickLogo');\n}\n\nfunction autoCollapseMenuByRouteMeta(route: RouteLocationNormalizedLoaded) {\n  // 只在双列模式下生效\n  if (\n    ['header-mixed-nav', 'sidebar-mixed-nav'].includes(\n      preferences.app.layout,\n    ) &&\n    route.meta &&\n    route.meta.hideInMenu\n  ) {\n    sidebarExtraVisible.value = false;\n  }\n}\n\nconst route = useRoute();\n\nonMounted(() => {\n  autoCollapseMenuByRouteMeta(route);\n});\n\nwatch(\n  () => preferences.app.layout,\n  async (val) => {\n    if (val === 'sidebar-mixed-nav' && preferences.sidebar.hidden) {\n      updatePreferences({\n        sidebar: {\n          hidden: false,\n        },\n      });\n    }\n  },\n);\n\n// 语言更新后，刷新页面\n// i18n.global.locale会在preference.app.locale变更之后才会更新，因此watchpreference.app.locale是不合适的，刷新页面时可能语言配置尚未完全加载完成\nwatch(i18n.global.locale, refresh, { flush: 'post' });\n\nconst slots: SetupContext['slots'] = useSlots();\nconst headerSlots = computed(() => {\n  return Object.keys(slots).filter((key) => key.startsWith('header-'));\n});\n</script>\n\n<template>\n  <VbenAdminLayout\n    v-model:sidebar-extra-visible=\"sidebarExtraVisible\"\n    :content-compact=\"preferences.app.contentCompact\"\n    :content-compact-width=\"preferences.app.contentCompactWidth\"\n    :content-padding=\"preferences.app.contentPadding\"\n    :content-padding-bottom=\"preferences.app.contentPaddingBottom\"\n    :content-padding-left=\"preferences.app.contentPaddingLeft\"\n    :content-padding-right=\"preferences.app.contentPaddingRight\"\n    :content-padding-top=\"preferences.app.contentPaddingTop\"\n    :footer-enable=\"preferences.footer.enable\"\n    :footer-fixed=\"preferences.footer.fixed\"\n    :footer-height=\"preferences.footer.height\"\n    :header-height=\"preferences.header.height\"\n    :header-hidden=\"preferences.header.hidden\"\n    :header-mode=\"preferences.header.mode\"\n    :header-theme=\"headerTheme\"\n    :header-toggle-sidebar-button=\"preferences.widget.sidebarToggle\"\n    :header-visible=\"preferences.header.enable\"\n    :is-mobile=\"preferences.app.isMobile\"\n    :layout=\"layout\"\n    :sidebar-collapse=\"preferences.sidebar.collapsed\"\n    :sidebar-collapse-show-title=\"preferences.sidebar.collapsedShowTitle\"\n    :sidebar-enable=\"sidebarVisible\"\n    :sidebar-collapsed-button=\"preferences.sidebar.collapsedButton\"\n    :sidebar-fixed-button=\"preferences.sidebar.fixedButton\"\n    :sidebar-expand-on-hover=\"preferences.sidebar.expandOnHover\"\n    :sidebar-extra-collapse=\"preferences.sidebar.extraCollapse\"\n    :sidebar-extra-collapsed-width=\"preferences.sidebar.extraCollapsedWidth\"\n    :sidebar-hidden=\"preferences.sidebar.hidden\"\n    :sidebar-mixed-width=\"preferences.sidebar.mixedWidth\"\n    :sidebar-theme=\"sidebarTheme\"\n    :sidebar-width=\"preferences.sidebar.width\"\n    :side-collapse-width=\"preferences.sidebar.collapseWidth\"\n    :tabbar-enable=\"preferences.tabbar.enable\"\n    :tabbar-height=\"preferences.tabbar.height\"\n    :z-index=\"preferences.app.zIndex\"\n    @side-mouse-leave=\"handleSideMouseLeave\"\n    @toggle-sidebar=\"toggleSidebar\"\n    @update:sidebar-collapse=\"\n      (value: boolean) => updatePreferences({ sidebar: { collapsed: value } })\n    \"\n    @update:sidebar-enable=\"\n      (value: boolean) => updatePreferences({ sidebar: { enable: value } })\n    \"\n    @update:sidebar-expand-on-hover=\"\n      (value: boolean) =>\n        updatePreferences({ sidebar: { expandOnHover: value } })\n    \"\n    @update:sidebar-extra-collapse=\"\n      (value: boolean) =>\n        updatePreferences({ sidebar: { extraCollapse: value } })\n    \"\n  >\n    <!-- logo -->\n    <template #logo>\n      <VbenLogo\n        v-if=\"preferences.logo.enable\"\n        :fit=\"preferences.logo.fit\"\n        :class=\"logoClass\"\n        :collapsed=\"logoCollapsed\"\n        :src=\"preferences.logo.source\"\n        :text=\"preferences.app.name\"\n        :theme=\"showHeaderNav ? headerTheme : theme\"\n        @click=\"clickLogo\"\n      >\n        <template v-if=\"$slots['logo-text']\" #text>\n          <slot name=\"logo-text\"></slot>\n        </template>\n      </VbenLogo>\n    </template>\n    <!-- 头部区域 -->\n    <template #header>\n      <LayoutHeader\n        :theme=\"theme\"\n        @clear-preferences-and-logout=\"clearPreferencesAndLogout\"\n      >\n        <template\n          v-if=\"!showHeaderNav && preferences.breadcrumb.enable\"\n          #breadcrumb\n        >\n          <Breadcrumb\n            :hide-when-only-one=\"preferences.breadcrumb.hideOnlyOne\"\n            :show-home=\"preferences.breadcrumb.showHome\"\n            :show-icon=\"preferences.breadcrumb.showIcon\"\n            :type=\"preferences.breadcrumb.styleType\"\n          />\n        </template>\n        <template v-if=\"showHeaderNav\" #menu>\n          <LayoutMenu\n            :default-active=\"headerActive\"\n            :menus=\"wrapperMenus(headerMenus)\"\n            :rounded=\"isMenuRounded\"\n            :theme=\"headerTheme\"\n            class=\"w-full\"\n            mode=\"horizontal\"\n            @select=\"handleMenuSelect\"\n          />\n        </template>\n        <template #user-dropdown>\n          <slot name=\"user-dropdown\"></slot>\n        </template>\n        <template #notification>\n          <slot name=\"notification\"></slot>\n        </template>\n        <template v-for=\"item in headerSlots\" #[item]>\n          <slot :name=\"item\"></slot>\n        </template>\n      </LayoutHeader>\n    </template>\n    <!-- 侧边菜单区域 -->\n    <template #menu>\n      <LayoutMenu\n        :accordion=\"preferences.navigation.accordion\"\n        :collapse=\"preferences.sidebar.collapsed\"\n        :collapse-show-title=\"preferences.sidebar.collapsedShowTitle\"\n        :default-active=\"sidebarActive\"\n        :menus=\"wrapperMenus(sidebarMenus)\"\n        :rounded=\"isMenuRounded\"\n        :theme=\"sidebarTheme\"\n        mode=\"vertical\"\n        @open=\"handleMenuOpen\"\n        @select=\"handleMenuSelect\"\n      />\n    </template>\n    <template #mixed-menu>\n      <LayoutMixedMenu\n        :active-path=\"extraActiveMenu\"\n        :menus=\"wrapperMenus(mixHeaderMenus, false)\"\n        :rounded=\"isMenuRounded\"\n        :theme=\"sidebarTheme\"\n        @default-select=\"handleDefaultSelect\"\n        @enter=\"handleMenuMouseEnter\"\n        @select=\"handleMixedMenuSelect\"\n      />\n    </template>\n    <!-- 侧边额外区域 -->\n    <template #side-extra>\n      <LayoutExtraMenu\n        :accordion=\"preferences.navigation.accordion\"\n        :collapse=\"preferences.sidebar.extraCollapse\"\n        :menus=\"wrapperMenus(extraMenus)\"\n        :rounded=\"isMenuRounded\"\n        :theme=\"sidebarTheme\"\n      />\n    </template>\n    <template #side-extra-title>\n      <VbenLogo\n        v-if=\"preferences.logo.enable\"\n        :fit=\"preferences.logo.fit\"\n        :text=\"preferences.app.name\"\n        :theme=\"theme\"\n      >\n        <template v-if=\"$slots['logo-text']\" #text>\n          <slot name=\"logo-text\"></slot>\n        </template>\n      </VbenLogo>\n    </template>\n\n    <template #tabbar>\n      <LayoutTabbar\n        v-if=\"preferences.tabbar.enable\"\n        :show-icon=\"preferences.tabbar.showIcon\"\n        :theme=\"theme\"\n      />\n    </template>\n\n    <!-- 主体内容 -->\n    <template #content>\n      <LayoutContent />\n    </template>\n\n    <template v-if=\"preferences.transition.loading\" #content-overlay>\n      <LayoutContentSpinner />\n    </template>\n\n    <!-- 页脚 -->\n    <template v-if=\"preferences.footer.enable\" #footer>\n      <LayoutFooter>\n        <Copyright\n          v-if=\"preferences.copyright.enable\"\n          v-bind=\"preferences.copyright\"\n        />\n      </LayoutFooter>\n    </template>\n\n    <template #extra>\n      <slot name=\"extra\"></slot>\n      <CheckUpdates\n        v-if=\"preferences.app.enableCheckUpdates\"\n        :check-updates-interval=\"preferences.app.checkUpdatesInterval\"\n      />\n\n      <Transition v-if=\"preferences.widget.lockScreen\" name=\"slide-up\">\n        <slot v-if=\"accessStore.isLockScreen\" name=\"lock-screen\"></slot>\n      </Transition>\n\n      <template v-if=\"preferencesButtonPosition.fixed\">\n        <Preferences\n          class=\"z-100 fixed bottom-20 right-0\"\n          @clear-preferences-and-logout=\"clearPreferencesAndLogout\"\n        />\n      </template>\n      <VbenBackTop />\n    </template>\n  </VbenAdminLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/menu/extra-menu.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { MenuRecordRaw } from '@vben/types';\n\nimport type { MenuProps } from '@vben-core/menu-ui';\n\nimport { useRoute } from 'vue-router';\n\nimport { Menu } from '@vben-core/menu-ui';\n\nimport { useNavigation } from './use-navigation';\n\ninterface Props extends MenuProps {\n  collapse?: boolean;\n  menus?: MenuRecordRaw[];\n}\n\nwithDefaults(defineProps<Props>(), {\n  accordion: true,\n  menus: () => [],\n});\n\nconst route = useRoute();\nconst { navigation } = useNavigation();\n\nasync function handleSelect(key: string) {\n  await navigation(key);\n}\n</script>\n\n<template>\n  <Menu\n    :accordion=\"accordion\"\n    :collapse=\"collapse\"\n    :default-active=\"route.meta?.activePath || route.path\"\n    :menus=\"menus\"\n    :rounded=\"rounded\"\n    :theme=\"theme\"\n    mode=\"vertical\"\n    @select=\"handleSelect\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/menu/index.ts",
    "content": "export { default as LayoutExtraMenu } from './extra-menu.vue';\nexport { default as LayoutMenu } from './menu.vue';\nexport { default as LayoutMixedMenu } from './mixed-menu.vue';\nexport * from './use-extra-menu';\nexport * from './use-mixed-menu';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/menu/menu.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { MenuRecordRaw } from '@vben/types';\n\nimport type { MenuProps } from '@vben-core/menu-ui';\n\nimport { Menu } from '@vben-core/menu-ui';\n\ninterface Props extends MenuProps {\n  menus?: MenuRecordRaw[];\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  accordion: true,\n  menus: () => [],\n});\n\nconst emit = defineEmits<{\n  open: [string, string[]];\n  select: [string, string?];\n}>();\n\nfunction handleMenuSelect(key: string) {\n  emit('select', key, props.mode);\n}\n\nfunction handleMenuOpen(key: string, path: string[]) {\n  emit('open', key, path);\n}\n</script>\n\n<template>\n  <Menu\n    :accordion=\"accordion\"\n    :collapse=\"collapse\"\n    :collapse-show-title=\"collapseShowTitle\"\n    :default-active=\"defaultActive\"\n    :menus=\"menus\"\n    :mode=\"mode\"\n    :rounded=\"rounded\"\n    scroll-to-active\n    :theme=\"theme\"\n    @open=\"handleMenuOpen\"\n    @select=\"handleMenuSelect\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/menu/mixed-menu.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { MenuRecordRaw } from '@vben/types';\n\nimport type { NormalMenuProps } from '@vben-core/menu-ui';\n\nimport { onBeforeMount } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { findMenuByPath } from '@vben/utils';\n\nimport { NormalMenu } from '@vben-core/menu-ui';\n\ninterface Props extends NormalMenuProps {}\n\nconst props = defineProps<Props>();\n\nconst emit = defineEmits<{\n  defaultSelect: [MenuRecordRaw, MenuRecordRaw?];\n  enter: [MenuRecordRaw];\n  select: [MenuRecordRaw];\n}>();\n\nconst route = useRoute();\n\nonBeforeMount(() => {\n  const menu = findMenuByPath(props.menus || [], route.path);\n  if (menu) {\n    const rootMenu = (props.menus || []).find(\n      (item) => item.path === menu.parents?.[0],\n    );\n    emit('defaultSelect', menu, rootMenu);\n  }\n});\n</script>\n\n<template>\n  <NormalMenu\n    :active-path=\"activePath\"\n    :collapse=\"collapse\"\n    :menus=\"menus\"\n    :rounded=\"rounded\"\n    :theme=\"theme\"\n    @enter=\"(menu) => emit('enter', menu)\"\n    @select=\"(menu) => emit('select', menu)\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/menu/use-extra-menu.ts",
    "content": "import type { ComputedRef } from 'vue';\n\nimport type { MenuRecordRaw } from '@vben/types';\n\nimport { computed, ref, watch } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore } from '@vben/stores';\nimport { findRootMenuByPath } from '@vben/utils';\n\nimport { useNavigation } from './use-navigation';\n\nfunction useExtraMenu(useRootMenus?: ComputedRef<MenuRecordRaw[]>) {\n  const accessStore = useAccessStore();\n  const { navigation, willOpenedByWindow } = useNavigation();\n\n  const menus = computed(() => useRootMenus?.value ?? accessStore.accessMenus);\n\n  /** 记录当前顶级菜单下哪个子菜单最后激活 */\n  const defaultSubMap = new Map<string, string>();\n  const extraRootMenus = ref<MenuRecordRaw[]>([]);\n  const route = useRoute();\n  const extraMenus = ref<MenuRecordRaw[]>([]);\n  const sidebarExtraVisible = ref<boolean>(false);\n  const extraActiveMenu = ref('');\n  const parentLevel = computed(() =>\n    preferences.app.layout === 'header-mixed-nav' ? 1 : 0,\n  );\n\n  /**\n   * 选择混合菜单事件\n   * @param menu\n   */\n  const handleMixedMenuSelect = async (menu: MenuRecordRaw) => {\n    const _extraMenus = menu?.children ?? [];\n    const hasChildren = _extraMenus.length > 0;\n\n    if (!willOpenedByWindow(menu.path)) {\n      extraMenus.value = _extraMenus ?? [];\n      extraActiveMenu.value = menu.parents?.[parentLevel.value] ?? menu.path;\n      sidebarExtraVisible.value = hasChildren;\n    }\n\n    if (!hasChildren) {\n      await navigation(menu.path);\n    } else if (preferences.sidebar.autoActivateChild) {\n      await navigation(\n        defaultSubMap.has(menu.path)\n          ? (defaultSubMap.get(menu.path) as string)\n          : menu.path,\n      );\n    }\n  };\n\n  /**\n   * 选择默认菜单事件\n   * @param menu\n   * @param rootMenu\n   */\n  const handleDefaultSelect = async (\n    menu: MenuRecordRaw,\n    rootMenu?: MenuRecordRaw,\n  ) => {\n    extraMenus.value = rootMenu?.children ?? extraRootMenus.value ?? [];\n    extraActiveMenu.value = menu.parents?.[parentLevel.value] ?? menu.path;\n\n    if (preferences.sidebar.expandOnHover) {\n      sidebarExtraVisible.value = extraMenus.value.length > 0;\n    }\n  };\n\n  /**\n   * 侧边菜单鼠标移出事件\n   */\n  const handleSideMouseLeave = () => {\n    if (preferences.sidebar.expandOnHover) {\n      return;\n    }\n\n    const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(\n      menus.value,\n      route.path,\n    );\n    extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? '';\n    extraMenus.value = rootMenu?.children ?? [];\n  };\n\n  const handleMenuMouseEnter = (menu: MenuRecordRaw) => {\n    if (!preferences.sidebar.expandOnHover) {\n      const { findMenu } = findRootMenuByPath(menus.value, menu.path);\n      extraMenus.value = findMenu?.children ?? [];\n      extraActiveMenu.value = menu.parents?.[parentLevel.value] ?? menu.path;\n      sidebarExtraVisible.value = extraMenus.value.length > 0;\n    }\n  };\n\n  function calcExtraMenus(path: string) {\n    const currentPath = route.meta?.activePath || path;\n    const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(\n      menus.value,\n      currentPath,\n      parentLevel.value,\n    );\n    extraRootMenus.value = rootMenu?.children ?? [];\n    if (rootMenuPath) defaultSubMap.set(rootMenuPath, currentPath);\n    extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? '';\n    extraMenus.value = rootMenu?.children ?? [];\n    if (preferences.sidebar.expandOnHover) {\n      sidebarExtraVisible.value = extraMenus.value.length > 0;\n    }\n  }\n\n  watch(\n    () => [route.path, preferences.app.layout],\n    ([path]) => {\n      calcExtraMenus(path || '');\n    },\n    { immediate: true },\n  );\n\n  return {\n    extraActiveMenu,\n    extraMenus,\n    handleDefaultSelect,\n    handleMenuMouseEnter,\n    handleMixedMenuSelect,\n    handleSideMouseLeave,\n    sidebarExtraVisible,\n  };\n}\n\nexport { useExtraMenu };\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts",
    "content": "import type { MenuRecordRaw } from '@vben/types';\n\nimport { computed, onBeforeMount, ref, watch } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { preferences, usePreferences } from '@vben/preferences';\nimport { useAccessStore } from '@vben/stores';\nimport { findRootMenuByPath } from '@vben/utils';\n\nimport { useNavigation } from './use-navigation';\n\nfunction useMixedMenu() {\n  const { navigation, willOpenedByWindow } = useNavigation();\n  const accessStore = useAccessStore();\n  const route = useRoute();\n  const splitSideMenus = ref<MenuRecordRaw[]>([]);\n  const rootMenuPath = ref<string>('');\n  const mixedRootMenuPath = ref<string>('');\n  const mixExtraMenus = ref<MenuRecordRaw[]>([]);\n  /** 记录当前顶级菜单下哪个子菜单最后激活 */\n  const defaultSubMap = new Map<string, string>();\n  const { isMixedNav, isHeaderMixedNav } = usePreferences();\n\n  const needSplit = computed(\n    () =>\n      (preferences.navigation.split && isMixedNav.value) ||\n      isHeaderMixedNav.value,\n  );\n\n  const sidebarVisible = computed(() => {\n    const enableSidebar = preferences.sidebar.enable;\n    if (needSplit.value) {\n      return enableSidebar && splitSideMenus.value.length > 0;\n    }\n    return enableSidebar;\n  });\n  const menus = computed(() => accessStore.accessMenus);\n\n  /**\n   * 头部菜单\n   */\n  const headerMenus = computed(() => {\n    if (!needSplit.value) {\n      return menus.value;\n    }\n    return menus.value.map((item) => {\n      return {\n        ...item,\n        children: [],\n      };\n    });\n  });\n\n  /**\n   * 侧边菜单\n   */\n  const sidebarMenus = computed(() => {\n    return needSplit.value ? splitSideMenus.value : menus.value;\n  });\n\n  const mixHeaderMenus = computed(() => {\n    return isHeaderMixedNav.value ? sidebarMenus.value : headerMenus.value;\n  });\n\n  /**\n   * 侧边菜单激活路径\n   */\n  const sidebarActive = computed(() => {\n    return (route?.meta?.activePath as string) ?? route.path;\n  });\n\n  /**\n   * 头部菜单激活路径\n   */\n  const headerActive = computed(() => {\n    if (!needSplit.value) {\n      return route.meta?.activePath ?? route.path;\n    }\n    return rootMenuPath.value;\n  });\n\n  /**\n   * 菜单点击事件处理\n   * @param key 菜单路径\n   * @param mode 菜单模式\n   */\n  const handleMenuSelect = (key: string, mode?: string) => {\n    if (!needSplit.value || mode === 'vertical') {\n      navigation(key);\n      return;\n    }\n    const rootMenu = menus.value.find((item) => item.path === key);\n    const _splitSideMenus = rootMenu?.children ?? [];\n\n    if (!willOpenedByWindow(key)) {\n      rootMenuPath.value = rootMenu?.path ?? '';\n      splitSideMenus.value = _splitSideMenus;\n    }\n\n    if (_splitSideMenus.length === 0) {\n      navigation(key);\n    } else if (rootMenu && preferences.sidebar.autoActivateChild) {\n      navigation(\n        defaultSubMap.has(rootMenu.path)\n          ? (defaultSubMap.get(rootMenu.path) as string)\n          : rootMenu.path,\n      );\n    }\n  };\n\n  /**\n   * 侧边菜单展开事件\n   * @param key 路由路径\n   * @param parentsPath 父级路径\n   */\n  const handleMenuOpen = (key: string, parentsPath: string[]) => {\n    if (parentsPath.length <= 1 && preferences.sidebar.autoActivateChild) {\n      navigation(\n        defaultSubMap.has(key) ? (defaultSubMap.get(key) as string) : key,\n      );\n    }\n  };\n\n  /**\n   * 计算侧边菜单\n   * @param path 路由路径\n   */\n  function calcSideMenus(path: string = route.path) {\n    let { rootMenu } = findRootMenuByPath(menus.value, path);\n    if (!rootMenu) {\n      rootMenu = menus.value.find((item) => item.path === path);\n    }\n    const result = findRootMenuByPath(rootMenu?.children || [], path, 1);\n    mixedRootMenuPath.value = result.rootMenuPath ?? '';\n    mixExtraMenus.value = result.rootMenu?.children ?? [];\n    rootMenuPath.value = rootMenu?.path ?? '';\n    splitSideMenus.value = rootMenu?.children ?? [];\n  }\n\n  watch(\n    () => route.path,\n    (path) => {\n      const currentPath = route?.meta?.activePath ?? route?.meta?.link ?? path;\n      if (willOpenedByWindow(currentPath)) {\n        return;\n      }\n      calcSideMenus(currentPath);\n      if (rootMenuPath.value)\n        defaultSubMap.set(rootMenuPath.value, currentPath);\n    },\n    { immediate: true },\n  );\n\n  // 初始化计算侧边菜单\n  onBeforeMount(() => {\n    calcSideMenus(route.meta?.activePath || route.path);\n  });\n\n  return {\n    handleMenuSelect,\n    handleMenuOpen,\n    headerActive,\n    headerMenus,\n    sidebarActive,\n    sidebarMenus,\n    mixHeaderMenus,\n    mixExtraMenus,\n    sidebarVisible,\n  };\n}\n\nexport { useMixedMenu };\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/menu/use-navigation.ts",
    "content": "import type { RouteRecordNormalized } from 'vue-router';\n\nimport { useRouter } from 'vue-router';\n\nimport { isHttpUrl, openRouteInNewWindow, openWindow } from '@vben/utils';\n\nfunction useNavigation() {\n  const router = useRouter();\n  const routeMetaMap = new Map<string, RouteRecordNormalized>();\n\n  // 初始化路由映射\n  const initRouteMetaMap = () => {\n    const routes = router.getRoutes();\n    routes.forEach((route) => {\n      routeMetaMap.set(route.path, route);\n    });\n  };\n\n  initRouteMetaMap();\n\n  // 监听路由变化\n  router.afterEach(() => {\n    initRouteMetaMap();\n  });\n\n  // 检查是否应该在新窗口打开\n  const shouldOpenInNewWindow = (path: string): boolean => {\n    if (isHttpUrl(path)) {\n      return true;\n    }\n    const route = routeMetaMap.get(path);\n    // 如果有外链或者设置了在新窗口打开，返回 true\n    return !!(route?.meta?.link || route?.meta?.openInNewWindow);\n  };\n\n  const resolveHref = (path: string): string => {\n    return router.resolve(path).href;\n  };\n\n  const navigation = async (path: string) => {\n    try {\n      const route = routeMetaMap.get(path);\n      const { openInNewWindow = false, query = {}, link } = route?.meta ?? {};\n\n      // 检查是否有外链\n      if (link && typeof link === 'string') {\n        openWindow(link, { target: '_blank' });\n        return;\n      }\n\n      if (isHttpUrl(path)) {\n        openWindow(path, { target: '_blank' });\n      } else if (openInNewWindow) {\n        openRouteInNewWindow(resolveHref(path));\n      } else {\n        await router.push({\n          path,\n          query,\n        });\n      }\n    } catch (error) {\n      console.error('Navigation failed:', error);\n      throw error;\n    }\n  };\n\n  const willOpenedByWindow = (path: string) => {\n    return shouldOpenInNewWindow(path);\n  };\n\n  return { navigation, willOpenedByWindow };\n}\n\nexport { useNavigation };\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/tabbar/index.ts",
    "content": "export { default as LayoutTabbar } from './tabbar.vue';\nexport * from './use-tabbar';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/tabbar/tabbar.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { useContentMaximize, useTabs } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\nimport { useTabbarStore } from '@vben/stores';\n\nimport { TabsToolMore, TabsToolScreen, TabsView } from '@vben-core/tabs-ui';\n\nimport { useTabbar } from './use-tabbar';\n\ndefineOptions({\n  name: 'LayoutTabbar',\n});\n\ndefineProps<{ showIcon?: boolean; theme?: string }>();\n\nconst route = useRoute();\nconst tabbarStore = useTabbarStore();\nconst { contentIsMaximize, toggleMaximize } = useContentMaximize();\nconst { unpinTab } = useTabs();\n\nconst {\n  createContextMenus,\n  currentActive,\n  currentTabs,\n  handleClick,\n  handleClose,\n} = useTabbar();\n\nconst menus = computed(() => {\n  const tab = tabbarStore.getTabByKey(currentActive.value);\n  const menus = createContextMenus(tab);\n  return menus.map((item) => {\n    return {\n      ...item,\n      label: item.text,\n      value: item.key,\n    };\n  });\n});\n\n// 刷新后如果不保持tab状态，关闭其他tab\nif (!preferences.tabbar.persist) {\n  tabbarStore.closeOtherTabs(route);\n}\n</script>\n\n<template>\n  <TabsView\n    :active=\"currentActive\"\n    :class=\"theme\"\n    :context-menus=\"createContextMenus\"\n    :draggable=\"preferences.tabbar.draggable\"\n    :show-icon=\"showIcon\"\n    :style-type=\"preferences.tabbar.styleType\"\n    :tabs=\"currentTabs\"\n    :wheelable=\"preferences.tabbar.wheelable\"\n    :middle-click-to-close=\"preferences.tabbar.middleClickToClose\"\n    @close=\"handleClose\"\n    @sort-tabs=\"tabbarStore.sortTabs\"\n    @unpin=\"unpinTab\"\n    @update:active=\"handleClick\"\n  />\n  <div class=\"flex-center h-full\">\n    <TabsToolMore v-if=\"preferences.tabbar.showMore\" :menus=\"menus\" />\n    <TabsToolScreen\n      v-if=\"preferences.tabbar.showMaximize\"\n      :screen=\"contentIsMaximize\"\n      @change=\"toggleMaximize\"\n      @update:screen=\"toggleMaximize\"\n    />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts",
    "content": "import type { RouteLocationNormalizedGeneric } from 'vue-router';\n\nimport type { TabDefinition } from '@vben/types';\n\nimport type { IContextMenuItem } from '@vben-core/tabs-ui';\n\nimport { computed, ref, watch } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\n\nimport { useContentMaximize, useTabs } from '@vben/hooks';\nimport {\n  ArrowLeftToLine,\n  ArrowRightLeft,\n  ArrowRightToLine,\n  ExternalLink,\n  FoldHorizontal,\n  Fullscreen,\n  Minimize2,\n  Pin,\n  PinOff,\n  RotateCw,\n  X,\n} from '@vben/icons';\nimport { $t, useI18n } from '@vben/locales';\nimport { getTabKey, useAccessStore, useTabbarStore } from '@vben/stores';\nimport { filterTree } from '@vben/utils';\n\nexport function useTabbar() {\n  const router = useRouter();\n  const route = useRoute();\n  const accessStore = useAccessStore();\n  const tabbarStore = useTabbarStore();\n  const { contentIsMaximize, toggleMaximize } = useContentMaximize();\n  const {\n    closeAllTabs,\n    closeCurrentTab,\n    closeLeftTabs,\n    closeOtherTabs,\n    closeRightTabs,\n    closeTabByKey,\n    getTabDisableState,\n    openTabInNewWindow,\n    refreshTab,\n    toggleTabPin,\n  } = useTabs();\n\n  /**\n   * 当前路径对应的tab的key\n   */\n  const currentActive = computed(() => {\n    return getTabKey(route);\n  });\n\n  const { locale } = useI18n();\n  const currentTabs = ref<RouteLocationNormalizedGeneric[]>();\n  watch(\n    [\n      () => tabbarStore.getTabs,\n      () => tabbarStore.updateTime,\n      () => locale.value,\n    ],\n    ([tabs]) => {\n      currentTabs.value = tabs.map((item) => wrapperTabLocale(item));\n    },\n  );\n\n  /**\n   * 初始化固定标签页\n   */\n  const initAffixTabs = () => {\n    const affixTabs = filterTree(router.getRoutes(), (route) => {\n      return !!route.meta?.affixTab;\n    });\n    tabbarStore.setAffixTabs(affixTabs);\n  };\n\n  // 点击tab,跳转路由\n  const handleClick = (key: string) => {\n    const { fullPath, path } = tabbarStore.getTabByKey(key);\n    router.push(fullPath || path);\n  };\n\n  // 关闭tab\n  const handleClose = async (key: string) => {\n    await closeTabByKey(key);\n  };\n\n  function wrapperTabLocale(tab: RouteLocationNormalizedGeneric) {\n    return {\n      ...tab,\n      meta: {\n        ...tab?.meta,\n        title: $t(tab?.meta?.title as string),\n      },\n    };\n  }\n\n  watch(\n    () => accessStore.accessMenus,\n    () => {\n      initAffixTabs();\n    },\n    { immediate: true },\n  );\n\n  watch(\n    () => route.fullPath,\n    () => {\n      const meta = route.matched?.[route.matched.length - 1]?.meta;\n      tabbarStore.addTab({\n        ...route,\n        meta: meta || route.meta,\n      });\n    },\n    { immediate: true },\n  );\n\n  const createContextMenus = (tab: TabDefinition) => {\n    const {\n      disabledCloseAll,\n      disabledCloseCurrent,\n      disabledCloseLeft,\n      disabledCloseOther,\n      disabledCloseRight,\n      disabledRefresh,\n    } = getTabDisableState(tab);\n\n    const affixTab = tab?.meta?.affixTab ?? false;\n\n    const menus: IContextMenuItem[] = [\n      {\n        disabled: disabledCloseCurrent,\n        handler: async () => {\n          await closeCurrentTab(tab);\n        },\n        icon: X,\n        key: 'close',\n        text: $t('preferences.tabbar.contextMenu.close'),\n      },\n      {\n        handler: async () => {\n          await toggleTabPin(tab);\n        },\n        icon: affixTab ? PinOff : Pin,\n        key: 'affix',\n        text: affixTab\n          ? $t('preferences.tabbar.contextMenu.unpin')\n          : $t('preferences.tabbar.contextMenu.pin'),\n      },\n      {\n        handler: async () => {\n          if (!contentIsMaximize.value) {\n            await router.push(tab.fullPath);\n          }\n          toggleMaximize();\n        },\n        icon: contentIsMaximize.value ? Minimize2 : Fullscreen,\n        key: contentIsMaximize.value ? 'restore-maximize' : 'maximize',\n        text: contentIsMaximize.value\n          ? $t('preferences.tabbar.contextMenu.restoreMaximize')\n          : $t('preferences.tabbar.contextMenu.maximize'),\n      },\n      {\n        disabled: disabledRefresh,\n        handler: () => refreshTab(),\n        icon: RotateCw,\n        key: 'reload',\n        text: $t('preferences.tabbar.contextMenu.reload'),\n      },\n      {\n        handler: async () => {\n          await openTabInNewWindow(tab);\n        },\n        icon: ExternalLink,\n        key: 'open-in-new-window',\n        separator: true,\n        text: $t('preferences.tabbar.contextMenu.openInNewWindow'),\n      },\n\n      {\n        disabled: disabledCloseLeft,\n        handler: async () => {\n          await closeLeftTabs(tab);\n        },\n        icon: ArrowLeftToLine,\n        key: 'close-left',\n        text: $t('preferences.tabbar.contextMenu.closeLeft'),\n      },\n      {\n        disabled: disabledCloseRight,\n        handler: async () => {\n          await closeRightTabs(tab);\n        },\n        icon: ArrowRightToLine,\n        key: 'close-right',\n        separator: true,\n        text: $t('preferences.tabbar.contextMenu.closeRight'),\n      },\n      {\n        disabled: disabledCloseOther,\n        handler: async () => {\n          await closeOtherTabs(tab);\n        },\n        icon: FoldHorizontal,\n        key: 'close-other',\n        text: $t('preferences.tabbar.contextMenu.closeOther'),\n      },\n      {\n        disabled: disabledCloseAll,\n        handler: closeAllTabs,\n        icon: ArrowRightLeft,\n        key: 'close-all',\n        text: $t('preferences.tabbar.contextMenu.closeAll'),\n      },\n    ];\n\n    return menus.filter((item) => tabbarStore.getMenuList.includes(item.key));\n  };\n\n  return {\n    createContextMenus,\n    currentActive,\n    currentTabs,\n    handleClick,\n    handleClose,\n  };\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/iframe/iframe-router-view.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { RouteLocationNormalized } from 'vue-router';\n\nimport { computed, ref } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { preferences } from '@vben/preferences';\nimport { useTabbarStore } from '@vben/stores';\n\nimport { VbenSpinner } from '@vben-core/shadcn-ui';\n\ndefineOptions({ name: 'IFrameRouterView' });\n\nconst spinningList = ref<boolean[]>([]);\nconst tabbarStore = useTabbarStore();\nconst route = useRoute();\n\nconst enableTabbar = computed(() => preferences.tabbar.enable);\n\nconst iframeRoutes = computed(() => {\n  if (!enableTabbar.value) {\n    return route.meta.iframeSrc ? [route] : [];\n  }\n  return tabbarStore.getTabs.filter((tab) => !!tab.meta?.iframeSrc);\n});\n\nconst tabNames = computed(\n  () => new Set(iframeRoutes.value.map((item) => item.name as string)),\n);\n\nconst showIframe = computed(() => iframeRoutes.value.length > 0);\n\nfunction routeShow(tabItem: RouteLocationNormalized) {\n  return tabItem.name === route.name;\n}\n\nfunction canRender(tabItem: RouteLocationNormalized) {\n  const { meta, name } = tabItem;\n\n  if (!name || !tabbarStore.renderRouteView) {\n    return false;\n  }\n\n  if (!enableTabbar.value) {\n    return routeShow(tabItem);\n  }\n\n  // 跟随 keepAlive 状态,与其他tab页保持一致\n  if (\n    !meta?.keepAlive &&\n    tabNames.value.has(name as string) &&\n    name !== route.name\n  ) {\n    return false;\n  }\n  return tabbarStore.getTabs.some((tab) => tab.name === name);\n}\n\nfunction hideLoading(index: number) {\n  spinningList.value[index] = false;\n}\n\nfunction showSpinning(index: number) {\n  const curSpinning = spinningList.value[index];\n  // 首次加载时显示loading\n  return curSpinning === undefined ? true : curSpinning;\n}\n</script>\n<template>\n  <template v-if=\"showIframe\">\n    <template v-for=\"(item, index) in iframeRoutes\" :key=\"item.fullPath\">\n      <div\n        v-if=\"canRender(item)\"\n        v-show=\"routeShow(item)\"\n        class=\"relative size-full\"\n      >\n        <VbenSpinner :spinning=\"showSpinning(index)\" />\n        <iframe\n          :src=\"item.meta.iframeSrc as string\"\n          class=\"size-full\"\n          @load=\"hideLoading(index)\"\n        ></iframe>\n      </div>\n    </template>\n  </template>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/iframe/iframe-view.vue",
    "content": "<template>\n  <div></div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/iframe/index.ts",
    "content": "export { default as IFrameRouterView } from './iframe-router-view.vue';\nexport { default as IFrameView } from './iframe-view.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/index.ts",
    "content": "export * from './authentication';\nexport * from './basic';\nexport * from './iframe';\nexport * from './widgets';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/breadcrumb.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { BreadcrumbStyleType } from '@vben/types';\n\nimport type { IBreadcrumb } from '@vben-core/shadcn-ui';\n\nimport { computed } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\n\nimport { $t } from '@vben/locales';\n\nimport { VbenBreadcrumbView } from '@vben-core/shadcn-ui';\n\ninterface Props {\n  hideWhenOnlyOne?: boolean;\n  showHome?: boolean;\n  showIcon?: boolean;\n  type?: BreadcrumbStyleType;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  showHome: false,\n  showIcon: false,\n  type: 'normal',\n});\n\nconst route = useRoute();\nconst router = useRouter();\n\nconst breadcrumbs = computed((): IBreadcrumb[] => {\n  const matched = route.matched;\n\n  const resultBreadcrumb: IBreadcrumb[] = [];\n\n  for (const match of matched) {\n    const { meta, path } = match;\n    const { hideChildrenInMenu, hideInBreadcrumb, icon, name, title } =\n      meta || {};\n    if (hideInBreadcrumb || hideChildrenInMenu || !path) {\n      continue;\n    }\n\n    resultBreadcrumb.push({\n      icon,\n      path: path || route.path,\n      title: title ? $t((title || name) as string) : '',\n    });\n  }\n  if (props.showHome) {\n    resultBreadcrumb.unshift({\n      icon: 'mdi:home-outline',\n      isHome: true,\n      path: '/',\n    });\n  }\n  if (props.hideWhenOnlyOne && resultBreadcrumb.length === 1) {\n    return [];\n  }\n\n  return resultBreadcrumb;\n});\n\nfunction handleSelect(path: string) {\n  router.push(path);\n}\n</script>\n<template>\n  <VbenBreadcrumbView\n    :breadcrumbs=\"breadcrumbs\"\n    :show-icon=\"showIcon\"\n    :style-type=\"type\"\n    class=\"ml-2\"\n    @select=\"handleSelect\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/check-updates/check-updates.vue",
    "content": "<script setup lang=\"ts\">\nimport { onMounted, onUnmounted, ref } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport { useVbenModal } from '@vben-core/popup-ui';\n\ninterface Props {\n  // 轮询时间，分钟\n  checkUpdatesInterval?: number;\n  // 检查更新的地址\n  checkUpdateUrl?: string;\n}\n\ndefineOptions({ name: 'CheckUpdates' });\n\nconst props = withDefaults(defineProps<Props>(), {\n  checkUpdatesInterval: 1,\n  checkUpdateUrl: import.meta.env.BASE_URL || '/',\n});\n\nlet isCheckingUpdates = false;\nconst currentVersionTag = ref('');\nconst lastVersionTag = ref('');\nconst timer = ref<ReturnType<typeof setInterval>>();\n\nconst [UpdateNoticeModal, modalApi] = useVbenModal({\n  closable: false,\n  closeOnPressEscape: false,\n  closeOnClickModal: false,\n  onConfirm() {\n    lastVersionTag.value = currentVersionTag.value;\n    window.location.reload();\n    // handleSubmitLogout();\n  },\n});\n\nasync function getVersionTag() {\n  try {\n    if (\n      location.hostname === 'localhost' ||\n      location.hostname === '127.0.0.1'\n    ) {\n      return null;\n    }\n    const response = await fetch(props.checkUpdateUrl, {\n      cache: 'no-cache',\n      method: 'HEAD',\n      redirect: 'manual',\n    });\n\n    return (\n      response.headers.get('etag') || response.headers.get('last-modified')\n    );\n  } catch {\n    console.error('Failed to fetch version tag');\n    return null;\n  }\n}\n\nasync function checkForUpdates() {\n  const versionTag = await getVersionTag();\n  if (!versionTag) {\n    return;\n  }\n\n  // 首次运行时不提示更新\n  if (!lastVersionTag.value) {\n    lastVersionTag.value = versionTag;\n    return;\n  }\n\n  if (lastVersionTag.value !== versionTag && versionTag) {\n    clearInterval(timer.value);\n    handleNotice(versionTag);\n  }\n}\nfunction handleNotice(versionTag: string) {\n  currentVersionTag.value = versionTag;\n  modalApi.open();\n}\n\nfunction start() {\n  if (props.checkUpdatesInterval <= 0) {\n    return;\n  }\n\n  // 每 checkUpdatesInterval(默认值为1) 分钟检查一次\n  timer.value = setInterval(\n    checkForUpdates,\n    props.checkUpdatesInterval * 60 * 1000,\n  );\n}\n\nfunction handleVisibilitychange() {\n  if (document.hidden) {\n    stop();\n  } else {\n    if (!isCheckingUpdates) {\n      isCheckingUpdates = true;\n      checkForUpdates().finally(() => {\n        isCheckingUpdates = false;\n        start();\n      });\n    }\n  }\n}\n\nfunction stop() {\n  clearInterval(timer.value);\n}\n\nonMounted(() => {\n  start();\n  document.addEventListener('visibilitychange', handleVisibilitychange);\n});\n\nonUnmounted(() => {\n  stop();\n  document.removeEventListener('visibilitychange', handleVisibilitychange);\n});\n</script>\n<template>\n  <UpdateNoticeModal\n    :cancel-text=\"$t('common.cancel')\"\n    :confirm-text=\"$t('common.refresh')\"\n    :fullscreen-button=\"false\"\n    :title=\"$t('ui.widgets.checkUpdatesTitle')\"\n    centered\n    content-class=\"px-8 min-h-10\"\n    footer-class=\"border-none mb-3 mr-3\"\n    header-class=\"border-none\"\n  >\n    {{ $t('ui.widgets.checkUpdatesDescription') }}\n  </UpdateNoticeModal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/check-updates/index.ts",
    "content": "export { default as CheckUpdates } from './check-updates.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/color-toggle.vue",
    "content": "<script setup lang=\"ts\">\nimport type { BuiltinThemeType } from '@vben/types';\n\nimport { Palette } from '@vben/icons';\nimport {\n  COLOR_PRESETS,\n  preferences,\n  updatePreferences,\n} from '@vben/preferences';\n\nimport { VbenIconButton } from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'AuthenticationColorToggle',\n});\n\nfunction handleUpdate(colorPrimary: string, type: BuiltinThemeType) {\n  updatePreferences({\n    theme: {\n      colorPrimary,\n      builtinType: type,\n    },\n  });\n}\n</script>\n\n<template>\n  <div class=\"group relative flex items-center overflow-hidden\">\n    <div\n      class=\"flex w-0 overflow-hidden transition-all duration-500 ease-out group-hover:w-60\"\n    >\n      <template v-for=\"preset in COLOR_PRESETS\" :key=\"preset.color\">\n        <VbenIconButton\n          class=\"flex-center flex-shrink-0\"\n          @click=\"handleUpdate(preset.color, preset.type)\"\n        >\n          <div\n            :style=\"{ backgroundColor: preset.color }\"\n            class=\"flex-center relative size-5 rounded-full hover:scale-110\"\n          >\n            <svg\n              v-if=\"preferences.theme.builtinType === preset.type\"\n              class=\"h-3.5 w-3.5 text-white\"\n              height=\"1em\"\n              viewBox=\"0 0 15 15\"\n              width=\"1em\"\n            >\n              <path\n                clip-rule=\"evenodd\"\n                d=\"M11.467 3.727c.289.189.37.576.181.865l-4.25 6.5a.625.625 0 0 1-.944.12l-2.75-2.5a.625.625 0 0 1 .841-.925l2.208 2.007l3.849-5.886a.625.625 0 0 1 .865-.181\"\n                fill=\"currentColor\"\n                fill-rule=\"evenodd\"\n              />\n            </svg>\n          </div>\n        </VbenIconButton>\n      </template>\n    </div>\n\n    <VbenIconButton>\n      <Palette class=\"text-primary size-4\" />\n    </VbenIconButton>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/global-search/global-search.vue",
    "content": "<script setup lang=\"ts\">\nimport type { MenuRecordRaw } from '@vben/types';\n\nimport { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport {\n  ArrowDown,\n  ArrowUp,\n  CornerDownLeft,\n  MdiKeyboardEsc,\n  Search,\n} from '@vben/icons';\nimport { $t } from '@vben/locales';\nimport { isWindowsOs } from '@vben/utils';\n\nimport { useVbenModal } from '@vben-core/popup-ui';\n\nimport { useMagicKeys, whenever } from '@vueuse/core';\n\nimport SearchPanel from './search-panel.vue';\n\ndefineOptions({\n  name: 'GlobalSearch',\n});\n\nconst props = withDefaults(\n  defineProps<{ enableShortcutKey?: boolean; menus?: MenuRecordRaw[] }>(),\n  {\n    enableShortcutKey: true,\n    menus: () => [],\n  },\n);\n\nconst keyword = ref('');\nconst searchInputRef = ref<HTMLInputElement>();\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (!isOpen) {\n      keyword.value = '';\n    }\n  },\n});\nconst open = modalApi.useStore((state) => state.isOpen);\n\nfunction handleClose() {\n  modalApi.close();\n  keyword.value = '';\n}\n\nconst keys = useMagicKeys();\nconst cmd = isWindowsOs() ? keys['ctrl+k'] : keys['cmd+k'];\nwhenever(cmd!, () => {\n  if (props.enableShortcutKey) {\n    modalApi.open();\n  }\n});\n\nwhenever(open, () => {\n  nextTick(() => {\n    searchInputRef.value?.focus();\n  });\n});\n\nconst preventDefaultBrowserSearchHotKey = (event: KeyboardEvent) => {\n  if (event.key?.toLowerCase() === 'k' && (event.metaKey || event.ctrlKey)) {\n    event.preventDefault();\n  }\n};\n\nconst toggleKeydownListener = () => {\n  if (props.enableShortcutKey) {\n    window.addEventListener('keydown', preventDefaultBrowserSearchHotKey);\n  } else {\n    window.removeEventListener('keydown', preventDefaultBrowserSearchHotKey);\n  }\n};\n\nconst toggleOpen = () => {\n  open.value ? modalApi.close() : modalApi.open();\n};\n\nwatch(() => props.enableShortcutKey, toggleKeydownListener);\n\nonMounted(() => {\n  toggleKeydownListener();\n\n  onUnmounted(() => {\n    window.removeEventListener('keydown', preventDefaultBrowserSearchHotKey);\n  });\n});\n</script>\n\n<template>\n  <div>\n    <Modal\n      :fullscreen-button=\"false\"\n      class=\"w-[600px]\"\n      header-class=\"py-2 border-b\"\n    >\n      <template #title>\n        <div class=\"flex items-center\">\n          <Search class=\"text-muted-foreground mr-2 size-4\" />\n          <input\n            ref=\"searchInputRef\"\n            v-model=\"keyword\"\n            :placeholder=\"$t('ui.widgets.search.searchNavigate')\"\n            class=\"ring-none placeholder:text-muted-foreground w-[80%] rounded-md border border-none bg-transparent p-2 pl-0 text-sm font-normal outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent\"\n          />\n        </div>\n      </template>\n\n      <SearchPanel :keyword=\"keyword\" :menus=\"menus\" @close=\"handleClose\" />\n      <template #footer>\n        <div class=\"flex w-full justify-start text-xs\">\n          <div class=\"mr-2 flex items-center\">\n            <CornerDownLeft class=\"mr-1 size-3\" />\n            {{ $t('ui.widgets.search.select') }}\n          </div>\n          <div class=\"mr-2 flex items-center\">\n            <ArrowUp class=\"mr-1 size-3\" />\n            <ArrowDown class=\"mr-1 size-3\" />\n            {{ $t('ui.widgets.search.navigate') }}\n          </div>\n          <div class=\"flex items-center\">\n            <MdiKeyboardEsc class=\"mr-1 size-3\" />\n            {{ $t('ui.widgets.search.close') }}\n          </div>\n        </div>\n      </template>\n    </Modal>\n    <div\n      class=\"md:bg-accent group flex h-8 cursor-pointer items-center gap-3 rounded-2xl border-none bg-none px-2 py-0.5 outline-none\"\n      @click=\"toggleOpen()\"\n    >\n      <Search\n        class=\"text-muted-foreground group-hover:text-foreground size-4 group-hover:opacity-100\"\n      />\n      <span\n        class=\"text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block\"\n      >\n        {{ $t('ui.widgets.search.title') }}\n      </span>\n      <span\n        v-if=\"enableShortcutKey\"\n        class=\"bg-background border-foreground/60 text-muted-foreground group-hover:text-foreground relative hidden rounded-sm rounded-r-xl px-1.5 py-1 text-xs leading-none group-hover:opacity-100 md:block\"\n      >\n        {{ isWindowsOs() ? 'Ctrl' : '⌘' }}\n        <kbd>K</kbd>\n      </span>\n      <span v-else></span>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/global-search/index.ts",
    "content": "export { default as GlobalSearch } from './global-search.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/global-search/search-panel.vue",
    "content": "<script setup lang=\"ts\">\nimport type { MenuRecordRaw } from '@vben/types';\n\nimport { nextTick, onMounted, ref, shallowRef, watch } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { SearchX, X } from '@vben/icons';\nimport { $t } from '@vben/locales';\nimport { mapTree, traverseTreeValues, uniqueByField } from '@vben/utils';\n\nimport { VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui';\nimport { isHttpUrl } from '@vben-core/shared/utils';\n\nimport { onKeyStroke, useLocalStorage, useThrottleFn } from '@vueuse/core';\n\ndefineOptions({\n  name: 'SearchPanel',\n});\n\nconst props = withDefaults(\n  defineProps<{ keyword?: string; menus?: MenuRecordRaw[] }>(),\n  {\n    keyword: '',\n    menus: () => [],\n  },\n);\nconst emit = defineEmits<{ close: [] }>();\n\nconst router = useRouter();\nconst searchHistory = useLocalStorage<MenuRecordRaw[]>(\n  `__search-history-${location.hostname}__`,\n  [],\n);\nconst activeIndex = ref(-1);\nconst searchItems = shallowRef<MenuRecordRaw[]>([]);\nconst searchResults = ref<MenuRecordRaw[]>([]);\n\nconst handleSearch = useThrottleFn(search, 200);\n\n// 搜索函数，用于根据搜索关键词查找匹配的菜单项\nfunction search(searchKey: string) {\n  // 去除搜索关键词的前后空格\n  searchKey = searchKey.trim();\n\n  // 如果搜索关键词为空，清空搜索结果并返回\n  if (!searchKey) {\n    searchResults.value = [];\n    return;\n  }\n\n  // 使用搜索关键词创建正则表达式\n  const reg = createSearchReg(searchKey);\n\n  // 初始化结果数组\n  const results: MenuRecordRaw[] = [];\n\n  // 遍历搜索项\n  traverseTreeValues(searchItems.value, (item) => {\n    // 如果菜单项的名称匹配正则表达式，将其添加到结果数组中\n    if (reg.test(item.name?.toLowerCase())) {\n      results.push(item);\n    }\n  });\n\n  // 更新搜索结果\n  searchResults.value = results;\n\n  // 如果有搜索结果，设置索引为 0\n  if (results.length > 0) {\n    activeIndex.value = 0;\n  }\n\n  // 赋值索引为 0\n  activeIndex.value = 0;\n}\n\n// When the keyboard up and down keys move to an invisible place\n// the scroll bar needs to scroll automatically\nfunction scrollIntoView() {\n  const element = document.querySelector(\n    `[data-search-item=\"${activeIndex.value}\"]`,\n  );\n\n  if (element) {\n    element.scrollIntoView({ block: 'nearest' });\n  }\n}\n\n// enter keyboard event\nasync function handleEnter() {\n  if (searchResults.value.length === 0) {\n    return;\n  }\n  const result = searchResults.value;\n  const index = activeIndex.value;\n  if (result.length === 0 || index < 0) {\n    return;\n  }\n  const to = result[index];\n  if (to) {\n    searchHistory.value = uniqueByField([...searchHistory.value, to], 'path');\n    handleClose();\n    await nextTick();\n    if (isHttpUrl(to.path)) {\n      window.open(to.path, '_blank');\n    } else {\n      router.push({ path: to.path, replace: true });\n    }\n  }\n}\n\n// Arrow key up\nfunction handleUp() {\n  if (searchResults.value.length === 0) {\n    return;\n  }\n  activeIndex.value--;\n  if (activeIndex.value < 0) {\n    activeIndex.value = searchResults.value.length - 1;\n  }\n  scrollIntoView();\n}\n\n// Arrow key down\nfunction handleDown() {\n  if (searchResults.value.length === 0) {\n    return;\n  }\n  activeIndex.value++;\n  if (activeIndex.value > searchResults.value.length - 1) {\n    activeIndex.value = 0;\n  }\n  scrollIntoView();\n}\n\n// close search modal\nfunction handleClose() {\n  searchResults.value = [];\n  emit('close');\n}\n\n// Activate when the mouse moves to a certain line\nfunction handleMouseenter(e: MouseEvent) {\n  const index = (e.target as HTMLElement)?.dataset.index;\n  activeIndex.value = Number(index);\n}\n\nfunction removeItem(index: number) {\n  if (props.keyword) {\n    searchResults.value.splice(index, 1);\n  } else {\n    searchHistory.value.splice(index, 1);\n  }\n  activeIndex.value = Math.max(activeIndex.value - 1, 0);\n  scrollIntoView();\n}\n\n// 存储所有需要转义的特殊字符\nconst code = new Set([\n  '$',\n  '(',\n  ')',\n  '*',\n  '+',\n  '.',\n  '?',\n  '[',\n  '\\\\',\n  ']',\n  '^',\n  '{',\n  '|',\n  '}',\n]);\n\n// 转换函数，用于转义特殊字符\nfunction transform(c: string) {\n  // 如果字符在特殊字符列表中，返回转义后的字符\n  // 如果不在，返回字符本身\n  return code.has(c) ? `\\\\${c}` : c;\n}\n\n// 创建搜索正则表达式\nfunction createSearchReg(key: string) {\n  // 将输入的字符串拆分为单个字符\n  // 对每个字符进行转义\n  // 然后用'.*'连接所有字符，创建正则表达式\n  const keys = [...key].map((item) => transform(item)).join('.*');\n  // 返回创建的正则表达式\n  return new RegExp(`.*${keys}.*`);\n}\n\nwatch(\n  () => props.keyword,\n  (val) => {\n    if (val) {\n      handleSearch(val);\n    } else {\n      searchResults.value = [...searchHistory.value];\n    }\n  },\n);\n\nonMounted(() => {\n  searchItems.value = mapTree(props.menus, (item) => {\n    return {\n      ...item,\n      name: $t(item?.name),\n    };\n  });\n  if (searchHistory.value.length > 0) {\n    searchResults.value = searchHistory.value;\n  }\n  // enter search\n  onKeyStroke('Enter', handleEnter);\n  // Monitor keyboard arrow keys\n  onKeyStroke('ArrowUp', handleUp);\n  onKeyStroke('ArrowDown', handleDown);\n  // esc close\n  onKeyStroke('Escape', handleClose);\n});\n</script>\n\n<template>\n  <VbenScrollbar>\n    <div class=\"!flex h-full justify-center px-2 sm:max-h-[450px]\">\n      <!-- 无搜索结果 -->\n      <div\n        v-if=\"keyword && searchResults.length === 0\"\n        class=\"text-muted-foreground text-center\"\n      >\n        <SearchX class=\"mx-auto mt-4 size-12\" />\n        <p class=\"mb-10 mt-6 text-xs\">\n          {{ $t('ui.widgets.search.noResults') }}\n          <span class=\"text-foreground text-sm font-medium\">\n            \"{{ keyword }}\"\n          </span>\n        </p>\n      </div>\n      <!-- 历史搜索记录 & 没有搜索结果 -->\n      <div\n        v-if=\"!keyword && searchResults.length === 0\"\n        class=\"text-muted-foreground text-center\"\n      >\n        <p class=\"my-10 text-xs\">\n          {{ $t('ui.widgets.search.noRecent') }}\n        </p>\n      </div>\n\n      <ul v-show=\"searchResults.length > 0\" class=\"w-full\">\n        <li\n          v-if=\"searchHistory.length > 0 && !keyword\"\n          class=\"text-muted-foreground mb-2 text-xs\"\n        >\n          {{ $t('ui.widgets.search.recent') }}\n        </li>\n        <li\n          v-for=\"(item, index) in uniqueByField(searchResults, 'path')\"\n          :key=\"item.path\"\n          :class=\"\n            activeIndex === index\n              ? 'active bg-primary text-primary-foreground'\n              : ''\n          \"\n          :data-index=\"index\"\n          :data-search-item=\"index\"\n          class=\"bg-accent flex-center group mb-3 w-full cursor-pointer rounded-lg px-4 py-4\"\n          @click=\"handleEnter\"\n          @mouseenter=\"handleMouseenter\"\n        >\n          <VbenIcon\n            :icon=\"item.icon\"\n            class=\"mr-2 size-5 flex-shrink-0\"\n            fallback\n          />\n\n          <span class=\"flex-1\">{{ item.name }}</span>\n          <div\n            class=\"flex-center dark:hover:bg-accent hover:text-primary-foreground rounded-full p-1 hover:scale-110\"\n            @click.stop=\"removeItem(index)\"\n          >\n            <X class=\"size-4\" />\n          </div>\n        </li>\n      </ul>\n    </div>\n  </VbenScrollbar>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/index.ts",
    "content": "export { default as Breadcrumb } from './breadcrumb.vue';\nexport * from './check-updates';\nexport { default as AuthenticationColorToggle } from './color-toggle.vue';\nexport * from './global-search';\nexport { default as LanguageToggle } from './language-toggle.vue';\nexport { default as AuthenticationLayoutToggle } from './layout-toggle.vue';\nexport * from './lock-screen';\nexport * from './notification';\nexport * from './preferences';\nexport * from './theme-toggle';\nexport * from './user-dropdown';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/language-toggle.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SupportedLanguagesType } from '@vben/locales';\n\nimport { SUPPORT_LANGUAGES } from '@vben/constants';\nimport { Languages } from '@vben/icons';\nimport { loadLocaleMessages } from '@vben/locales';\nimport { preferences, updatePreferences } from '@vben/preferences';\n\nimport { VbenDropdownRadioMenu, VbenIconButton } from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'LanguageToggle',\n});\n\nasync function handleUpdate(value: string | undefined) {\n  if (!value) return;\n  const locale = value as SupportedLanguagesType;\n  updatePreferences({\n    app: {\n      locale,\n    },\n  });\n  await loadLocaleMessages(locale);\n}\n</script>\n\n<template>\n  <div>\n    <VbenDropdownRadioMenu\n      :menus=\"SUPPORT_LANGUAGES\"\n      :model-value=\"preferences.app.locale\"\n      @update:model-value=\"handleUpdate\"\n    >\n      <VbenIconButton class=\"hover:animate-[shrink_0.3s_ease-in-out]\">\n        <Languages class=\"text-foreground size-4\" />\n      </VbenIconButton>\n    </VbenDropdownRadioMenu>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/layout-toggle.vue",
    "content": "<script setup lang=\"ts\">\nimport type { AuthPageLayoutType } from '@vben/types';\n\nimport type { VbenDropdownMenuItem } from '@vben-core/shadcn-ui';\n\nimport { computed } from 'vue';\n\nimport { InspectionPanel, PanelLeft, PanelRight } from '@vben/icons';\nimport { $t } from '@vben/locales';\nimport {\n  preferences,\n  updatePreferences,\n  usePreferences,\n} from '@vben/preferences';\n\nimport { VbenDropdownRadioMenu, VbenIconButton } from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'AuthenticationLayoutToggle',\n});\n\nconst menus = computed((): VbenDropdownMenuItem[] => [\n  {\n    icon: PanelLeft,\n    label: $t('authentication.layout.alignLeft'),\n    value: 'panel-left',\n  },\n  {\n    icon: InspectionPanel,\n    label: $t('authentication.layout.center'),\n    value: 'panel-center',\n  },\n  {\n    icon: PanelRight,\n    label: $t('authentication.layout.alignRight'),\n    value: 'panel-right',\n  },\n]);\n\nconst { authPanelCenter, authPanelLeft, authPanelRight } = usePreferences();\n\nfunction handleUpdate(value: string | undefined) {\n  if (!value) return;\n  updatePreferences({\n    app: {\n      authPageLayout: value as AuthPageLayoutType,\n    },\n  });\n}\n</script>\n\n<template>\n  <VbenDropdownRadioMenu\n    :menus=\"menus\"\n    :model-value=\"preferences.app.authPageLayout\"\n    @update:model-value=\"handleUpdate\"\n  >\n    <VbenIconButton>\n      <PanelRight v-if=\"authPanelRight\" class=\"size-4\" />\n      <PanelLeft v-if=\"authPanelLeft\" class=\"size-4\" />\n      <InspectionPanel v-if=\"authPanelCenter\" class=\"size-4\" />\n    </VbenIconButton>\n  </VbenDropdownRadioMenu>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/lock-screen/index.ts",
    "content": "export { default as LockScreenModal } from './lock-screen-modal.vue';\nexport { default as LockScreen } from './lock-screen.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Recordable } from '@vben/types';\n\nimport { computed, reactive } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport { useVbenForm, z } from '@vben-core/form-ui';\nimport { useVbenModal } from '@vben-core/popup-ui';\nimport { VbenAvatar, VbenButton } from '@vben-core/shadcn-ui';\n\ninterface Props {\n  avatar?: string;\n  text?: string;\n}\n\ndefineOptions({\n  name: 'LockScreenModal',\n});\n\nwithDefaults(defineProps<Props>(), {\n  avatar: '',\n  text: '',\n});\n\nconst emit = defineEmits<{\n  submit: [Recordable<any>];\n}>();\n\nconst [Form, { resetForm, validate, getValues }] = useVbenForm(\n  reactive({\n    commonConfig: {\n      hideLabel: true,\n      hideRequiredMark: true,\n    },\n    schema: computed(() => [\n      {\n        component: 'VbenInputPassword' as const,\n        componentProps: {\n          placeholder: $t('ui.widgets.lockScreen.placeholder'),\n        },\n        fieldName: 'lockScreenPassword',\n        formFieldProps: { validateOnBlur: false },\n        label: $t('authentication.password'),\n        rules: z\n          .string()\n          .min(1, { message: $t('ui.widgets.lockScreen.placeholder') }),\n      },\n    ]),\n    showDefaultActions: false,\n  }),\n);\n\nconst [Modal] = useVbenModal({\n  onConfirm() {\n    handleSubmit();\n  },\n  onOpenChange(isOpen) {\n    if (isOpen) {\n      resetForm();\n    }\n  },\n});\n\nasync function handleSubmit() {\n  const { valid } = await validate();\n  const values = await getValues();\n  if (valid) {\n    emit('submit', values?.lockScreenPassword);\n  }\n}\n</script>\n\n<template>\n  <Modal\n    :footer=\"false\"\n    :fullscreen-button=\"false\"\n    :title=\"$t('ui.widgets.lockScreen.title')\"\n  >\n    <div\n      class=\"mb-10 flex w-full flex-col items-center px-10\"\n      @keydown.enter.prevent=\"handleSubmit\"\n    >\n      <div class=\"w-full\">\n        <div class=\"ml-2 flex w-full flex-col items-center\">\n          <VbenAvatar\n            :src=\"avatar\"\n            class=\"size-20\"\n            dot-class=\"bottom-0 right-1 border-2 size-4 bg-green-500\"\n          />\n          <div class=\"text-foreground my-6 flex items-center font-medium\">\n            {{ text }}\n          </div>\n        </div>\n        <Form />\n        <VbenButton class=\"mt-1 w-full\" @click=\"handleSubmit\">\n          {{ $t('ui.widgets.lockScreen.screenButton') }}\n        </VbenButton>\n      </div>\n    </div>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, reactive, ref } from 'vue';\n\nimport { LockKeyhole } from '@vben/icons';\nimport { $t, useI18n } from '@vben/locales';\nimport { storeToRefs, useAccessStore } from '@vben/stores';\n\nimport { useScrollLock } from '@vben-core/composables';\nimport { useVbenForm, z } from '@vben-core/form-ui';\nimport { VbenAvatar, VbenButton } from '@vben-core/shadcn-ui';\n\nimport { useDateFormat, useNow } from '@vueuse/core';\n\ninterface Props {\n  avatar?: string;\n}\n\ndefineOptions({\n  name: 'LockScreen',\n});\n\nwithDefaults(defineProps<Props>(), {\n  avatar: '',\n});\n\ndefineEmits<{ toLogin: [] }>();\n\nconst { locale } = useI18n();\nconst accessStore = useAccessStore();\n\nconst now = useNow();\nconst meridiem = useDateFormat(now, 'A');\nconst hour = useDateFormat(now, 'HH');\nconst minute = useDateFormat(now, 'mm');\nconst date = useDateFormat(now, 'YYYY-MM-DD dddd', { locales: locale.value });\n\nconst showUnlockForm = ref(false);\nconst { lockScreenPassword } = storeToRefs(accessStore);\n\nconst [Form, { form, validate }] = useVbenForm(\n  reactive({\n    commonConfig: {\n      hideLabel: true,\n      hideRequiredMark: true,\n    },\n    schema: computed(() => [\n      {\n        component: 'VbenInputPassword' as const,\n        componentProps: {\n          placeholder: $t('ui.widgets.lockScreen.placeholder'),\n        },\n        fieldName: 'password',\n        label: $t('authentication.password'),\n        rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n      },\n    ]),\n    showDefaultActions: false,\n  }),\n);\n\nconst validPass = computed(\n  () => lockScreenPassword?.value === form?.values?.password,\n);\n\nasync function handleSubmit() {\n  const { valid } = await validate();\n  if (valid) {\n    if (validPass.value) {\n      accessStore.unlockScreen();\n    } else {\n      form.setFieldError('password', $t('authentication.passwordErrorTip'));\n    }\n  }\n}\n\nfunction toggleUnlockForm() {\n  showUnlockForm.value = !showUnlockForm.value;\n}\n\nuseScrollLock();\n</script>\n\n<template>\n  <div class=\"bg-background fixed z-[2000] size-full\">\n    <transition name=\"slide-left\">\n      <div v-show=\"!showUnlockForm\" class=\"size-full\">\n        <div\n          class=\"flex-col-center text-foreground/80 hover:text-foreground group fixed left-1/2 top-6 z-[2001] -translate-x-1/2 cursor-pointer text-xl font-semibold\"\n          @click=\"toggleUnlockForm\"\n        >\n          <LockKeyhole\n            class=\"size-5 transition-all duration-300 group-hover:scale-125\"\n          />\n          <span>{{ $t('ui.widgets.lockScreen.unlock') }}</span>\n        </div>\n        <div class=\"flex h-full w-full items-center justify-center\">\n          <div class=\"flex w-full justify-center gap-4 px-4 sm:gap-6 md:gap-8\">\n            <div\n              class=\"bg-accent relative flex h-[140px] w-[140px] items-center justify-center rounded-xl text-[36px] sm:h-[160px] sm:w-[160px] sm:text-[42px] md:h-[200px] md:w-[200px] md:text-[72px]\"\n            >\n              <span\n                class=\"absolute left-3 top-3 text-xs font-semibold sm:text-sm md:text-xl\"\n              >\n                {{ meridiem }}\n              </span>\n              {{ hour }}\n            </div>\n            <div\n              class=\"bg-accent flex h-[140px] w-[140px] items-center justify-center rounded-xl text-[36px] sm:h-[160px] sm:w-[160px] sm:text-[42px] md:h-[200px] md:w-[200px] md:text-[72px]\"\n            >\n              {{ minute }}\n            </div>\n          </div>\n        </div>\n      </div>\n    </transition>\n\n    <transition name=\"slide-right\">\n      <div\n        v-if=\"showUnlockForm\"\n        class=\"flex-center size-full\"\n        @keydown.enter.prevent=\"handleSubmit\"\n      >\n        <div class=\"flex-col-center mb-10 w-[90%] max-w-[300px] px-4\">\n          <VbenAvatar :src=\"avatar\" class=\"enter-x mb-6 size-20\" />\n          <div class=\"enter-x mb-2 w-full items-center\">\n            <Form />\n          </div>\n          <VbenButton class=\"enter-x w-full\" @click=\"handleSubmit\">\n            {{ $t('ui.widgets.lockScreen.entry') }}\n          </VbenButton>\n          <VbenButton\n            class=\"enter-x my-2 w-full\"\n            variant=\"ghost\"\n            @click=\"$emit('toLogin')\"\n          >\n            {{ $t('ui.widgets.lockScreen.backToLogin') }}\n          </VbenButton>\n          <VbenButton\n            class=\"enter-x mr-2 w-full\"\n            variant=\"ghost\"\n            @click=\"toggleUnlockForm\"\n          >\n            {{ $t('common.back') }}\n          </VbenButton>\n        </div>\n      </div>\n    </transition>\n\n    <div\n      class=\"enter-y absolute bottom-5 w-full text-center text-xl md:text-2xl xl:text-xl 2xl:text-3xl\"\n    >\n      <div v-if=\"showUnlockForm\" class=\"enter-x mb-2 text-2xl md:text-3xl\">\n        {{ hour }}:{{ minute }}\n        <span class=\"text-base md:text-lg\">{{ meridiem }}</span>\n      </div>\n      <div class=\"text-xl md:text-3xl\">{{ date }}</div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/notification/index.ts",
    "content": "export { default as Notification } from './notification.vue';\n\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/notification/notification.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { NotificationItem } from './types';\n\nimport { Bell, MailCheck } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport {\n  VbenButton,\n  VbenIconButton,\n  VbenPopover,\n  VbenScrollbar,\n} from '@vben-core/shadcn-ui';\n\nimport { useToggle } from '@vueuse/core';\n\ninterface Props {\n  /**\n   * 显示圆点\n   */\n  dot?: boolean;\n  /**\n   * 消息列表\n   */\n  notifications?: NotificationItem[];\n}\n\ndefineOptions({ name: 'NotificationPopup' });\n\nwithDefaults(defineProps<Props>(), {\n  dot: false,\n  notifications: () => [],\n});\n\nconst emit = defineEmits<{\n  clear: [];\n  makeAll: [];\n  read: [NotificationItem];\n  viewAll: [];\n}>();\n\nconst [open, toggle] = useToggle();\n\nfunction close() {\n  open.value = false;\n}\n\nfunction handleViewAll() {\n  emit('viewAll');\n  close();\n}\n\nfunction handleMakeAll() {\n  emit('makeAll');\n}\n\nfunction handleClear() {\n  emit('clear');\n}\n\nfunction handleClick(item: NotificationItem) {\n  emit('read', item);\n}\n</script>\n<template>\n  <VbenPopover\n    v-model:open=\"open\"\n    content-class=\"relative right-2 w-[360px] p-0\"\n  >\n    <template #trigger>\n      <div class=\"flex-center mr-2 h-full\" @click.stop=\"toggle()\">\n        <VbenIconButton class=\"bell-button text-foreground relative\">\n          <span\n            v-if=\"dot\"\n            class=\"bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded\"\n          ></span>\n          <Bell class=\"size-4\" />\n        </VbenIconButton>\n      </div>\n    </template>\n\n    <div class=\"relative\">\n      <div class=\"flex items-center justify-between p-4 py-3\">\n        <div class=\"text-foreground\">{{ $t('ui.widgets.notifications') }}</div>\n        <VbenIconButton\n          :disabled=\"notifications.length <= 0\"\n          :tooltip=\"$t('ui.widgets.markAllAsRead')\"\n          @click=\"handleMakeAll\"\n        >\n          <MailCheck class=\"size-4\" />\n        </VbenIconButton>\n      </div>\n      <VbenScrollbar v-if=\"notifications.length > 0\">\n        <ul class=\"!flex max-h-[360px] w-full flex-col\">\n          <template v-for=\"item in notifications\" :key=\"item.title\">\n            <li\n              class=\"hover:bg-accent border-border relative flex w-full cursor-pointer items-start gap-5 border-t px-3 py-3\"\n              @click=\"handleClick(item)\"\n            >\n              <span\n                v-if=\"!item.isRead\"\n                class=\"bg-primary absolute right-2 top-2 h-2 w-2 rounded\"\n              ></span>\n\n              <span\n                class=\"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full\"\n              >\n                <img\n                  :src=\"item.avatar\"\n                  class=\"aspect-square h-full w-full object-cover\"\n                  role=\"img\"\n                />\n              </span>\n              <div class=\"flex flex-col gap-1 leading-none\">\n                <p class=\"font-semibold\">{{ item.title }}</p>\n                <p class=\"text-muted-foreground my-1 line-clamp-2 text-xs\">\n                  {{ item.message }}\n                </p>\n                <p class=\"text-muted-foreground line-clamp-2 text-xs\">\n                  {{ item.date }}\n                </p>\n              </div>\n            </li>\n          </template>\n        </ul>\n      </VbenScrollbar>\n\n      <template v-else>\n        <div class=\"flex-center text-muted-foreground min-h-[150px] w-full\">\n          {{ $t('common.noData') }}\n        </div>\n      </template>\n\n      <div\n        class=\"border-border flex items-center justify-between border-t px-4 py-3\"\n      >\n        <VbenButton\n          :disabled=\"notifications.length <= 0\"\n          size=\"sm\"\n          variant=\"ghost\"\n          @click=\"handleClear\"\n        >\n          {{ $t('ui.widgets.clearNotifications') }}\n        </VbenButton>\n        <VbenButton size=\"sm\" @click=\"handleViewAll\">\n          {{ $t('ui.widgets.viewAll') }}\n        </VbenButton>\n      </div>\n    </div>\n  </VbenPopover>\n</template>\n\n<style scoped>\n:deep(.bell-button) {\n  &:hover {\n    svg {\n      animation: bell-ring 1s both;\n    }\n  }\n}\n\n@keyframes bell-ring {\n  0%,\n  100% {\n    transform-origin: top;\n  }\n\n  15% {\n    transform: rotateZ(10deg);\n  }\n\n  30% {\n    transform: rotateZ(-10deg);\n  }\n\n  45% {\n    transform: rotateZ(5deg);\n  }\n\n  60% {\n    transform: rotateZ(-5deg);\n  }\n\n  75% {\n    transform: rotateZ(2deg);\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/notification/types.ts",
    "content": "interface NotificationItem {\n  avatar: string;\n  date: string;\n  isRead?: boolean;\n  message: string;\n  title: string;\n}\n\nexport type { NotificationItem };\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/block.vue",
    "content": "<script setup lang=\"ts\">\ninterface Props {\n  title?: string;\n}\n\ndefineOptions({\n  name: 'PreferenceBlock',\n});\n\nwithDefaults(defineProps<Props>(), {\n  title: '',\n});\n</script>\n\n<template>\n  <div class=\"flex flex-col py-4\">\n    <h3 class=\"mb-3 font-semibold leading-none tracking-tight\">\n      {{ title }}\n    </h3>\n    <slot></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/checkbox-item.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { useSlots } from 'vue';\n\nimport { CircleHelp } from '@vben/icons';\n\nimport { VbenCheckButtonGroup, VbenTooltip } from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'PreferenceCheckboxItem',\n});\n\nwithDefaults(\n  defineProps<{\n    disabled?: boolean;\n    items?: SelectOption[];\n    multiple?: boolean;\n    onBtnClick?: (value: string) => void;\n    placeholder?: string;\n  }>(),\n  {\n    disabled: false,\n    placeholder: '',\n    items: () => [],\n    onBtnClick: () => {},\n    multiple: false,\n  },\n);\n\nconst inputValue = defineModel<string[]>();\n\nconst slots = useSlots();\n</script>\n\n<template>\n  <div\n    :class=\"{\n      'hover:bg-accent': !slots.tip,\n      'pointer-events-none opacity-50': disabled,\n    }\"\n    class=\"my-1 flex w-full items-center justify-between rounded-md px-2 py-1\"\n  >\n    <span class=\"flex items-center text-sm\">\n      <slot></slot>\n\n      <VbenTooltip v-if=\"slots.tip\" side=\"bottom\">\n        <template #trigger>\n          <CircleHelp class=\"ml-1 size-3 cursor-help\" />\n        </template>\n        <slot name=\"tip\"></slot>\n      </VbenTooltip>\n    </span>\n    <VbenCheckButtonGroup\n      v-model=\"inputValue\"\n      class=\"h-8 w-[165px]\"\n      :options=\"items\"\n      :disabled=\"disabled\"\n      :multiple=\"multiple\"\n      @btn-click=\"onBtnClick\"\n    />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue",
    "content": "<script setup lang=\"ts\">\nimport { $t } from '@vben/locales';\n\nimport SwitchItem from '../switch-item.vue';\n\ndefineOptions({\n  name: 'PreferenceAnimation',\n});\n\nconst transitionProgress = defineModel<boolean>('transitionProgress', {\n  // 默认值\n  default: false,\n});\nconst transitionName = defineModel<string>('transitionName');\nconst transitionEnable = defineModel<boolean>('transitionEnable');\nconst transitionLoading = defineModel<boolean>('transitionLoading');\n\nconst transitionPreset = ['fade', 'fade-slide', 'fade-up', 'fade-down'];\n\nfunction handleClick(value: string) {\n  transitionName.value = value;\n}\n</script>\n\n<template>\n  <SwitchItem v-model=\"transitionProgress\">\n    {{ $t('preferences.animation.progress') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"transitionLoading\">\n    {{ $t('preferences.animation.loading') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"transitionEnable\">\n    {{ $t('preferences.animation.transition') }}\n  </SwitchItem>\n  <div\n    v-if=\"transitionEnable\"\n    class=\"mb-2 mt-3 flex justify-between gap-3 px-2\"\n  >\n    <div\n      v-for=\"item in transitionPreset\"\n      :key=\"item\"\n      :class=\"{\n        'outline-box-active': transitionName === item,\n      }\"\n      class=\"outline-box p-2\"\n      @click=\"handleClick(item)\"\n    >\n      <div :class=\"`${item}-slow`\" class=\"bg-accent h-10 w-12 rounded-md\"></div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue",
    "content": "<script setup lang=\"ts\">\nimport { SUPPORT_LANGUAGES } from '@vben/constants';\nimport { $t } from '@vben/locales';\n\nimport InputItem from '../input-item.vue';\nimport SelectItem from '../select-item.vue';\nimport SwitchItem from '../switch-item.vue';\n\ndefineOptions({\n  name: 'PreferenceGeneralConfig',\n});\n\nconst appLocale = defineModel<string>('appLocale');\nconst appDynamicTitle = defineModel<boolean>('appDynamicTitle');\nconst appWatermark = defineModel<boolean>('appWatermark');\nconst appWatermarkContent = defineModel<string>('appWatermarkContent');\nconst appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');\n</script>\n\n<template>\n  <SelectItem v-model=\"appLocale\" :items=\"SUPPORT_LANGUAGES\">\n    {{ $t('preferences.language') }}\n  </SelectItem>\n  <SwitchItem v-model=\"appDynamicTitle\">\n    {{ $t('preferences.dynamicTitle') }}\n  </SwitchItem>\n  <SwitchItem\n    v-model=\"appWatermark\"\n    @update:model-value=\"\n      (val) => {\n        if (!val) appWatermarkContent = '';\n      }\n    \"\n  >\n    {{ $t('preferences.watermark') }}\n  </SwitchItem>\n  <InputItem\n    v-if=\"appWatermark\"\n    v-model=\"appWatermarkContent\"\n    :placeholder=\"$t('preferences.watermarkContent')\"\n  >\n    {{ $t('preferences.watermarkContent') }}\n  </InputItem>\n  <SwitchItem v-model=\"appEnableCheckUpdates\">\n    {{ $t('preferences.checkUpdates') }}\n  </SwitchItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/index.ts",
    "content": "export { default as Block } from './block.vue';\nexport { default as Animation } from './general/animation.vue';\nexport { default as General } from './general/general.vue';\nexport { default as Breadcrumb } from './layout/breadcrumb.vue';\nexport { default as Content } from './layout/content.vue';\nexport { default as Copyright } from './layout/copyright.vue';\nexport { default as Footer } from './layout/footer.vue';\nexport { default as Header } from './layout/header.vue';\nexport { default as Layout } from './layout/layout.vue';\nexport { default as Navigation } from './layout/navigation.vue';\nexport { default as Sidebar } from './layout/sidebar.vue';\nexport { default as Tabbar } from './layout/tabbar.vue';\nexport { default as Widget } from './layout/widget.vue';\nexport { default as GlobalShortcutKeys } from './shortcut-keys/global.vue';\nexport { default as SwitchItem } from './switch-item.vue';\nexport { default as BuiltinTheme } from './theme/builtin.vue';\nexport { default as ColorMode } from './theme/color-mode.vue';\nexport { default as Radius } from './theme/radius.vue';\nexport { default as Theme } from './theme/theme.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { useSlots } from 'vue';\n\nimport { CircleHelp, CircleX } from '@vben/icons';\n\nimport { Input, VbenTooltip } from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'PreferenceSelectItem',\n});\n\nwithDefaults(\n  defineProps<{\n    disabled?: boolean;\n    items?: SelectOption[];\n    placeholder?: string;\n  }>(),\n  {\n    disabled: false,\n    placeholder: '',\n    items: () => [],\n  },\n);\n\nconst inputValue = defineModel<string>();\n\nconst slots = useSlots();\n</script>\n\n<template>\n  <div\n    :class=\"{\n      'hover:bg-accent': !slots.tip,\n      'pointer-events-none opacity-50': disabled,\n    }\"\n    class=\"my-1 flex w-full items-center justify-between rounded-md px-2 py-1\"\n  >\n    <span class=\"flex items-center text-sm\">\n      <slot></slot>\n\n      <VbenTooltip v-if=\"slots.tip\" side=\"bottom\">\n        <template #trigger>\n          <CircleHelp class=\"ml-1 size-3 cursor-help\" />\n        </template>\n        <slot name=\"tip\"></slot>\n      </VbenTooltip>\n    </span>\n    <div class=\"relative\">\n      <Input\n        v-model=\"inputValue\"\n        class=\"h-8 w-[165px]\"\n        :placeholder=\"placeholder\"\n      />\n      <CircleX\n        v-if=\"inputValue\"\n        class=\"hover:text-foreground text-foreground/60 absolute right-2 top-1/2 size-3 -translate-y-1/2 transform cursor-pointer\"\n        @click=\"() => (inputValue = '')\"\n      />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { computed } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport SwitchItem from '../switch-item.vue';\nimport ToggleItem from '../toggle-item.vue';\n\ndefineOptions({\n  name: 'PreferenceBreadcrumbConfig',\n});\n\nconst props = defineProps<{ disabled?: boolean }>();\n\nconst breadcrumbEnable = defineModel<boolean>('breadcrumbEnable');\nconst breadcrumbShowIcon = defineModel<boolean>('breadcrumbShowIcon');\nconst breadcrumbStyleType = defineModel<string>('breadcrumbStyleType');\nconst breadcrumbShowHome = defineModel<boolean>('breadcrumbShowHome');\nconst breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne');\n\nconst typeItems: SelectOption[] = [\n  { label: $t('preferences.normal'), value: 'normal' },\n  { label: $t('preferences.breadcrumb.background'), value: 'background' },\n];\n\nconst disableItem = computed(() => {\n  return !breadcrumbEnable.value || props.disabled;\n});\n</script>\n\n<template>\n  <SwitchItem v-model=\"breadcrumbEnable\" :disabled=\"disabled\">\n    {{ $t('preferences.breadcrumb.enable') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"breadcrumbHideOnlyOne\" :disabled=\"disableItem\">\n    {{ $t('preferences.breadcrumb.hideOnlyOne') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"breadcrumbShowIcon\" :disabled=\"disableItem\">\n    {{ $t('preferences.breadcrumb.icon') }}\n  </SwitchItem>\n  <SwitchItem\n    v-model=\"breadcrumbShowHome\"\n    :disabled=\"disableItem || !breadcrumbShowIcon\"\n  >\n    {{ $t('preferences.breadcrumb.home') }}\n  </SwitchItem>\n  <ToggleItem\n    v-model=\"breadcrumbStyleType\"\n    :disabled=\"disableItem\"\n    :items=\"typeItems\"\n  >\n    {{ $t('preferences.breadcrumb.style') }}\n  </ToggleItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Component } from 'vue';\n\nimport { computed } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport { ContentCompact, ContentWide } from '../../icons';\n\ndefineOptions({\n  name: 'PreferenceLayoutContent',\n});\n\nconst modelValue = defineModel<string>({ default: 'wide' });\n\nconst components: Record<string, Component> = {\n  compact: ContentCompact,\n  wide: ContentWide,\n};\n\nconst PRESET = computed(() => [\n  {\n    name: $t('preferences.wide'),\n    type: 'wide',\n  },\n  {\n    name: $t('preferences.compact'),\n    type: 'compact',\n  },\n]);\n\nfunction activeClass(theme: string): string[] {\n  return theme === modelValue.value ? ['outline-box-active'] : [];\n}\n</script>\n\n<template>\n  <div class=\"flex w-full gap-5\">\n    <template v-for=\"theme in PRESET\" :key=\"theme.name\">\n      <div\n        class=\"flex w-[100px] cursor-pointer flex-col\"\n        @click=\"modelValue = theme.type\"\n      >\n        <div :class=\"activeClass(theme.type)\" class=\"outline-box flex-center\">\n          <component :is=\"components[theme.type]\" />\n        </div>\n        <div class=\"text-muted-foreground mt-2 text-center text-xs\">\n          {{ theme.name }}\n        </div>\n      </div>\n    </template>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport InputItem from '../input-item.vue';\nimport SwitchItem from '../switch-item.vue';\n\nconst props = defineProps<{ disabled: boolean }>();\n\nconst copyrightEnable = defineModel<boolean>('copyrightEnable');\nconst copyrightDate = defineModel<string>('copyrightDate');\nconst copyrightIcp = defineModel<string>('copyrightIcp');\nconst copyrightIcpLink = defineModel<string>('copyrightIcpLink');\nconst copyrightCompanyName = defineModel<string>('copyrightCompanyName');\nconst copyrightCompanySiteLink = defineModel<string>(\n  'copyrightCompanySiteLink',\n);\n\nconst itemDisabled = computed(() => props.disabled || !copyrightEnable.value);\n</script>\n\n<template>\n  <SwitchItem v-model=\"copyrightEnable\" :disabled=\"disabled\">\n    {{ $t('preferences.copyright.enable') }}\n  </SwitchItem>\n\n  <InputItem v-model=\"copyrightCompanyName\" :disabled=\"itemDisabled\">\n    {{ $t('preferences.copyright.companyName') }}\n  </InputItem>\n  <InputItem v-model=\"copyrightCompanySiteLink\" :disabled=\"itemDisabled\">\n    {{ $t('preferences.copyright.companySiteLink') }}\n  </InputItem>\n  <InputItem v-model=\"copyrightDate\" :disabled=\"itemDisabled\">\n    {{ $t('preferences.copyright.date') }}\n  </InputItem>\n\n  <InputItem v-model=\"copyrightIcp\" :disabled=\"itemDisabled\">\n    {{ $t('preferences.copyright.icp') }}\n  </InputItem>\n  <InputItem v-model=\"copyrightIcpLink\" :disabled=\"itemDisabled\">\n    {{ $t('preferences.copyright.icpLink') }}\n  </InputItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue",
    "content": "<script setup lang=\"ts\">\nimport { $t } from '@vben/locales';\n\nimport SwitchItem from '../switch-item.vue';\n\nconst footerEnable = defineModel<boolean>('footerEnable');\nconst footerFixed = defineModel<boolean>('footerFixed');\n</script>\n\n<template>\n  <SwitchItem v-model=\"footerEnable\">\n    {{ $t('preferences.footer.visible') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"footerFixed\" :disabled=\"!footerEnable\">\n    {{ $t('preferences.footer.fixed') }}\n  </SwitchItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue",
    "content": "<script setup lang=\"ts\">\nimport type {\n  LayoutHeaderMenuAlignType,\n  LayoutHeaderModeType,\n  SelectOption,\n} from '@vben/types';\n\nimport { $t } from '@vben/locales';\n\nimport SelectItem from '../select-item.vue';\nimport SwitchItem from '../switch-item.vue';\nimport ToggleItem from '../toggle-item.vue';\n\ndefineProps<{ disabled: boolean }>();\n\nconst headerEnable = defineModel<boolean>('headerEnable');\nconst headerMode = defineModel<LayoutHeaderModeType>('headerMode');\nconst headerMenuAlign =\n  defineModel<LayoutHeaderMenuAlignType>('headerMenuAlign');\n\nconst localeItems: SelectOption[] = [\n  {\n    label: $t('preferences.header.modeStatic'),\n    value: 'static',\n  },\n  {\n    label: $t('preferences.header.modeFixed'),\n    value: 'fixed',\n  },\n  {\n    label: $t('preferences.header.modeAuto'),\n    value: 'auto',\n  },\n  {\n    label: $t('preferences.header.modeAutoScroll'),\n    value: 'auto-scroll',\n  },\n];\n\nconst headerMenuAlignItems: SelectOption[] = [\n  {\n    label: $t('preferences.header.menuAlignStart'),\n    value: 'start',\n  },\n  {\n    label: $t('preferences.header.menuAlignCenter'),\n    value: 'center',\n  },\n  {\n    label: $t('preferences.header.menuAlignEnd'),\n    value: 'end',\n  },\n];\n</script>\n\n<template>\n  <SwitchItem v-model=\"headerEnable\" :disabled=\"disabled\">\n    {{ $t('preferences.header.visible') }}\n  </SwitchItem>\n  <SelectItem\n    v-model=\"headerMode\"\n    :disabled=\"!headerEnable\"\n    :items=\"localeItems\"\n  >\n    {{ $t('preferences.mode') }}\n  </SelectItem>\n  <ToggleItem\n    v-model=\"headerMenuAlign\"\n    :disabled=\"!headerEnable\"\n    :items=\"headerMenuAlignItems\"\n  >\n    {{ $t('preferences.header.menuAlign') }}\n  </ToggleItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Component } from 'vue';\n\nimport type { LayoutType } from '@vben/types';\n\nimport { computed } from 'vue';\n\nimport { CircleHelp } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport { VbenTooltip } from '@vben-core/shadcn-ui';\n\nimport {\n  FullContent,\n  HeaderMixedNav,\n  HeaderNav,\n  HeaderSidebarNav,\n  MixedNav,\n  SidebarMixedNav,\n  SidebarNav,\n} from '../../icons';\n\ninterface PresetItem {\n  name: string;\n  tip: string;\n  type: LayoutType;\n}\n\ndefineOptions({\n  name: 'PreferenceLayout',\n});\n\nconst modelValue = defineModel<LayoutType>({ default: 'sidebar-nav' });\n\nconst components: Record<LayoutType, Component> = {\n  'full-content': FullContent,\n  'header-nav': HeaderNav,\n  'mixed-nav': MixedNav,\n  'sidebar-mixed-nav': SidebarMixedNav,\n  'sidebar-nav': SidebarNav,\n  'header-mixed-nav': HeaderMixedNav,\n  'header-sidebar-nav': HeaderSidebarNav,\n};\n\nconst PRESET = computed((): PresetItem[] => [\n  {\n    name: $t('preferences.vertical'),\n    tip: $t('preferences.verticalTip'),\n    type: 'sidebar-nav',\n  },\n  {\n    name: $t('preferences.twoColumn'),\n    tip: $t('preferences.twoColumnTip'),\n    type: 'sidebar-mixed-nav',\n  },\n  {\n    name: $t('preferences.horizontal'),\n    tip: $t('preferences.horizontalTip'),\n    type: 'header-nav',\n  },\n  {\n    name: $t('preferences.headerSidebarNav'),\n    tip: $t('preferences.headerSidebarNavTip'),\n    type: 'header-sidebar-nav',\n  },\n  {\n    name: $t('preferences.mixedMenu'),\n    tip: $t('preferences.mixedMenuTip'),\n    type: 'mixed-nav',\n  },\n  {\n    name: $t('preferences.headerTwoColumn'),\n    tip: $t('preferences.headerTwoColumnTip'),\n    type: 'header-mixed-nav',\n  },\n  {\n    name: $t('preferences.fullContent'),\n    tip: $t('preferences.fullContentTip'),\n    type: 'full-content',\n  },\n]);\n\nfunction activeClass(theme: string): string[] {\n  return theme === modelValue.value ? ['outline-box-active'] : [];\n}\n</script>\n\n<template>\n  <div class=\"flex w-full flex-wrap gap-5\">\n    <template v-for=\"theme in PRESET\" :key=\"theme.name\">\n      <div\n        class=\"flex w-[100px] cursor-pointer flex-col\"\n        @click=\"modelValue = theme.type\"\n      >\n        <div :class=\"activeClass(theme.type)\" class=\"outline-box flex-center\">\n          <component :is=\"components[theme.type]\" />\n        </div>\n        <div\n          class=\"text-muted-foreground flex-center hover:text-foreground mt-2 text-center text-xs\"\n        >\n          {{ theme.name }}\n          <VbenTooltip v-if=\"theme.tip\" side=\"bottom\">\n            <template #trigger>\n              <CircleHelp class=\"ml-1 size-3 cursor-help\" />\n            </template>\n            {{ theme.tip }}\n          </VbenTooltip>\n        </div>\n      </div>\n    </template>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { $t } from '@vben/locales';\n\nimport SwitchItem from '../switch-item.vue';\nimport ToggleItem from '../toggle-item.vue';\n\ndefineOptions({\n  name: 'PreferenceNavigationConfig',\n});\n\ndefineProps<{ disabled?: boolean; disabledNavigationSplit?: boolean }>();\n\nconst navigationStyleType = defineModel<string>('navigationStyleType');\nconst navigationSplit = defineModel<boolean>('navigationSplit');\nconst navigationAccordion = defineModel<boolean>('navigationAccordion');\n\nconst stylesItems: SelectOption[] = [\n  { label: $t('preferences.rounded'), value: 'rounded' },\n  { label: $t('preferences.plain'), value: 'plain' },\n];\n</script>\n\n<template>\n  <ToggleItem\n    v-model=\"navigationStyleType\"\n    :disabled=\"disabled\"\n    :items=\"stylesItems\"\n  >\n    {{ $t('preferences.navigationMenu.style') }}\n  </ToggleItem>\n  <SwitchItem\n    v-model=\"navigationSplit\"\n    :disabled=\"disabledNavigationSplit || disabled\"\n  >\n    {{ $t('preferences.navigationMenu.split') }}\n    <template #tip>\n      {{ $t('preferences.navigationMenu.splitTip') }}\n    </template>\n  </SwitchItem>\n  <SwitchItem v-model=\"navigationAccordion\" :disabled=\"disabled\">\n    {{ $t('preferences.navigationMenu.accordion') }}\n  </SwitchItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { LayoutType } from '@vben/types';\n\nimport { onMounted } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport CheckboxItem from '../checkbox-item.vue';\nimport NumberFieldItem from '../number-field-item.vue';\nimport SwitchItem from '../switch-item.vue';\n\ndefineProps<{ currentLayout?: LayoutType; disabled: boolean }>();\n\nconst sidebarEnable = defineModel<boolean>('sidebarEnable');\nconst sidebarWidth = defineModel<number>('sidebarWidth');\nconst sidebarCollapsedShowTitle = defineModel<boolean>(\n  'sidebarCollapsedShowTitle',\n);\nconst sidebarAutoActivateChild = defineModel<boolean>(\n  'sidebarAutoActivateChild',\n);\nconst sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');\nconst sidebarExpandOnHover = defineModel<boolean>('sidebarExpandOnHover');\n\nconst sidebarButtons = defineModel<string[]>('sidebarButtons', { default: [] });\nconst sidebarCollapsedButton = defineModel<boolean>('sidebarCollapsedButton');\nconst sidebarFixedButton = defineModel<boolean>('sidebarFixedButton');\n\nonMounted(() => {\n  if (\n    sidebarCollapsedButton.value &&\n    !sidebarButtons.value.includes('collapsed')\n  ) {\n    sidebarButtons.value.push('collapsed');\n  }\n  if (sidebarFixedButton.value && !sidebarButtons.value.includes('fixed')) {\n    sidebarButtons.value.push('fixed');\n  }\n});\n\nconst handleCheckboxChange = () => {\n  sidebarCollapsedButton.value = !!sidebarButtons.value.includes('collapsed');\n  sidebarFixedButton.value = !!sidebarButtons.value.includes('fixed');\n};\n</script>\n\n<template>\n  <SwitchItem v-model=\"sidebarEnable\" :disabled=\"disabled\">\n    {{ $t('preferences.sidebar.visible') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"sidebarCollapsed\" :disabled=\"!sidebarEnable || disabled\">\n    {{ $t('preferences.sidebar.collapsed') }}\n  </SwitchItem>\n  <SwitchItem\n    v-model=\"sidebarExpandOnHover\"\n    :disabled=\"!sidebarEnable || disabled || !sidebarCollapsed\"\n    :tip=\"$t('preferences.sidebar.expandOnHoverTip')\"\n  >\n    {{ $t('preferences.sidebar.expandOnHover') }}\n  </SwitchItem>\n  <SwitchItem\n    v-model=\"sidebarCollapsedShowTitle\"\n    :disabled=\"!sidebarEnable || disabled || !sidebarCollapsed\"\n  >\n    {{ $t('preferences.sidebar.collapsedShowTitle') }}\n  </SwitchItem>\n  <SwitchItem\n    v-model=\"sidebarAutoActivateChild\"\n    :disabled=\"\n      !sidebarEnable ||\n      !['sidebar-mixed-nav', 'mixed-nav', 'header-mixed-nav'].includes(\n        currentLayout as string,\n      ) ||\n      disabled\n    \"\n    :tip=\"$t('preferences.sidebar.autoActivateChildTip')\"\n  >\n    {{ $t('preferences.sidebar.autoActivateChild') }}\n  </SwitchItem>\n  <CheckboxItem\n    :items=\"[\n      { label: $t('preferences.sidebar.buttonCollapsed'), value: 'collapsed' },\n      { label: $t('preferences.sidebar.buttonFixed'), value: 'fixed' },\n    ]\"\n    multiple\n    v-model=\"sidebarButtons\"\n    :on-btn-click=\"handleCheckboxChange\"\n  >\n    {{ $t('preferences.sidebar.buttons') }}\n  </CheckboxItem>\n  <NumberFieldItem\n    v-model=\"sidebarWidth\"\n    :disabled=\"!sidebarEnable || disabled\"\n    :max=\"320\"\n    :min=\"160\"\n    :step=\"10\"\n  >\n    {{ $t('preferences.sidebar.width') }}\n  </NumberFieldItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { computed } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport NumberFieldItem from '../number-field-item.vue';\nimport SelectItem from '../select-item.vue';\nimport SwitchItem from '../switch-item.vue';\n\ndefineOptions({\n  name: 'PreferenceTabsConfig',\n});\n\ndefineProps<{ disabled?: boolean }>();\n\nconst tabbarEnable = defineModel<boolean>('tabbarEnable');\nconst tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');\nconst tabbarPersist = defineModel<boolean>('tabbarPersist');\nconst tabbarDraggable = defineModel<boolean>('tabbarDraggable');\nconst tabbarWheelable = defineModel<boolean>('tabbarWheelable');\nconst tabbarStyleType = defineModel<string>('tabbarStyleType');\nconst tabbarShowMore = defineModel<boolean>('tabbarShowMore');\nconst tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');\nconst tabbarMaxCount = defineModel<number>('tabbarMaxCount');\nconst tabbarMiddleClickToClose = defineModel<boolean>(\n  'tabbarMiddleClickToClose',\n);\n\nconst styleItems = computed((): SelectOption[] => [\n  {\n    label: $t('preferences.tabbar.styleType.chrome'),\n    value: 'chrome',\n  },\n  {\n    label: $t('preferences.tabbar.styleType.plain'),\n    value: 'plain',\n  },\n  {\n    label: $t('preferences.tabbar.styleType.card'),\n    value: 'card',\n  },\n\n  {\n    label: $t('preferences.tabbar.styleType.brisk'),\n    value: 'brisk',\n  },\n]);\n</script>\n\n<template>\n  <SwitchItem v-model=\"tabbarEnable\" :disabled=\"disabled\">\n    {{ $t('preferences.tabbar.enable') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"tabbarPersist\" :disabled=\"!tabbarEnable\">\n    {{ $t('preferences.tabbar.persist') }}\n  </SwitchItem>\n  <NumberFieldItem\n    v-model=\"tabbarMaxCount\"\n    :disabled=\"!tabbarEnable\"\n    :max=\"30\"\n    :min=\"0\"\n    :step=\"5\"\n    :tip=\"$t('preferences.tabbar.maxCountTip')\"\n  >\n    {{ $t('preferences.tabbar.maxCount') }}\n  </NumberFieldItem>\n  <SwitchItem v-model=\"tabbarDraggable\" :disabled=\"!tabbarEnable\">\n    {{ $t('preferences.tabbar.draggable') }}\n  </SwitchItem>\n  <SwitchItem\n    v-model=\"tabbarWheelable\"\n    :disabled=\"!tabbarEnable\"\n    :tip=\"$t('preferences.tabbar.wheelableTip')\"\n  >\n    {{ $t('preferences.tabbar.wheelable') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"tabbarMiddleClickToClose\" :disabled=\"!tabbarEnable\">\n    {{ $t('preferences.tabbar.middleClickClose') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"tabbarShowIcon\" :disabled=\"!tabbarEnable\">\n    {{ $t('preferences.tabbar.icon') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"tabbarShowMore\" :disabled=\"!tabbarEnable\">\n    {{ $t('preferences.tabbar.showMore') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"tabbarShowMaximize\" :disabled=\"!tabbarEnable\">\n    {{ $t('preferences.tabbar.showMaximize') }}\n  </SwitchItem>\n  <SelectItem v-model=\"tabbarStyleType\" :items=\"styleItems\">\n    {{ $t('preferences.tabbar.styleType.title') }}\n  </SelectItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { computed } from 'vue';\n\nimport { $t } from '@vben/locales';\n\nimport SelectItem from '../select-item.vue';\nimport SwitchItem from '../switch-item.vue';\n\ndefineOptions({\n  name: 'PreferenceInterfaceControl',\n});\n\nconst widgetGlobalSearch = defineModel<boolean>('widgetGlobalSearch');\nconst widgetFullscreen = defineModel<boolean>('widgetFullscreen');\nconst widgetLanguageToggle = defineModel<boolean>('widgetLanguageToggle');\nconst widgetNotification = defineModel<boolean>('widgetNotification');\nconst widgetThemeToggle = defineModel<boolean>('widgetThemeToggle');\nconst widgetSidebarToggle = defineModel<boolean>('widgetSidebarToggle');\nconst widgetLockScreen = defineModel<boolean>('widgetLockScreen');\nconst appPreferencesButtonPosition = defineModel<string>(\n  'appPreferencesButtonPosition',\n);\nconst widgetRefresh = defineModel<boolean>('widgetRefresh');\n\nconst positionItems = computed((): SelectOption[] => [\n  {\n    label: $t('preferences.position.auto'),\n    value: 'auto',\n  },\n  {\n    label: $t('preferences.position.header'),\n    value: 'header',\n  },\n  {\n    label: $t('preferences.position.fixed'),\n    value: 'fixed',\n  },\n]);\n</script>\n\n<template>\n  <SwitchItem v-model=\"widgetGlobalSearch\">\n    {{ $t('preferences.widget.globalSearch') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"widgetThemeToggle\">\n    {{ $t('preferences.widget.themeToggle') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"widgetLanguageToggle\">\n    {{ $t('preferences.widget.languageToggle') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"widgetFullscreen\">\n    {{ $t('preferences.widget.fullscreen') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"widgetNotification\">\n    {{ $t('preferences.widget.notification') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"widgetLockScreen\">\n    {{ $t('preferences.widget.lockScreen') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"widgetSidebarToggle\">\n    {{ $t('preferences.widget.sidebarToggle') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"widgetRefresh\">\n    {{ $t('preferences.widget.refresh') }}\n  </SwitchItem>\n  <SelectItem v-model=\"appPreferencesButtonPosition\" :items=\"positionItems\">\n    {{ $t('preferences.position.title') }}\n  </SelectItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { useSlots } from 'vue';\n\nimport { CircleHelp } from '@vben/icons';\n\nimport {\n  NumberField,\n  NumberFieldContent,\n  NumberFieldDecrement,\n  NumberFieldIncrement,\n  NumberFieldInput,\n  VbenTooltip,\n} from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'PreferenceSelectItem',\n});\n\nwithDefaults(\n  defineProps<{\n    disabled?: boolean;\n    items?: SelectOption[];\n    placeholder?: string;\n    tip?: string;\n  }>(),\n  {\n    disabled: false,\n    placeholder: '',\n    tip: '',\n    items: () => [],\n  },\n);\n\nconst inputValue = defineModel<number>();\n\nconst slots = useSlots();\n</script>\n\n<template>\n  <div\n    :class=\"{\n      'hover:bg-accent': !slots.tip,\n      'pointer-events-none opacity-50': disabled,\n    }\"\n    class=\"my-1 flex w-full items-center justify-between rounded-md px-2 py-1\"\n  >\n    <span class=\"flex items-center text-sm\">\n      <slot></slot>\n\n      <VbenTooltip v-if=\"slots.tip || tip\" side=\"bottom\">\n        <template #trigger>\n          <CircleHelp class=\"ml-1 size-3 cursor-help\" />\n        </template>\n        <slot name=\"tip\">\n          <template v-if=\"tip\">\n            <p v-for=\"(line, index) in tip.split('\\n')\" :key=\"index\">\n              {{ line }}\n            </p>\n          </template>\n        </slot>\n      </VbenTooltip>\n    </span>\n\n    <NumberField v-model=\"inputValue\" v-bind=\"$attrs\" class=\"w-[165px]\">\n      <NumberFieldContent>\n        <NumberFieldDecrement />\n        <NumberFieldInput />\n        <NumberFieldIncrement />\n      </NumberFieldContent>\n    </NumberField>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { useSlots } from 'vue';\n\nimport { CircleHelp } from '@vben/icons';\n\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n  VbenTooltip,\n} from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'PreferenceSelectItem',\n});\n\nwithDefaults(\n  defineProps<{\n    disabled?: boolean;\n    items?: SelectOption[];\n    placeholder?: string;\n  }>(),\n  {\n    disabled: false,\n    placeholder: '',\n    items: () => [],\n  },\n);\n\nconst selectValue = defineModel<string>();\n\nconst slots = useSlots();\n</script>\n\n<template>\n  <div\n    :class=\"{\n      'hover:bg-accent': !slots.tip,\n      'pointer-events-none opacity-50': disabled,\n    }\"\n    class=\"my-1 flex w-full items-center justify-between rounded-md px-2 py-1\"\n  >\n    <span class=\"flex items-center text-sm\">\n      <slot></slot>\n\n      <VbenTooltip v-if=\"slots.tip\" side=\"bottom\">\n        <template #trigger>\n          <CircleHelp class=\"ml-1 size-3 cursor-help\" />\n        </template>\n        <slot name=\"tip\"></slot>\n      </VbenTooltip>\n    </span>\n    <Select v-model=\"selectValue\">\n      <SelectTrigger class=\"h-8 w-[165px]\">\n        <SelectValue :placeholder=\"placeholder\" />\n      </SelectTrigger>\n      <SelectContent>\n        <template v-for=\"item in items\" :key=\"item.value\">\n          <SelectItem :value=\"item.value\"> {{ item.label }} </SelectItem>\n        </template>\n      </SelectContent>\n    </Select>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\nimport { $t } from '@vben/locales';\nimport { isWindowsOs } from '@vben/utils';\n\nimport SwitchItem from '../switch-item.vue';\n\ndefineOptions({\n  name: 'PreferenceGeneralConfig',\n});\n\nconst shortcutKeysEnable = defineModel<boolean>('shortcutKeysEnable');\nconst shortcutKeysGlobalSearch = defineModel<boolean>(\n  'shortcutKeysGlobalSearch',\n);\nconst shortcutKeysLogout = defineModel<boolean>('shortcutKeysLogout');\n// const shortcutKeysPreferences = defineModel<boolean>('shortcutKeysPreferences');\nconst shortcutKeysLockScreen = defineModel<boolean>('shortcutKeysLockScreen');\n\nconst altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));\n</script>\n\n<template>\n  <SwitchItem v-model=\"shortcutKeysEnable\">\n    {{ $t('preferences.shortcutKeys.title') }}\n  </SwitchItem>\n  <SwitchItem\n    v-model=\"shortcutKeysGlobalSearch\"\n    :disabled=\"!shortcutKeysEnable\"\n  >\n    {{ $t('preferences.shortcutKeys.search') }}\n    <template #shortcut>\n      {{ isWindowsOs() ? 'Ctrl' : '⌘' }}\n      <kbd> K </kbd>\n    </template>\n  </SwitchItem>\n  <SwitchItem v-model=\"shortcutKeysLogout\" :disabled=\"!shortcutKeysEnable\">\n    {{ $t('preferences.shortcutKeys.logout') }}\n    <template #shortcut> {{ altView }} Q </template>\n  </SwitchItem>\n  <!-- <SwitchItem v-model=\"shortcutKeysPreferences\" :disabled=\"!shortcutKeysEnable\">\n    {{ $t('preferences.shortcutKeys.preferences') }}\n    <template #shortcut> {{ altView }} , </template>\n  </SwitchItem> -->\n  <SwitchItem v-model=\"shortcutKeysLockScreen\" :disabled=\"!shortcutKeysEnable\">\n    {{ $t('ui.widgets.lockScreen.title') }}\n    <template #shortcut> {{ altView }} L </template>\n  </SwitchItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue",
    "content": "<script setup lang=\"ts\">\nimport { useSlots } from 'vue';\n\nimport { CircleHelp } from '@vben/icons';\n\nimport { Switch, VbenTooltip } from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'PreferenceSwitchItem',\n});\n\nwithDefaults(defineProps<{ disabled?: boolean; tip?: string }>(), {\n  disabled: false,\n  tip: '',\n});\n\nconst checked = defineModel<boolean>();\n\nconst slots = useSlots();\n\nfunction handleClick() {\n  checked.value = !checked.value;\n}\n</script>\n\n<template>\n  <div\n    :class=\"{\n      'pointer-events-none opacity-50': disabled,\n    }\"\n    class=\"hover:bg-accent my-1 flex w-full items-center justify-between rounded-md px-2 py-2.5\"\n    @click=\"handleClick\"\n  >\n    <span class=\"flex items-center text-sm\">\n      <slot></slot>\n\n      <VbenTooltip v-if=\"slots.tip || tip\" side=\"bottom\">\n        <template #trigger>\n          <CircleHelp class=\"ml-1 size-3 cursor-help\" />\n        </template>\n        <slot name=\"tip\">\n          <template v-if=\"tip\">\n            <p v-for=\"(line, index) in tip.split('\\n')\" :key=\"index\">\n              {{ line }}\n            </p>\n          </template>\n        </slot>\n      </VbenTooltip>\n    </span>\n    <span v-if=\"$slots.shortcut\" class=\"ml-auto mr-2 text-xs opacity-60\">\n      <slot name=\"shortcut\"></slot>\n    </span>\n    <Switch v-model:checked=\"checked\" @click.stop />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue",
    "content": "<script setup lang=\"ts\">\nimport type { BuiltinThemePreset } from '@vben/preferences';\nimport type { BuiltinThemeType } from '@vben/types';\n\nimport { computed, ref, watch } from 'vue';\n\nimport { UserRoundPen } from '@vben/icons';\nimport { $t } from '@vben/locales';\nimport { BUILT_IN_THEME_PRESETS } from '@vben/preferences';\nimport { convertToHsl, TinyColor } from '@vben/utils';\n\nimport { useThrottleFn } from '@vueuse/core';\n\ndefineOptions({\n  name: 'PreferenceBuiltinTheme',\n});\n\nconst props = defineProps<{ isDark: boolean }>();\n\nconst colorInput = ref();\nconst modelValue = defineModel<BuiltinThemeType>({ default: 'default' });\nconst themeColorPrimary = defineModel<string>('themeColorPrimary');\n\nconst updateThemeColorPrimary = useThrottleFn(\n  (value: string) => {\n    themeColorPrimary.value = value;\n  },\n  300,\n  true,\n  true,\n);\n\nconst inputValue = computed(() => {\n  return new TinyColor(themeColorPrimary.value || '').toHexString();\n});\n\nconst builtinThemePresets = computed(() => {\n  return [...BUILT_IN_THEME_PRESETS];\n});\n\nfunction typeView(name: BuiltinThemeType) {\n  switch (name) {\n    case 'custom': {\n      return $t('preferences.theme.builtin.custom');\n    }\n    case 'deep-blue': {\n      return $t('preferences.theme.builtin.deepBlue');\n    }\n    case 'deep-green': {\n      return $t('preferences.theme.builtin.deepGreen');\n    }\n    case 'default': {\n      return $t('preferences.theme.builtin.default');\n    }\n    case 'gray': {\n      return $t('preferences.theme.builtin.gray');\n    }\n    case 'green': {\n      return $t('preferences.theme.builtin.green');\n    }\n\n    case 'neutral': {\n      return $t('preferences.theme.builtin.neutral');\n    }\n    case 'orange': {\n      return $t('preferences.theme.builtin.orange');\n    }\n    case 'pink': {\n      return $t('preferences.theme.builtin.pink');\n    }\n    case 'rose': {\n      return $t('preferences.theme.builtin.rose');\n    }\n    case 'sky-blue': {\n      return $t('preferences.theme.builtin.skyBlue');\n    }\n    case 'slate': {\n      return $t('preferences.theme.builtin.slate');\n    }\n    case 'violet': {\n      return $t('preferences.theme.builtin.violet');\n    }\n    case 'yellow': {\n      return $t('preferences.theme.builtin.yellow');\n    }\n    case 'zinc': {\n      return $t('preferences.theme.builtin.zinc');\n    }\n  }\n}\n\nfunction handleSelect(theme: BuiltinThemePreset) {\n  modelValue.value = theme.type;\n}\n\nfunction handleInputChange(e: Event) {\n  const target = e.target as HTMLInputElement;\n  updateThemeColorPrimary(convertToHsl(target.value));\n}\n\nfunction selectColor() {\n  colorInput.value?.[0]?.click?.();\n}\n\nwatch(\n  () => [modelValue.value, props.isDark] as [BuiltinThemeType, boolean],\n  ([themeType, isDark], [_, isDarkPrev]) => {\n    const theme = builtinThemePresets.value.find(\n      (item) => item.type === themeType,\n    );\n    if (theme) {\n      const primaryColor = isDark\n        ? theme.darkPrimaryColor || theme.primaryColor\n        : theme.primaryColor;\n\n      if (!(theme.type === 'custom' && isDark !== isDarkPrev)) {\n        themeColorPrimary.value = primaryColor || theme.color;\n      }\n    }\n  },\n);\n</script>\n\n<template>\n  <div class=\"flex w-full flex-wrap justify-between\">\n    <template v-for=\"theme in builtinThemePresets\" :key=\"theme.type\">\n      <div class=\"flex cursor-pointer flex-col\" @click=\"handleSelect(theme)\">\n        <div\n          :class=\"{\n            'outline-box-active': theme.type === modelValue,\n          }\"\n          class=\"outline-box flex-center group cursor-pointer\"\n        >\n          <template v-if=\"theme.type !== 'custom'\">\n            <div\n              :style=\"{ backgroundColor: theme.color }\"\n              class=\"mx-9 my-2 size-5 rounded-md\"\n            ></div>\n          </template>\n          <template v-else>\n            <div class=\"size-full px-9 py-2\" @click.stop=\"selectColor\">\n              <div class=\"flex-center relative size-5 rounded-sm\">\n                <UserRoundPen\n                  class=\"z-1 absolute size-5 opacity-60 group-hover:opacity-100\"\n                />\n                <input\n                  ref=\"colorInput\"\n                  :value=\"inputValue\"\n                  class=\"absolute inset-0 opacity-0\"\n                  type=\"color\"\n                  @input=\"handleInputChange\"\n                />\n              </div>\n            </div>\n          </template>\n        </div>\n        <div class=\"text-muted-foreground my-2 text-center text-xs\">\n          {{ typeView(theme.type) }}\n        </div>\n      </div>\n    </template>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue",
    "content": "<script setup lang=\"ts\">\nimport { $t } from '@vben/locales';\n\nimport SwitchItem from '../switch-item.vue';\n\ndefineOptions({\n  name: 'PreferenceColorMode',\n});\n\nconst appColorWeakMode = defineModel<boolean>('appColorWeakMode', {\n  default: false,\n});\n\nconst appColorGrayMode = defineModel<boolean>('appColorGrayMode', {\n  default: false,\n});\n</script>\n\n<template>\n  <SwitchItem v-model=\"appColorWeakMode\">\n    {{ $t('preferences.theme.weakMode') }}\n  </SwitchItem>\n  <SwitchItem v-model=\"appColorGrayMode\">\n    {{ $t('preferences.theme.grayMode') }}\n  </SwitchItem>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue",
    "content": "<script setup lang=\"ts\">\nimport { ToggleGroup, ToggleGroupItem } from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'PreferenceColorMode',\n});\n\nconst modelValue = defineModel<string | undefined>('themeRadius', {\n  default: '0.5',\n});\n\nconst items = [\n  { label: '0', value: '0' },\n  { label: '0.25', value: '0.25' },\n  { label: '0.5', value: '0.5' },\n  { label: '0.75', value: '0.75' },\n  { label: '1', value: '1' },\n];\n</script>\n\n<template>\n  <ToggleGroup\n    v-model=\"modelValue\"\n    class=\"gap-2\"\n    size=\"sm\"\n    type=\"single\"\n    variant=\"outline\"\n  >\n    <template v-for=\"item in items\" :key=\"item.value\">\n      <ToggleGroupItem\n        :value=\"item.value\"\n        class=\"data-[state=on]:bg-primary data-[state=on]:text-primary-foreground h-7 w-16 rounded-sm\"\n      >\n        {{ item.label }}\n      </ToggleGroupItem>\n    </template>\n  </ToggleGroup>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Component } from 'vue';\n\nimport type { ThemeModeType } from '@vben/types';\n\nimport { MoonStar, Sun, SunMoon } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport SwitchItem from '../switch-item.vue';\n\ndefineOptions({\n  name: 'PreferenceTheme',\n});\n\nconst modelValue = defineModel<string>({ default: 'auto' });\nconst themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');\nconst themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');\n\nconst THEME_PRESET: Array<{ icon: Component; name: ThemeModeType }> = [\n  {\n    icon: Sun,\n    name: 'light',\n  },\n  {\n    icon: MoonStar,\n    name: 'dark',\n  },\n  {\n    icon: SunMoon,\n    name: 'auto',\n  },\n];\n\nfunction activeClass(theme: string): string[] {\n  return theme === modelValue.value ? ['outline-box-active'] : [];\n}\n\nfunction nameView(name: string) {\n  switch (name) {\n    case 'auto': {\n      return $t('preferences.followSystem');\n    }\n    case 'dark': {\n      return $t('preferences.theme.dark');\n    }\n    case 'light': {\n      return $t('preferences.theme.light');\n    }\n  }\n}\n</script>\n\n<template>\n  <div class=\"flex w-full flex-wrap justify-between\">\n    <template v-for=\"theme in THEME_PRESET\" :key=\"theme.name\">\n      <div\n        class=\"flex cursor-pointer flex-col\"\n        @click=\"modelValue = theme.name\"\n      >\n        <div\n          :class=\"activeClass(theme.name)\"\n          class=\"outline-box flex-center py-4\"\n        >\n          <component :is=\"theme.icon\" class=\"mx-9 size-5\" />\n        </div>\n        <div class=\"text-muted-foreground mt-2 text-center text-xs\">\n          {{ nameView(theme.name) }}\n        </div>\n      </div>\n    </template>\n\n    <SwitchItem\n      v-model=\"themeSemiDarkSidebar\"\n      :disabled=\"modelValue === 'dark'\"\n      class=\"mt-6\"\n    >\n      {{ $t('preferences.theme.darkSidebar') }}\n    </SwitchItem>\n    <SwitchItem v-model=\"themeSemiDarkHeader\" :disabled=\"modelValue === 'dark'\">\n      {{ $t('preferences.theme.darkHeader') }}\n    </SwitchItem>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SelectOption } from '@vben/types';\n\nimport { ToggleGroup, ToggleGroupItem } from '@vben-core/shadcn-ui';\n\ndefineOptions({\n  name: 'PreferenceToggleItem',\n});\n\nwithDefaults(defineProps<{ disabled?: boolean; items?: SelectOption[] }>(), {\n  disabled: false,\n  items: () => [],\n});\n\nconst modelValue = defineModel<string>();\n</script>\n\n<template>\n  <div\n    :class=\"{\n      'pointer-events-none opacity-50': disabled,\n    }\"\n    class=\"hover:bg-accent flex w-full items-center justify-between rounded-md px-2 py-2\"\n    disabled\n  >\n    <span class=\"text-sm\">\n      <slot></slot>\n    </span>\n    <ToggleGroup\n      v-model=\"modelValue\"\n      class=\"gap-2\"\n      size=\"sm\"\n      type=\"single\"\n      variant=\"outline\"\n    >\n      <template v-for=\"item in items\" :key=\"item.value\">\n        <ToggleGroupItem\n          :value=\"item.value\"\n          class=\"data-[state=on]:bg-primary data-[state=on]:text-primary-foreground h-7 rounded-sm\"\n        >\n          {{ item.label }}\n        </ToggleGroupItem>\n      </template>\n    </ToggleGroup>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue",
    "content": "<template>\n  <svg\n    class=\"custom-radio-image\"\n    fill=\"none\"\n    height=\"66\"\n    width=\"104\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g>\n      <rect\n        id=\"svg_1\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.02\"\n        height=\"66\"\n        rx=\"4\"\n        stroke=\"null\"\n        width=\"104\"\n        x=\"0.13514\"\n        y=\"0.13514\"\n      />\n      <rect\n        id=\"svg_8\"\n        fill=\"hsl(var(--primary))\"\n        height=\"9.07027\"\n        stroke=\"null\"\n        width=\"104.07934\"\n        x=\"-0.07419\"\n        y=\"-0.05773\"\n      />\n      <rect\n        id=\"svg_3\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"15.58168\"\n        y=\"3.20832\"\n      />\n      <path\n        id=\"svg_12\"\n        d=\"m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z\"\n        fill=\"#ffffff\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_13\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.51892\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"41.98275\"\n        x=\"45.37589\"\n        y=\"13.53192\"\n      />\n      <path\n        id=\"svg_14\"\n        d=\"m16.4123,15.53192c0,-1.08676 0.74096,-2 1.62271,-2l21.74653,0c0.88175,0 1.62271,0.91324 1.62271,2l0,17.24865c0,1.08676 -0.74096,2 -1.62271,2l-21.74653,0c-0.88175,0 -1.62271,-0.91324 -1.62271,-2l0,-17.24865z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_15\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.65405\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"71.10636\"\n        x=\"16.54743\"\n        y=\"39.34689\"\n      />\n      <rect\n        id=\"svg_21\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"28.14924\"\n        y=\"3.07319\"\n      />\n      <rect\n        id=\"svg_22\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"41.25735\"\n        y=\"3.20832\"\n      />\n      <rect\n        id=\"svg_23\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"54.23033\"\n        y=\"3.07319\"\n      />\n      <rect\n        id=\"svg_4\"\n        fill=\"#ffffff\"\n        height=\"7.13843\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"7.78397\"\n        x=\"1.5327\"\n        y=\"0.881\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue",
    "content": "<template>\n  <svg\n    class=\"custom-radio-image\"\n    fill=\"none\"\n    height=\"66\"\n    width=\"104\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g>\n      <path\n        id=\"svg_1\"\n        d=\"m0.13514,4.13514c0,-2.17352 1.82648,-4 4,-4l96,0c2.17352,0 4,1.82648 4,4l0,58c0,2.17352 -1.82648,4 -4,4l-96,0c-2.17352,0 -4,-1.82648 -4,-4l0,-58z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.02\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_13\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"26.57155\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"53.18333\"\n        x=\"45.79979\"\n        y=\"3.77232\"\n      />\n      <path\n        id=\"svg_14\"\n        d=\"m4.28142,5.96169c0,-1.37748 1.06465,-2.53502 2.33158,-2.53502l31.2463,0c1.26693,0 2.33158,1.15754 2.33158,2.53502l0,21.86282c0,1.37748 -1.06465,2.53502 -2.33158,2.53502l-31.2463,0c-1.26693,0 -2.33158,-1.15754 -2.33158,-2.53502l0,-21.86282z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_15\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"25.02247\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"94.39371\"\n        x=\"4.56735\"\n        y=\"34.92584\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/header-mixed-nav.vue",
    "content": "<template>\n  <svg\n    class=\"custom-radio-image\"\n    fill=\"none\"\n    height=\"66\"\n    width=\"104\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g>\n      <rect\n        id=\"svg_1\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.02\"\n        height=\"66\"\n        rx=\"4\"\n        stroke=\"null\"\n        width=\"104\"\n        x=\"0.13514\"\n        y=\"0.13514\"\n      />\n      <path\n        id=\"svg_2\"\n        d=\"m-3.37838,3.7543a1.93401,4.02457 0 0 1 1.93401,-4.02457l11.3488,0l0,66.40541l-11.3488,0a1.93401,4.02457 0 0 1 -1.93401,-4.02457l0,-58.35627z\"\n        fill=\"hsl(var(--primary))\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_3\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"5.47439\"\n        x=\"1.64059\"\n        y=\"15.46086\"\n      />\n      <rect\n        id=\"svg_4\"\n        fill=\"#ffffff\"\n        height=\"7.67897\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"8.18938\"\n        x=\"0.58676\"\n        y=\"1.42154\"\n      />\n      <rect\n        id=\"svg_8\"\n        fill=\"hsl(var(--primary))\"\n        height=\"9.07027\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"75.91967\"\n        x=\"25.38277\"\n        y=\"1.42876\"\n      />\n      <rect\n        id=\"svg_9\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"27.91529\"\n        y=\"3.69284\"\n      />\n      <rect\n        id=\"svg_10\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"80.75054\"\n        y=\"3.62876\"\n      />\n      <rect\n        id=\"svg_11\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"87.78868\"\n        y=\"3.69981\"\n      />\n      <rect\n        id=\"svg_12\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"94.6847\"\n        y=\"3.62876\"\n      />\n      <rect\n        id=\"svg_13\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.51892\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"42.9287\"\n        x=\"58.75427\"\n        y=\"14.613\"\n      />\n      <rect\n        id=\"svg_14\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"20.97838\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"28.36894\"\n        x=\"26.14342\"\n        y=\"14.613\"\n      />\n      <rect\n        id=\"svg_15\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.65405\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"75.09493\"\n        x=\"26.34264\"\n        y=\"39.68822\"\n      />\n      <rect\n        id=\"svg_5\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"5.47439\"\n        x=\"1.79832\"\n        y=\"28.39462\"\n      />\n      <rect\n        id=\"svg_6\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"5.47439\"\n        x=\"1.64059\"\n        y=\"41.80156\"\n      />\n      <rect\n        id=\"svg_7\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"5.47439\"\n        x=\"1.64059\"\n        y=\"55.36623\"\n      />\n      <rect\n        id=\"svg_16\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"65.72065\"\n        stroke=\"null\"\n        width=\"12.49265\"\n        x=\"9.85477\"\n        y=\"-0.02618\"\n      />\n      <rect\n        id=\"svg_21\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"35.14924\"\n        y=\"4.07319\"\n      />\n      <rect\n        id=\"svg_22\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"47.25735\"\n        y=\"4.20832\"\n      />\n      <rect\n        id=\"svg_23\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"59.23033\"\n        y=\"4.07319\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue",
    "content": "<template>\n  <svg\n    class=\"custom-radio-image\"\n    fill=\"none\"\n    height=\"66\"\n    width=\"104\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g>\n      <rect\n        id=\"svg_1\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.02\"\n        height=\"66\"\n        rx=\"4\"\n        stroke=\"null\"\n        width=\"104\"\n        x=\"0.13514\"\n        y=\"0.13514\"\n      />\n      <rect\n        id=\"svg_8\"\n        fill=\"hsl(var(--primary))\"\n        height=\"9.07027\"\n        stroke=\"null\"\n        width=\"104.07934\"\n        x=\"-0.07419\"\n        y=\"-0.05773\"\n      />\n      <rect\n        id=\"svg_3\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"15.58168\"\n        y=\"3.20832\"\n      />\n      <path\n        id=\"svg_12\"\n        d=\"m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z\"\n        fill=\"#ffffff\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_13\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.51892\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"53.60438\"\n        x=\"43.484\"\n        y=\"13.66705\"\n      />\n      <path\n        id=\"svg_14\"\n        d=\"m3.43932,15.53192c0,-1.08676 1.03344,-2 2.26323,-2l30.33036,0c1.22979,0 2.26323,0.91324 2.26323,2l0,17.24865c0,1.08676 -1.03344,2 -2.26323,2l-30.33036,0c-1.22979,0 -2.26323,-0.91324 -2.26323,-2l0,-17.24865z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_15\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.65405\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"95.02528\"\n        x=\"3.30419\"\n        y=\"39.34689\"\n      />\n      <rect\n        id=\"svg_21\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"28.14924\"\n        y=\"3.07319\"\n      />\n      <rect\n        id=\"svg_22\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"41.25735\"\n        y=\"3.20832\"\n      />\n      <rect\n        id=\"svg_23\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"54.23033\"\n        y=\"3.07319\"\n      />\n      <rect\n        id=\"svg_4\"\n        fill=\"#ffffff\"\n        height=\"7.13843\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"7.78397\"\n        x=\"1.5327\"\n        y=\"0.881\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/header-sidebar-nav.vue",
    "content": "<template>\n  <svg\n    class=\"custom-radio-image\"\n    fill=\"none\"\n    height=\"66\"\n    width=\"104\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g>\n      <rect\n        id=\"svg_1\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.02\"\n        height=\"66\"\n        rx=\"4\"\n        stroke=\"null\"\n        width=\"104\"\n        x=\"0.13514\"\n        y=\"0.13514\"\n      />\n      <rect\n        id=\"svg_8\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"9.07027\"\n        stroke=\"null\"\n        width=\"104.07934\"\n        x=\"-0.07419\"\n        y=\"-0.05773\"\n      />\n      <rect\n        id=\"svg_3\"\n        fill=\"#b2b2b2\"\n        height=\"1.689\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"6.52486\"\n        x=\"10.08168\"\n        y=\"3.50832\"\n      />\n      <rect\n        id=\"svg_10\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"80.75054\"\n        y=\"2.89362\"\n      />\n      <rect\n        id=\"svg_11\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"87.58249\"\n        y=\"2.89362\"\n      />\n      <path\n        id=\"svg_12\"\n        d=\"m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z\"\n        fill=\"#ffffff\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_13\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.51892\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"44.13071\"\n        x=\"53.37873\"\n        y=\"13.45652\"\n      />\n      <path\n        id=\"svg_14\"\n        d=\"m19.4393,15.74245c0,-1.08676 0.79001,-2 1.73013,-2l23.18605,0c0.94011,0 1.73013,0.91324 1.73013,2l0,17.24865c0,1.08676 -0.79001,2 -1.73013,2l-23.18605,0c-0.94011,0 -1.73013,-0.91324 -1.73013,-2l0,-17.24865z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_15\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.65405\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"78.39372\"\n        x=\"19.93575\"\n        y=\"39.34689\"\n      />\n      <rect\n        id=\"svg_21\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"28.14924\"\n        y=\"3.07319\"\n      />\n      <rect\n        id=\"svg_22\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"41.25735\"\n        y=\"3.20832\"\n      />\n      <rect\n        id=\"svg_23\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"54.23033\"\n        y=\"3.07319\"\n      />\n      <rect\n        id=\"svg_4\"\n        fill=\"#ffffff\"\n        height=\"5.13843\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"5.78397\"\n        x=\"1.5327\"\n        y=\"1.081\"\n      />\n      <rect\n        id=\"svg_5\"\n        fill=\"hsl(var(--primary))\"\n        height=\"56.81191\"\n        stroke=\"null\"\n        width=\"15.44642\"\n        x=\"-0.06423\"\n        y=\"9.03113\"\n      />\n      <path\n        id=\"svg_2\"\n        d=\"m2.38669,15.38074c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z\"\n        fill=\"#fff\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <path\n        id=\"svg_6\"\n        d=\"m2.38669,28.43336c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z\"\n        fill=\"#fff\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <path\n        id=\"svg_7\"\n        d=\"m2.17616,41.27545c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z\"\n        fill=\"#fff\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <path\n        id=\"svg_9\"\n        d=\"m2.17616,54.32806c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z\"\n        fill=\"#fff\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/index.ts",
    "content": "import HeaderNav from './header-nav.vue';\n\nexport { default as ContentCompact } from './content-compact.vue';\nexport { default as FullContent } from './full-content.vue';\nexport { default as HeaderMixedNav } from './header-mixed-nav.vue';\nexport { default as HeaderSidebarNav } from './header-sidebar-nav.vue';\nexport { default as MixedNav } from './mixed-nav.vue';\nexport { default as SidebarMixedNav } from './sidebar-mixed-nav.vue';\nexport { default as SidebarNav } from './sidebar-nav.vue';\n\nconst ContentWide = HeaderNav;\nexport { ContentWide, HeaderNav };\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue",
    "content": "<template>\n  <svg\n    class=\"custom-radio-image\"\n    fill=\"none\"\n    height=\"66\"\n    width=\"104\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g>\n      <rect\n        id=\"svg_1\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.02\"\n        height=\"66\"\n        rx=\"4\"\n        stroke=\"null\"\n        width=\"104\"\n        x=\"0.13514\"\n        y=\"0.13514\"\n      />\n      <rect\n        id=\"svg_8\"\n        fill=\"hsl(var(--primary))\"\n        height=\"9.07027\"\n        stroke=\"null\"\n        width=\"104.07934\"\n        x=\"-0.07419\"\n        y=\"-0.05773\"\n      />\n      <rect\n        id=\"svg_3\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"15.58168\"\n        y=\"3.20832\"\n      />\n      <path\n        id=\"svg_12\"\n        d=\"m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z\"\n        fill=\"#ffffff\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_13\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.51892\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"44.13071\"\n        x=\"53.37873\"\n        y=\"13.45652\"\n      />\n      <path\n        id=\"svg_14\"\n        d=\"m19.4393,15.74245c0,-1.08676 0.79001,-2 1.73013,-2l23.18605,0c0.94011,0 1.73013,0.91324 1.73013,2l0,17.24865c0,1.08676 -0.79001,2 -1.73013,2l-23.18605,0c-0.94011,0 -1.73013,-0.91324 -1.73013,-2l0,-17.24865z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_15\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.65405\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"78.39372\"\n        x=\"19.93575\"\n        y=\"39.34689\"\n      />\n      <rect\n        id=\"svg_21\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"28.14924\"\n        y=\"3.07319\"\n      />\n      <rect\n        id=\"svg_22\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"41.25735\"\n        y=\"3.20832\"\n      />\n      <rect\n        id=\"svg_23\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"7.52486\"\n        x=\"54.23033\"\n        y=\"3.07319\"\n      />\n      <rect\n        id=\"svg_4\"\n        fill=\"#ffffff\"\n        height=\"7.13843\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"7.78397\"\n        x=\"1.5327\"\n        y=\"0.881\"\n      />\n      <rect\n        id=\"svg_5\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"56.81191\"\n        stroke=\"null\"\n        width=\"15.44642\"\n        x=\"-0.06423\"\n        y=\"9.03113\"\n      />\n      <path\n        id=\"svg_2\"\n        d=\"m2.38669,15.38074c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <path\n        id=\"svg_6\"\n        d=\"m2.38669,28.43336c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <path\n        id=\"svg_7\"\n        d=\"m2.17616,41.27545c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n      <path\n        id=\"svg_9\"\n        d=\"m2.17616,54.32806c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        opacity=\"undefined\"\n        stroke=\"null\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/setting.vue",
    "content": "<template>\n  <svg\n    height=\"1em\"\n    viewBox=\"0 0 24 24\"\n    width=\"1em\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <path\n      d=\"M19.9 12.66a1 1 0 0 1 0-1.32l1.28-1.44a1 1 0 0 0 .12-1.17l-2-3.46a1 1 0 0 0-1.07-.48l-1.88.38a1 1 0 0 1-1.15-.66l-.61-1.83a1 1 0 0 0-.95-.68h-4a1 1 0 0 0-1 .68l-.56 1.83a1 1 0 0 1-1.15.66L5 4.79a1 1 0 0 0-1 .48L2 8.73a1 1 0 0 0 .1 1.17l1.27 1.44a1 1 0 0 1 0 1.32L2.1 14.1a1 1 0 0 0-.1 1.17l2 3.46a1 1 0 0 0 1.07.48l1.88-.38a1 1 0 0 1 1.15.66l.61 1.83a1 1 0 0 0 1 .68h4a1 1 0 0 0 .95-.68l.61-1.83a1 1 0 0 1 1.15-.66l1.88.38a1 1 0 0 0 1.07-.48l2-3.46a1 1 0 0 0-.12-1.17ZM18.41 14l.8.9l-1.28 2.22l-1.18-.24a3 3 0 0 0-3.45 2L12.92 20h-2.56L10 18.86a3 3 0 0 0-3.45-2l-1.18.24l-1.3-2.21l.8-.9a3 3 0 0 0 0-4l-.8-.9l1.28-2.2l1.18.24a3 3 0 0 0 3.45-2L10.36 4h2.56l.38 1.14a3 3 0 0 0 3.45 2l1.18-.24l1.28 2.22l-.8.9a3 3 0 0 0 0 3.98m-6.77-6a4 4 0 1 0 4 4a4 4 0 0 0-4-4m0 6a2 2 0 1 1 2-2a2 2 0 0 1-2 2\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue",
    "content": "<template>\n  <svg\n    class=\"custom-radio-image\"\n    fill=\"none\"\n    height=\"66\"\n    width=\"104\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g>\n      <rect\n        id=\"svg_1\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.02\"\n        height=\"66\"\n        rx=\"4\"\n        stroke=\"null\"\n        width=\"104\"\n        x=\"0.13514\"\n        y=\"0.13514\"\n      />\n      <path\n        id=\"svg_2\"\n        d=\"m-3.37838,3.7543a1.93401,4.02457 0 0 1 1.93401,-4.02457l11.3488,0l0,66.40541l-11.3488,0a1.93401,4.02457 0 0 1 -1.93401,-4.02457l0,-58.35627z\"\n        fill=\"hsl(var(--primary))\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_3\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"5.47439\"\n        x=\"1.64059\"\n        y=\"15.46086\"\n      />\n      <rect\n        id=\"svg_4\"\n        fill=\"#ffffff\"\n        height=\"7.67897\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"8.18938\"\n        x=\"0.58676\"\n        y=\"1.42154\"\n      />\n      <rect\n        id=\"svg_8\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"9.07027\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"75.91967\"\n        x=\"25.38277\"\n        y=\"1.42876\"\n      />\n      <rect\n        id=\"svg_9\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"27.91529\"\n        y=\"3.69284\"\n      />\n      <rect\n        id=\"svg_10\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"80.75054\"\n        y=\"3.62876\"\n      />\n      <rect\n        id=\"svg_11\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"87.78868\"\n        y=\"3.69981\"\n      />\n      <rect\n        id=\"svg_12\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"94.6847\"\n        y=\"3.62876\"\n      />\n      <rect\n        id=\"svg_13\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.51892\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"42.9287\"\n        x=\"58.75427\"\n        y=\"14.613\"\n      />\n      <rect\n        id=\"svg_14\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"20.97838\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"28.36894\"\n        x=\"26.14342\"\n        y=\"14.613\"\n      />\n      <rect\n        id=\"svg_15\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.65405\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"75.09493\"\n        x=\"26.34264\"\n        y=\"39.68822\"\n      />\n      <rect\n        id=\"svg_5\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"5.47439\"\n        x=\"1.79832\"\n        y=\"28.39462\"\n      />\n      <rect\n        id=\"svg_6\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"5.47439\"\n        x=\"1.64059\"\n        y=\"41.80156\"\n      />\n      <rect\n        id=\"svg_7\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        stroke=\"null\"\n        width=\"5.47439\"\n        x=\"1.64059\"\n        y=\"55.36623\"\n      />\n      <rect\n        id=\"svg_16\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"65.72065\"\n        stroke=\"null\"\n        width=\"12.49265\"\n        x=\"9.85477\"\n        y=\"-0.02618\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue",
    "content": "<template>\n  <svg\n    class=\"custom-radio-image\"\n    fill=\"none\"\n    height=\"66\"\n    width=\"104\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g>\n      <rect\n        id=\"svg_1\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.02\"\n        height=\"66\"\n        rx=\"4\"\n        stroke=\"null\"\n        width=\"104\"\n      />\n      <path\n        id=\"svg_2\"\n        d=\"m-3.37838,3.61916a4.4919,4.02457 0 0 1 4.4919,-4.02457l26.35848,0l0,66.40541l-26.35848,0a4.4919,4.02457 0 0 1 -4.4919,-4.02457l0,-58.35627z\"\n        fill=\"hsl(var(--primary))\"\n        stroke=\"null\"\n      />\n      <rect\n        id=\"svg_3\"\n        fill=\"#e5e5e5\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        width=\"17.66\"\n        x=\"4.906\"\n        y=\"23.884\"\n      />\n      <rect\n        id=\"svg_4\"\n        fill=\"#ffffff\"\n        height=\"9.706\"\n        rx=\"2\"\n        width=\"9.811\"\n        x=\"8.83\"\n        y=\"5.881\"\n      />\n      <path\n        id=\"svg_5\"\n        d=\"m4.906,35.833c0,-0.75801 0.63699,-1.395 1.395,-1.395l14.87,0c0.75801,0 1.395,0.63699 1.395,1.395l0,-0.001c0,0.75801 -0.63699,1.395 -1.395,1.395l-14.87,0c-0.75801,0 -1.395,-0.63699 -1.395,-1.395l0,0.001z\"\n        fill=\"#ffffff\"\n        opacity=\"undefined\"\n      />\n      <rect\n        id=\"svg_6\"\n        fill=\"#ffffff\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        width=\"17.66\"\n        x=\"4.906\"\n        y=\"44.992\"\n      />\n      <rect\n        id=\"svg_7\"\n        fill=\"#ffffff\"\n        height=\"2.789\"\n        rx=\"1.395\"\n        width=\"17.66\"\n        x=\"4.906\"\n        y=\"55.546\"\n      />\n      <rect\n        id=\"svg_8\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"9.07027\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"73.53879\"\n        x=\"28.97986\"\n        y=\"1.42876\"\n      />\n      <rect\n        id=\"svg_9\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"32.039\"\n        y=\"3.89903\"\n      />\n      <rect\n        id=\"svg_10\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"80.75054\"\n        y=\"3.62876\"\n      />\n      <rect\n        id=\"svg_11\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"87.58249\"\n        y=\"3.49362\"\n      />\n      <rect\n        id=\"svg_12\"\n        fill=\"#b2b2b2\"\n        height=\"4.4\"\n        rx=\"1\"\n        stroke=\"null\"\n        width=\"3.925\"\n        x=\"94.6847\"\n        y=\"3.62876\"\n      />\n      <rect\n        id=\"svg_13\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.51892\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"45.63141\"\n        x=\"56.05157\"\n        y=\"14.613\"\n      />\n      <rect\n        id=\"svg_14\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"20.97838\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"22.82978\"\n        x=\"29.38527\"\n        y=\"14.613\"\n      />\n      <rect\n        id=\"svg_15\"\n        fill=\"currentColor\"\n        fill-opacity=\"0.08\"\n        height=\"21.65405\"\n        rx=\"2\"\n        stroke=\"null\"\n        width=\"72.45771\"\n        x=\"28.97986\"\n        y=\"39.48203\"\n      />\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/index.ts",
    "content": "export { default as PreferencesButton } from './preferences-button.vue';\nexport { default as Preferences } from './preferences.vue';\nexport * from './use-open-preferences';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/preferences-button.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Settings } from '@vben/icons';\n\nimport { VbenIconButton } from '@vben-core/shadcn-ui';\n\nimport Preferences from './preferences.vue';\n\nconst emit = defineEmits<{ clearPreferencesAndLogout: [] }>();\n\nfunction clearPreferencesAndLogout() {\n  emit('clearPreferencesAndLogout');\n}\n</script>\n<template>\n  <Preferences @clear-preferences-and-logout=\"clearPreferencesAndLogout\">\n    <VbenIconButton class=\"hover:animate-[shrink_0.3s_ease-in-out]\">\n      <Settings class=\"text-foreground size-4\" />\n    </VbenIconButton>\n  </Preferences>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue",
    "content": "<script setup lang=\"ts\">\nimport type { SupportedLanguagesType } from '@vben/locales';\nimport type {\n  BreadcrumbStyleType,\n  BuiltinThemeType,\n  ContentCompactType,\n  LayoutHeaderMenuAlignType,\n  LayoutHeaderModeType,\n  LayoutType,\n  NavigationStyleType,\n  PreferencesButtonPositionType,\n  ThemeModeType,\n} from '@vben/types';\n\nimport type { SegmentedItem } from '@vben-core/shadcn-ui';\n\nimport { computed, ref } from 'vue';\n\nimport { Copy, Pin, PinOff, RotateCw } from '@vben/icons';\nimport { $t, loadLocaleMessages } from '@vben/locales';\nimport {\n  clearPreferencesCache,\n  preferences,\n  resetPreferences,\n  usePreferences,\n} from '@vben/preferences';\n\nimport { useVbenDrawer } from '@vben-core/popup-ui';\nimport {\n  VbenButton,\n  VbenIconButton,\n  VbenSegmented,\n} from '@vben-core/shadcn-ui';\nimport { globalShareState } from '@vben-core/shared/global-state';\n\nimport { useClipboard } from '@vueuse/core';\n\nimport {\n  Animation,\n  Block,\n  Breadcrumb,\n  BuiltinTheme,\n  ColorMode,\n  Content,\n  Copyright,\n  Footer,\n  General,\n  GlobalShortcutKeys,\n  Header,\n  Layout,\n  Navigation,\n  Radius,\n  Sidebar,\n  Tabbar,\n  Theme,\n  Widget,\n} from './blocks';\n\nconst emit = defineEmits<{ clearPreferencesAndLogout: [] }>();\n\nconst message = globalShareState.getMessage();\n\nconst appLocale = defineModel<SupportedLanguagesType>('appLocale');\nconst appDynamicTitle = defineModel<boolean>('appDynamicTitle');\nconst appLayout = defineModel<LayoutType>('appLayout');\nconst appColorGrayMode = defineModel<boolean>('appColorGrayMode');\nconst appColorWeakMode = defineModel<boolean>('appColorWeakMode');\nconst appContentCompact = defineModel<ContentCompactType>('appContentCompact');\nconst appWatermark = defineModel<boolean>('appWatermark');\nconst appWatermarkContent = defineModel<string>('appWatermarkContent');\nconst appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');\nconst appEnableStickyPreferencesNavigationBar = defineModel<boolean>(\n  'appEnableStickyPreferencesNavigationBar',\n);\nconst appPreferencesButtonPosition = defineModel<PreferencesButtonPositionType>(\n  'appPreferencesButtonPosition',\n);\n\nconst transitionProgress = defineModel<boolean>('transitionProgress');\nconst transitionName = defineModel<string>('transitionName');\nconst transitionLoading = defineModel<boolean>('transitionLoading');\nconst transitionEnable = defineModel<boolean>('transitionEnable');\n\nconst themeColorPrimary = defineModel<string>('themeColorPrimary');\nconst themeBuiltinType = defineModel<BuiltinThemeType>('themeBuiltinType');\nconst themeMode = defineModel<ThemeModeType>('themeMode');\nconst themeRadius = defineModel<string>('themeRadius');\nconst themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');\nconst themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');\n\nconst sidebarEnable = defineModel<boolean>('sidebarEnable');\nconst sidebarWidth = defineModel<number>('sidebarWidth');\nconst sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');\nconst sidebarCollapsedShowTitle = defineModel<boolean>(\n  'sidebarCollapsedShowTitle',\n);\nconst sidebarAutoActivateChild = defineModel<boolean>(\n  'sidebarAutoActivateChild',\n);\nconst sidebarExpandOnHover = defineModel<boolean>('sidebarExpandOnHover');\nconst sidebarCollapsedButton = defineModel<boolean>('sidebarCollapsedButton');\nconst sidebarFixedButton = defineModel<boolean>('sidebarFixedButton');\nconst headerEnable = defineModel<boolean>('headerEnable');\nconst headerMode = defineModel<LayoutHeaderModeType>('headerMode');\nconst headerMenuAlign =\n  defineModel<LayoutHeaderMenuAlignType>('headerMenuAlign');\n\nconst breadcrumbEnable = defineModel<boolean>('breadcrumbEnable');\nconst breadcrumbShowIcon = defineModel<boolean>('breadcrumbShowIcon');\nconst breadcrumbShowHome = defineModel<boolean>('breadcrumbShowHome');\nconst breadcrumbStyleType = defineModel<BreadcrumbStyleType>(\n  'breadcrumbStyleType',\n);\nconst breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne');\n\nconst tabbarEnable = defineModel<boolean>('tabbarEnable');\nconst tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');\nconst tabbarShowMore = defineModel<boolean>('tabbarShowMore');\nconst tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');\nconst tabbarPersist = defineModel<boolean>('tabbarPersist');\nconst tabbarDraggable = defineModel<boolean>('tabbarDraggable');\nconst tabbarWheelable = defineModel<boolean>('tabbarWheelable');\nconst tabbarStyleType = defineModel<string>('tabbarStyleType');\nconst tabbarMaxCount = defineModel<number>('tabbarMaxCount');\nconst tabbarMiddleClickToClose = defineModel<boolean>(\n  'tabbarMiddleClickToClose',\n);\n\nconst navigationStyleType = defineModel<NavigationStyleType>(\n  'navigationStyleType',\n);\nconst navigationSplit = defineModel<boolean>('navigationSplit');\nconst navigationAccordion = defineModel<boolean>('navigationAccordion');\n\n// const logoVisible = defineModel<boolean>('logoVisible');\n\nconst footerEnable = defineModel<boolean>('footerEnable');\nconst footerFixed = defineModel<boolean>('footerFixed');\n\nconst copyrightSettingShow = defineModel<boolean>('copyrightSettingShow');\nconst copyrightEnable = defineModel<boolean>('copyrightEnable');\nconst copyrightCompanyName = defineModel<string>('copyrightCompanyName');\nconst copyrightCompanySiteLink = defineModel<string>(\n  'copyrightCompanySiteLink',\n);\nconst copyrightDate = defineModel<string>('copyrightDate');\nconst copyrightIcp = defineModel<string>('copyrightIcp');\nconst copyrightIcpLink = defineModel<string>('copyrightIcpLink');\n\nconst shortcutKeysEnable = defineModel<boolean>('shortcutKeysEnable');\nconst shortcutKeysGlobalSearch = defineModel<boolean>(\n  'shortcutKeysGlobalSearch',\n);\nconst shortcutKeysGlobalLogout = defineModel<boolean>(\n  'shortcutKeysGlobalLogout',\n);\n\nconst shortcutKeysGlobalLockScreen = defineModel<boolean>(\n  'shortcutKeysGlobalLockScreen',\n);\n\nconst widgetGlobalSearch = defineModel<boolean>('widgetGlobalSearch');\nconst widgetFullscreen = defineModel<boolean>('widgetFullscreen');\nconst widgetLanguageToggle = defineModel<boolean>('widgetLanguageToggle');\nconst widgetNotification = defineModel<boolean>('widgetNotification');\nconst widgetThemeToggle = defineModel<boolean>('widgetThemeToggle');\nconst widgetSidebarToggle = defineModel<boolean>('widgetSidebarToggle');\nconst widgetLockScreen = defineModel<boolean>('widgetLockScreen');\nconst widgetRefresh = defineModel<boolean>('widgetRefresh');\n\nconst {\n  diffPreference,\n  isDark,\n  isFullContent,\n  isHeaderNav,\n  isHeaderSidebarNav,\n  isMixedNav,\n  isSideMixedNav,\n  isSideMode,\n  isSideNav,\n} = usePreferences();\nconst { copy } = useClipboard({ legacy: true });\n\nconst [Drawer] = useVbenDrawer();\n\nconst activeTab = ref('appearance');\n\nconst tabs = computed((): SegmentedItem[] => {\n  return [\n    {\n      label: $t('preferences.appearance'),\n      value: 'appearance',\n    },\n    {\n      label: $t('preferences.layout'),\n      value: 'layout',\n    },\n    {\n      label: $t('preferences.shortcutKeys.title'),\n      value: 'shortcutKey',\n    },\n    {\n      label: $t('preferences.general'),\n      value: 'general',\n    },\n  ];\n});\n\nconst showBreadcrumbConfig = computed(() => {\n  return (\n    !isFullContent.value &&\n    !isMixedNav.value &&\n    !isHeaderNav.value &&\n    preferences.header.enable\n  );\n});\n\nasync function handleCopy() {\n  await copy(JSON.stringify(diffPreference.value, null, 2));\n\n  message.copyPreferencesSuccess?.(\n    $t('preferences.copyPreferencesSuccessTitle'),\n    $t('preferences.copyPreferencesSuccess'),\n  );\n}\n\nasync function handleClearCache() {\n  resetPreferences();\n  clearPreferencesCache();\n  emit('clearPreferencesAndLogout');\n}\n\nasync function handleReset() {\n  if (!diffPreference.value) {\n    return;\n  }\n  resetPreferences();\n  await loadLocaleMessages(preferences.app.locale);\n}\n</script>\n\n<template>\n  <div>\n    <Drawer\n      :description=\"$t('preferences.subtitle')\"\n      :title=\"$t('preferences.title')\"\n      class=\"!border-0 sm:max-w-sm\"\n    >\n      <template #extra>\n        <div class=\"flex items-center\">\n          <VbenIconButton\n            :disabled=\"!diffPreference\"\n            :tooltip=\"$t('preferences.resetTip')\"\n            class=\"relative\"\n            @click=\"handleReset\"\n          >\n            <span\n              v-if=\"diffPreference\"\n              class=\"bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded\"\n            ></span>\n            <RotateCw class=\"size-4\" />\n          </VbenIconButton>\n          <VbenIconButton\n            :tooltip=\"\n              appEnableStickyPreferencesNavigationBar\n                ? $t('preferences.disableStickyPreferencesNavigationBar')\n                : $t('preferences.enableStickyPreferencesNavigationBar')\n            \"\n            class=\"relative\"\n            @click=\"\n              () =>\n                (appEnableStickyPreferencesNavigationBar =\n                  !appEnableStickyPreferencesNavigationBar)\n            \"\n          >\n            <PinOff\n              v-if=\"appEnableStickyPreferencesNavigationBar\"\n              class=\"size-4\"\n            />\n            <Pin v-else class=\"size-4\" />\n          </VbenIconButton>\n        </div>\n      </template>\n\n      <div>\n        <VbenSegmented\n          v-model=\"activeTab\"\n          :tabs=\"tabs\"\n          :class=\"{\n            'sticky-tabs-header': appEnableStickyPreferencesNavigationBar,\n          }\"\n        >\n          <template #general>\n            <Block :title=\"$t('preferences.general')\">\n              <General\n                v-model:app-dynamic-title=\"appDynamicTitle\"\n                v-model:app-enable-check-updates=\"appEnableCheckUpdates\"\n                v-model:app-locale=\"appLocale\"\n                v-model:app-watermark=\"appWatermark\"\n                v-model:app-watermark-content=\"appWatermarkContent\"\n              />\n            </Block>\n\n            <Block :title=\"$t('preferences.animation.title')\">\n              <Animation\n                v-model:transition-enable=\"transitionEnable\"\n                v-model:transition-loading=\"transitionLoading\"\n                v-model:transition-name=\"transitionName\"\n                v-model:transition-progress=\"transitionProgress\"\n              />\n            </Block>\n          </template>\n          <template #appearance>\n            <Block :title=\"$t('preferences.theme.title')\">\n              <Theme\n                v-model=\"themeMode\"\n                v-model:theme-semi-dark-header=\"themeSemiDarkHeader\"\n                v-model:theme-semi-dark-sidebar=\"themeSemiDarkSidebar\"\n              />\n            </Block>\n            <Block :title=\"$t('preferences.theme.builtin.title')\">\n              <BuiltinTheme\n                v-model=\"themeBuiltinType\"\n                v-model:theme-color-primary=\"themeColorPrimary\"\n                :is-dark=\"isDark\"\n              />\n            </Block>\n            <Block :title=\"$t('preferences.theme.radius')\">\n              <Radius v-model=\"themeRadius\" />\n            </Block>\n            <Block :title=\"$t('preferences.other')\">\n              <ColorMode\n                v-model:app-color-gray-mode=\"appColorGrayMode\"\n                v-model:app-color-weak-mode=\"appColorWeakMode\"\n              />\n            </Block>\n          </template>\n          <template #layout>\n            <Block :title=\"$t('preferences.layout')\">\n              <Layout v-model=\"appLayout\" />\n            </Block>\n            <Block :title=\"$t('preferences.content')\">\n              <Content v-model=\"appContentCompact\" />\n            </Block>\n\n            <Block :title=\"$t('preferences.sidebar.title')\">\n              <Sidebar\n                v-model:sidebar-auto-activate-child=\"sidebarAutoActivateChild\"\n                v-model:sidebar-collapsed=\"sidebarCollapsed\"\n                v-model:sidebar-collapsed-show-title=\"sidebarCollapsedShowTitle\"\n                v-model:sidebar-enable=\"sidebarEnable\"\n                v-model:sidebar-expand-on-hover=\"sidebarExpandOnHover\"\n                v-model:sidebar-width=\"sidebarWidth\"\n                v-model:sidebar-collapsed-button=\"sidebarCollapsedButton\"\n                v-model:sidebar-fixed-button=\"sidebarFixedButton\"\n                :current-layout=\"appLayout\"\n                :disabled=\"!isSideMode\"\n              />\n            </Block>\n\n            <Block :title=\"$t('preferences.header.title')\">\n              <Header\n                v-model:header-enable=\"headerEnable\"\n                v-model:header-menu-align=\"headerMenuAlign\"\n                v-model:header-mode=\"headerMode\"\n                :disabled=\"isFullContent\"\n              />\n            </Block>\n\n            <Block :title=\"$t('preferences.navigationMenu.title')\">\n              <Navigation\n                v-model:navigation-accordion=\"navigationAccordion\"\n                v-model:navigation-split=\"navigationSplit\"\n                v-model:navigation-style-type=\"navigationStyleType\"\n                :disabled=\"isFullContent\"\n                :disabled-navigation-split=\"!isMixedNav\"\n              />\n            </Block>\n\n            <Block :title=\"$t('preferences.breadcrumb.title')\">\n              <Breadcrumb\n                v-model:breadcrumb-enable=\"breadcrumbEnable\"\n                v-model:breadcrumb-hide-only-one=\"breadcrumbHideOnlyOne\"\n                v-model:breadcrumb-show-home=\"breadcrumbShowHome\"\n                v-model:breadcrumb-show-icon=\"breadcrumbShowIcon\"\n                v-model:breadcrumb-style-type=\"breadcrumbStyleType\"\n                :disabled=\"\n                  !showBreadcrumbConfig ||\n                  !(isSideNav || isSideMixedNav || isHeaderSidebarNav)\n                \"\n              />\n            </Block>\n            <Block :title=\"$t('preferences.tabbar.title')\">\n              <Tabbar\n                v-model:tabbar-draggable=\"tabbarDraggable\"\n                v-model:tabbar-enable=\"tabbarEnable\"\n                v-model:tabbar-persist=\"tabbarPersist\"\n                v-model:tabbar-show-icon=\"tabbarShowIcon\"\n                v-model:tabbar-show-maximize=\"tabbarShowMaximize\"\n                v-model:tabbar-show-more=\"tabbarShowMore\"\n                v-model:tabbar-style-type=\"tabbarStyleType\"\n                v-model:tabbar-wheelable=\"tabbarWheelable\"\n                v-model:tabbar-max-count=\"tabbarMaxCount\"\n                v-model:tabbar-middle-click-to-close=\"tabbarMiddleClickToClose\"\n              />\n            </Block>\n            <Block :title=\"$t('preferences.widget.title')\">\n              <Widget\n                v-model:app-preferences-button-position=\"\n                  appPreferencesButtonPosition\n                \"\n                v-model:widget-fullscreen=\"widgetFullscreen\"\n                v-model:widget-global-search=\"widgetGlobalSearch\"\n                v-model:widget-language-toggle=\"widgetLanguageToggle\"\n                v-model:widget-lock-screen=\"widgetLockScreen\"\n                v-model:widget-notification=\"widgetNotification\"\n                v-model:widget-refresh=\"widgetRefresh\"\n                v-model:widget-sidebar-toggle=\"widgetSidebarToggle\"\n                v-model:widget-theme-toggle=\"widgetThemeToggle\"\n              />\n            </Block>\n            <Block :title=\"$t('preferences.footer.title')\">\n              <Footer\n                v-model:footer-enable=\"footerEnable\"\n                v-model:footer-fixed=\"footerFixed\"\n              />\n            </Block>\n            <Block\n              v-if=\"copyrightSettingShow\"\n              :title=\"$t('preferences.copyright.title')\"\n            >\n              <Copyright\n                v-model:copyright-company-name=\"copyrightCompanyName\"\n                v-model:copyright-company-site-link=\"copyrightCompanySiteLink\"\n                v-model:copyright-date=\"copyrightDate\"\n                v-model:copyright-enable=\"copyrightEnable\"\n                v-model:copyright-icp=\"copyrightIcp\"\n                v-model:copyright-icp-link=\"copyrightIcpLink\"\n                :disabled=\"!footerEnable\"\n              />\n            </Block>\n          </template>\n\n          <template #shortcutKey>\n            <Block :title=\"$t('preferences.shortcutKeys.global')\">\n              <GlobalShortcutKeys\n                v-model:shortcut-keys-enable=\"shortcutKeysEnable\"\n                v-model:shortcut-keys-global-search=\"shortcutKeysGlobalSearch\"\n                v-model:shortcut-keys-lock-screen=\"shortcutKeysGlobalLockScreen\"\n                v-model:shortcut-keys-logout=\"shortcutKeysGlobalLogout\"\n              />\n            </Block>\n          </template>\n        </VbenSegmented>\n      </div>\n\n      <template #footer>\n        <VbenButton\n          :disabled=\"!diffPreference\"\n          class=\"mx-4 w-full\"\n          size=\"sm\"\n          variant=\"default\"\n          @click=\"handleCopy\"\n        >\n          <Copy class=\"mr-2 size-3\" />\n          {{ $t('preferences.copyPreferences') }}\n        </VbenButton>\n        <VbenButton\n          :disabled=\"!diffPreference\"\n          class=\"mr-4 w-full\"\n          size=\"sm\"\n          variant=\"ghost\"\n          @click=\"handleClearCache\"\n        >\n          {{ $t('preferences.clearAndLogout') }}\n        </VbenButton>\n      </template>\n    </Drawer>\n  </div>\n</template>\n\n<style scoped>\n:deep(.sticky-tabs-header [role='tablist']) {\n  position: sticky;\n  top: -12px;\n  z-index: 10;\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/preferences.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { Settings } from '@vben/icons';\nimport { $t, loadLocaleMessages } from '@vben/locales';\nimport { preferences, updatePreferences } from '@vben/preferences';\nimport { capitalizeFirstLetter } from '@vben/utils';\n\nimport { useVbenDrawer } from '@vben-core/popup-ui';\nimport { VbenButton } from '@vben-core/shadcn-ui';\n\nimport PreferencesDrawer from './preferences-drawer.vue';\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  connectedComponent: PreferencesDrawer,\n});\n\n/**\n * preferences 转成 vue props\n * preferences.widget.fullscreen=>widgetFullscreen\n */\nconst attrs = computed(() => {\n  const result: Record<string, any> = {};\n  for (const [key, value] of Object.entries(preferences)) {\n    for (const [subKey, subValue] of Object.entries(value)) {\n      result[`${key}${capitalizeFirstLetter(subKey)}`] = subValue;\n    }\n  }\n  return result;\n});\n\n/**\n * preferences 转成 vue listener\n * preferences.widget.fullscreen=>@update:widgetFullscreen\n */\nconst listen = computed(() => {\n  const result: Record<string, any> = {};\n  for (const [key, value] of Object.entries(preferences)) {\n    if (typeof value === 'object') {\n      for (const subKey of Object.keys(value)) {\n        result[`update:${key}${capitalizeFirstLetter(subKey)}`] = (\n          val: any,\n        ) => {\n          updatePreferences({ [key]: { [subKey]: val } });\n          if (key === 'app' && subKey === 'locale') {\n            loadLocaleMessages(val);\n          }\n        };\n      }\n    } else {\n      result[key] = value;\n    }\n  }\n  return result;\n});\n</script>\n<template>\n  <div>\n    <Drawer v-bind=\"{ ...$attrs, ...attrs }\" v-on=\"listen\" />\n\n    <div @click=\"() => drawerApi.open()\">\n      <slot>\n        <VbenButton\n          :title=\"$t('preferences.title')\"\n          class=\"bg-primary flex-col-center size-10 cursor-pointer rounded-l-lg rounded-r-none border-none\"\n        >\n          <Settings class=\"size-5\" />\n        </VbenButton>\n      </slot>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts",
    "content": "import { ref } from 'vue';\n\nconst openPreferences = ref(false);\n\nfunction useOpenPreferences() {\n  function handleOpenPreference() {\n    openPreferences.value = true;\n  }\n\n  return {\n    handleOpenPreference,\n    openPreferences,\n  };\n}\n\nexport { useOpenPreferences };\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/theme-toggle/index.ts",
    "content": "export { default as ThemeToggle } from './theme-toggle.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed, nextTick } from 'vue';\n\nimport { VbenButton } from '@vben-core/shadcn-ui';\n\ninterface Props {\n  /**\n   * 类型\n   */\n  type?: 'icon' | 'normal';\n}\n\ndefineOptions({\n  name: 'ThemeToggleButton',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  type: 'normal',\n});\n\nconst isDark = defineModel<boolean>();\n\nconst theme = computed(() => {\n  return isDark.value ? 'light' : 'dark';\n});\n\nconst bindProps = computed(() => {\n  const type = props.type;\n\n  return type === 'normal'\n    ? {\n        variant: 'heavy' as const,\n      }\n    : {\n        class: 'rounded-full',\n        size: 'icon' as const,\n        style: { padding: '7px' },\n        variant: 'icon' as const,\n      };\n});\n\nfunction toggleTheme(event: MouseEvent) {\n  const isAppearanceTransition =\n    // @ts-expect-error\n    document.startViewTransition &&\n    !window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n  if (!isAppearanceTransition || !event) {\n    isDark.value = !isDark.value;\n    return;\n  }\n  const x = event.clientX;\n  const y = event.clientY;\n  const endRadius = Math.hypot(\n    Math.max(x, innerWidth - x),\n    Math.max(y, innerHeight - y),\n  );\n  // @ts-ignore startViewTransition\n  const transition = document.startViewTransition(async () => {\n    isDark.value = !isDark.value;\n    await nextTick();\n  });\n  transition.ready.then(() => {\n    const clipPath = [\n      `circle(0px at ${x}px ${y}px)`,\n      `circle(${endRadius}px at ${x}px ${y}px)`,\n    ];\n    const animate = document.documentElement.animate(\n      {\n        clipPath: isDark.value ? [...clipPath].reverse() : clipPath,\n      },\n      {\n        duration: 450,\n        easing: 'ease-in',\n        pseudoElement: isDark.value\n          ? '::view-transition-old(root)'\n          : '::view-transition-new(root)',\n      },\n    );\n    animate.onfinish = () => {\n      transition.skipTransition();\n    };\n  });\n}\n</script>\n\n<template>\n  <VbenButton\n    :aria-label=\"theme\"\n    :class=\"[`is-${theme}`]\"\n    aria-live=\"polite\"\n    class=\"theme-toggle cursor-pointer border-none bg-none hover:animate-[shrink_0.3s_ease-in-out]\"\n    v-bind=\"bindProps\"\n    @click.stop=\"toggleTheme\"\n  >\n    <svg aria-hidden=\"true\" height=\"24\" viewBox=\"0 0 24 24\" width=\"24\">\n      <mask\n        id=\"theme-toggle-moon\"\n        class=\"theme-toggle__moon\"\n        fill=\"hsl(var(--foreground)/80%)\"\n        stroke=\"none\"\n      >\n        <rect fill=\"white\" height=\"100%\" width=\"100%\" x=\"0\" y=\"0\" />\n        <circle cx=\"40\" cy=\"8\" fill=\"black\" r=\"11\" />\n      </mask>\n      <circle\n        id=\"sun\"\n        class=\"theme-toggle__sun\"\n        cx=\"12\"\n        cy=\"12\"\n        mask=\"url(#theme-toggle-moon)\"\n        r=\"11\"\n      />\n      <g class=\"theme-toggle__sun-beams\">\n        <line x1=\"12\" x2=\"12\" y1=\"1\" y2=\"3\" />\n        <line x1=\"12\" x2=\"12\" y1=\"21\" y2=\"23\" />\n        <line x1=\"4.22\" x2=\"5.64\" y1=\"4.22\" y2=\"5.64\" />\n        <line x1=\"18.36\" x2=\"19.78\" y1=\"18.36\" y2=\"19.78\" />\n        <line x1=\"1\" x2=\"3\" y1=\"12\" y2=\"12\" />\n        <line x1=\"21\" x2=\"23\" y1=\"12\" y2=\"12\" />\n        <line x1=\"4.22\" x2=\"5.64\" y1=\"19.78\" y2=\"18.36\" />\n        <line x1=\"18.36\" x2=\"19.78\" y1=\"5.64\" y2=\"4.22\" />\n      </g>\n    </svg>\n  </VbenButton>\n</template>\n\n<style scoped>\n.theme-toggle {\n  &__moon {\n    & > circle {\n      transition: transform 0.5s cubic-bezier(0, 0, 0.3, 1);\n    }\n  }\n\n  &__sun {\n    @apply fill-foreground/90 stroke-none;\n\n    transform-origin: center center;\n    transition: transform 1.6s cubic-bezier(0.25, 0, 0.2, 1);\n\n    &:hover > svg > & {\n      @apply fill-foreground/90;\n    }\n  }\n\n  &__sun-beams {\n    @apply stroke-foreground/90 stroke-[2px];\n\n    transform-origin: center center;\n    transition:\n      transform 1.6s cubic-bezier(0.5, 1.5, 0.75, 1.25),\n      opacity 0.6s cubic-bezier(0.25, 0, 0.3, 1);\n\n    &:hover > svg > & {\n      @apply stroke-foreground;\n    }\n  }\n\n  &.is-light {\n    .theme-toggle__sun {\n      @apply scale-50;\n    }\n\n    .theme-toggle__sun-beams {\n      transform: rotateZ(0.25turn);\n    }\n  }\n\n  &.is-dark {\n    .theme-toggle__moon {\n      & > circle {\n        transform: translateX(-20px);\n      }\n    }\n\n    .theme-toggle__sun-beams {\n      @apply opacity-0;\n    }\n  }\n\n  &:hover > svg {\n    .theme-toggle__sun,\n    .theme-toggle__moon {\n      @apply fill-foreground;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { ThemeModeType } from '@vben/types';\n\nimport { MoonStar, Sun, SunMoon } from '@vben/icons';\nimport { $t } from '@vben/locales';\nimport {\n  preferences,\n  updatePreferences,\n  usePreferences,\n} from '@vben/preferences';\n\nimport {\n  ToggleGroup,\n  ToggleGroupItem,\n  VbenTooltip,\n} from '@vben-core/shadcn-ui';\n\nimport ThemeButton from './theme-button.vue';\n\ndefineOptions({\n  name: 'ThemeToggle',\n});\n\nwithDefaults(defineProps<{ shouldOnHover?: boolean }>(), {\n  shouldOnHover: false,\n});\n\nfunction handleChange(isDark: boolean | undefined) {\n  updatePreferences({\n    theme: { mode: isDark ? 'dark' : 'light' },\n  });\n}\n\nconst { isDark } = usePreferences();\n\nconst PRESETS = [\n  {\n    icon: Sun,\n    name: 'light',\n    title: $t('preferences.theme.light'),\n  },\n  {\n    icon: MoonStar,\n    name: 'dark',\n    title: $t('preferences.theme.dark'),\n  },\n  {\n    icon: SunMoon,\n    name: 'auto',\n    title: $t('preferences.followSystem'),\n  },\n];\n</script>\n<template>\n  <div>\n    <VbenTooltip :disabled=\"!shouldOnHover\" side=\"bottom\">\n      <template #trigger>\n        <ThemeButton\n          :model-value=\"isDark\"\n          type=\"icon\"\n          @update:model-value=\"handleChange\"\n        />\n      </template>\n      <ToggleGroup\n        :model-value=\"preferences.theme.mode\"\n        class=\"gap-2\"\n        type=\"single\"\n        variant=\"outline\"\n        @update:model-value=\"\n          (val) => updatePreferences({ theme: { mode: val as ThemeModeType } })\n        \"\n      >\n        <ToggleGroupItem\n          v-for=\"item in PRESETS\"\n          :key=\"item.name\"\n          :value=\"item.name\"\n        >\n          <component :is=\"item.icon\" class=\"size-5\" />\n        </ToggleGroupItem>\n      </ToggleGroup>\n    </VbenTooltip>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/user-dropdown/index.ts",
    "content": "export { default as UserDropdown } from './user-dropdown.vue';\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Component } from 'vue';\n\nimport type { AnyFunction } from '@vben/types';\n\nimport { computed, useTemplateRef, watch } from 'vue';\n\nimport { useHoverToggle } from '@vben/hooks';\nimport { LockKeyhole, LogOut } from '@vben/icons';\nimport { $t } from '@vben/locales';\nimport { preferences, usePreferences } from '@vben/preferences';\nimport { useAccessStore } from '@vben/stores';\nimport { isWindowsOs } from '@vben/utils';\n\nimport { useVbenModal } from '@vben-core/popup-ui';\nimport {\n  Badge,\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuTrigger,\n  VbenAvatar,\n  VbenIcon,\n} from '@vben-core/shadcn-ui';\n\nimport { useMagicKeys, whenever } from '@vueuse/core';\n\nimport { LockScreenModal } from '../lock-screen';\n\ninterface Props {\n  /**\n   * 头像\n   */\n  avatar?: string;\n  /**\n   * @zh_CN 描述\n   */\n  description?: string;\n  /**\n   * 是否启用快捷键\n   */\n  enableShortcutKey?: boolean;\n  /**\n   * 菜单数组\n   */\n  menus?: Array<{\n    handler: AnyFunction;\n    icon?: Component | Function | string;\n    text: string;\n  }>;\n\n  /**\n   * 标签文本\n   */\n  tagText?: string;\n  /**\n   * 文本\n   */\n  text?: string;\n  /** 触发方式 */\n  trigger?: 'both' | 'click' | 'hover';\n  /** hover触发时，延迟响应的时间 */\n  hoverDelay?: number;\n}\n\ndefineOptions({\n  name: 'UserDropdown',\n});\n\nconst props = withDefaults(defineProps<Props>(), {\n  avatar: '',\n  description: '',\n  enableShortcutKey: true,\n  menus: () => [],\n  showShortcutKey: true,\n  tagText: '',\n  text: '',\n  trigger: 'click',\n  hoverDelay: 500,\n});\n\nconst emit = defineEmits<{ logout: [] }>();\n\nconst { globalLockScreenShortcutKey, globalLogoutShortcutKey } =\n  usePreferences();\nconst accessStore = useAccessStore();\nconst [LockModal, lockModalApi] = useVbenModal({\n  connectedComponent: LockScreenModal,\n});\nconst [LogoutModal, logoutModalApi] = useVbenModal({\n  onConfirm() {\n    handleSubmitLogout();\n  },\n});\n\nconst refTrigger = useTemplateRef('refTrigger');\nconst refContent = useTemplateRef('refContent');\nconst [openPopover, hoverWatcher] = useHoverToggle(\n  [refTrigger, refContent],\n  () => props.hoverDelay,\n);\n\nwatch(\n  () => props.trigger === 'hover' || props.trigger === 'both',\n  (val) => {\n    if (val) {\n      hoverWatcher.enable();\n    } else {\n      hoverWatcher.disable();\n    }\n  },\n  {\n    immediate: true,\n  },\n);\n\nconst altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));\n\nconst enableLogoutShortcutKey = computed(() => {\n  return props.enableShortcutKey && globalLogoutShortcutKey.value;\n});\n\nconst enableLockScreenShortcutKey = computed(() => {\n  return props.enableShortcutKey && globalLockScreenShortcutKey.value;\n});\n\nconst enableShortcutKey = computed(() => {\n  return props.enableShortcutKey && preferences.shortcutKeys.enable;\n});\n\nfunction handleOpenLock() {\n  lockModalApi.open();\n}\n\nfunction handleSubmitLock(lockScreenPassword: string) {\n  lockModalApi.close();\n  accessStore.lockScreen(lockScreenPassword);\n}\n\nfunction handleLogout() {\n  // emit\n  logoutModalApi.open();\n  openPopover.value = false;\n}\n\nfunction handleSubmitLogout() {\n  emit('logout');\n  logoutModalApi.close();\n}\n\nif (enableShortcutKey.value) {\n  const keys = useMagicKeys();\n  whenever(keys['Alt+KeyQ']!, () => {\n    if (enableLogoutShortcutKey.value) {\n      handleLogout();\n    }\n  });\n\n  whenever(keys['Alt+KeyL']!, () => {\n    if (enableLockScreenShortcutKey.value) {\n      handleOpenLock();\n    }\n  });\n}\n</script>\n\n<template>\n  <LockModal\n    v-if=\"preferences.widget.lockScreen\"\n    :avatar=\"avatar\"\n    :text=\"text\"\n    @submit=\"handleSubmitLock\"\n  />\n\n  <LogoutModal\n    :cancel-text=\"$t('common.cancel')\"\n    :confirm-text=\"$t('common.confirm')\"\n    :fullscreen-button=\"false\"\n    :title=\"$t('common.prompt')\"\n    centered\n    content-class=\"px-8 min-h-10\"\n    footer-class=\"border-none mb-3 mr-3\"\n    header-class=\"border-none\"\n  >\n    {{ $t('ui.widgets.logoutTip') }}\n  </LogoutModal>\n\n  <DropdownMenu v-model:open=\"openPopover\">\n    <DropdownMenuTrigger ref=\"refTrigger\" :disabled=\"props.trigger === 'hover'\">\n      <div class=\"hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full p-1.5\">\n        <div class=\"hover:text-accent-foreground flex-center\">\n          <VbenAvatar :alt=\"text\" :src=\"avatar\" class=\"size-8\" dot />\n        </div>\n      </div>\n    </DropdownMenuTrigger>\n    <DropdownMenuContent class=\"mr-2 min-w-[240px] p-0 pb-1\">\n      <div ref=\"refContent\">\n        <DropdownMenuLabel class=\"flex items-center p-3\">\n          <VbenAvatar\n            :alt=\"text\"\n            :src=\"avatar\"\n            class=\"size-12\"\n            dot\n            dot-class=\"bottom-0 right-1 border-2 size-4 bg-green-500\"\n          />\n          <div class=\"ml-2 w-full\">\n            <div\n              v-if=\"tagText || text || $slots.tagText\"\n              class=\"text-foreground mb-1 flex items-center text-sm font-medium\"\n            >\n              {{ text }}\n              <slot name=\"tagText\">\n                <Badge v-if=\"tagText\" class=\"ml-2 text-green-400\">\n                  {{ tagText }}\n                </Badge>\n              </slot>\n            </div>\n            <div class=\"text-muted-foreground text-xs font-normal\">\n              {{ description }}\n            </div>\n          </div>\n        </DropdownMenuLabel>\n        <DropdownMenuSeparator v-if=\"menus?.length\" />\n        <DropdownMenuItem\n          v-for=\"menu in menus\"\n          :key=\"menu.text\"\n          class=\"mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8\"\n          @click=\"menu.handler\"\n        >\n          <VbenIcon :icon=\"menu.icon\" class=\"mr-2 size-4\" />\n          {{ menu.text }}\n        </DropdownMenuItem>\n        <DropdownMenuSeparator />\n        <DropdownMenuItem\n          v-if=\"preferences.widget.lockScreen\"\n          class=\"mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8\"\n          @click=\"handleOpenLock\"\n        >\n          <LockKeyhole class=\"mr-2 size-4\" />\n          {{ $t('ui.widgets.lockScreen.title') }}\n          <DropdownMenuShortcut v-if=\"enableLockScreenShortcutKey\">\n            {{ altView }} L\n          </DropdownMenuShortcut>\n        </DropdownMenuItem>\n        <DropdownMenuSeparator v-if=\"preferences.widget.lockScreen\" />\n        <DropdownMenuItem\n          class=\"mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8\"\n          @click=\"handleLogout\"\n        >\n          <LogOut class=\"mr-2 size-4\" />\n          {{ $t('common.logout') }}\n          <DropdownMenuShortcut v-if=\"enableLogoutShortcutKey\">\n            {{ altView }} Q\n          </DropdownMenuShortcut>\n        </DropdownMenuItem>\n      </div>\n    </DropdownMenuContent>\n  </DropdownMenu>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/layouts/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/README.md",
    "content": "# @vben/plugins\n\n该目录用于存放项目中集成的第三方库及其相关插件。每个插件都包含了可重用的逻辑、配置和组件，方便在项目中进行统一管理和调用。\n\n## 注意\n\n所有的第三方插件都必须以 `subpath` 形式引入，例：\n\n以 `echarts` 为例，引入方式如下：\n\n**packages.json**\n\n```json\n\"exports\": {\n    \"./echarts\": {\n      \"types\": \"./src/echarts/index.ts\",\n      \"default\": \"./src/echarts/index.ts\"\n    }\n  }\n```\n\n**使用方式**\n\n```ts\nimport { useEcharts } from '@vben/plugins/echarts';\n```\n\n这样做的好处是，应用可以自行选择是否使用插件，而不会因为插件的引入及副作用而导致打包体积增大，只引入需要的插件即可。\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/package.json",
    "content": "{\n  \"name\": \"@vben/plugins\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/effects/plugins\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \"./echarts\": {\n      \"types\": \"./src/echarts/index.ts\",\n      \"default\": \"./src/echarts/index.ts\"\n    },\n    \"./vxe-table\": {\n      \"types\": \"./src/vxe-table/index.ts\",\n      \"default\": \"./src/vxe-table/index.ts\"\n    },\n    \"./motion\": {\n      \"types\": \"./src/motion/index.ts\",\n      \"default\": \"./src/motion/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/form-ui\": \"workspace:*\",\n    \"@vben-core/shadcn-ui\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben/hooks\": \"workspace:*\",\n    \"@vben/icons\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"@vueuse/motion\": \"catalog:\",\n    \"echarts\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vxe-pc-ui\": \"catalog:\",\n    \"vxe-table\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/echarts/echarts-ui.vue",
    "content": "<script setup lang=\"ts\">\ninterface Props {\n  height?: string;\n  width?: string;\n}\n\nwithDefaults(defineProps<Props>(), {\n  height: '300px',\n  width: '100%',\n});\n</script>\n\n<template>\n  <div v-bind=\"$attrs\" :style=\"{ height, width }\"></div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/echarts/echarts.ts",
    "content": "import type {\n  // 系列类型的定义后缀都为 SeriesOption\n  BarSeriesOption,\n  LineSeriesOption,\n} from 'echarts/charts';\nimport type {\n  DatasetComponentOption,\n  GridComponentOption,\n  // 组件类型的定义后缀都为 ComponentOption\n  TitleComponentOption,\n  TooltipComponentOption,\n} from 'echarts/components';\nimport type { ComposeOption } from 'echarts/core';\n\nimport { BarChart, LineChart, PieChart, RadarChart } from 'echarts/charts';\nimport {\n  // 数据集组件\n  DatasetComponent,\n  GridComponent,\n  LegendComponent,\n  TitleComponent,\n  ToolboxComponent,\n  TooltipComponent,\n  // 内置数据转换器组件 (filter, sort)\n  TransformComponent,\n} from 'echarts/components';\nimport * as echarts from 'echarts/core';\nimport { LabelLayout, UniversalTransition } from 'echarts/features';\nimport { CanvasRenderer } from 'echarts/renderers';\n\n// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型\nexport type ECOption = ComposeOption<\n  | BarSeriesOption\n  | DatasetComponentOption\n  | GridComponentOption\n  | LineSeriesOption\n  | TitleComponentOption\n  | TooltipComponentOption\n>;\n\n// 注册必须的组件\necharts.use([\n  TitleComponent,\n  PieChart,\n  RadarChart,\n  TooltipComponent,\n  GridComponent,\n  DatasetComponent,\n  TransformComponent,\n  BarChart,\n  LineChart,\n  LabelLayout,\n  UniversalTransition,\n  CanvasRenderer,\n  LegendComponent,\n  ToolboxComponent,\n]);\n\nexport default echarts;\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/echarts/index.ts",
    "content": "export * from './echarts';\nexport { default as EchartsUI } from './echarts-ui.vue';\nexport * from './use-echarts';\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/echarts/use-echarts.ts",
    "content": "import type { EChartsOption } from 'echarts';\n\nimport type { Ref } from 'vue';\n\nimport type { Nullable } from '@vben/types';\n\nimport type EchartsUI from './echarts-ui.vue';\n\nimport { computed, nextTick, watch } from 'vue';\n\nimport { usePreferences } from '@vben/preferences';\n\nimport {\n  tryOnUnmounted,\n  useDebounceFn,\n  useResizeObserver,\n  useTimeoutFn,\n  useWindowSize,\n} from '@vueuse/core';\n\nimport echarts from './echarts';\n\ntype EchartsUIType = typeof EchartsUI | undefined;\n\ntype EchartsThemeType = 'dark' | 'light' | null;\n\nfunction useEcharts(chartRef: Ref<EchartsUIType>) {\n  let chartInstance: echarts.ECharts | null = null;\n  let cacheOptions: EChartsOption = {};\n\n  const { isDark } = usePreferences();\n  const { height, width } = useWindowSize();\n  const resizeHandler: () => void = useDebounceFn(resize, 200);\n\n  const getChartEl = (): HTMLElement | null => {\n    const refValue = chartRef?.value as unknown;\n    if (!refValue) return null;\n    if (refValue instanceof HTMLElement) {\n      return refValue;\n    }\n    const maybeComponent = refValue as { $el?: HTMLElement };\n    return maybeComponent.$el ?? null;\n  };\n\n  const isElHidden = (el: HTMLElement | null): boolean => {\n    if (!el) return true;\n    return el.offsetHeight === 0 || el.offsetWidth === 0;\n  };\n\n  const getOptions = computed((): EChartsOption => {\n    if (!isDark.value) {\n      return {};\n    }\n\n    return {\n      backgroundColor: 'transparent',\n    };\n  });\n\n  const initCharts = (t?: EchartsThemeType) => {\n    const el = chartRef?.value?.$el;\n    if (!el) {\n      return;\n    }\n    chartInstance = echarts.init(el, t || isDark.value ? 'dark' : null);\n\n    return chartInstance;\n  };\n\n  const renderEcharts = (\n    options: EChartsOption,\n    clear = true\n  ): Promise<Nullable<echarts.ECharts>> => {\n    cacheOptions = options;\n    const currentOptions = {\n      ...options,\n      ...getOptions.value,\n    };\n    return new Promise((resolve) => {\n      if (chartRef.value?.offsetHeight === 0) {\n        useTimeoutFn(async () => {\n          resolve(await renderEcharts(currentOptions));\n        }, 30);\n        return;\n      }\n      nextTick(() => {\n        const el = getChartEl();\n        if (isElHidden(el)) {\n          useTimeoutFn(async () => {\n            resolve(await renderEcharts(currentOptions));\n          }, 30);\n          return;\n        }\n        useTimeoutFn(() => {\n          if (!chartInstance) {\n            const instance = initCharts();\n            if (!instance) return;\n          }\n          clear && chartInstance?.clear();\n          chartInstance?.setOption(currentOptions);\n          resolve(chartInstance);\n        }, 30);\n      });\n    });\n  };\n\n  function resize() {\n    const el = getChartEl();\n    if (isElHidden(el)) {\n      return;\n    }\n    chartInstance?.resize({\n      animation: {\n        duration: 300,\n        easing: 'quadraticIn',\n      },\n    });\n  }\n\n  watch([width, height], () => {\n    resizeHandler?.();\n  });\n\n  useResizeObserver(chartRef as never, resizeHandler);\n\n  watch(isDark, () => {\n    if (chartInstance) {\n      chartInstance.dispose();\n      initCharts();\n      renderEcharts(cacheOptions);\n      resize();\n    }\n  });\n\n  tryOnUnmounted(() => {\n    // 销毁实例，释放资源\n    chartInstance?.dispose();\n  });\n  return {\n    renderEcharts,\n    resize,\n    getChartInstance: () => chartInstance,\n  };\n}\n\nexport { useEcharts };\n\nexport type { EchartsUIType };\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/motion/index.ts",
    "content": "export * from './types';\n\nexport {\n  MotionComponent as Motion,\n  MotionDirective,\n  MotionGroupComponent as MotionGroup,\n  MotionPlugin,\n} from '@vueuse/motion';\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/motion/types.ts",
    "content": "export const MotionPresets = [\n  'fade',\n  'fadeVisible',\n  'fadeVisibleOnce',\n  'rollBottom',\n  'rollLeft',\n  'rollRight',\n  'rollTop',\n  'rollVisibleBottom',\n  'rollVisibleLeft',\n  'rollVisibleRight',\n  'rollVisibleTop',\n  'pop',\n  'popVisible',\n  'popVisibleOnce',\n  'slideBottom',\n  'slideLeft',\n  'slideRight',\n  'slideTop',\n  'slideVisibleBottom',\n  'slideVisibleLeft',\n  'slideVisibleRight',\n  'slideVisibleTop',\n] as const;\n\nexport type MotionPreset = (typeof MotionPresets)[number];\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/vxe-table/api.ts",
    "content": "import type { VxeGridInstance } from 'vxe-table';\n\nimport type { ExtendedFormApi } from '@vben-core/form-ui';\n\nimport type { VxeGridProps } from './types';\n\nimport { toRaw } from 'vue';\n\nimport { Store } from '@vben-core/shared/store';\nimport {\n  bindMethods,\n  isBoolean,\n  isFunction,\n  mergeWithArrayOverride,\n  StateHandler,\n} from '@vben-core/shared/utils';\n\nfunction getDefaultState(): VxeGridProps {\n  return {\n    class: '',\n    gridClass: '',\n    gridOptions: {},\n    gridEvents: {},\n    formOptions: undefined,\n    showSearchForm: true,\n  };\n}\n\nexport class VxeGridApi<T extends Record<string, any> = any> {\n  public formApi = {} as ExtendedFormApi;\n\n  // private prevState: null | VxeGridProps = null;\n  public grid = {} as VxeGridInstance<T>;\n  public state: null | VxeGridProps<T> = null;\n\n  public store: Store<VxeGridProps<T>>;\n\n  private isMounted = false;\n\n  private stateHandler: StateHandler;\n\n  constructor(options: VxeGridProps = {}) {\n    const storeState = { ...options };\n\n    const defaultState = getDefaultState();\n    this.store = new Store<VxeGridProps>(\n      mergeWithArrayOverride(storeState, defaultState),\n      {\n        onUpdate: () => {\n          // this.prevState = this.state;\n          this.state = this.store.state;\n        },\n      },\n    );\n\n    this.state = this.store.state;\n    this.stateHandler = new StateHandler();\n    bindMethods(this);\n  }\n\n  mount(instance: null | VxeGridInstance, formApi: ExtendedFormApi) {\n    if (!this.isMounted && instance) {\n      this.grid = instance;\n      this.formApi = formApi;\n      this.stateHandler.setConditionTrue();\n      this.isMounted = true;\n    }\n  }\n\n  async query(params: Record<string, any> = {}) {\n    try {\n      await this.grid.commitProxy('query', toRaw(params));\n    } catch (error) {\n      console.error('Error occurred while querying:', error);\n    }\n  }\n\n  async reload(params: Record<string, any> = {}) {\n    try {\n      await this.grid.commitProxy('reload', toRaw(params));\n    } catch (error) {\n      console.error('Error occurred while reloading:', error);\n    }\n  }\n\n  setGridOptions(options: Partial<VxeGridProps['gridOptions']>) {\n    this.setState({\n      gridOptions: options,\n    });\n  }\n\n  setLoading(isLoading: boolean) {\n    this.setState({\n      gridOptions: {\n        loading: isLoading,\n      },\n    });\n  }\n\n  setState(\n    stateOrFn:\n      | ((prev: VxeGridProps<T>) => Partial<VxeGridProps<T>>)\n      | Partial<VxeGridProps<T>>,\n  ) {\n    if (isFunction(stateOrFn)) {\n      this.store.setState((prev) => {\n        return mergeWithArrayOverride(stateOrFn(prev), prev);\n      });\n    } else {\n      this.store.setState((prev) => mergeWithArrayOverride(stateOrFn, prev));\n    }\n  }\n\n  toggleSearchForm(show?: boolean) {\n    this.setState({\n      showSearchForm: isBoolean(show) ? show : !this.state?.showSearchForm,\n    });\n    // nextTick(() => {\n    //   this.grid.recalculate();\n    // });\n    return this.state?.showSearchForm;\n  }\n\n  unmount() {\n    this.isMounted = false;\n    this.stateHandler.reset();\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/vxe-table/extends.ts",
    "content": "import type { VxeGridProps, VxeUIExport } from 'vxe-table';\n\nimport type { Recordable } from '@vben/types';\n\nimport type { VxeGridApi } from './api';\n\nimport { formatDate, formatDateTime, isFunction } from '@vben/utils';\n\nexport function extendProxyOptions(\n  api: VxeGridApi,\n  options: VxeGridProps,\n  getFormValues: () => Recordable<any>,\n) {\n  [\n    'query',\n    'querySuccess',\n    'queryError',\n    'queryAll',\n    'queryAllSuccess',\n    'queryAllError',\n  ].forEach((key) => {\n    extendProxyOption(key, api, options, getFormValues);\n  });\n}\n\nfunction extendProxyOption(\n  key: string,\n  api: VxeGridApi,\n  options: VxeGridProps,\n  getFormValues: () => Recordable<any>,\n) {\n  const { proxyConfig } = options;\n  const configFn = (proxyConfig?.ajax as Recordable<any>)?.[key];\n  if (!isFunction(configFn)) {\n    return options;\n  }\n\n  const wrapperFn = async (\n    params: Recordable<any>,\n    customValues: Recordable<any>,\n    ...args: Recordable<any>[]\n  ) => {\n    const formValues = getFormValues();\n    const data = await configFn(\n      params,\n      {\n        /**\n         * 开启toolbarConfig.refresh功能\n         * 点击刷新按钮 这里的值为PointerEvent 会携带错误参数\n         */\n        ...(customValues instanceof PointerEvent ? {} : customValues),\n        ...formValues,\n      },\n      ...args,\n    );\n    return data;\n  };\n  api.setState({\n    gridOptions: {\n      proxyConfig: {\n        ajax: {\n          [key]: wrapperFn,\n        },\n      },\n    },\n  });\n}\n\nexport function extendsDefaultFormatter(vxeUI: VxeUIExport) {\n  vxeUI.formats.add('formatDate', {\n    tableCellFormatMethod({ cellValue }) {\n      return formatDate(cellValue);\n    },\n  });\n\n  vxeUI.formats.add('formatDateTime', {\n    tableCellFormatMethod({ cellValue }) {\n      return formatDateTime(cellValue);\n    },\n  });\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/vxe-table/index.ts",
    "content": "export { setupVbenVxeTable } from './init';\nexport type { VxeTableGridOptions } from './types';\nexport * from './use-vxe-grid';\n\nexport { default as VbenVxeGrid } from './use-vxe-grid.vue';\nexport type {\n  VxeGridListeners,\n  VxeGridProps,\n  VxeGridPropTypes,\n} from 'vxe-table';\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/vxe-table/init.ts",
    "content": "import type { SetupVxeTable } from './types';\n\nimport { defineComponent, watch } from 'vue';\n\nimport { usePreferences } from '@vben/preferences';\n\nimport { useVbenForm } from '@vben-core/form-ui';\n\nimport {\n  VxeButton,\n  VxeCheckbox,\n\n  // VxeFormGather,\n  // VxeForm,\n  // VxeFormItem,\n  VxeIcon,\n  VxeInput,\n  VxeLoading,\n  VxeModal,\n  VxeNumberInput,\n  VxePager,\n  // VxeList,\n  // VxeModal,\n  // VxeOptgroup,\n  // VxeOption,\n  // VxePulldown,\n  // VxeRadio,\n  // VxeRadioButton,\n  VxeRadioGroup,\n  VxeSelect,\n  VxeTooltip,\n  VxeUI,\n  VxeUpload,\n  // VxeSwitch,\n  // VxeTextarea,\n} from 'vxe-pc-ui';\nimport enUS from 'vxe-pc-ui/lib/language/en-US';\n// 导入默认的语言\nimport zhCN from 'vxe-pc-ui/lib/language/zh-CN';\nimport {\n  VxeColgroup,\n  VxeColumn,\n  VxeGrid,\n  VxeTable,\n  VxeToolbar,\n} from 'vxe-table';\n\nimport { extendsDefaultFormatter } from './extends';\n\n// 是否加载过\nlet isInit = false;\n\n// eslint-disable-next-line import/no-mutable-exports\nexport let useTableForm: typeof useVbenForm;\n\n// 部分组件，如果没注册，vxe-table 会报错，这里实际没用组件，只是为了不报错，同时可以减少打包体积\nconst createVirtualComponent = (name = '') => {\n  return defineComponent({\n    name,\n  });\n};\n\nexport function initVxeTable() {\n  if (isInit) {\n    return;\n  }\n\n  VxeUI.component(VxeTable);\n  VxeUI.component(VxeColumn);\n  VxeUI.component(VxeColgroup);\n  VxeUI.component(VxeGrid);\n  VxeUI.component(VxeToolbar);\n\n  VxeUI.component(VxeButton);\n  // VxeUI.component(VxeButtonGroup);\n  VxeUI.component(VxeCheckbox);\n  // VxeUI.component(VxeCheckboxGroup);\n  VxeUI.component(createVirtualComponent('VxeForm'));\n  // VxeUI.component(VxeFormGather);\n  // VxeUI.component(VxeFormItem);\n  VxeUI.component(VxeIcon);\n  VxeUI.component(VxeInput);\n  // VxeUI.component(VxeList);\n  VxeUI.component(VxeLoading);\n  VxeUI.component(VxeModal);\n  VxeUI.component(VxeNumberInput);\n  // VxeUI.component(VxeOptgroup);\n  // VxeUI.component(VxeOption);\n  VxeUI.component(VxePager);\n  // VxeUI.component(VxePulldown);\n  // VxeUI.component(VxeRadio);\n  // VxeUI.component(VxeRadioButton);\n  VxeUI.component(VxeRadioGroup);\n  VxeUI.component(VxeSelect);\n  // VxeUI.component(VxeSwitch);\n  // VxeUI.component(VxeTextarea);\n  VxeUI.component(VxeTooltip);\n  VxeUI.component(VxeUpload);\n\n  isInit = true;\n}\n\nexport function setupVbenVxeTable(setupOptions: SetupVxeTable) {\n  const { configVxeTable, useVbenForm } = setupOptions;\n\n  initVxeTable();\n  useTableForm = useVbenForm;\n\n  const { isDark, locale } = usePreferences();\n\n  const localMap = {\n    'zh-CN': zhCN,\n    'en-US': enUS,\n  };\n\n  watch(\n    [() => isDark.value, () => locale.value],\n    ([isDarkValue, localeValue]) => {\n      VxeUI.setTheme(isDarkValue ? 'dark' : 'light');\n      VxeUI.setI18n(localeValue, localMap[localeValue]);\n      VxeUI.setLanguage(localeValue);\n    },\n    {\n      immediate: true,\n    },\n  );\n\n  extendsDefaultFormatter(VxeUI);\n\n  configVxeTable(VxeUI);\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/vxe-table/style.css",
    "content": ":root .vxe-grid {\n  --vxe-ui-font-color: hsl(var(--foreground));\n  --vxe-ui-font-primary-color: hsl(var(--primary));\n\n  /* --vxe-ui-font-lighten-color: #babdc0;\n  --vxe-ui-font-darken-color: #86898e; */\n  --vxe-ui-font-disabled-color: hsl(var(--foreground) / 50%);\n\n  /* base */\n  --vxe-ui-base-popup-border-color: hsl(var(--border));\n  --vxe-ui-input-disabled-color: hsl(var(--border) / 60%);\n\n  /* --vxe-ui-base-popup-box-shadow: 0px 12px 30px 8px rgb(0 0 0 / 50%); */\n\n  /* layout */\n  --vxe-ui-layout-background-color: hsl(var(--background));\n  --vxe-ui-table-resizable-line-color: hsl(var(--heavy));\n\n  /* --vxe-ui-table-fixed-left-scrolling-box-shadow: 8px 0px 10px -5px hsl(var(--accent));\n  --vxe-ui-table-fixed-right-scrolling-box-shadow: -8px 0px 10px -5px hsl(var(--accent)); */\n\n  /* input */\n  --vxe-ui-input-border-color: hsl(var(--border));\n\n  /* --vxe-ui-input-placeholder-color: #8d9095; */\n\n  /* --vxe-ui-input-disabled-background-color: #262727; */\n\n  /* loading */\n  --vxe-ui-loading-background-color: hsl(var(--overlay-content));\n\n  /* table */\n  --vxe-ui-table-header-background-color: hsl(var(--accent));\n  --vxe-ui-table-border-color: hsl(var(--border));\n  --vxe-ui-table-row-hover-background-color: hsl(var(--accent-hover));\n  --vxe-ui-table-row-striped-background-color: hsl(var(--accent) / 60%);\n  --vxe-ui-table-row-hover-striped-background-color: hsl(var(--accent));\n  --vxe-ui-table-row-radio-checked-background-color: hsl(var(--accent));\n  --vxe-ui-table-row-hover-radio-checked-background-color: hsl(\n    var(--accent-hover)\n  );\n  --vxe-ui-table-row-checkbox-checked-background-color: hsl(var(--accent));\n  --vxe-ui-table-row-hover-checkbox-checked-background-color: hsl(\n    var(--accent-hover)\n  );\n  --vxe-ui-table-row-current-background-color: hsl(var(--accent));\n  --vxe-ui-table-row-hover-current-background-color: hsl(var(--accent-hover));\n  --vxe-ui-font-primary-tinge-color: hsl(var(--primary));\n  --vxe-ui-font-primary-lighten-color: hsl(var(--primary) / 60%);\n  --vxe-ui-font-primary-darken-color: hsl(var(--primary));\n\n  height: auto !important;\n\n  /* --vxe-ui-table-fixed-scrolling-box-shadow-color: rgb(0 0 0 / 80%); */\n}\n\n.vxe-pager {\n  .vxe-pager--prev-btn:not(.is--disabled):active,\n  .vxe-pager--next-btn:not(.is--disabled):active,\n  .vxe-pager--num-btn:not(.is--disabled):active,\n  .vxe-pager--jump-prev:not(.is--disabled):active,\n  .vxe-pager--jump-next:not(.is--disabled):active,\n  .vxe-pager--prev-btn:not(.is--disabled):focus,\n  .vxe-pager--next-btn:not(.is--disabled):focus,\n  .vxe-pager--num-btn:not(.is--disabled):focus,\n  .vxe-pager--jump-prev:not(.is--disabled):focus,\n  .vxe-pager--jump-next:not(.is--disabled):focus {\n    color: hsl(var(--accent-foreground));\n    background-color: hsl(var(--accent));\n    border: 1px solid hsl(var(--border));\n    box-shadow: 0 0 0 1px hsl(var(--border));\n  }\n\n  .vxe-pager--wrapper {\n    display: flex;\n    align-items: center;\n  }\n\n  .vxe-pager--sizes {\n    margin-right: auto;\n  }\n}\n\n.vxe-pager--wrapper {\n  @apply justify-center md:justify-end;\n}\n\n.vxe-tools--operate {\n  margin-right: 0.25rem;\n  margin-left: 0.75rem;\n}\n\n.vxe-table-custom--checkbox-option:hover {\n  background: none !important;\n}\n\n.vxe-toolbar {\n  padding: 0;\n}\n\n.vxe-buttons--wrapper:not(:empty),\n.vxe-tools--operate:not(:empty),\n.vxe-tools--wrapper:not(:empty) {\n  padding: 0.6em 0;\n}\n\n.vxe-tools--operate:not(:has(button)) {\n  margin-left: 0;\n}\n\n.vxe-grid--layout-header-wrapper {\n  overflow: visible;\n}\n\n.vxe-grid--layout-body-content-wrapper {\n  overflow: hidden;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/vxe-table/types.ts",
    "content": "import type {\n  VxeGridListeners,\n  VxeGridPropTypes,\n  VxeGridProps as VxeTableGridProps,\n  VxeUIExport,\n} from 'vxe-table';\n\nimport type { Ref } from 'vue';\n\nimport type { ClassType, DeepPartial } from '@vben/types';\n\nimport type { BaseFormComponentType, VbenFormProps } from '@vben-core/form-ui';\n\nimport type { VxeGridApi } from './api';\n\nimport { useVbenForm } from '@vben-core/form-ui';\n\nexport interface VxePaginationInfo {\n  currentPage: number;\n  pageSize: number;\n  total: number;\n}\n\ninterface ToolbarConfigOptions extends VxeGridPropTypes.ToolbarConfig {\n  /** 是否显示切换搜索表单的按钮 */\n  search?: boolean;\n}\n\nexport interface VxeTableGridOptions<T = any> extends VxeTableGridProps<T> {\n  /** 工具栏配置 */\n  toolbarConfig?: ToolbarConfigOptions;\n}\n\nexport interface SeparatorOptions {\n  show?: boolean;\n  backgroundColor?: string;\n}\n\nexport interface VxeGridProps<\n  T extends Record<string, any> = any,\n  D extends BaseFormComponentType = BaseFormComponentType,\n> {\n  /**\n   * 标题\n   */\n  tableTitle?: string;\n  /**\n   * 标题帮助\n   */\n  tableTitleHelp?: string;\n  /**\n   * 组件class\n   */\n  class?: ClassType;\n  /**\n   * vxe-grid class\n   */\n  gridClass?: ClassType;\n  /**\n   * vxe-grid 配置\n   */\n  gridOptions?: DeepPartial<VxeTableGridOptions<T>>;\n  /**\n   * vxe-grid 事件\n   */\n  gridEvents?: DeepPartial<VxeGridListeners<T>>;\n  /**\n   * 表单配置\n   */\n  formOptions?: VbenFormProps<D>;\n  /**\n   * 显示搜索表单\n   */\n  showSearchForm?: boolean;\n  /**\n   * 搜索表单与表格主体之间的分隔条\n   */\n  separator?: boolean | SeparatorOptions;\n}\n\nexport type ExtendedVxeGridApi<\n  D extends Record<string, any> = any,\n  F extends BaseFormComponentType = BaseFormComponentType,\n> = VxeGridApi<D> & {\n  useStore: <T = NoInfer<VxeGridProps<D, F>>>(\n    selector?: (state: NoInfer<VxeGridProps<any, any>>) => T,\n  ) => Readonly<Ref<T>>;\n};\n\nexport interface SetupVxeTable {\n  configVxeTable: (ui: VxeUIExport) => void;\n  useVbenForm: typeof useVbenForm;\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts",
    "content": "import type { VxeGridSlots, VxeGridSlotTypes } from 'vxe-table';\n\nimport type { SlotsType } from 'vue';\n\nimport type { BaseFormComponentType } from '@vben-core/form-ui';\n\nimport type { ExtendedVxeGridApi, VxeGridProps } from './types';\n\nimport { defineComponent, h, onBeforeUnmount } from 'vue';\n\nimport { useStore } from '@vben-core/shared/store';\n\nimport { VxeGridApi } from './api';\nimport VxeGrid from './use-vxe-grid.vue';\n\ntype FilteredSlots<T> = {\n  [K in keyof VxeGridSlots<T> as K extends 'form'\n    ? never\n    : K]: VxeGridSlots<T>[K];\n};\n\nexport function useVbenVxeGrid<\n  T extends Record<string, any> = any,\n  D extends BaseFormComponentType = BaseFormComponentType,\n>(options: VxeGridProps<T, D>) {\n  // const IS_REACTIVE = isReactive(options);\n  const api = new VxeGridApi(options);\n  const extendedApi: ExtendedVxeGridApi<T, D> = api as ExtendedVxeGridApi<T, D>;\n  extendedApi.useStore = (selector) => {\n    return useStore(api.store, selector);\n  };\n\n  const Grid = defineComponent(\n    (props: VxeGridProps<T>, { attrs, slots }) => {\n      onBeforeUnmount(() => {\n        api.unmount();\n      });\n      api.setState({ ...props, ...attrs });\n      return () => h(VxeGrid, { ...props, ...attrs, api: extendedApi }, slots);\n    },\n    {\n      name: 'VbenVxeGrid',\n      inheritAttrs: false,\n      slots: Object as SlotsType<\n        {\n          // 表格标题\n          'table-title': undefined;\n          // 工具栏左侧部分\n          'toolbar-actions': VxeGridSlotTypes.DefaultSlotParams<T>;\n          // 工具栏右侧部分\n          'toolbar-tools': VxeGridSlotTypes.DefaultSlotParams<T>;\n        } & FilteredSlots<T>\n      >,\n    },\n  );\n  // Add reactivity support\n  // if (IS_REACTIVE) {\n  //   watch(\n  //     () => options,\n  //     () => {\n  //       api.setState(options);\n  //     },\n  //     { immediate: true },\n  //   );\n  // }\n\n  return [Grid, extendedApi] as const;\n}\n\nexport type UseVbenVxeGrid = typeof useVbenVxeGrid;\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  VxeGridDefines,\n  VxeGridInstance,\n  VxeGridListeners,\n  VxeGridPropTypes,\n  VxeGridProps as VxeTableGridProps,\n  VxeToolbarPropTypes,\n} from 'vxe-table';\n\nimport type { SetupContext } from 'vue';\n\nimport type { VbenFormProps } from '@vben-core/form-ui';\n\nimport type { ExtendedVxeGridApi, VxeGridProps } from './types';\n\nimport {\n  computed,\n  nextTick,\n  onMounted,\n  onUnmounted,\n  toRaw,\n  useSlots,\n  useTemplateRef,\n  watch,\n} from 'vue';\n\nimport { usePriorityValues } from '@vben/hooks';\nimport { EmptyIcon } from '@vben/icons';\nimport { $t } from '@vben/locales';\nimport { usePreferences } from '@vben/preferences';\nimport {\n  cloneDeep,\n  cn,\n  isBoolean,\n  isEqual,\n  mergeWithArrayOverride,\n} from '@vben/utils';\n\nimport { VbenHelpTooltip, VbenLoading } from '@vben-core/shadcn-ui';\n\nimport { VxeButton } from 'vxe-pc-ui';\nimport { VxeGrid, VxeUI } from 'vxe-table';\n\nimport { extendProxyOptions } from './extends';\nimport { useTableForm } from './init';\n\nimport 'vxe-table/styles/cssvar.scss';\nimport 'vxe-pc-ui/styles/cssvar.scss';\nimport './style.css';\n\ninterface Props extends VxeGridProps {\n  api: ExtendedVxeGridApi;\n}\n\nconst props = withDefaults(defineProps<Props>(), {});\n\nconst FORM_SLOT_PREFIX = 'form-';\n\nconst TOOLBAR_ACTIONS = 'toolbar-actions';\nconst TOOLBAR_TOOLS = 'toolbar-tools';\nconst TABLE_TITLE = 'table-title';\n\nconst gridRef = useTemplateRef<VxeGridInstance>('gridRef');\n\nconst state = props.api?.useStore?.();\n\nconst {\n  gridOptions,\n  class: className,\n  gridClass,\n  gridEvents,\n  formOptions,\n  tableTitle,\n  tableTitleHelp,\n  showSearchForm,\n  separator,\n} = usePriorityValues(props, state);\n\nconst { isMobile } = usePreferences();\nconst isSeparator = computed(() => {\n  if (\n    !formOptions.value ||\n    showSearchForm.value === false ||\n    separator.value === false\n  ) {\n    return false;\n  }\n  if (separator.value === true || separator.value === undefined) {\n    return true;\n  }\n  return separator.value.show !== false;\n});\nconst separatorBg = computed(() => {\n  return !separator.value ||\n    isBoolean(separator.value) ||\n    !separator.value.backgroundColor\n    ? undefined\n    : separator.value.backgroundColor;\n});\nconst slots: SetupContext['slots'] = useSlots();\n\nconst [Form, formApi] = useTableForm({\n  compact: true,\n  handleSubmit: async () => {\n    const formValues = await formApi.getValues();\n    formApi.setLatestSubmissionValues(toRaw(formValues));\n    props.api.reload(formValues);\n  },\n  handleReset: async () => {\n    const prevValues = await formApi.getValues();\n    await formApi.resetForm();\n    const formValues = await formApi.getValues();\n    formApi.setLatestSubmissionValues(formValues);\n    // 如果值发生了变化，submitOnChange会触发刷新。所以只在submitOnChange为false或者值没有发生变化时，手动刷新\n    if (isEqual(prevValues, formValues) || !formOptions.value?.submitOnChange) {\n      props.api.reload(formValues);\n    }\n  },\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  showCollapseButton: true,\n  submitButtonOptions: {\n    content: computed(() => $t('common.search')),\n  },\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n});\n\nconst showTableTitle = computed(() => {\n  return !!slots[TABLE_TITLE]?.() || tableTitle.value;\n});\n\nconst showToolbar = computed(() => {\n  return (\n    !!slots[TOOLBAR_ACTIONS]?.() ||\n    !!slots[TOOLBAR_TOOLS]?.() ||\n    showTableTitle.value\n  );\n});\n\nconst toolbarOptions = computed(() => {\n  const slotActions = slots[TOOLBAR_ACTIONS]?.();\n  const slotTools = slots[TOOLBAR_TOOLS]?.();\n  const searchBtn: VxeToolbarPropTypes.ToolConfig = {\n    code: 'search',\n    icon: 'vxe-icon-search',\n    circle: true,\n    status: showSearchForm.value ? 'primary' : undefined,\n    title: showSearchForm.value\n      ? $t('common.hideSearchPanel')\n      : $t('common.showSearchPanel'),\n  };\n  // 将搜索按钮合并到用户配置的toolbarConfig.tools中\n  const toolbarConfig: VxeGridPropTypes.ToolbarConfig = {\n    tools: (gridOptions.value?.toolbarConfig?.tools ??\n      []) as VxeToolbarPropTypes.ToolConfig[],\n  };\n  if (gridOptions.value?.toolbarConfig?.search && !!formOptions.value) {\n    toolbarConfig.tools = Array.isArray(toolbarConfig.tools)\n      ? [...toolbarConfig.tools, searchBtn]\n      : [searchBtn];\n  }\n\n  if (!showToolbar.value) {\n    return { toolbarConfig };\n  }\n\n  // 强制使用固定的toolbar配置，不允许用户自定义\n  // 减少配置的复杂度，以及后续维护的成本\n  toolbarConfig.slots = {\n    ...(slotActions || showTableTitle.value\n      ? { buttons: TOOLBAR_ACTIONS }\n      : {}),\n    ...(slotTools ? { tools: TOOLBAR_TOOLS } : {}),\n  };\n  return { toolbarConfig };\n});\n\nconst options = computed(() => {\n  const globalGridConfig = VxeUI?.getConfig()?.grid ?? {};\n\n  const mergedOptions: VxeTableGridProps = cloneDeep(\n    mergeWithArrayOverride(\n      {},\n      toRaw(toolbarOptions.value),\n      toRaw(gridOptions.value),\n      globalGridConfig,\n    ),\n  );\n\n  if (mergedOptions.proxyConfig) {\n    const { ajax } = mergedOptions.proxyConfig;\n    mergedOptions.proxyConfig.enabled = !!ajax;\n    // 不自动加载数据, 由组件控制\n    mergedOptions.proxyConfig.autoLoad = false;\n  }\n\n  if (mergedOptions.pagerConfig) {\n    const mobileLayouts = [\n      'PrevJump',\n      'PrevPage',\n      'Number',\n      'NextPage',\n      'NextJump',\n    ] as any;\n    const layouts = [\n      'Total',\n      'Sizes',\n      'Home',\n      ...mobileLayouts,\n      'End',\n    ] as readonly string[];\n    mergedOptions.pagerConfig = mergeWithArrayOverride(\n      {},\n      mergedOptions.pagerConfig,\n      {\n        pageSize: 20,\n        background: true,\n        pageSizes: [10, 20, 30, 50, 100, 200],\n        className: 'mt-2 w-full',\n        layouts: isMobile.value ? mobileLayouts : layouts,\n        size: 'mini' as const,\n      },\n    );\n  }\n  if (mergedOptions.formConfig) {\n    mergedOptions.formConfig.enabled = false;\n  }\n  return mergedOptions;\n});\n\nfunction onToolbarToolClick(event: VxeGridDefines.ToolbarToolClickEventParams) {\n  if (event.code === 'search') {\n    onSearchBtnClick();\n  }\n  (\n    gridEvents.value?.toolbarToolClick as VxeGridListeners['toolbarToolClick']\n  )?.(event);\n}\n\nfunction onSearchBtnClick() {\n  props.api?.toggleSearchForm?.();\n}\n\nconst events = computed(() => {\n  return {\n    ...gridEvents.value,\n    toolbarToolClick: onToolbarToolClick,\n  };\n});\n\nconst delegatedSlots = computed(() => {\n  const resultSlots: string[] = [];\n\n  for (const key of Object.keys(slots)) {\n    if (\n      !['empty', 'form', 'loading', TOOLBAR_ACTIONS, TOOLBAR_TOOLS].includes(\n        key,\n      )\n    ) {\n      resultSlots.push(key);\n    }\n  }\n  return resultSlots;\n});\n\nconst delegatedFormSlots = computed(() => {\n  const resultSlots: string[] = [];\n\n  for (const key of Object.keys(slots)) {\n    if (key.startsWith(FORM_SLOT_PREFIX)) {\n      resultSlots.push(key);\n    }\n  }\n  return resultSlots.map((key) => key.replace(FORM_SLOT_PREFIX, ''));\n});\n\nconst showDefaultEmpty = computed(() => {\n  // 检查是否有原生的 VXE Table 空状态配置\n  const hasEmptyText = options.value.emptyText !== undefined;\n  const hasEmptyRender = options.value.emptyRender !== undefined;\n\n  // 如果有原生配置，就不显示默认的空状态\n  return !hasEmptyText && !hasEmptyRender;\n});\n\nasync function init() {\n  await nextTick();\n  const globalGridConfig = VxeUI?.getConfig()?.grid ?? {};\n  const defaultGridOptions: VxeTableGridProps = mergeWithArrayOverride(\n    {},\n    toRaw(gridOptions.value),\n    toRaw(globalGridConfig),\n  );\n  // 内部主动加载数据，防止form的默认值影响\n  const autoLoad = defaultGridOptions.proxyConfig?.autoLoad;\n  const enableProxyConfig = options.value.proxyConfig?.enabled;\n  if (enableProxyConfig && autoLoad) {\n    props.api.grid.commitProxy?.(\n      'query',\n      formOptions.value ? ((await formApi.getValues()) ?? {}) : {},\n    );\n    // props.api.reload(formApi.form?.values ?? {});\n  }\n\n  // form 由 vben-form代替，所以不适配formConfig，这里给出警告\n  const formConfig = gridOptions.value?.formConfig;\n  // 处理某个页面加载多个Table时，第2个之后的Table初始化报出警告\n  // 因为第一次初始化之后会把defaultGridOptions和gridOptions合并后缓存进State\n  if (formConfig && formConfig.enabled) {\n    console.warn(\n      '[Vben Vxe Table]: The formConfig in the grid is not supported, please use the `formOptions` props',\n    );\n  }\n  props.api?.setState?.({ gridOptions: defaultGridOptions });\n  // form 由 vben-form 代替，所以需要保证query相关事件可以拿到参数\n  extendProxyOptions(props.api, defaultGridOptions, () =>\n    formApi.getLatestSubmissionValues(),\n  );\n}\n\n// formOptions支持响应式\nwatch(\n  formOptions,\n  () => {\n    formApi.setState((prev) => {\n      const finalFormOptions: VbenFormProps = mergeWithArrayOverride(\n        {},\n        formOptions.value,\n        prev,\n      );\n      return {\n        ...finalFormOptions,\n        collapseTriggerResize: !!finalFormOptions.showCollapseButton,\n      };\n    });\n  },\n  {\n    immediate: true,\n  },\n);\n\nconst isCompactForm = computed(() => {\n  return formApi.getState()?.compact;\n});\n\nonMounted(() => {\n  props.api?.mount?.(gridRef.value, formApi);\n  init();\n});\n\nonUnmounted(() => {\n  formApi?.unmount?.();\n  props.api?.unmount?.();\n});\n</script>\n\n<template>\n  <div :class=\"cn('bg-card h-full rounded-md', className)\">\n    <VxeGrid\n      ref=\"gridRef\"\n      :class=\"\n        cn(\n          'p-2',\n          {\n            'pt-0': showToolbar && !formOptions,\n          },\n          gridClass,\n        )\n      \"\n      v-bind=\"options\"\n      v-on=\"events\"\n    >\n      <!-- 左侧操作区域或者title -->\n      <template v-if=\"showToolbar\" #toolbar-actions=\"slotProps\">\n        <slot v-if=\"showTableTitle\" name=\"table-title\">\n          <div class=\"mr-1 pl-1 text-[1rem]\">\n            {{ tableTitle }}\n            <VbenHelpTooltip v-if=\"tableTitleHelp\" trigger-class=\"pb-1\">\n              {{ tableTitleHelp }}\n            </VbenHelpTooltip>\n          </div>\n        </slot>\n        <slot name=\"toolbar-actions\" v-bind=\"slotProps\"> </slot>\n      </template>\n\n      <!-- 继承默认的slot -->\n      <template\n        v-for=\"slotName in delegatedSlots\"\n        :key=\"slotName\"\n        #[slotName]=\"slotProps\"\n      >\n        <slot :name=\"slotName\" v-bind=\"slotProps\"></slot>\n      </template>\n      <template #toolbar-tools=\"slotProps\">\n        <slot name=\"toolbar-tools\" v-bind=\"slotProps\"></slot>\n        <VxeButton\n          icon=\"vxe-icon-search\"\n          circle\n          class=\"ml-2\"\n          v-if=\"gridOptions?.toolbarConfig?.search && !!formOptions\"\n          :status=\"showSearchForm ? 'primary' : undefined\"\n          :title=\"$t('common.search')\"\n          @click=\"onSearchBtnClick\"\n        />\n      </template>\n\n      <!-- form表单 -->\n      <template #form>\n        <div\n          v-if=\"formOptions\"\n          v-show=\"showSearchForm !== false\"\n          :class=\"\n            cn(\n              'relative rounded py-3',\n              isCompactForm\n                ? isSeparator\n                  ? 'pb-8'\n                  : 'pb-4'\n                : isSeparator\n                  ? 'pb-4'\n                  : 'pb-0',\n            )\n          \"\n        >\n          <slot name=\"form\">\n            <Form>\n              <template\n                v-for=\"slotName in delegatedFormSlots\"\n                :key=\"slotName\"\n                #[slotName]=\"slotProps\"\n              >\n                <slot\n                  :name=\"`${FORM_SLOT_PREFIX}${slotName}`\"\n                  v-bind=\"slotProps\"\n                ></slot>\n              </template>\n              <template #reset-before=\"slotProps\">\n                <slot name=\"reset-before\" v-bind=\"slotProps\"></slot>\n              </template>\n              <template #submit-before=\"slotProps\">\n                <slot name=\"submit-before\" v-bind=\"slotProps\"></slot>\n              </template>\n              <template #expand-before=\"slotProps\">\n                <slot name=\"expand-before\" v-bind=\"slotProps\"></slot>\n              </template>\n              <template #expand-after=\"slotProps\">\n                <slot name=\"expand-after\" v-bind=\"slotProps\"></slot>\n              </template>\n            </Form>\n          </slot>\n          <div\n            v-if=\"isSeparator\"\n            :style=\"{\n              ...(separatorBg ? { backgroundColor: separatorBg } : undefined),\n            }\"\n            class=\"bg-background-deep z-100 absolute -left-2 bottom-1 h-2 w-[calc(100%+1rem)] overflow-hidden md:bottom-2 md:h-3\"\n          ></div>\n        </div>\n      </template>\n      <!-- loading -->\n      <template #loading>\n        <slot name=\"loading\">\n          <VbenLoading :spinning=\"true\" />\n        </slot>\n      </template>\n      <!-- 统一控状态 -->\n      <template v-if=\"showDefaultEmpty\" #empty>\n        <slot name=\"empty\">\n          <EmptyIcon class=\"mx-auto\" />\n          <div class=\"mt-2\">{{ $t('common.noData') }}</div>\n        </slot>\n      </template>\n    </VxeGrid>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/effects/plugins/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/package.json",
    "content": "{\n  \"name\": \"@vben/request\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/effects/request\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"axios\": \"catalog:\",\n    \"qs\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/qs\": \"catalog:\",\n    \"axios-mock-adapter\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/index.ts",
    "content": "export * from './request-client';\nexport * from 'axios';\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/index.ts",
    "content": "export * from './preset-interceptors';\nexport * from './request-client';\nexport type * from './types';\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/modules/downloader.test.ts",
    "content": "import type { AxiosRequestConfig } from 'axios';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { FileDownloader } from './downloader';\n\ndescribe('fileDownloader', () => {\n  let fileDownloader: FileDownloader;\n  const mockAxiosInstance = {\n    get: vi.fn(),\n  } as any;\n\n  beforeEach(() => {\n    fileDownloader = new FileDownloader(mockAxiosInstance);\n  });\n\n  it('should create an instance of FileDownloader', () => {\n    expect(fileDownloader).toBeInstanceOf(FileDownloader);\n  });\n\n  it('should download a file and return a Blob', async () => {\n    const url = 'https://example.com/file';\n    const mockBlob = new Blob(['file content'], { type: 'text/plain' });\n    const mockResponse: Blob = mockBlob;\n\n    mockAxiosInstance.get.mockResolvedValueOnce(mockResponse);\n\n    const result = await fileDownloader.download(url);\n\n    expect(result).toBeInstanceOf(Blob);\n    expect(result).toEqual(mockBlob);\n    expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, {\n      responseType: 'blob',\n      responseReturn: 'body',\n    });\n  });\n\n  it('should merge provided config with default config', async () => {\n    const url = 'https://example.com/file';\n    const mockBlob = new Blob(['file content'], { type: 'text/plain' });\n    const mockResponse: Blob = mockBlob;\n\n    mockAxiosInstance.get.mockResolvedValueOnce(mockResponse);\n\n    const customConfig: AxiosRequestConfig = {\n      headers: { 'Custom-Header': 'value' },\n    };\n\n    const result = await fileDownloader.download(url, customConfig);\n    expect(result).toBeInstanceOf(Blob);\n    expect(result).toEqual(mockBlob);\n    expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, {\n      ...customConfig,\n      responseType: 'blob',\n      responseReturn: 'body',\n    });\n  });\n\n  it('should handle errors gracefully', async () => {\n    const url = 'https://example.com/file';\n    mockAxiosInstance.get.mockRejectedValueOnce(new Error('Network Error'));\n    await expect(fileDownloader.download(url)).rejects.toThrow('Network Error');\n  });\n\n  it('should handle empty URL gracefully', async () => {\n    const url = '';\n    mockAxiosInstance.get.mockRejectedValueOnce(\n      new Error('Request failed with status code 404'),\n    );\n\n    await expect(fileDownloader.download(url)).rejects.toThrow(\n      'Request failed with status code 404',\n    );\n  });\n\n  it('should handle null URL gracefully', async () => {\n    const url = null as unknown as string;\n    mockAxiosInstance.get.mockRejectedValueOnce(\n      new Error('Request failed with status code 404'),\n    );\n\n    await expect(fileDownloader.download(url)).rejects.toThrow(\n      'Request failed with status code 404',\n    );\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/modules/downloader.ts",
    "content": "import type { RequestClient } from '../request-client';\nimport type { RequestClientConfig } from '../types';\n\ntype DownloadRequestConfig = {\n  /**\n   * 定义期望获得的数据类型。\n   * raw: 原始的AxiosResponse，包括headers、status等。\n   * body: 只返回响应数据的BODY部分(Blob)\n   */\n  responseReturn?: 'body' | 'raw';\n} & Omit<RequestClientConfig, 'responseReturn'>;\n\nclass FileDownloader {\n  private client: RequestClient;\n\n  constructor(client: RequestClient) {\n    this.client = client;\n  }\n  /**\n   * 下载文件\n   * @param url 文件的完整链接\n   * @param config 配置信息，可选。\n   * @returns 如果config.responseReturn为'body'，则返回Blob(默认)，否则返回RequestResponse<Blob>\n   */\n  public async download<T = Blob>(\n    url: string,\n    config?: DownloadRequestConfig,\n  ): Promise<T> {\n    const finalConfig: DownloadRequestConfig = {\n      responseReturn: 'body',\n      ...config,\n      responseType: 'blob',\n    };\n\n    const response = await this.client.get<T>(url, finalConfig);\n\n    return response;\n  }\n}\n\nexport { FileDownloader };\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/modules/interceptor.ts",
    "content": "import type { AxiosInstance, AxiosResponse } from 'axios';\n\nimport type {\n  RequestInterceptorConfig,\n  ResponseInterceptorConfig,\n} from '../types';\n\nconst defaultRequestInterceptorConfig: RequestInterceptorConfig = {\n  fulfilled: (response) => response,\n  rejected: (error) => Promise.reject(error),\n};\n\nconst defaultResponseInterceptorConfig: ResponseInterceptorConfig = {\n  fulfilled: (response: AxiosResponse) => response,\n  rejected: (error) => Promise.reject(error),\n};\n\nclass InterceptorManager {\n  private axiosInstance: AxiosInstance;\n\n  constructor(instance: AxiosInstance) {\n    this.axiosInstance = instance;\n  }\n\n  addRequestInterceptor({\n    fulfilled,\n    rejected,\n  }: RequestInterceptorConfig = defaultRequestInterceptorConfig) {\n    this.axiosInstance.interceptors.request.use(fulfilled, rejected);\n  }\n\n  addResponseInterceptor<T = any>({\n    fulfilled,\n    rejected,\n  }: ResponseInterceptorConfig<T> = defaultResponseInterceptorConfig) {\n    this.axiosInstance.interceptors.response.use(fulfilled, rejected);\n  }\n}\n\nexport { InterceptorManager };\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/modules/sse.test.ts",
    "content": "import type { RequestClient } from '../request-client';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { SSE } from './sse';\n\n// 模拟 TextDecoder\nconst OriginalTextDecoder = globalThis.TextDecoder;\n\nbeforeEach(() => {\n  vi.stubGlobal(\n    'TextDecoder',\n    class {\n      private decoder = new OriginalTextDecoder();\n      decode(value: Uint8Array, opts?: any) {\n        return this.decoder.decode(value, opts);\n      }\n    },\n  );\n});\n\n// 创建 fetch mock\nconst createFetchMock = (chunks: string[], ok = true) => {\n  const encoder = new TextEncoder();\n  let index = 0;\n  return vi.fn().mockResolvedValue({\n    ok,\n    status: ok ? 200 : 500,\n    body: {\n      getReader: () => ({\n        read: async () => {\n          if (index < chunks.length) {\n            return { done: false, value: encoder.encode(chunks[index++]) };\n          }\n          return { done: true, value: undefined };\n        },\n      }),\n    },\n  });\n};\n\ndescribe('sSE', () => {\n  let client: RequestClient;\n  let sse: SSE;\n\n  beforeEach(() => {\n    vi.restoreAllMocks();\n    client = {\n      getBaseUrl: () => 'http://localhost',\n      instance: {\n        interceptors: {\n          request: {\n            handlers: [],\n          },\n        },\n      },\n    } as unknown as RequestClient;\n    sse = new SSE(client);\n  });\n\n  it('should call requestSSE when postSSE is used', async () => {\n    const spy = vi.spyOn(sse, 'requestSSE').mockResolvedValue(undefined);\n    await sse.postSSE('/test', { foo: 'bar' }, { headers: { a: '1' } });\n    expect(spy).toHaveBeenCalledWith(\n      '/test',\n      { foo: 'bar' },\n      {\n        headers: { a: '1' },\n        method: 'POST',\n      },\n    );\n  });\n\n  it('should throw error if fetch response not ok', async () => {\n    vi.stubGlobal('fetch', createFetchMock([], false));\n    await expect(sse.requestSSE('/bad')).rejects.toThrow(\n      'HTTP error! status: 500',\n    );\n  });\n\n  it('should trigger onMessage and onEnd callbacks', async () => {\n    const messages: string[] = [];\n    const onMessage = vi.fn((msg: string) => messages.push(msg));\n    const onEnd = vi.fn();\n\n    vi.stubGlobal('fetch', createFetchMock(['hello', ' world']));\n\n    await sse.requestSSE('/sse', undefined, { onMessage, onEnd });\n\n    expect(onMessage).toHaveBeenCalledTimes(2);\n    expect(messages.join('')).toBe('hello world');\n    // onEnd 不再带参数\n    expect(onEnd).toHaveBeenCalled();\n  });\n\n  it('should apply request interceptors', async () => {\n    const interceptor = vi.fn(async (config) => {\n      config.headers['x-test'] = 'intercepted';\n      return config;\n    });\n    (client.instance.interceptors.request as any).handlers.push({\n      fulfilled: interceptor,\n    });\n\n    // 创建 fetch mock，并挂到全局\n    const fetchMock = createFetchMock(['data']);\n    vi.stubGlobal('fetch', fetchMock);\n\n    await sse.requestSSE('/sse', undefined, {});\n\n    expect(interceptor).toHaveBeenCalled();\n    expect(fetchMock).toHaveBeenCalledWith(\n      'http://localhost/sse',\n      expect.objectContaining({\n        headers: expect.any(Headers),\n      }),\n    );\n\n    const calls = fetchMock.mock?.calls;\n    expect(calls).toBeDefined();\n    expect(calls?.length).toBeGreaterThan(0);\n\n    const init = calls?.[0]?.[1] as RequestInit;\n    expect(init).toBeDefined();\n\n    const headers = init?.headers as Headers;\n    expect(headers?.get('x-test')).toBe('intercepted');\n    expect(headers?.get('accept')).toBe('text/event-stream');\n  });\n\n  it('should throw error when no reader', async () => {\n    vi.stubGlobal(\n      'fetch',\n      vi.fn().mockResolvedValue({\n        ok: true,\n        status: 200,\n        body: null,\n      }),\n    );\n    await expect(sse.requestSSE('/sse')).rejects.toThrow('No reader');\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/modules/sse.ts",
    "content": "import type { AxiosRequestHeaders, InternalAxiosRequestConfig } from 'axios';\n\nimport type { RequestClient } from '../request-client';\nimport type { SseRequestOptions } from '../types';\n\n/**\n * SSE模块\n */\nclass SSE {\n  private client: RequestClient;\n\n  constructor(client: RequestClient) {\n    this.client = client;\n  }\n\n  public async postSSE(\n    url: string,\n    data?: any,\n    requestOptions?: SseRequestOptions,\n  ) {\n    return this.requestSSE(url, data, {\n      ...requestOptions,\n      method: 'POST',\n    });\n  }\n\n  /**\n   * SSE请求方法\n   * @param url - 请求URL\n   * @param data - 请求数据\n   * @param requestOptions - SSE请求选项\n   */\n  public async requestSSE(\n    url: string,\n    data?: any,\n    requestOptions?: SseRequestOptions,\n  ) {\n    const baseUrl = this.client.getBaseUrl() || '';\n\n    let axiosConfig: InternalAxiosRequestConfig<any> = {\n      url,\n      method: (requestOptions?.method as any) ?? 'GET',\n      headers: {} as AxiosRequestHeaders,\n    };\n    const requestInterceptors = this.client.instance.interceptors\n      .request as any;\n    if (\n      requestInterceptors.handlers &&\n      requestInterceptors.handlers.length > 0\n    ) {\n      for (const handler of requestInterceptors.handlers) {\n        if (typeof handler?.fulfilled === 'function') {\n          const next = await handler.fulfilled(axiosConfig as any);\n          if (next) axiosConfig = next as InternalAxiosRequestConfig<any>;\n        }\n      }\n    }\n\n    const merged = new Headers();\n    Object.entries(\n      (axiosConfig.headers ?? {}) as Record<string, string>,\n    ).forEach(([k, v]) => merged.set(k, String(v)));\n    if (requestOptions?.headers) {\n      new Headers(requestOptions.headers).forEach((v, k) => merged.set(k, v));\n    }\n    if (!merged.has('accept')) {\n      merged.set('accept', 'text/event-stream');\n    }\n\n    let bodyInit = requestOptions?.body ?? data;\n    const ct = (merged.get('content-type') || '').toLowerCase();\n    if (\n      bodyInit &&\n      typeof bodyInit === 'object' &&\n      !ArrayBuffer.isView(bodyInit as any) &&\n      !(bodyInit instanceof ArrayBuffer) &&\n      !(bodyInit instanceof Blob) &&\n      !(bodyInit instanceof FormData) &&\n      ct.includes('application/json')\n    ) {\n      bodyInit = JSON.stringify(bodyInit);\n    }\n    const requestInit: RequestInit = {\n      ...requestOptions,\n      method: axiosConfig.method,\n      headers: merged,\n      body: bodyInit,\n    };\n\n    const response = await fetch(safeJoinUrl(baseUrl, url), requestInit);\n    if (!response.ok) {\n      throw new Error(`HTTP error! status: ${response.status}`);\n    }\n\n    const reader = response.body?.getReader();\n    const decoder = new TextDecoder();\n\n    if (!reader) {\n      throw new Error('No reader');\n    }\n    let isEnd = false;\n    while (!isEnd) {\n      const { done, value } = await reader.read();\n      if (done) {\n        isEnd = true;\n        decoder.decode(new Uint8Array(0), { stream: false });\n        requestOptions?.onEnd?.();\n        reader.releaseLock?.();\n        break;\n      }\n      const content = decoder.decode(value, { stream: true });\n      requestOptions?.onMessage?.(content);\n    }\n  }\n}\n\nfunction safeJoinUrl(baseUrl: string | undefined, url: string): string {\n  if (!baseUrl) {\n    return url; // 没有 baseUrl，直接返回 url\n  }\n\n  // 如果 url 本身就是绝对地址，直接返回\n  if (/^https?:\\/\\//i.test(url)) {\n    return url;\n  }\n\n  // 如果 baseUrl 是完整 URL，就用 new URL\n  if (/^https?:\\/\\//i.test(baseUrl)) {\n    return new URL(url, baseUrl).toString();\n  }\n\n  // 否则，当作路径拼接\n  return `${baseUrl.replace(/\\/+$/, '')}/${url.replace(/^\\/+/, '')}`;\n}\n\nexport { SSE };\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/modules/uploader.test.ts",
    "content": "import type { AxiosRequestConfig, AxiosResponse } from 'axios';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { FileUploader } from './uploader';\n\ndescribe('fileUploader', () => {\n  let fileUploader: FileUploader;\n  // Mock the AxiosInstance\n  const mockAxiosInstance = {\n    post: vi.fn(),\n  } as any;\n\n  beforeEach(() => {\n    fileUploader = new FileUploader(mockAxiosInstance);\n  });\n\n  it('should create an instance of FileUploader', () => {\n    expect(fileUploader).toBeInstanceOf(FileUploader);\n  });\n\n  it('should upload a file and return the response', async () => {\n    const url = 'https://example.com/upload';\n    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });\n    const mockResponse: AxiosResponse = {\n      config: {} as any,\n      data: { success: true },\n      headers: {},\n      status: 200,\n      statusText: 'OK',\n    };\n\n    (\n      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>\n    ).mockResolvedValueOnce(mockResponse);\n\n    const result = await fileUploader.upload(url, { file });\n    expect(result).toEqual(mockResponse);\n    expect(mockAxiosInstance.post).toHaveBeenCalledWith(\n      url,\n      expect.any(FormData),\n      {\n        headers: {\n          'Content-Type': 'multipart/form-data',\n        },\n      },\n    );\n  });\n\n  it('should merge provided config with default config', async () => {\n    const url = 'https://example.com/upload';\n    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });\n    const mockResponse: AxiosResponse = {\n      config: {} as any,\n      data: { success: true },\n      headers: {},\n      status: 200,\n      statusText: 'OK',\n    };\n\n    (\n      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>\n    ).mockResolvedValueOnce(mockResponse);\n\n    const customConfig: AxiosRequestConfig = {\n      headers: { 'Custom-Header': 'value' },\n    };\n\n    const result = await fileUploader.upload(url, { file }, customConfig);\n    expect(result).toEqual(mockResponse);\n    expect(mockAxiosInstance.post).toHaveBeenCalledWith(\n      url,\n      expect.any(FormData),\n      {\n        headers: {\n          'Content-Type': 'multipart/form-data',\n          'Custom-Header': 'value',\n        },\n      },\n    );\n  });\n\n  it('should handle errors gracefully', async () => {\n    const url = 'https://example.com/upload';\n    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });\n    (\n      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>\n    ).mockRejectedValueOnce(new Error('Network Error'));\n\n    await expect(fileUploader.upload(url, { file })).rejects.toThrow(\n      'Network Error',\n    );\n  });\n\n  it('should handle empty URL gracefully', async () => {\n    const url = '';\n    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });\n    (\n      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>\n    ).mockRejectedValueOnce(new Error('Request failed with status code 404'));\n\n    await expect(fileUploader.upload(url, { file })).rejects.toThrow(\n      'Request failed with status code 404',\n    );\n  });\n\n  it('should handle null URL gracefully', async () => {\n    const url = null as unknown as string;\n    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });\n    (\n      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>\n    ).mockRejectedValueOnce(new Error('Request failed with status code 404'));\n\n    await expect(fileUploader.upload(url, { file })).rejects.toThrow(\n      'Request failed with status code 404',\n    );\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/modules/uploader.ts",
    "content": "import type { RequestClient } from '../request-client';\nimport type { RequestClientConfig } from '../types';\n\nimport { isUndefined } from '@vben/utils';\n\nclass FileUploader {\n  private client: RequestClient;\n\n  constructor(client: RequestClient) {\n    this.client = client;\n  }\n\n  public async upload<T = any>(\n    url: string,\n    data: Record<string, any> & { file: Blob | File },\n    config?: RequestClientConfig,\n  ): Promise<T> {\n    const formData = new FormData();\n\n    Object.entries(data).forEach(([key, value]) => {\n      if (Array.isArray(value)) {\n        value.forEach((item, index) => {\n          !isUndefined(item) && formData.append(`${key}[${index}]`, item);\n        });\n      } else {\n        !isUndefined(value) && formData.append(key, value);\n      }\n    });\n\n    const finalConfig: RequestClientConfig = {\n      ...config,\n      headers: {\n        'Content-Type': 'multipart/form-data',\n        ...config?.headers,\n      },\n    };\n\n    return this.client.post(url, formData, finalConfig);\n  }\n}\n\nexport { FileUploader };\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/preset-interceptors.ts",
    "content": "import type { RequestClient } from './request-client';\nimport type { MakeErrorMessageFn, ResponseInterceptorConfig } from './types';\n\nimport { $t } from '@vben/locales';\nimport { isFunction } from '@vben/utils';\n\nimport axios from 'axios';\n\nexport const defaultResponseInterceptor = ({\n  codeField = 'code',\n  dataField = 'data',\n  successCode = 0,\n}: {\n  /** 响应数据中代表访问结果的字段名 */\n  codeField: string;\n  /** 响应数据中装载实际数据的字段名，或者提供一个函数从响应数据中解析需要返回的数据 */\n  dataField: ((response: any) => any) | string;\n  /** 当codeField所指定的字段值与successCode相同时，代表接口访问成功。如果提供一个函数，则返回true代表接口访问成功 */\n  successCode: ((code: any) => boolean) | number | string;\n}): ResponseInterceptorConfig => {\n  return {\n    fulfilled: (response) => {\n      const { config, data: responseData, status } = response;\n\n      if (config.responseReturn === 'raw') {\n        return response;\n      }\n\n      if (status >= 200 && status < 400) {\n        if (config.responseReturn === 'body') {\n          return responseData;\n        } else if (\n          isFunction(successCode)\n            ? successCode(responseData[codeField])\n            : responseData[codeField] === successCode\n        ) {\n          return isFunction(dataField)\n            ? dataField(responseData)\n            : responseData[dataField];\n        }\n      }\n      throw Object.assign({}, response, { response });\n    },\n  };\n};\n\nexport const authenticateResponseInterceptor = ({\n  client,\n  doReAuthenticate,\n  doRefreshToken,\n  enableRefreshToken,\n  formatToken,\n}: {\n  client: RequestClient;\n  doReAuthenticate: () => Promise<void>;\n  doRefreshToken: () => Promise<string>;\n  enableRefreshToken: boolean;\n  formatToken: (token: string) => null | string;\n}): ResponseInterceptorConfig => {\n  return {\n    rejected: async (error) => {\n      const { config, response } = error;\n      // 如果不是 401 错误，直接抛出异常\n      if (response?.status !== 401) {\n        throw error;\n      }\n      // 判断是否启用了 refreshToken 功能\n      // 如果没有启用或者已经是重试请求了，直接跳转到重新登录\n      if (!enableRefreshToken || config.__isRetryRequest) {\n        await doReAuthenticate();\n        throw error;\n      }\n      // 如果正在刷新 token，则将请求加入队列，等待刷新完成\n      if (client.isRefreshing) {\n        return new Promise((resolve) => {\n          client.refreshTokenQueue.push((newToken: string) => {\n            config.headers.Authorization = formatToken(newToken);\n            resolve(client.request(config.url, { ...config }));\n          });\n        });\n      }\n\n      // 标记开始刷新 token\n      client.isRefreshing = true;\n      // 标记当前请求为重试请求，避免无限循环\n      config.__isRetryRequest = true;\n\n      try {\n        const newToken = await doRefreshToken();\n\n        // 处理队列中的请求\n        client.refreshTokenQueue.forEach((callback) => callback(newToken));\n        // 清空队列\n        client.refreshTokenQueue = [];\n\n        return client.request(error.config.url, { ...error.config });\n      } catch (refreshError) {\n        // 如果刷新 token 失败，处理错误（如强制登出或跳转登录页面）\n        client.refreshTokenQueue.forEach((callback) => callback(''));\n        client.refreshTokenQueue = [];\n        console.error('Refresh token failed, please login again.');\n        await doReAuthenticate();\n\n        throw refreshError;\n      } finally {\n        client.isRefreshing = false;\n      }\n    },\n  };\n};\n\nexport const errorMessageResponseInterceptor = (\n  makeErrorMessage?: MakeErrorMessageFn,\n): ResponseInterceptorConfig => {\n  return {\n    rejected: (error: any) => {\n      if (axios.isCancel(error)) {\n        return Promise.reject(error);\n      }\n\n      const err: string = error?.toString?.() ?? '';\n      let errMsg = '';\n      if (err?.includes('Network Error')) {\n        errMsg = $t('ui.fallback.http.networkError');\n      } else if (error?.message?.includes?.('timeout')) {\n        errMsg = $t('ui.fallback.http.requestTimeout');\n      }\n      if (errMsg) {\n        makeErrorMessage?.(errMsg, error);\n        return Promise.reject(error);\n      }\n\n      let errorMessage = '';\n      const status = error?.response?.status;\n\n      switch (status) {\n        case 400: {\n          errorMessage = $t('ui.fallback.http.badRequest');\n          break;\n        }\n        case 401: {\n          errorMessage = $t('ui.fallback.http.unauthorized');\n          break;\n        }\n        case 403: {\n          errorMessage = $t('ui.fallback.http.forbidden');\n          break;\n        }\n        case 404: {\n          errorMessage = $t('ui.fallback.http.notFound');\n          break;\n        }\n        case 408: {\n          errorMessage = $t('ui.fallback.http.requestTimeout');\n          break;\n        }\n        default: {\n          errorMessage = $t('ui.fallback.http.internalServerError');\n        }\n      }\n      makeErrorMessage?.(errorMessage, error);\n      return Promise.reject(error);\n    },\n  };\n};\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/request-client.test.ts",
    "content": "import axios from 'axios';\nimport MockAdapter from 'axios-mock-adapter';\nimport { afterEach, beforeEach, describe, expect, it } from 'vitest';\n\nimport { RequestClient } from './request-client';\n\ndescribe('requestClient', () => {\n  let mock: MockAdapter;\n  let requestClient: RequestClient;\n\n  beforeEach(() => {\n    mock = new MockAdapter(axios);\n    requestClient = new RequestClient();\n  });\n\n  afterEach(() => {\n    mock.reset();\n  });\n\n  it('should successfully make a GET request', async () => {\n    mock.onGet('test/url').reply(200, { data: 'response' });\n\n    const response = await requestClient.get('test/url');\n\n    expect(response.data).toEqual({ data: 'response' });\n  });\n\n  it('should successfully make a POST request', async () => {\n    const postData = { key: 'value' };\n    const mockData = { data: 'response' };\n    mock.onPost('/test/post', postData).reply(200, mockData);\n    const response = await requestClient.post('/test/post', postData);\n    expect(response.data).toEqual(mockData);\n  });\n\n  it('should successfully make a PUT request', async () => {\n    const putData = { key: 'updatedValue' };\n    const mockData = { data: 'updated response' };\n    mock.onPut('/test/put', putData).reply(200, mockData);\n    const response = await requestClient.put('/test/put', putData);\n    expect(response.data).toEqual(mockData);\n  });\n\n  it('should successfully make a DELETE request', async () => {\n    const mockData = { data: 'delete response' };\n    mock.onDelete('/test/delete').reply(200, mockData);\n    const response = await requestClient.delete('/test/delete');\n    expect(response.data).toEqual(mockData);\n  });\n\n  it('should handle network errors', async () => {\n    mock.onGet('/test/error').networkError();\n    try {\n      await requestClient.get('/test/error');\n      expect(true).toBe(false);\n    } catch (error: any) {\n      expect(error.isAxiosError).toBe(true);\n      expect(error.message).toBe('Network Error');\n    }\n  });\n\n  it('should handle timeout', async () => {\n    mock.onGet('/test/timeout').timeout();\n    try {\n      await requestClient.get('/test/timeout');\n      expect(true).toBe(false);\n    } catch (error: any) {\n      expect(error.isAxiosError).toBe(true);\n      expect(error.code).toBe('ECONNABORTED');\n    }\n  });\n\n  it('should successfully upload a file', async () => {\n    const fileData = new Blob(['file contents'], { type: 'text/plain' });\n\n    mock.onPost('/test/upload').reply((config) => {\n      return config.data instanceof FormData && config.data.has('file')\n        ? [200, { data: 'file uploaded' }]\n        : [400, { error: 'Bad Request' }];\n    });\n\n    const response = await requestClient.upload('/test/upload', {\n      file: fileData,\n    });\n    expect(response.data).toEqual({ data: 'file uploaded' });\n  });\n\n  it('should successfully download a file as a blob', async () => {\n    const mockFileContent = new Blob(['mock file content'], {\n      type: 'text/plain',\n    });\n\n    mock.onGet('/test/download').reply(200, mockFileContent);\n\n    const res = await requestClient.download('/test/download');\n\n    expect(res.data).toBeInstanceOf(Blob);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/request-client.ts",
    "content": "import type { AxiosInstance, AxiosResponse } from 'axios';\n\nimport type { RequestClientConfig, RequestClientOptions } from './types';\n\nimport { bindMethods, isString, merge } from '@vben/utils';\n\nimport axios from 'axios';\nimport qs from 'qs';\n\nimport { FileDownloader } from './modules/downloader';\nimport { InterceptorManager } from './modules/interceptor';\nimport { SSE } from './modules/sse';\nimport { FileUploader } from './modules/uploader';\n\nfunction getParamsSerializer(\n  paramsSerializer: RequestClientOptions['paramsSerializer'],\n) {\n  if (isString(paramsSerializer)) {\n    switch (paramsSerializer) {\n      case 'brackets': {\n        return (params: any) =>\n          qs.stringify(params, { arrayFormat: 'brackets' });\n      }\n      case 'comma': {\n        return (params: any) => qs.stringify(params, { arrayFormat: 'comma' });\n      }\n      case 'indices': {\n        return (params: any) =>\n          qs.stringify(params, { arrayFormat: 'indices' });\n      }\n      case 'repeat': {\n        return (params: any) => qs.stringify(params, { arrayFormat: 'repeat' });\n      }\n    }\n  }\n  return paramsSerializer;\n}\n\nclass RequestClient {\n  public addRequestInterceptor: InterceptorManager['addRequestInterceptor'];\n\n  public addResponseInterceptor: InterceptorManager['addResponseInterceptor'];\n  public download: FileDownloader['download'];\n\n  public readonly instance: AxiosInstance;\n  // 是否正在刷新token\n  public isRefreshing = false;\n  public postSSE: SSE['postSSE'];\n  // 刷新token队列\n  public refreshTokenQueue: ((token: string) => void)[] = [];\n  public requestSSE: SSE['requestSSE'];\n  public upload: FileUploader['upload'];\n\n  /**\n   * 构造函数，用于创建Axios实例\n   * @param options - Axios请求配置，可选\n   */\n  constructor(options: RequestClientOptions = {}) {\n    // 合并默认配置和传入的配置\n    const defaultConfig: RequestClientOptions = {\n      headers: {\n        'Content-Type': 'application/json;charset=utf-8',\n      },\n      responseReturn: 'raw',\n      // 默认超时时间\n      timeout: 10_000,\n    };\n    const { ...axiosConfig } = options;\n    const requestConfig = merge(axiosConfig, defaultConfig);\n    requestConfig.paramsSerializer = getParamsSerializer(\n      requestConfig.paramsSerializer,\n    );\n    this.instance = axios.create(requestConfig);\n\n    bindMethods(this);\n\n    // 实例化拦截器管理器\n    const interceptorManager = new InterceptorManager(this.instance);\n    this.addRequestInterceptor =\n      interceptorManager.addRequestInterceptor.bind(interceptorManager);\n    this.addResponseInterceptor =\n      interceptorManager.addResponseInterceptor.bind(interceptorManager);\n\n    // 实例化文件上传器\n    const fileUploader = new FileUploader(this);\n    this.upload = fileUploader.upload.bind(fileUploader);\n    // 实例化文件下载器\n    const fileDownloader = new FileDownloader(this);\n    this.download = fileDownloader.download.bind(fileDownloader);\n    // 实例化SSE模块\n    const sse = new SSE(this);\n    this.postSSE = sse.postSSE.bind(sse);\n    this.requestSSE = sse.requestSSE.bind(sse);\n  }\n\n  /**\n   * DELETE请求方法\n   */\n  public delete<T = any>(\n    url: string,\n    config?: RequestClientConfig,\n  ): Promise<T> {\n    return this.request<T>(url, { ...config, method: 'DELETE' });\n  }\n\n  /**\n   * GET请求方法\n   */\n  public get<T = any>(url: string, config?: RequestClientConfig): Promise<T> {\n    return this.request<T>(url, { ...config, method: 'GET' });\n  }\n\n  /**\n   * 获取基础URL\n   */\n  public getBaseUrl() {\n    return this.instance.defaults.baseURL;\n  }\n\n  /**\n   * POST请求方法\n   */\n  public post<T = any>(\n    url: string,\n    data?: any,\n    config?: RequestClientConfig,\n  ): Promise<T> {\n    return this.request<T>(url, { ...config, data, method: 'POST' });\n  }\n\n  /**\n   * PUT请求方法\n   */\n  public put<T = any>(\n    url: string,\n    data?: any,\n    config?: RequestClientConfig,\n  ): Promise<T> {\n    return this.request<T>(url, { ...config, data, method: 'PUT' });\n  }\n\n  /**\n   * 通用的请求方法\n   */\n  public async request<T>(\n    url: string,\n    config: RequestClientConfig,\n  ): Promise<T> {\n    try {\n      const response: AxiosResponse<T> = await this.instance({\n        url,\n        ...config,\n        ...(config.paramsSerializer\n          ? { paramsSerializer: getParamsSerializer(config.paramsSerializer) }\n          : {}),\n      });\n      return response as T;\n    } catch (error: any) {\n      throw error.response ? error.response.data : error;\n    }\n  }\n}\n\nexport { RequestClient };\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/src/request-client/types.ts",
    "content": "import type {\n  AxiosRequestConfig,\n  AxiosResponse,\n  CreateAxiosDefaults,\n  InternalAxiosRequestConfig,\n} from 'axios';\n\ntype ExtendOptions<T = any> = {\n  /**\n   * 参数序列化方式。预置的有\n   * - brackets: ids[]=1&ids[]=2&ids[]=3\n   * - comma: ids=1,2,3\n   * - indices: ids[0]=1&ids[1]=2&ids[2]=3\n   * - repeat: ids=1&ids=2&ids=3\n   */\n  paramsSerializer?:\n    | 'brackets'\n    | 'comma'\n    | 'indices'\n    | 'repeat'\n    | AxiosRequestConfig<T>['paramsSerializer'];\n  /**\n   * 响应数据的返回方式。\n   * - raw: 原始的AxiosResponse，包括headers、status等，不做是否成功请求的检查。\n   * - body: 返回响应数据的BODY部分（只会根据status检查请求是否成功，忽略对code的判断，这种情况下应由调用方检查请求是否成功）。\n   * - data: 解构响应的BODY数据，只返回其中的data节点数据（会检查status和code是否为成功状态）。\n   */\n  responseReturn?: 'body' | 'data' | 'raw';\n};\ntype RequestClientConfig<T = any> = AxiosRequestConfig<T> & ExtendOptions<T>;\n\ntype RequestResponse<T = any> = AxiosResponse<T> & {\n  config: RequestClientConfig<T>;\n};\n\ntype RequestContentType =\n  | 'application/json;charset=utf-8'\n  | 'application/octet-stream;charset=utf-8'\n  | 'application/x-www-form-urlencoded;charset=utf-8'\n  | 'multipart/form-data;charset=utf-8';\n\ntype RequestClientOptions = CreateAxiosDefaults & ExtendOptions;\n\n/**\n * SSE 请求选项\n */\ninterface SseRequestOptions extends RequestInit {\n  onMessage?: (message: string) => void;\n  onEnd?: () => void;\n}\n\ninterface RequestInterceptorConfig {\n  fulfilled?: (\n    config: ExtendOptions & InternalAxiosRequestConfig,\n  ) =>\n    | (ExtendOptions & InternalAxiosRequestConfig<any>)\n    | Promise<ExtendOptions & InternalAxiosRequestConfig<any>>;\n  rejected?: (error: any) => any;\n}\n\ninterface ResponseInterceptorConfig<T = any> {\n  fulfilled?: (\n    response: RequestResponse<T>,\n  ) => Promise<RequestResponse> | RequestResponse;\n  rejected?: (error: any) => any;\n}\n\ntype MakeErrorMessageFn = (message: string, error: any) => void;\n\ninterface HttpResponse<T = any> {\n  /**\n   * 0 表示成功 其他表示失败\n   * 0 means success, others means fail\n   */\n  code: number;\n  data: T;\n  message: string;\n}\n\nexport type {\n  HttpResponse,\n  MakeErrorMessageFn,\n  RequestClientConfig,\n  RequestClientOptions,\n  RequestContentType,\n  RequestInterceptorConfig,\n  RequestResponse,\n  ResponseInterceptorConfig,\n  SseRequestOptions,\n};\n"
  },
  {
    "path": "hiauth-front/packages/effects/request/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/icons/README.md",
    "content": "# @vben/icons\n\n用于多个 `app` 公用的图标文件，继承了 `@vben-core/icons` 的所有能力。业务上有通用图标可以放在这里。\n\n## 用法\n\n### 添加依赖\n\n```bash\n# 进入目标应用目录，例如 apps/xxxx-app\n# cd apps/xxxx-app\npnpm add @vben/icons\n```\n\n### 使用\n\n```ts\nimport { X } from '@vben/icons';\n```\n"
  },
  {
    "path": "hiauth-front/packages/icons/package.json",
    "content": "{\n  \"name\": \"@vben/icons\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/icons\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/icons\": \"workspace:*\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/icons/src/iconify/index.ts",
    "content": "import { createIconifyIcon } from '@vben-core/icons';\n\nexport * from '@vben-core/icons';\n\nexport const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');\n"
  },
  {
    "path": "hiauth-front/packages/icons/src/icons/empty-icon.vue",
    "content": "<template>\n  <svg\n    height=\"41\"\n    viewBox=\"0 0 64 41\"\n    width=\"64\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(0 1)\">\n      <ellipse\n        cx=\"32\"\n        cy=\"33\"\n        fill=\"hsl(var(--background-deep))\"\n        rx=\"32\"\n        ry=\"7\"\n      />\n      <g fill-rule=\"nonzero\" stroke=\"hsl(var(--heavy))\">\n        <path\n          d=\"M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z\"\n        />\n        <path\n          d=\"M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z\"\n          fill=\"hsl(var(--accent))\"\n        />\n      </g>\n    </g>\n  </svg>\n</template>\n"
  },
  {
    "path": "hiauth-front/packages/icons/src/index.ts",
    "content": "export * from './iconify';\nexport { default as EmptyIcon } from './icons/empty-icon.vue';\nexport * from './svg';\n"
  },
  {
    "path": "hiauth-front/packages/icons/src/svg/index.ts",
    "content": "import { createIconifyIcon } from '@vben-core/icons';\n\nimport './load.js';\n\nconst SvgAvatar1Icon = createIconifyIcon('svg:avatar-1');\nconst SvgAvatar2Icon = createIconifyIcon('svg:avatar-2');\nconst SvgAvatar3Icon = createIconifyIcon('svg:avatar-3');\nconst SvgAvatar4Icon = createIconifyIcon('svg:avatar-4');\nconst SvgDownloadIcon = createIconifyIcon('svg:download');\nconst SvgCardIcon = createIconifyIcon('svg:card');\nconst SvgBellIcon = createIconifyIcon('svg:bell');\nconst SvgCakeIcon = createIconifyIcon('svg:cake');\nconst SvgAntdvLogoIcon = createIconifyIcon('svg:antdv-logo');\nconst SvgGithubIcon = createIconifyIcon('svg:github');\nconst SvgGoogleIcon = createIconifyIcon('svg:google');\nconst SvgQQChatIcon = createIconifyIcon('svg:qqchat');\nconst SvgWeChatIcon = createIconifyIcon('svg:wechat');\nconst SvgDingDingIcon = createIconifyIcon('svg:dingding');\n\nexport {\n  SvgAntdvLogoIcon,\n  SvgAvatar1Icon,\n  SvgAvatar2Icon,\n  SvgAvatar3Icon,\n  SvgAvatar4Icon,\n  SvgBellIcon,\n  SvgCakeIcon,\n  SvgCardIcon,\n  SvgDingDingIcon,\n  SvgDownloadIcon,\n  SvgGithubIcon,\n  SvgGoogleIcon,\n  SvgQQChatIcon,\n  SvgWeChatIcon,\n};\n"
  },
  {
    "path": "hiauth-front/packages/icons/src/svg/load.ts",
    "content": "import type { IconifyIconStructure } from '@vben-core/icons';\n\nimport { addIcon } from '@vben-core/icons';\n\nlet loaded = false;\nif (!loaded) {\n  loadSvgIcons();\n  loaded = true;\n}\n\nfunction parseSvg(svgData: string): IconifyIconStructure {\n  const parser = new DOMParser();\n  const xmlDoc = parser.parseFromString(svgData, 'image/svg+xml');\n  const svgElement = xmlDoc.documentElement;\n\n  const svgContent = [...svgElement.childNodes]\n    .filter((node) => node.nodeType === Node.ELEMENT_NODE)\n    .map((node) => new XMLSerializer().serializeToString(node))\n    .join('');\n\n  const viewBoxValue = svgElement.getAttribute('viewBox') || '';\n  const [left, top, width, height] = viewBoxValue.split(' ').map((val) => {\n    const num = Number(val);\n    return Number.isNaN(num) ? undefined : num;\n  });\n\n  return {\n    body: svgContent,\n    height,\n    left,\n    top,\n    width,\n  };\n}\n\n/**\n * 自定义的svg图片转化为组件\n * @example ./svg/avatar.svg\n * <Icon icon=\"svg:avatar\"></Icon>\n */\nasync function loadSvgIcons() {\n  const svgEagers = import.meta.glob('./icons/**', {\n    eager: true,\n    query: '?raw',\n  });\n\n  await Promise.all(\n    Object.entries(svgEagers).map((svg) => {\n      const [key, body] = svg as [string, string | { default: string }];\n\n      // ./icons/xxxx.svg => xxxxxx\n      const start = key.lastIndexOf('/') + 1;\n      const end = key.lastIndexOf('.');\n      const iconName = key.slice(start, end);\n\n      return addIcon(`svg:${iconName}`, {\n        ...parseSvg(typeof body === 'object' ? body.default : body),\n      });\n    }),\n  );\n}\n"
  },
  {
    "path": "hiauth-front/packages/icons/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/package.json",
    "content": "{\n  \"name\": \"@vben/locales\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/locales\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@intlify/core-base\": \"catalog:\",\n    \"@vben-core/composables\": \"workspace:*\",\n    \"vue\": \"catalog:\",\n    \"vue-i18n\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/i18n.ts",
    "content": "import type { App } from 'vue';\nimport type { Locale } from 'vue-i18n';\n\nimport type {\n  ImportLocaleFn,\n  LoadMessageFn,\n  LocaleSetupOptions,\n  SupportedLanguagesType,\n} from './typing';\n\nimport { unref } from 'vue';\nimport { createI18n } from 'vue-i18n';\n\nimport { useSimpleLocale } from '@vben-core/composables';\n\nconst i18n = createI18n({\n  globalInjection: true,\n  legacy: false,\n  locale: '',\n  messages: {},\n});\n\nconst modules = import.meta.glob('./langs/**/*.json');\n\nconst { setSimpleLocale } = useSimpleLocale();\n\nconst localesMap = loadLocalesMapFromDir(\n  /\\.\\/langs\\/([^/]+)\\/(.*)\\.json$/,\n  modules,\n);\nlet loadMessages: LoadMessageFn;\n\n/**\n * Load locale modules\n * @param modules\n */\nfunction loadLocalesMap(modules: Record<string, () => Promise<unknown>>) {\n  const localesMap: Record<Locale, ImportLocaleFn> = {};\n\n  for (const [path, loadLocale] of Object.entries(modules)) {\n    const key = path.match(/([\\w-]*)\\.(json)/)?.[1];\n    if (key) {\n      localesMap[key] = loadLocale as ImportLocaleFn;\n    }\n  }\n  return localesMap;\n}\n\n/**\n * Load locale modules with directory structure\n * @param regexp - Regular expression to match language and file names\n * @param modules - The modules object containing paths and import functions\n * @returns A map of locales to their corresponding import functions\n */\nfunction loadLocalesMapFromDir(\n  regexp: RegExp,\n  modules: Record<string, () => Promise<unknown>>,\n): Record<Locale, ImportLocaleFn> {\n  const localesRaw: Record<Locale, Record<string, () => Promise<unknown>>> = {};\n  const localesMap: Record<Locale, ImportLocaleFn> = {};\n\n  // Iterate over the modules to extract language and file names\n  for (const path in modules) {\n    const match = path.match(regexp);\n    if (match) {\n      const [_, locale, fileName] = match;\n      if (locale && fileName) {\n        if (!localesRaw[locale]) {\n          localesRaw[locale] = {};\n        }\n        if (modules[path]) {\n          localesRaw[locale][fileName] = modules[path];\n        }\n      }\n    }\n  }\n\n  // Convert raw locale data into async import functions\n  for (const [locale, files] of Object.entries(localesRaw)) {\n    localesMap[locale] = async () => {\n      const messages: Record<string, any> = {};\n      for (const [fileName, importFn] of Object.entries(files)) {\n        messages[fileName] = ((await importFn()) as any)?.default;\n      }\n      return { default: messages };\n    };\n  }\n\n  return localesMap;\n}\n\n/**\n * Set i18n language\n * @param locale\n */\nfunction setI18nLanguage(locale: Locale) {\n  i18n.global.locale.value = locale;\n\n  document?.querySelector('html')?.setAttribute('lang', locale);\n}\n\nasync function setupI18n(app: App, options: LocaleSetupOptions = {}) {\n  const { defaultLocale = 'zh-CN' } = options;\n  // app可以自行扩展一些第三方库和组件库的国际化\n  loadMessages = options.loadMessages || (async () => ({}));\n  app.use(i18n);\n  await loadLocaleMessages(defaultLocale);\n\n  // 在控制台打印警告\n  i18n.global.setMissingHandler((locale, key) => {\n    if (options.missingWarn && key.includes('.')) {\n      console.warn(\n        `[intlify] Not found '${key}' key in '${locale}' locale messages.`,\n      );\n    }\n  });\n}\n\n/**\n * Load locale messages\n * @param lang\n */\nasync function loadLocaleMessages(lang: SupportedLanguagesType) {\n  if (unref(i18n.global.locale) === lang) {\n    return setI18nLanguage(lang);\n  }\n  setSimpleLocale(lang);\n\n  const message = await localesMap[lang]?.();\n\n  if (message?.default) {\n    i18n.global.setLocaleMessage(lang, message.default);\n  }\n\n  const mergeMessage = await loadMessages(lang);\n  i18n.global.mergeLocaleMessage(lang, mergeMessage);\n\n  return setI18nLanguage(lang);\n}\n\nexport {\n  i18n,\n  loadLocaleMessages,\n  loadLocalesMap,\n  loadLocalesMapFromDir,\n  setupI18n,\n};\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/index.ts",
    "content": "import {\n  i18n,\n  loadLocaleMessages,\n  loadLocalesMap,\n  loadLocalesMapFromDir,\n  setupI18n,\n} from './i18n';\n\nconst $t = i18n.global.t;\nconst $te = i18n.global.te;\n\nexport {\n  $t,\n  $te,\n  i18n,\n  loadLocaleMessages,\n  loadLocalesMap,\n  loadLocalesMapFromDir,\n  setupI18n,\n};\nexport {\n  type ImportLocaleFn,\n  type LocaleSetupOptions,\n  type SupportedLanguagesType,\n} from './typing';\nexport type { CompileError } from '@intlify/core-base';\n\nexport { useI18n } from 'vue-i18n';\n\nexport type { Locale } from 'vue-i18n';\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/langs/en-US/authentication.json",
    "content": "{\n  \"welcomeBack\": \"Welcome Back\",\n  \"pageTitle\": \"Plug-and-play Admin system\",\n  \"pageDesc\": \"Efficient, versatile frontend template\",\n  \"loginSuccess\": \"Login Successful\",\n  \"loginSuccessDesc\": \"Welcome Back\",\n  \"loginSubtitle\": \"Enter your account details to manage your projects\",\n  \"selectAccount\": \"Quick Select Account\",\n  \"username\": \"Username\",\n  \"password\": \"Password\",\n  \"usernameTip\": \"Please enter username\",\n  \"passwordErrorTip\": \"Password is incorrect\",\n  \"passwordTip\": \"Please enter password\",\n  \"verifyRequiredTip\": \"Please complete the verification first\",\n  \"rememberMe\": \"Remember Me\",\n  \"createAnAccount\": \"Create an Account\",\n  \"createAccount\": \"Create Account\",\n  \"alreadyHaveAccount\": \"Already have an account?\",\n  \"accountTip\": \"Don't have an account?\",\n  \"signUp\": \"Sign Up\",\n  \"signUpSubtitle\": \"Make managing your applications simple and fun\",\n  \"confirmPassword\": \"Confirm Password\",\n  \"confirmPasswordTip\": \"The passwords do not match\",\n  \"agree\": \"I agree to\",\n  \"privacyPolicy\": \"Privacy-policy\",\n  \"terms\": \"Terms\",\n  \"agreeTip\": \"Please agree to the Privacy Policy and Terms\",\n  \"goToLogin\": \"Login instead\",\n  \"passwordStrength\": \"Use 8 or more characters with a mix of letters, numbers & symbols\",\n  \"forgetPassword\": \"Forget Password?\",\n  \"forgetPasswordSubtitle\": \"Enter your email and we'll send you instructions to reset your password\",\n  \"emailTip\": \"Please enter email\",\n  \"emailValidErrorTip\": \"The email format you entered is incorrect\",\n  \"sendResetLink\": \"Send Reset Link\",\n  \"email\": \"Email\",\n  \"qrcodeSubtitle\": \"Scan the QR code with your phone to login\",\n  \"qrcodePrompt\": \"Click 'Confirm' after scanning to complete login\",\n  \"qrcodeLogin\": \"QR Code Login\",\n  \"wechatLogin\": \"Wechat Login\",\n  \"qqLogin\": \"QQ Login\",\n  \"githubLogin\": \"Github Login\",\n  \"googleLogin\": \"Google Login\",\n  \"dingdingLogin\": \"Dingding Login\",\n  \"codeSubtitle\": \"Enter your phone number to start managing your project\",\n  \"code\": \"Security code\",\n  \"codeTip\": \"Security code required {0} characters\",\n  \"mobile\": \"Mobile\",\n  \"mobileLogin\": \"Mobile Login\",\n  \"mobileTip\": \"Please enter mobile number\",\n  \"mobileErrortip\": \"The phone number format is incorrect\",\n  \"sendCode\": \"Get Security code\",\n  \"sendText\": \"Resend in {0}s\",\n  \"thirdPartyLogin\": \"Or continue with\",\n  \"weChat\": \"WeChat\",\n  \"qq\": \"QQ\",\n  \"gitHub\": \"GitHub\",\n  \"google\": \"Google\",\n  \"loginAgainTitle\": \"Please Log In Again\",\n  \"loginAgainSubTitle\": \"Your login session has expired. Please log in again to continue.\",\n  \"layout\": {\n    \"center\": \"Align Center\",\n    \"alignLeft\": \"Align Left\",\n    \"alignRight\": \"Align Right\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/langs/en-US/common.json",
    "content": "{\n  \"back\": \"Back\",\n  \"backToHome\": \"Back To Home\",\n  \"login\": \"Login\",\n  \"logout\": \"Logout\",\n  \"prompt\": \"Prompt\",\n  \"cancel\": \"Cancel\",\n  \"confirm\": \"Confirm\",\n  \"reset\": \"Reset\",\n  \"noData\": \"No Data\",\n  \"refresh\": \"Refresh\",\n  \"loadingMenu\": \"Loading Menu\",\n  \"query\": \"Search\",\n  \"search\": \"Search\",\n  \"enabled\": \"Enabled\",\n  \"disabled\": \"Disabled\",\n  \"edit\": \"Edit\",\n  \"delete\": \"Delete\",\n  \"create\": \"Create\",\n  \"yes\": \"Yes\",\n  \"no\": \"No\",\n  \"showSearchPanel\": \"Show search panel\",\n  \"hideSearchPanel\": \"Hide search panel\"\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/langs/en-US/preferences.json",
    "content": "{\n  \"title\": \"Preferences\",\n  \"subtitle\": \"Customize Preferences & Preview in Real Time\",\n  \"enableStickyPreferencesNavigationBar\": \"Enable sticky preferences navigation bar\",\n  \"disableStickyPreferencesNavigationBar\": \"Disable sticky preferences navigation bar\",\n  \"resetTip\": \"Data has changed, click to reset\",\n  \"resetTitle\": \"Reset Preferences\",\n  \"resetSuccess\": \"Preferences reset successfully\",\n  \"appearance\": \"Appearance\",\n  \"layout\": \"Layout\",\n  \"content\": \"Content\",\n  \"other\": \"Other\",\n  \"wide\": \"Wide\",\n  \"compact\": \"Fixed\",\n  \"followSystem\": \"Follow System\",\n  \"vertical\": \"Vertical\",\n  \"verticalTip\": \"Side vertical menu mode\",\n  \"horizontal\": \"Horizontal\",\n  \"horizontalTip\": \"Horizontal menu mode, all menus displayed at the top\",\n  \"twoColumn\": \"Two Column\",\n  \"twoColumnTip\": \"Vertical Two Column Menu Mode\",\n  \"headerSidebarNav\": \"Header Vertical\",\n  \"headerSidebarNavTip\": \"Header Full Width, Sidebar Navigation Mode\",\n  \"headerTwoColumn\": \"Header Two Column\",\n  \"headerTwoColumnTip\": \"Header Navigation & Sidebar Two Column co-exists\",\n  \"mixedMenu\": \"Mixed Menu\",\n  \"mixedMenuTip\": \"Vertical & Horizontal Menu Co-exists\",\n  \"fullContent\": \"Full Content\",\n  \"fullContentTip\": \"Only display content body, hide all menus\",\n  \"normal\": \"Normal\",\n  \"plain\": \"Plain\",\n  \"rounded\": \"Rounded\",\n  \"copyPreferences\": \"Copy Preferences\",\n  \"copyPreferencesSuccessTitle\": \"Copy successful\",\n  \"copyPreferencesSuccess\": \"Copy successful, please override in `src/preferences.ts` under app\",\n  \"clearAndLogout\": \"Clear Cache & Logout\",\n  \"mode\": \"Mode\",\n  \"general\": \"General\",\n  \"language\": \"Language\",\n  \"dynamicTitle\": \"Dynamic Title\",\n  \"watermark\": \"Watermark\",\n  \"watermarkContent\": \"Please input Watermark content\",\n  \"checkUpdates\": \"Periodic update check\",\n  \"position\": {\n    \"title\": \"Preferences Postion\",\n    \"header\": \"Header\",\n    \"auto\": \"Auto\",\n    \"fixed\": \"Fixed\"\n  },\n  \"sidebar\": {\n    \"buttons\": \"Show Buttons\",\n    \"buttonFixed\": \"Fixed\",\n    \"buttonCollapsed\": \"Collapsed\",\n    \"title\": \"Sidebar\",\n    \"width\": \"Width\",\n    \"visible\": \"Show Sidebar\",\n    \"collapsed\": \"Collpase Menu\",\n    \"collapsedShowTitle\": \"Show Menu Title\",\n    \"autoActivateChild\": \"Auto Activate SubMenu\",\n    \"autoActivateChildTip\": \"`Enabled` to automatically activate the submenu while click menu.\",\n    \"expandOnHover\": \"Expand On Hover\",\n    \"expandOnHoverTip\": \"When the mouse hovers over menu, \\n `Enabled` to expand children menus \\n `Disabled` to expand whole sidebar.\"\n  },\n  \"tabbar\": {\n    \"title\": \"Tabbar\",\n    \"enable\": \"Enable Tab Bar\",\n    \"icon\": \"Show Tabbar Icon\",\n    \"showMore\": \"Show More Button\",\n    \"showMaximize\": \"Show Maximize Button\",\n    \"persist\": \"Persist Tabs\",\n    \"maxCount\": \"Max Count of Tabs\",\n    \"maxCountTip\": \"When the number of tabs exceeds the maximum,\\nthe oldest tab will be closed.\\n Set to 0 to disable count checking.\",\n    \"draggable\": \"Enable Draggable Sort\",\n    \"wheelable\": \"Support Mouse Wheel\",\n    \"middleClickClose\": \"Close Tab when Mouse Middle Button Click\",\n    \"wheelableTip\": \"When enabled, the Tabbar area responds to vertical scrolling events of the scroll wheel.\",\n    \"styleType\": {\n      \"title\": \"Tabs Style\",\n      \"chrome\": \"Chrome\",\n      \"card\": \"Card\",\n      \"plain\": \"Plain\",\n      \"brisk\": \"Brisk\"\n    },\n    \"contextMenu\": {\n      \"reload\": \"Reload\",\n      \"close\": \"Close\",\n      \"pin\": \"Pin\",\n      \"unpin\": \"Unpin\",\n      \"closeLeft\": \"Close Left Tabs\",\n      \"closeRight\": \"Close Right Tabs\",\n      \"closeOther\": \"Close Other Tabs\",\n      \"closeAll\": \"Close All Tabs\",\n      \"openInNewWindow\": \"Open in New Window\",\n      \"maximize\": \"Maximize\",\n      \"restoreMaximize\": \"Restore\"\n    }\n  },\n  \"navigationMenu\": {\n    \"title\": \"Navigation Menu\",\n    \"style\": \"Navigation Menu Style\",\n    \"accordion\": \"Sidebar Accordion Menu\",\n    \"split\": \"Navigation Menu Separation\",\n    \"splitTip\": \"When enabled, the sidebar displays the top bar's submenu\"\n  },\n  \"breadcrumb\": {\n    \"title\": \"Breadcrumb\",\n    \"home\": \"Show Home Button\",\n    \"enable\": \"Enable Breadcrumb\",\n    \"icon\": \"Show Breadcrumb Icon\",\n    \"background\": \"background\",\n    \"style\": \"Breadcrumb Style\",\n    \"hideOnlyOne\": \"Hidden when only one\"\n  },\n  \"animation\": {\n    \"title\": \"Animation\",\n    \"loading\": \"Page Loading\",\n    \"transition\": \"Page Transition\",\n    \"progress\": \"Page Progress\"\n  },\n  \"theme\": {\n    \"title\": \"Theme\",\n    \"radius\": \"Radius\",\n    \"light\": \"Light\",\n    \"dark\": \"Dark\",\n    \"darkSidebar\": \"Semi Dark Sidebar\",\n    \"darkHeader\": \"Semi Dark Header\",\n    \"weakMode\": \"Weak Mode\",\n    \"grayMode\": \"Gray Mode\",\n    \"builtin\": {\n      \"title\": \"Built-in\",\n      \"default\": \"Default\",\n      \"violet\": \"Violet\",\n      \"pink\": \"Pink\",\n      \"rose\": \"Rose\",\n      \"skyBlue\": \"Sky Blue\",\n      \"deepBlue\": \"Deep Blue\",\n      \"green\": \"Green\",\n      \"deepGreen\": \"Deep Green\",\n      \"orange\": \"Orange\",\n      \"yellow\": \"Yellow\",\n      \"zinc\": \"Zinc\",\n      \"neutral\": \"Neutral\",\n      \"slate\": \"Slate\",\n      \"gray\": \"Gray\",\n      \"custom\": \"Custom\"\n    }\n  },\n  \"header\": {\n    \"title\": \"Header\",\n    \"visible\": \"Show Header\",\n    \"modeStatic\": \"Static\",\n    \"modeFixed\": \"Fixed\",\n    \"modeAuto\": \"Auto hide & Show\",\n    \"modeAutoScroll\": \"Scroll to Hide & Show\",\n    \"menuAlign\": \"Menu Align\",\n    \"menuAlignStart\": \"Start\",\n    \"menuAlignEnd\": \"End\",\n    \"menuAlignCenter\": \"Center\"\n  },\n  \"footer\": {\n    \"title\": \"Footer\",\n    \"visible\": \"Show Footer\",\n    \"fixed\": \"Fixed at Bottom\"\n  },\n  \"copyright\": {\n    \"title\": \"Copyright\",\n    \"enable\": \"Enable Copyright\",\n    \"companyName\": \"Company Name\",\n    \"companySiteLink\": \"Company Site Link\",\n    \"date\": \"Date\",\n    \"icp\": \"ICP License Number\",\n    \"icpLink\": \"ICP Site Link\"\n  },\n  \"shortcutKeys\": {\n    \"title\": \"Shortcut Keys\",\n    \"global\": \"Global\",\n    \"search\": \"Global Search\",\n    \"logout\": \"Logout\",\n    \"preferences\": \"Preferences\"\n  },\n  \"widget\": {\n    \"title\": \"Widget\",\n    \"globalSearch\": \"Enable Global Search\",\n    \"fullscreen\": \"Enable Fullscreen\",\n    \"themeToggle\": \"Enable Theme Toggle\",\n    \"languageToggle\": \"Enable Language Toggle\",\n    \"notification\": \"Enable Notification\",\n    \"sidebarToggle\": \"Enable Sidebar Toggle\",\n    \"lockScreen\": \"Enable Lock Screen\",\n    \"refresh\": \"Enable Refresh\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/langs/en-US/ui.json",
    "content": "{\n  \"formRules\": {\n    \"required\": \"Please enter {0}\",\n    \"selectRequired\": \"Please select {0}\",\n    \"minLength\": \"{0} must be at least {1} characters\",\n    \"maxLength\": \"{0} can be at most {1} characters\",\n    \"length\": \"{0} must be {1} characters long\",\n    \"alreadyExists\": \"{0} `{1}` already exists\",\n    \"startWith\": \"{0} must start with `{1}`\",\n    \"invalidURL\": \"Please input a valid URL\"\n  },\n  \"actionTitle\": {\n    \"edit\": \"Modify {0}\",\n    \"create\": \"Create {0}\",\n    \"delete\": \"Delete {0}\",\n    \"view\": \"View {0}\"\n  },\n  \"actionMessage\": {\n    \"deleteConfirm\": \"Are you sure to delete {0}?\",\n    \"deleting\": \"Deleting {0} ...\",\n    \"deleteSuccess\": \"{0} deleted successfully\",\n    \"operationSuccess\": \"Operation succeeded\",\n    \"operationFailed\": \"Operation failed\"\n  },\n  \"placeholder\": {\n    \"input\": \"Please enter\",\n    \"select\": \"Please select\"\n  },\n  \"captcha\": {\n    \"title\": \"Please complete the security verification\",\n    \"sliderSuccessText\": \"Passed\",\n    \"sliderDefaultText\": \"Slider and drag\",\n    \"alt\": \"Supports img tag src attribute value\",\n    \"sliderRotateDefaultTip\": \"Click picture to refresh\",\n    \"sliderTranslateDefaultTip\": \"Click picture to refresh\",\n    \"sliderRotateFailTip\": \"Validation failed\",\n    \"sliderRotateSuccessTip\": \"Validation successful, time {0} seconds\",\n    \"sliderTranslateFailTip\": \"Validation failed\",\n    \"sliderTranslateSuccessTip\": \"Validation successful, time {0} seconds\",\n    \"refreshAriaLabel\": \"Refresh captcha\",\n    \"confirmAriaLabel\": \"Confirm selection\",\n    \"confirm\": \"Confirm\",\n    \"pointAriaLabel\": \"Click point\",\n    \"clickInOrder\": \"Please click in order\"\n  },\n  \"iconPicker\": {\n    \"placeholder\": \"Select an icon\",\n    \"search\": \"Search icon...\"\n  },\n  \"jsonViewer\": {\n    \"copy\": \"Copy\",\n    \"copied\": \"Copied\"\n  },\n  \"fallback\": {\n    \"pageNotFound\": \"Oops! Page Not Found\",\n    \"pageNotFoundDesc\": \"Sorry, we couldn't find the page you were looking for.\",\n    \"forbidden\": \"Oops! Access Denied\",\n    \"forbiddenDesc\": \"Sorry, but you don't have permission to access this page.\",\n    \"internalError\": \"Oops! Something Went Wrong\",\n    \"internalErrorDesc\": \"Sorry, but the server encountered an error.\",\n    \"offline\": \"Offline Page\",\n    \"offlineError\": \"Oops! Network Error\",\n    \"offlineErrorDesc\": \"Sorry, can't connect to the internet. Check your connection.\",\n    \"comingSoon\": \"Coming Soon\",\n    \"http\": {\n      \"requestTimeout\": \"The request timed out. Please try again later.\",\n      \"networkError\": \"A network error occurred. Please check your internet connection and try again.\",\n      \"badRequest\": \"Bad Request. Please check your input and try again.\",\n      \"unauthorized\": \"Unauthorized. Please log in to continue.\",\n      \"forbidden\": \"Forbidden. You do not have permission to access this resource.\",\n      \"notFound\": \"Not Found. The requested resource could not be found.\",\n      \"internalServerError\": \"Internal Server Error. Something went wrong on our end. Please try again later.\"\n    }\n  },\n  \"widgets\": {\n    \"document\": \"Document\",\n    \"qa\": \"Q&A\",\n    \"setting\": \"Settings\",\n    \"logoutTip\": \"Do you want to logout?\",\n    \"viewAll\": \"View All Messages\",\n    \"notifications\": \"Notifications\",\n    \"markAllAsRead\": \"Make All as Read\",\n    \"clearNotifications\": \"Clear\",\n    \"checkUpdatesTitle\": \"New Version Available\",\n    \"checkUpdatesDescription\": \"Click to refresh and get the latest version\",\n    \"search\": {\n      \"title\": \"Search\",\n      \"searchNavigate\": \"Search Navigation\",\n      \"select\": \"Select\",\n      \"navigate\": \"Navigate\",\n      \"close\": \"Close\",\n      \"noResults\": \"No Search Results Found\",\n      \"noRecent\": \"No Search History\",\n      \"recent\": \"Search History\"\n    },\n    \"lockScreen\": {\n      \"title\": \"Lock Screen\",\n      \"screenButton\": \"Locking\",\n      \"password\": \"Password\",\n      \"placeholder\": \"Please enter password\",\n      \"unlock\": \"Click to unlock\",\n      \"errorPasswordTip\": \"Password error, please re-enter\",\n      \"backToLogin\": \"Back to login\",\n      \"entry\": \"Enter the system\"\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/langs/zh-CN/authentication.json",
    "content": "{\n  \"welcomeBack\": \"欢迎回来\",\n  \"pageTitle\": \"开箱即用的大型中后台管理系统\",\n  \"pageDesc\": \"工程化、高性能、跨组件库的前端模版\",\n  \"loginSuccess\": \"登录成功\",\n  \"loginSuccessDesc\": \"欢迎回来\",\n  \"loginSubtitle\": \"请输入您的帐户信息以开始管理您的项目\",\n  \"selectAccount\": \"快速选择账号\",\n  \"username\": \"账号\",\n  \"password\": \"密码\",\n  \"usernameTip\": \"请输入用户名\",\n  \"passwordTip\": \"请输入密码\",\n  \"verifyRequiredTip\": \"请先完成验证\",\n  \"passwordErrorTip\": \"密码错误\",\n  \"rememberMe\": \"记住账号\",\n  \"createAnAccount\": \"创建一个账号\",\n  \"createAccount\": \"创建账号\",\n  \"alreadyHaveAccount\": \"已经有账号了?\",\n  \"accountTip\": \"还没有账号?\",\n  \"signUp\": \"注册\",\n  \"signUpSubtitle\": \"让您的应用程序管理变得简单而有趣\",\n  \"confirmPassword\": \"确认密码\",\n  \"confirmPasswordTip\": \"两次输入的密码不一致\",\n  \"agree\": \"我同意\",\n  \"privacyPolicy\": \"隐私政策\",\n  \"terms\": \"条款\",\n  \"agreeTip\": \"请同意隐私政策和条款\",\n  \"goToLogin\": \"去登录\",\n  \"passwordStrength\": \"使用 8 个或更多字符，混合字母、数字和符号\",\n  \"forgetPassword\": \"忘记密码?\",\n  \"forgetPasswordSubtitle\": \"输入您的电子邮件，我们将向您发送重置密码的连接\",\n  \"emailTip\": \"请输入邮箱\",\n  \"emailValidErrorTip\": \"你输入的邮箱格式不正确\",\n  \"sendResetLink\": \"发送重置链接\",\n  \"email\": \"邮箱\",\n  \"qrcodeSubtitle\": \"请用手机扫描二维码登录\",\n  \"qrcodePrompt\": \"扫码后点击 '确认'，即可完成登录\",\n  \"qrcodeLogin\": \"扫码登录\",\n  \"wechatLogin\": \"微信登录\",\n  \"qqLogin\": \"QQ登录\",\n  \"githubLogin\": \"Github登录\",\n  \"googleLogin\": \"Google登录\",\n  \"dingdingLogin\": \"钉钉登录\",\n  \"codeSubtitle\": \"请输入您的手机号码以开始管理您的项目\",\n  \"code\": \"验证码\",\n  \"codeTip\": \"请输入{0}位验证码\",\n  \"mobile\": \"手机号码\",\n  \"mobileTip\": \"请输入手机号\",\n  \"mobileErrortip\": \"手机号码格式错误\",\n  \"mobileLogin\": \"手机号登录\",\n  \"sendCode\": \"获取验证码\",\n  \"sendText\": \"{0}秒后重新获取\",\n  \"thirdPartyLogin\": \"其他登录方式\",\n  \"weChat\": \"微信\",\n  \"qq\": \"QQ\",\n  \"gitHub\": \"GitHub\",\n  \"google\": \"Google\",\n  \"loginAgainTitle\": \"重新登录\",\n  \"loginAgainSubTitle\": \"您的登录状态已过期，请重新登录以继续。\",\n  \"layout\": {\n    \"center\": \"居中\",\n    \"alignLeft\": \"居左\",\n    \"alignRight\": \"居右\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/langs/zh-CN/common.json",
    "content": "{\n  \"back\": \"返回\",\n  \"backToHome\": \"返回首页\",\n  \"login\": \"登录\",\n  \"logout\": \"退出登录\",\n  \"prompt\": \"提示\",\n  \"cancel\": \"取消\",\n  \"confirm\": \"确认\",\n  \"reset\": \"重置\",\n  \"noData\": \"暂无数据\",\n  \"refresh\": \"刷新\",\n  \"loadingMenu\": \"加载菜单中\",\n  \"query\": \"查询\",\n  \"search\": \"搜索\",\n  \"enabled\": \"已启用\",\n  \"disabled\": \"已禁用\",\n  \"edit\": \"修改\",\n  \"delete\": \"删除\",\n  \"create\": \"新增\",\n  \"yes\": \"是\",\n  \"no\": \"否\",\n  \"showSearchPanel\": \"显示搜索面板\",\n  \"hideSearchPanel\": \"隐藏搜索面板\"\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/langs/zh-CN/preferences.json",
    "content": "{\n  \"title\": \"偏好设置\",\n  \"subtitle\": \"自定义偏好设置 & 实时预览\",\n  \"enableStickyPreferencesNavigationBar\": \"开启首选项导航栏吸顶效果\",\n  \"disableStickyPreferencesNavigationBar\": \"关闭首选项导航栏吸顶效果\",\n  \"resetTitle\": \"重置偏好设置\",\n  \"resetTip\": \"数据有变化，点击可进行重置\",\n  \"resetSuccess\": \"重置偏好设置成功\",\n  \"appearance\": \"外观\",\n  \"layout\": \"布局\",\n  \"content\": \"内容\",\n  \"other\": \"其它\",\n  \"wide\": \"流式\",\n  \"compact\": \"定宽\",\n  \"followSystem\": \"跟随系统\",\n  \"vertical\": \"垂直\",\n  \"verticalTip\": \"侧边垂直菜单模式\",\n  \"horizontal\": \"水平\",\n  \"horizontalTip\": \"水平菜单模式，菜单全部显示在顶部\",\n  \"twoColumn\": \"双列菜单\",\n  \"twoColumnTip\": \"垂直双列菜单模式\",\n  \"headerSidebarNav\": \"侧边导航\",\n  \"headerSidebarNavTip\": \"顶部通栏，侧边导航模式\",\n  \"headerTwoColumn\": \"混合双列\",\n  \"headerTwoColumnTip\": \"双列、水平菜单共存模式\",\n  \"mixedMenu\": \"混合垂直\",\n  \"mixedMenuTip\": \"垂直水平菜单共存\",\n  \"fullContent\": \"内容全屏\",\n  \"fullContentTip\": \"不显示任何菜单，只显示内容主体\",\n  \"normal\": \"常规\",\n  \"plain\": \"朴素\",\n  \"rounded\": \"圆润\",\n  \"copyPreferences\": \"复制偏好设置\",\n  \"copyPreferencesSuccessTitle\": \"复制成功\",\n  \"copyPreferencesSuccess\": \"复制成功，请在 app 下的 `src/preferences.ts`内进行覆盖\",\n  \"clearAndLogout\": \"清空缓存 & 退出登录\",\n  \"mode\": \"模式\",\n  \"general\": \"通用\",\n  \"language\": \"语言\",\n  \"dynamicTitle\": \"动态标题\",\n  \"watermark\": \"水印\",\n  \"watermarkContent\": \"请输入水印文案\",\n  \"checkUpdates\": \"定时检查更新\",\n  \"position\": {\n    \"title\": \"偏好设置位置\",\n    \"header\": \"顶栏\",\n    \"auto\": \"自动\",\n    \"fixed\": \"固定\"\n  },\n  \"sidebar\": {\n    \"buttons\": \"显示按钮\",\n    \"buttonFixed\": \"固定按钮\",\n    \"buttonCollapsed\": \"折叠按钮\",\n    \"title\": \"侧边栏\",\n    \"width\": \"宽度\",\n    \"visible\": \"显示侧边栏\",\n    \"collapsed\": \"折叠菜单\",\n    \"collapsedShowTitle\": \"折叠显示菜单名\",\n    \"autoActivateChild\": \"自动激活子菜单\",\n    \"autoActivateChildTip\": \"点击顶层菜单时,自动激活第一个子菜单或者上一次激活的子菜单\",\n    \"expandOnHover\": \"鼠标悬停展开\",\n    \"expandOnHoverTip\": \"鼠标在折叠区域悬浮时，`启用`则展开当前子菜单，`禁用`则展开整个侧边栏\"\n  },\n  \"tabbar\": {\n    \"title\": \"标签栏\",\n    \"enable\": \"启用标签栏\",\n    \"icon\": \"显示标签栏图标\",\n    \"showMore\": \"显示更多按钮\",\n    \"showMaximize\": \"显示最大化按钮\",\n    \"persist\": \"持久化标签页\",\n    \"maxCount\": \"最大标签数\",\n    \"maxCountTip\": \"每次打开新的标签时如果超过最大标签数，\\n会自动关闭一个最先打开的标签\\n设置为 0 则不限制\",\n    \"draggable\": \"启动拖拽排序\",\n    \"wheelable\": \"启用纵向滚轮响应\",\n    \"middleClickClose\": \"点击鼠标中键关闭标签页\",\n    \"wheelableTip\": \"开启后，标签栏区域可以响应滚轮的纵向滚动事件。\\n关闭时，只能响应系统的横向滚动事件（需要按下Shift再滚动滚轮）\",\n    \"styleType\": {\n      \"title\": \"标签页风格\",\n      \"chrome\": \"谷歌\",\n      \"card\": \"卡片\",\n      \"plain\": \"朴素\",\n      \"brisk\": \"轻快\"\n    },\n    \"contextMenu\": {\n      \"reload\": \"重新加载\",\n      \"close\": \"关闭\",\n      \"pin\": \"固定\",\n      \"unpin\": \"取消固定\",\n      \"closeLeft\": \"关闭左侧标签页\",\n      \"closeRight\": \"关闭右侧标签页\",\n      \"closeOther\": \"关闭其它标签页\",\n      \"closeAll\": \"关闭全部标签页\",\n      \"openInNewWindow\": \"在新窗口打开\",\n      \"maximize\": \"最大化\",\n      \"restoreMaximize\": \"还原\"\n    }\n  },\n  \"navigationMenu\": {\n    \"title\": \"导航菜单\",\n    \"style\": \"导航菜单风格\",\n    \"accordion\": \"侧边导航菜单手风琴模式\",\n    \"split\": \"导航菜单分离\",\n    \"splitTip\": \"开启时，侧边栏显示顶栏对应菜单的子菜单\"\n  },\n  \"breadcrumb\": {\n    \"title\": \"面包屑导航\",\n    \"enable\": \"开启面包屑导航\",\n    \"icon\": \"显示面包屑图标\",\n    \"home\": \"显示首页按钮\",\n    \"style\": \"面包屑风格\",\n    \"hideOnlyOne\": \"仅有一个时隐藏\",\n    \"background\": \"背景\"\n  },\n  \"animation\": {\n    \"title\": \"动画\",\n    \"loading\": \"页面切换 Loading\",\n    \"transition\": \"页面切换动画\",\n    \"progress\": \"页面切换进度条\"\n  },\n  \"theme\": {\n    \"title\": \"主题\",\n    \"radius\": \"圆角\",\n    \"light\": \"浅色\",\n    \"dark\": \"深色\",\n    \"darkSidebar\": \"深色侧边栏\",\n    \"darkHeader\": \"深色顶栏\",\n    \"weakMode\": \"色弱模式\",\n    \"grayMode\": \"灰色模式\",\n    \"builtin\": {\n      \"title\": \"内置主题\",\n      \"default\": \"默认\",\n      \"violet\": \"紫罗兰\",\n      \"pink\": \"樱花粉\",\n      \"rose\": \"玫瑰红\",\n      \"skyBlue\": \"天蓝色\",\n      \"deepBlue\": \"深蓝色\",\n      \"green\": \"浅绿色\",\n      \"deepGreen\": \"深绿色\",\n      \"orange\": \"橙黄色\",\n      \"yellow\": \"柠檬黄\",\n      \"zinc\": \"锌色灰\",\n      \"neutral\": \"中性色\",\n      \"slate\": \"石板灰\",\n      \"gray\": \"中灰色\",\n      \"custom\": \"自定义\"\n    }\n  },\n  \"header\": {\n    \"title\": \"顶栏\",\n    \"modeStatic\": \"静止\",\n    \"modeFixed\": \"固定\",\n    \"modeAuto\": \"自动隐藏和显示\",\n    \"modeAutoScroll\": \"滚动隐藏和显示\",\n    \"visible\": \"显示顶栏\",\n    \"menuAlign\": \"菜单位置\",\n    \"menuAlignStart\": \"左侧\",\n    \"menuAlignEnd\": \"右侧\",\n    \"menuAlignCenter\": \"居中\"\n  },\n  \"footer\": {\n    \"title\": \"底栏\",\n    \"visible\": \"显示底栏\",\n    \"fixed\": \"固定在底部\"\n  },\n  \"copyright\": {\n    \"title\": \"版权\",\n    \"enable\": \"启用版权\",\n    \"companyName\": \"公司名\",\n    \"companySiteLink\": \"公司主页\",\n    \"date\": \"日期\",\n    \"icp\": \"ICP 备案号\",\n    \"icpLink\": \"ICP 网站链接\"\n  },\n  \"shortcutKeys\": {\n    \"title\": \"快捷键\",\n    \"global\": \"全局\",\n    \"search\": \"全局搜索\",\n    \"logout\": \"退出登录\",\n    \"preferences\": \"偏好设置\"\n  },\n  \"widget\": {\n    \"title\": \"小部件\",\n    \"globalSearch\": \"启用全局搜索\",\n    \"fullscreen\": \"启用全屏\",\n    \"themeToggle\": \"启用主题切换\",\n    \"languageToggle\": \"启用语言切换\",\n    \"notification\": \"启用通知\",\n    \"sidebarToggle\": \"启用侧边栏切换\",\n    \"lockScreen\": \"启用锁屏\",\n    \"refresh\": \"启用刷新\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/langs/zh-CN/ui.json",
    "content": "{\n  \"formRules\": {\n    \"required\": \"请输入{0}\",\n    \"selectRequired\": \"请选择{0}\",\n    \"minLength\": \"{0}至少{1}个字符\",\n    \"maxLength\": \"{0}最多{1}个字符\",\n    \"length\": \"{0}长度必须为{1}个字符\",\n    \"alreadyExists\": \"{0} `{1}` 已存在\",\n    \"startWith\": \"{0}必须以 {1} 开头\",\n    \"invalidURL\": \"请输入有效的链接\"\n  },\n  \"actionTitle\": {\n    \"edit\": \"修改{0}\",\n    \"create\": \"新增{0}\",\n    \"delete\": \"删除{0}\",\n    \"view\": \"查看{0}\"\n  },\n  \"actionMessage\": {\n    \"deleteConfirm\": \"确定删除 {0} 吗？\",\n    \"deleting\": \"正在删除 {0} ...\",\n    \"deleteSuccess\": \"{0} 删除成功\",\n    \"operationSuccess\": \"操作成功\",\n    \"operationFailed\": \"操作失败\"\n  },\n  \"placeholder\": {\n    \"input\": \"请输入\",\n    \"select\": \"请选择\"\n  },\n  \"captcha\": {\n    \"title\": \"请完成安全验证\",\n    \"sliderSuccessText\": \"验证通过\",\n    \"sliderDefaultText\": \"请按住滑块拖动\",\n    \"sliderRotateDefaultTip\": \"点击图片可刷新\",\n    \"sliderTranslateDefaultTip\": \"点击图片可刷新\",\n    \"sliderRotateFailTip\": \"验证失败\",\n    \"sliderRotateSuccessTip\": \"验证成功，耗时{0}秒\",\n    \"sliderTranslateFailTip\": \"验证失败\",\n    \"sliderTranslateSuccessTip\": \"验证成功，耗时{0}秒\",\n    \"alt\": \"支持img标签src属性值\",\n    \"refreshAriaLabel\": \"刷新验证码\",\n    \"confirmAriaLabel\": \"确认选择\",\n    \"confirm\": \"确认\",\n    \"pointAriaLabel\": \"点击点\",\n    \"clickInOrder\": \"请依次点击\"\n  },\n  \"iconPicker\": {\n    \"placeholder\": \"选择一个图标\",\n    \"search\": \"搜索图标...\"\n  },\n  \"jsonViewer\": {\n    \"copy\": \"复制\",\n    \"copied\": \"已复制\"\n  },\n  \"fallback\": {\n    \"pageNotFound\": \"哎呀！未找到页面\",\n    \"pageNotFoundDesc\": \"抱歉，我们无法找到您要找的页面。\",\n    \"forbidden\": \"哎呀！访问被拒绝\",\n    \"forbiddenDesc\": \"抱歉，您没有权限访问此页面。\",\n    \"internalError\": \"哎呀！出错了\",\n    \"internalErrorDesc\": \"抱歉，服务器遇到错误。\",\n    \"offline\": \"离线页面\",\n    \"offlineError\": \"哎呀！网络错误\",\n    \"offlineErrorDesc\": \"抱歉，无法连接到互联网，请检查您的网络连接并重试。\",\n    \"comingSoon\": \"即将推出\",\n    \"http\": {\n      \"requestTimeout\": \"请求超时，请稍后再试。\",\n      \"networkError\": \"网络异常，请检查您的网络连接后重试。\",\n      \"badRequest\": \"请求错误。请检查您的输入并重试。\",\n      \"unauthorized\": \"登录认证过期，请重新登录后继续。\",\n      \"forbidden\": \"禁止访问, 您没有权限访问此资源。\",\n      \"notFound\": \"未找到, 请求的资源不存在。\",\n      \"internalServerError\": \"内部服务器错误，请稍后再试。\"\n    }\n  },\n  \"widgets\": {\n    \"document\": \"文档\",\n    \"qa\": \"问题 & 帮助\",\n    \"setting\": \"设置\",\n    \"logoutTip\": \"是否退出登录？\",\n    \"viewAll\": \"查看所有消息\",\n    \"notifications\": \"通知\",\n    \"markAllAsRead\": \"全部标记为已读\",\n    \"clearNotifications\": \"清空\",\n    \"checkUpdatesTitle\": \"新版本可用\",\n    \"checkUpdatesDescription\": \"点击刷新以获取最新版本\",\n    \"search\": {\n      \"title\": \"搜索\",\n      \"searchNavigate\": \"搜索导航菜单\",\n      \"select\": \"选择\",\n      \"navigate\": \"导航\",\n      \"close\": \"关闭\",\n      \"noResults\": \"未找到搜索结果\",\n      \"noRecent\": \"没有搜索历史\",\n      \"recent\": \"搜索历史\"\n    },\n    \"lockScreen\": {\n      \"title\": \"锁定屏幕\",\n      \"screenButton\": \"锁定\",\n      \"password\": \"密码\",\n      \"placeholder\": \"请输入锁屏密码\",\n      \"unlock\": \"点击解锁\",\n      \"errorPasswordTip\": \"密码错误，请重新输入\",\n      \"backToLogin\": \"返回登录\",\n      \"entry\": \"进入系统\"\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/src/typing.ts",
    "content": "export type SupportedLanguagesType = 'en-US' | 'zh-CN';\n\nexport type ImportLocaleFn = () => Promise<{ default: Record<string, string> }>;\n\nexport type LoadMessageFn = (\n  lang: SupportedLanguagesType,\n) => Promise<Record<string, string> | undefined>;\n\nexport interface LocaleSetupOptions {\n  /**\n   * Default language\n   * @default zh-CN\n   */\n  defaultLocale?: SupportedLanguagesType;\n  /**\n   * Load message function\n   * @param lang\n   * @returns\n   */\n  loadMessages?: LoadMessageFn;\n  /**\n   * Whether to warn when the key is not found\n   */\n  missingWarn?: boolean;\n}\n"
  },
  {
    "path": "hiauth-front/packages/locales/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/preferences/package.json",
    "content": "{\n  \"name\": \"@vben/preferences\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/preferences\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/preferences\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/preferences/src/index.ts",
    "content": "import type { Preferences } from '@vben-core/preferences';\nimport type { DeepPartial } from '@vben-core/typings';\n\n/**\n * 如果你想所有的app都使用相同的默认偏好设置，你可以在这里定义\n * 而不是去修改 @vben-core/preferences 中的默认偏好设置\n * @param preferences\n * @returns\n */\n\nfunction defineOverridesPreferences(preferences: DeepPartial<Preferences>) {\n  return preferences;\n}\n\nexport { defineOverridesPreferences };\n\nexport * from '@vben-core/preferences';\n"
  },
  {
    "path": "hiauth-front/packages/preferences/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/stores/package.json",
    "content": "{\n  \"name\": \"@vben/stores\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/stores\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/preferences\": \"workspace:*\",\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"pinia\": \"catalog:\",\n    \"pinia-plugin-persistedstate\": \"catalog:\",\n    \"secure-ls\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/stores/shim-pinia.d.ts",
    "content": "// https://github.com/vuejs/pinia/issues/2098\ndeclare module 'pinia' {\n  export function acceptHMRUpdate(\n    initialUseStore: any | StoreDefinition,\n    hot: any,\n  ): (newModule: any) => any;\n}\n\nexport {};\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/index.ts",
    "content": "export * from './modules';\nexport * from './setup';\nexport { defineStore, storeToRefs } from 'pinia';\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/modules/access.test.ts",
    "content": "import { createPinia, setActivePinia } from 'pinia';\nimport { beforeEach, describe, expect, it } from 'vitest';\n\nimport { useAccessStore } from './access';\n\ndescribe('useAccessStore', () => {\n  beforeEach(() => {\n    setActivePinia(createPinia());\n  });\n\n  it('updates accessMenus state', () => {\n    const store = useAccessStore();\n    expect(store.accessMenus).toEqual([]);\n    store.setAccessMenus([{ name: 'Dashboard', path: '/dashboard' }]);\n    expect(store.accessMenus).toEqual([\n      { name: 'Dashboard', path: '/dashboard' },\n    ]);\n  });\n\n  it('updates accessToken state correctly', () => {\n    const store = useAccessStore();\n    expect(store.accessToken).toBeNull(); // 初始状态\n    store.setAccessToken('abc123');\n    expect(store.accessToken).toBe('abc123');\n  });\n\n  it('returns the correct accessToken', () => {\n    const store = useAccessStore();\n    store.setAccessToken('xyz789');\n    expect(store.accessToken).toBe('xyz789');\n  });\n\n  // 测试设置空的访问菜单列表\n  it('handles empty accessMenus correctly', () => {\n    const store = useAccessStore();\n    store.setAccessMenus([]);\n    expect(store.accessMenus).toEqual([]);\n  });\n\n  // 测试设置空的访问路由列表\n  it('handles empty accessRoutes correctly', () => {\n    const store = useAccessStore();\n    store.setAccessRoutes([]);\n    expect(store.accessRoutes).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/modules/access.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport type { MenuRecordRaw } from '@vben-core/typings';\n\nimport { acceptHMRUpdate, defineStore } from 'pinia';\n\ntype AccessToken = null | string;\n\ninterface AccessState {\n  /**\n   * 权限码\n   */\n  accessCodes: string[];\n  /**\n   * 可访问的菜单列表\n   */\n  accessMenus: MenuRecordRaw[];\n  /**\n   * 可访问的路由列表\n   */\n  accessRoutes: RouteRecordRaw[];\n  /**\n   * 登录 accessToken\n   */\n  accessToken: AccessToken;\n  /**\n   * 是否已经检查过权限\n   */\n  isAccessChecked: boolean;\n  /**\n   * 是否锁屏状态\n   */\n  isLockScreen: boolean;\n  /**\n   * 锁屏密码\n   */\n  lockScreenPassword?: string;\n  /**\n   * 登录是否过期\n   */\n  loginExpired: boolean;\n  /**\n   * 登录 accessToken\n   */\n  refreshToken: AccessToken;\n}\n\n/**\n * @zh_CN 访问权限相关\n */\nexport const useAccessStore = defineStore('core-access', {\n  actions: {\n    getMenuByPath(path: string) {\n      function findMenu(\n        menus: MenuRecordRaw[],\n        path: string,\n      ): MenuRecordRaw | undefined {\n        for (const menu of menus) {\n          if (menu.path === path) {\n            return menu;\n          }\n          if (menu.children) {\n            const matched = findMenu(menu.children, path);\n            if (matched) {\n              return matched;\n            }\n          }\n        }\n      }\n      return findMenu(this.accessMenus, path);\n    },\n    lockScreen(password: string) {\n      this.isLockScreen = true;\n      this.lockScreenPassword = password;\n    },\n    setAccessCodes(codes: string[]) {\n      this.accessCodes = codes;\n    },\n    setAccessMenus(menus: MenuRecordRaw[]) {\n      this.accessMenus = menus;\n    },\n    setAccessRoutes(routes: RouteRecordRaw[]) {\n      this.accessRoutes = routes;\n    },\n    setAccessToken(token: AccessToken) {\n      this.accessToken = token;\n    },\n    setIsAccessChecked(isAccessChecked: boolean) {\n      this.isAccessChecked = isAccessChecked;\n    },\n    setLoginExpired(loginExpired: boolean) {\n      this.loginExpired = loginExpired;\n    },\n    setRefreshToken(token: AccessToken) {\n      this.refreshToken = token;\n    },\n    unlockScreen() {\n      this.isLockScreen = false;\n      this.lockScreenPassword = undefined;\n    },\n  },\n  persist: {\n    // 持久化\n    pick: [\n      'accessToken',\n      'refreshToken',\n      'accessCodes',\n      'isLockScreen',\n      'lockScreenPassword',\n    ],\n  },\n  state: (): AccessState => ({\n    accessCodes: [],\n    accessMenus: [],\n    accessRoutes: [],\n    accessToken: null,\n    isAccessChecked: false,\n    isLockScreen: false,\n    lockScreenPassword: undefined,\n    loginExpired: false,\n    refreshToken: null,\n  }),\n});\n\n// 解决热更新问题\nconst hot = import.meta.hot;\nif (hot) {\n  hot.accept(acceptHMRUpdate(useAccessStore, hot));\n}\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/modules/index.ts",
    "content": "export * from './access';\nexport * from './tabbar';\nexport * from './user';\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/modules/tabbar.test.ts",
    "content": "import { createRouter, createWebHistory } from 'vue-router';\n\nimport { createPinia, setActivePinia } from 'pinia';\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { useTabbarStore } from './tabbar';\n\ndescribe('useAccessStore', () => {\n  const router = createRouter({\n    history: createWebHistory(),\n    routes: [],\n  });\n  router.push = vi.fn();\n  router.replace = vi.fn();\n  beforeEach(() => {\n    setActivePinia(createPinia());\n    vi.clearAllMocks();\n  });\n\n  it('adds a new tab', () => {\n    const store = useTabbarStore();\n    const tab: any = {\n      fullPath: '/home',\n      meta: {},\n      key: '/home',\n      name: 'Home',\n      path: '/home',\n    };\n    const addNewTab = store.addTab(tab);\n    expect(store.tabs.length).toBe(1);\n    expect(store.tabs[0]).toEqual(addNewTab);\n  });\n\n  it('adds a new tab if it does not exist', () => {\n    const store = useTabbarStore();\n    const newTab: any = {\n      fullPath: '/new',\n      meta: {},\n      name: 'New',\n      path: '/new',\n    };\n    const addNewTab = store.addTab(newTab);\n    expect(store.tabs).toContainEqual(addNewTab);\n  });\n\n  it('updates an existing tab instead of adding a new one', () => {\n    const store = useTabbarStore();\n    const initialTab: any = {\n      fullPath: '/existing',\n      meta: {\n        fullPathKey: false,\n      },\n      name: 'Existing',\n      path: '/existing',\n      query: {},\n    };\n    store.addTab(initialTab);\n    const updatedTab = { ...initialTab, query: { id: '1' } };\n    store.addTab(updatedTab);\n    expect(store.tabs.length).toBe(1);\n    expect(store.tabs[0]?.query).toEqual({ id: '1' });\n  });\n\n  it('closes all tabs', async () => {\n    const store = useTabbarStore();\n    store.addTab({\n      fullPath: '/home',\n      meta: {},\n      name: 'Home',\n      path: '/home',\n    } as any);\n    router.replace = vi.fn();\n\n    await store.closeAllTabs(router);\n\n    expect(store.tabs.length).toBe(1);\n  });\n\n  it('closes a non-affix tab', () => {\n    const store = useTabbarStore();\n    const tab: any = {\n      fullPath: '/closable',\n      meta: {},\n      name: 'Closable',\n      path: '/closable',\n    };\n    store.tabs.push(tab);\n    store._close(tab);\n    expect(store.tabs.length).toBe(0);\n  });\n\n  it('does not close an affix tab', () => {\n    const store = useTabbarStore();\n    const affixTab: any = {\n      fullPath: '/affix',\n      meta: { affixTab: true },\n      name: 'Affix',\n      path: '/affix',\n    };\n    store.tabs.push(affixTab);\n    store._close(affixTab);\n    expect(store.tabs.length).toBe(1); // Affix tab should not be closed\n  });\n\n  it('returns all cache tabs', () => {\n    const store = useTabbarStore();\n    store.cachedTabs.add('Home');\n    store.cachedTabs.add('About');\n    expect(store.getCachedTabs).toEqual(['Home', 'About']);\n  });\n\n  it('returns all tabs, including affix tabs', () => {\n    const store = useTabbarStore();\n    const normalTab: any = {\n      fullPath: '/normal',\n      meta: {},\n      name: 'Normal',\n      path: '/normal',\n    };\n    const affixTab: any = {\n      fullPath: '/affix',\n      meta: { affixTab: true },\n      name: 'Affix',\n      path: '/affix',\n    };\n    store.tabs.push(normalTab);\n    store.affixTabs.push(affixTab);\n    expect(store.getTabs).toContainEqual(normalTab);\n    expect(store.affixTabs).toContainEqual(affixTab);\n  });\n\n  it('navigates to a specific tab', async () => {\n    const store = useTabbarStore();\n    const tab: any = { meta: {}, name: 'Dashboard', path: '/dashboard' };\n\n    await store._goToTab(tab, router);\n\n    expect(router.replace).toHaveBeenCalledWith({\n      params: {},\n      path: '/dashboard',\n      query: {},\n    });\n  });\n\n  it('closes multiple tabs by paths', async () => {\n    const store = useTabbarStore();\n    store.addTab({\n      fullPath: '/home',\n      meta: {},\n      name: 'Home',\n      path: '/home',\n    } as any);\n    store.addTab({\n      fullPath: '/about',\n      meta: {},\n      name: 'About',\n      path: '/about',\n    } as any);\n    store.addTab({\n      fullPath: '/contact',\n      meta: {},\n      name: 'Contact',\n      path: '/contact',\n    } as any);\n\n    await store._bulkCloseByKeys(['/home', '/contact']);\n\n    expect(store.tabs).toHaveLength(1);\n    expect(store.tabs[0]?.name).toBe('About');\n  });\n\n  it('closes all tabs to the left of the specified tab', async () => {\n    const store = useTabbarStore();\n    store.addTab({\n      fullPath: '/home',\n      meta: {},\n      name: 'Home',\n      path: '/home',\n    } as any);\n    store.addTab({\n      fullPath: '/about',\n      meta: {},\n      name: 'About',\n      path: '/about',\n    } as any);\n    const targetTab: any = {\n      fullPath: '/contact',\n      meta: {},\n      name: 'Contact',\n      path: '/contact',\n    };\n    const addTargetTab = store.addTab(targetTab);\n    await store.closeLeftTabs(addTargetTab);\n\n    expect(store.tabs).toHaveLength(1);\n    expect(store.tabs[0]?.name).toBe('Contact');\n  });\n\n  it('closes all tabs except the specified tab', async () => {\n    const store = useTabbarStore();\n    store.addTab({\n      fullPath: '/home',\n      meta: {},\n      name: 'Home',\n      path: '/home',\n    } as any);\n    const targetTab: any = {\n      fullPath: '/about',\n      meta: {},\n      name: 'About',\n      path: '/about',\n    };\n    const addTargetTab = store.addTab(targetTab);\n    store.addTab({\n      fullPath: '/contact',\n      meta: {},\n      name: 'Contact',\n      path: '/contact',\n    } as any);\n\n    await store.closeOtherTabs(addTargetTab);\n\n    expect(store.tabs).toHaveLength(1);\n    expect(store.tabs[0]?.name).toBe('About');\n  });\n\n  it('closes all tabs to the right of the specified tab', async () => {\n    const store = useTabbarStore();\n    const targetTab: any = {\n      fullPath: '/home',\n      meta: {},\n      name: 'Home',\n      path: '/home',\n    };\n    const addTargetTab = store.addTab(targetTab);\n    store.addTab({\n      fullPath: '/about',\n      meta: {},\n      name: 'About',\n      path: '/about',\n    } as any);\n    store.addTab({\n      fullPath: '/contact',\n      meta: {},\n      name: 'Contact',\n      path: '/contact',\n    } as any);\n\n    await store.closeRightTabs(addTargetTab);\n\n    expect(store.tabs).toHaveLength(1);\n    expect(store.tabs[0]?.name).toBe('Home');\n  });\n\n  it('closes the tab with the specified key', async () => {\n    const store = useTabbarStore();\n    const keyToClose = '/about';\n    store.addTab({\n      fullPath: '/home',\n      meta: {},\n      name: 'Home',\n      path: '/home',\n    } as any);\n    store.addTab({\n      fullPath: keyToClose,\n      meta: {},\n      name: 'About',\n      path: '/about',\n    } as any);\n    store.addTab({\n      fullPath: '/contact',\n      meta: {},\n      name: 'Contact',\n      path: '/contact',\n    } as any);\n\n    await store.closeTabByKey(keyToClose, router);\n\n    expect(store.tabs).toHaveLength(2);\n    expect(\n      store.tabs.find((tab) => tab.fullPath === keyToClose),\n    ).toBeUndefined();\n  });\n\n  it('refreshes the current tab', async () => {\n    const store = useTabbarStore();\n    const currentTab: any = {\n      fullPath: '/dashboard',\n      meta: { name: 'Dashboard' },\n      name: 'Dashboard',\n      path: '/dashboard',\n    };\n    router.currentRoute.value = currentTab;\n\n    await store.refresh(router);\n\n    expect(store.excludeCachedTabs.has('Dashboard')).toBe(false);\n    expect(store.renderRouteView).toBe(true);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/modules/tabbar.ts",
    "content": "import type { ComputedRef } from 'vue';\nimport type {\n  RouteLocationNormalized,\n  Router,\n  RouteRecordNormalized,\n} from 'vue-router';\n\nimport type { TabDefinition } from '@vben-core/typings';\n\nimport { toRaw } from 'vue';\n\nimport { preferences } from '@vben-core/preferences';\nimport {\n  openRouteInNewWindow,\n  startProgress,\n  stopProgress,\n} from '@vben-core/shared/utils';\n\nimport { acceptHMRUpdate, defineStore } from 'pinia';\n\ninterface TabbarState {\n  /**\n   * @zh_CN 当前打开的标签页列表缓存\n   */\n  cachedTabs: Set<string>;\n  /**\n   * @zh_CN 拖拽结束的索引\n   */\n  dragEndIndex: number;\n  /**\n   * @zh_CN 需要排除缓存的标签页\n   */\n  excludeCachedTabs: Set<string>;\n  /**\n   * @zh_CN 标签右键菜单列表\n   */\n  menuList: string[];\n  /**\n   * @zh_CN 是否刷新\n   */\n  renderRouteView?: boolean;\n  /**\n   * @zh_CN 当前打开的标签页列表\n   */\n  tabs: TabDefinition[];\n  /**\n   * @zh_CN 更新时间，用于一些更新场景，使用watch深度监听的话，会损耗性能\n   */\n  updateTime?: number;\n}\n\n/**\n * @zh_CN 访问权限相关\n */\nexport const useTabbarStore = defineStore('core-tabbar', {\n  actions: {\n    /**\n     * Close tabs in bulk\n     */\n    async _bulkCloseByKeys(keys: string[]) {\n      const keySet = new Set(keys);\n      this.tabs = this.tabs.filter(\n        (item) => !keySet.has(getTabKeyFromTab(item)),\n      );\n\n      await this.updateCacheTabs();\n    },\n    /**\n     * @zh_CN 关闭标签页\n     * @param tab\n     */\n    _close(tab: TabDefinition) {\n      if (isAffixTab(tab)) {\n        return;\n      }\n      const index = this.tabs.findIndex((item) => equalTab(item, tab));\n      index !== -1 && this.tabs.splice(index, 1);\n    },\n    /**\n     * @zh_CN 跳转到默认标签页\n     */\n    async _goToDefaultTab(router: Router) {\n      if (this.getTabs.length <= 0) {\n        return;\n      }\n      const firstTab = this.getTabs[0];\n      if (firstTab) {\n        await this._goToTab(firstTab, router);\n      }\n    },\n    /**\n     * @zh_CN 跳转到标签页\n     * @param tab\n     * @param router\n     */\n    async _goToTab(tab: TabDefinition, router: Router) {\n      const { params, path, query } = tab;\n      const toParams = {\n        params: params || {},\n        path,\n        query: query || {},\n      };\n      await router.replace(toParams);\n    },\n    /**\n     * @zh_CN 添加标签页\n     * @param routeTab\n     */\n    addTab(routeTab: TabDefinition): TabDefinition {\n      let tab = cloneTab(routeTab);\n      if (!tab.key) {\n        tab.key = getTabKey(routeTab);\n      }\n      if (!isTabShown(tab)) {\n        return tab;\n      }\n\n      const tabIndex = this.tabs.findIndex((item) => {\n        return equalTab(item, tab);\n      });\n\n      if (tabIndex === -1) {\n        const maxCount = preferences.tabbar.maxCount;\n        // 获取动态路由打开数，超过 0 即代表需要控制打开数\n        const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ??\n          -1) as number;\n        // 如果动态路由层级大于 0 了，那么就要限制该路由的打开数限制了\n        // 获取到已经打开的动态路由数, 判断是否大于某一个值\n        if (\n          maxNumOfOpenTab > 0 &&\n          this.tabs.filter((tab) => tab.name === routeTab.name).length >=\n            maxNumOfOpenTab\n        ) {\n          // 关闭第一个\n          const index = this.tabs.findIndex(\n            (item) => item.name === routeTab.name,\n          );\n          index !== -1 && this.tabs.splice(index, 1);\n        } else if (maxCount > 0 && this.tabs.length >= maxCount) {\n          // 关闭第一个\n          const index = this.tabs.findIndex(\n            (item) =>\n              !Reflect.has(item.meta, 'affixTab') || !item.meta.affixTab,\n          );\n          index !== -1 && this.tabs.splice(index, 1);\n        }\n        this.tabs.push(tab);\n      } else {\n        // 页面已经存在，不重复添加选项卡，只更新选项卡参数\n        const currentTab = toRaw(this.tabs)[tabIndex];\n        const mergedTab = {\n          ...currentTab,\n          ...tab,\n          meta: { ...currentTab?.meta, ...tab.meta },\n        };\n        if (currentTab) {\n          const curMeta = currentTab.meta;\n          if (Reflect.has(curMeta, 'affixTab')) {\n            mergedTab.meta.affixTab = curMeta.affixTab;\n          }\n          if (Reflect.has(curMeta, 'newTabTitle')) {\n            mergedTab.meta.newTabTitle = curMeta.newTabTitle;\n          }\n        }\n        tab = mergedTab;\n        this.tabs.splice(tabIndex, 1, mergedTab);\n      }\n      this.updateCacheTabs();\n      return tab;\n    },\n    /**\n     * @zh_CN 关闭所有标签页\n     */\n    async closeAllTabs(router: Router) {\n      const newTabs = this.tabs.filter((tab) => isAffixTab(tab));\n      this.tabs = newTabs.length > 0 ? newTabs : [...this.tabs].splice(0, 1);\n      await this._goToDefaultTab(router);\n      this.updateCacheTabs();\n    },\n    /**\n     * @zh_CN 关闭左侧标签页\n     * @param tab\n     */\n    async closeLeftTabs(tab: TabDefinition) {\n      const index = this.tabs.findIndex((item) => equalTab(item, tab));\n\n      if (index < 1) {\n        return;\n      }\n\n      const leftTabs = this.tabs.slice(0, index);\n      const keys: string[] = [];\n\n      for (const item of leftTabs) {\n        if (!isAffixTab(item)) {\n          keys.push(item.key as string);\n        }\n      }\n      await this._bulkCloseByKeys(keys);\n    },\n    /**\n     * @zh_CN 关闭其他标签页\n     * @param tab\n     */\n    async closeOtherTabs(tab: TabDefinition) {\n      const closeKeys = this.tabs.map((item) => getTabKeyFromTab(item));\n\n      const keys: string[] = [];\n\n      for (const key of closeKeys) {\n        if (key !== getTabKeyFromTab(tab)) {\n          const closeTab = this.tabs.find(\n            (item) => getTabKeyFromTab(item) === key,\n          );\n          if (!closeTab) {\n            continue;\n          }\n          if (!isAffixTab(closeTab)) {\n            keys.push(closeTab.key as string);\n          }\n        }\n      }\n      await this._bulkCloseByKeys(keys);\n    },\n    /**\n     * @zh_CN 关闭右侧标签页\n     * @param tab\n     */\n    async closeRightTabs(tab: TabDefinition) {\n      const index = this.tabs.findIndex((item) => equalTab(item, tab));\n\n      if (index !== -1 && index < this.tabs.length - 1) {\n        const rightTabs = this.tabs.slice(index + 1);\n\n        const keys: string[] = [];\n        for (const item of rightTabs) {\n          if (!isAffixTab(item)) {\n            keys.push(item.key as string);\n          }\n        }\n        await this._bulkCloseByKeys(keys);\n      }\n    },\n\n    /**\n     * @zh_CN 关闭标签页\n     * @param tab\n     * @param router\n     */\n    async closeTab(tab: TabDefinition, router: Router) {\n      const { currentRoute } = router;\n      // 关闭不是激活选项卡\n      if (getTabKey(currentRoute.value) !== getTabKeyFromTab(tab)) {\n        this._close(tab);\n        this.updateCacheTabs();\n        return;\n      }\n      const index = this.getTabs.findIndex(\n        (item) => getTabKeyFromTab(item) === getTabKey(currentRoute.value),\n      );\n\n      const before = this.getTabs[index - 1];\n      const after = this.getTabs[index + 1];\n\n      // 下一个tab存在，跳转到下一个\n      if (after) {\n        this._close(tab);\n        await this._goToTab(after, router);\n        // 上一个tab存在，跳转到上一个\n      } else if (before) {\n        this._close(tab);\n        await this._goToTab(before, router);\n      } else {\n        console.error('Failed to close the tab; only one tab remains open.');\n      }\n    },\n\n    /**\n     * @zh_CN 通过key关闭标签页\n     * @param key\n     * @param router\n     */\n    async closeTabByKey(key: string, router: Router) {\n      const originKey = decodeURIComponent(key);\n      const index = this.tabs.findIndex(\n        (item) => getTabKeyFromTab(item) === originKey,\n      );\n      if (index === -1) {\n        return;\n      }\n\n      const tab = this.tabs[index];\n      if (tab) {\n        await this.closeTab(tab, router);\n      }\n    },\n\n    /**\n     * 根据tab的key获取tab\n     * @param key\n     */\n    getTabByKey(key: string) {\n      return this.getTabs.find(\n        (item) => getTabKeyFromTab(item) === key,\n      ) as TabDefinition;\n    },\n    /**\n     * @zh_CN 新窗口打开标签页\n     * @param tab\n     */\n    async openTabInNewWindow(tab: TabDefinition) {\n      openRouteInNewWindow(tab.fullPath || tab.path);\n    },\n\n    /**\n     * @zh_CN 固定标签页\n     * @param tab\n     */\n    async pinTab(tab: TabDefinition) {\n      const index = this.tabs.findIndex((item) => equalTab(item, tab));\n      if (index === -1) {\n        return;\n      }\n      const oldTab = this.tabs[index];\n      tab.meta.affixTab = true;\n      tab.meta.title = oldTab?.meta?.title as string;\n      // this.addTab(tab);\n      this.tabs.splice(index, 1, tab);\n      // 过滤固定tabs，后面更改affixTabOrder的值的话可能会有问题，目前行464排序affixTabs没有设置值\n      const affixTabs = this.tabs.filter((tab) => isAffixTab(tab));\n      // 获得固定tabs的index\n      const newIndex = affixTabs.findIndex((item) => equalTab(item, tab));\n      // 交换位置重新排序\n      await this.sortTabs(index, newIndex);\n    },\n\n    /**\n     * 刷新标签页\n     */\n    async refresh(router: Router | string) {\n      // 如果是Router路由，那么就根据当前路由刷新\n      // 如果是string字符串，为路由名称，则定向刷新指定标签页，不能是当前路由名称，否则不会刷新\n      if (typeof router === 'string') {\n        return await this.refreshByName(router);\n      }\n\n      const { currentRoute } = router;\n      const { name } = currentRoute.value;\n\n      this.excludeCachedTabs.add(name as string);\n      this.renderRouteView = false;\n      startProgress();\n\n      await new Promise((resolve) => setTimeout(resolve, 200));\n\n      this.excludeCachedTabs.delete(name as string);\n      this.renderRouteView = true;\n      stopProgress();\n    },\n\n    /**\n     * 根据路由名称刷新指定标签页\n     */\n    async refreshByName(name: string) {\n      this.excludeCachedTabs.add(name);\n      await new Promise((resolve) => setTimeout(resolve, 200));\n      this.excludeCachedTabs.delete(name);\n    },\n\n    /**\n     * @zh_CN 重置标签页标题\n     */\n    async resetTabTitle(tab: TabDefinition) {\n      if (tab?.meta?.newTabTitle) {\n        return;\n      }\n      const findTab = this.tabs.find((item) => equalTab(item, tab));\n      if (findTab) {\n        findTab.meta.newTabTitle = undefined;\n        await this.updateCacheTabs();\n      }\n    },\n\n    /**\n     * 设置固定标签页\n     * @param tabs\n     */\n    setAffixTabs(tabs: RouteRecordNormalized[]) {\n      for (const tab of tabs) {\n        tab.meta.affixTab = true;\n        this.addTab(routeToTab(tab));\n      }\n    },\n\n    /**\n     * @zh_CN 更新菜单列表\n     * @param list\n     */\n    setMenuList(list: string[]) {\n      this.menuList = list;\n    },\n\n    /**\n     * @zh_CN 设置标签页标题\n     *\n     * @zh_CN 支持设置静态标题字符串或计算属性作为动态标题\n     * @zh_CN 当标题为计算属性时,标题会随计算属性值变化而自动更新\n     * @zh_CN 适用于需要根据状态或多语言动态更新标题的场景\n     *\n     * @param {TabDefinition} tab - 标签页对象\n     * @param {ComputedRef<string> | string} title - 标题内容,支持静态字符串或计算属性\n     *\n     * @example\n     * // 设置静态标题\n     * setTabTitle(tab, '新标签页');\n     *\n     * @example\n     * // 设置动态标题\n     * setTabTitle(tab, computed(() => t('common.dashboard')));\n     */\n    async setTabTitle(tab: TabDefinition, title: ComputedRef<string> | string) {\n      const findTab = this.tabs.find((item) => equalTab(item, tab));\n\n      if (findTab) {\n        findTab.meta.newTabTitle = title;\n\n        await this.updateCacheTabs();\n      }\n    },\n    setUpdateTime() {\n      this.updateTime = Date.now();\n    },\n    /**\n     * @zh_CN 设置标签页顺序\n     * @param oldIndex\n     * @param newIndex\n     */\n    async sortTabs(oldIndex: number, newIndex: number) {\n      const currentTab = this.tabs[oldIndex];\n      if (!currentTab) {\n        return;\n      }\n      this.tabs.splice(oldIndex, 1);\n      this.tabs.splice(newIndex, 0, currentTab);\n      this.dragEndIndex = this.dragEndIndex + 1;\n    },\n\n    /**\n     * @zh_CN 切换固定标签页\n     * @param tab\n     */\n    async toggleTabPin(tab: TabDefinition) {\n      const affixTab = tab?.meta?.affixTab ?? false;\n\n      await (affixTab ? this.unpinTab(tab) : this.pinTab(tab));\n    },\n\n    /**\n     * @zh_CN 取消固定标签页\n     * @param tab\n     */\n    async unpinTab(tab: TabDefinition) {\n      const index = this.tabs.findIndex((item) => equalTab(item, tab));\n      if (index === -1) {\n        return;\n      }\n      const oldTab = this.tabs[index];\n      tab.meta.affixTab = false;\n      tab.meta.title = oldTab?.meta?.title as string;\n      // this.addTab(tab);\n      this.tabs.splice(index, 1, tab);\n      // 过滤固定tabs，后面更改affixTabOrder的值的话可能会有问题，目前行464排序affixTabs没有设置值\n      const affixTabs = this.tabs.filter((tab) => isAffixTab(tab));\n      // 获得固定tabs的index,使用固定tabs的下一个位置也就是活动tabs的第一个位置\n      const newIndex = affixTabs.length;\n      // 交换位置重新排序\n      await this.sortTabs(index, newIndex);\n    },\n    /**\n     * 根据当前打开的选项卡更新缓存\n     */\n    async updateCacheTabs() {\n      const cacheMap = new Set<string>();\n\n      for (const tab of this.tabs) {\n        // 跳过不需要持久化的标签页\n        const keepAlive = tab.meta?.keepAlive;\n        if (!keepAlive) {\n          continue;\n        }\n        (tab.matched || []).forEach((t, i) => {\n          if (i > 0) {\n            cacheMap.add(t.name as string);\n          }\n        });\n\n        const name = tab.name as string;\n        cacheMap.add(name);\n      }\n      this.cachedTabs = cacheMap;\n    },\n  },\n  getters: {\n    affixTabs(): TabDefinition[] {\n      const affixTabs = this.tabs.filter((tab) => isAffixTab(tab));\n\n      return affixTabs.sort((a, b) => {\n        const orderA = (a.meta?.affixTabOrder ?? 0) as number;\n        const orderB = (b.meta?.affixTabOrder ?? 0) as number;\n        return orderA - orderB;\n      });\n    },\n    getCachedTabs(): string[] {\n      return [...this.cachedTabs];\n    },\n    getExcludeCachedTabs(): string[] {\n      return [...this.excludeCachedTabs];\n    },\n    getMenuList(): string[] {\n      return this.menuList;\n    },\n    getTabs(): TabDefinition[] {\n      const normalTabs = this.tabs.filter((tab) => !isAffixTab(tab));\n      return [...this.affixTabs, ...normalTabs].filter(Boolean);\n    },\n  },\n  persist: [\n    // tabs不需要保存在localStorage\n    {\n      pick: ['tabs'],\n      storage: sessionStorage,\n    },\n  ],\n  state: (): TabbarState => ({\n    cachedTabs: new Set(),\n    dragEndIndex: 0,\n    excludeCachedTabs: new Set(),\n    menuList: [\n      'close',\n      'affix',\n      'maximize',\n      'reload',\n      'open-in-new-window',\n      'close-left',\n      'close-right',\n      'close-other',\n      'close-all',\n    ],\n    renderRouteView: true,\n    tabs: [],\n    updateTime: Date.now(),\n  }),\n});\n\n// 解决热更新问题\nconst hot = import.meta.hot;\nif (hot) {\n  hot.accept(acceptHMRUpdate(useTabbarStore, hot));\n}\n\n/**\n * @zh_CN 克隆路由,防止路由被修改\n * @param route\n */\nfunction cloneTab(route: TabDefinition): TabDefinition {\n  if (!route) {\n    return route;\n  }\n  const { matched, meta, ...opt } = route;\n  return {\n    ...opt,\n    matched: (matched\n      ? matched.map((item) => ({\n          meta: item.meta,\n          name: item.name,\n          path: item.path,\n        }))\n      : undefined) as RouteRecordNormalized[],\n    meta: {\n      ...meta,\n      newTabTitle: meta.newTabTitle,\n    },\n  };\n}\n\n/**\n * @zh_CN 是否是固定标签页\n * @param tab\n */\nfunction isAffixTab(tab: TabDefinition) {\n  return tab?.meta?.affixTab ?? false;\n}\n\n/**\n * @zh_CN 是否显示标签\n * @param tab\n */\nfunction isTabShown(tab: TabDefinition) {\n  const matched = tab?.matched ?? [];\n  return !tab.meta.hideInTab && matched.every((item) => !item.meta.hideInTab);\n}\n\n/**\n * 从route获取tab页的key\n * @param tab\n */\nfunction getTabKey(tab: RouteLocationNormalized | RouteRecordNormalized) {\n  const {\n    fullPath,\n    path,\n    meta: { fullPathKey } = {},\n    query = {},\n  } = tab as RouteLocationNormalized;\n  // pageKey可能是数组（查询参数重复时可能出现）\n  const pageKey = Array.isArray(query.pageKey)\n    ? query.pageKey[0]\n    : query.pageKey;\n  let rawKey;\n  if (pageKey) {\n    rawKey = pageKey;\n  } else {\n    rawKey = fullPathKey === false ? path : (fullPath ?? path);\n  }\n  try {\n    return decodeURIComponent(rawKey);\n  } catch {\n    return rawKey;\n  }\n}\n\n/**\n * 从tab获取tab页的key\n * 如果tab没有key,那么就从route获取key\n * @param tab\n */\nfunction getTabKeyFromTab(tab: TabDefinition): string {\n  return tab.key ?? getTabKey(tab);\n}\n\n/**\n * 比较两个tab是否相等\n * @param a\n * @param b\n */\nfunction equalTab(a: TabDefinition, b: TabDefinition) {\n  return getTabKeyFromTab(a) === getTabKeyFromTab(b);\n}\n\nfunction routeToTab(route: RouteRecordNormalized) {\n  return {\n    meta: route.meta,\n    name: route.name,\n    path: route.path,\n    key: getTabKey(route),\n  } as TabDefinition;\n}\n\nexport { getTabKey };\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/modules/user.test.ts",
    "content": "import { createPinia, setActivePinia } from 'pinia';\nimport { beforeEach, describe, expect, it } from 'vitest';\n\nimport { useUserStore } from './user';\n\ndescribe('useUserStore', () => {\n  beforeEach(() => {\n    setActivePinia(createPinia());\n  });\n\n  it('returns correct userInfo', () => {\n    const store = useUserStore();\n    const userInfo: any = { name: 'Jane Doe', roles: [{ value: 'user' }] };\n    store.setUserInfo(userInfo);\n    expect(store.userInfo).toEqual(userInfo);\n  });\n\n  // 测试重置用户信息时的行为\n  it('clears userInfo and userRoles when setting null userInfo', () => {\n    const store = useUserStore();\n    store.setUserInfo({\n      roles: [{ roleName: 'User', value: 'user' }],\n    } as any);\n    expect(store.userInfo).not.toBeNull();\n    expect(store.userRoles.length).toBeGreaterThan(0);\n\n    store.setUserInfo(null as any);\n    expect(store.userInfo).toBeNull();\n    expect(store.userRoles).toEqual([]);\n  });\n\n  // 测试在没有用户角色时返回空数组\n  it('returns an empty array for userRoles if not set', () => {\n    const store = useUserStore();\n    expect(store.userRoles).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/modules/user.ts",
    "content": "import { acceptHMRUpdate, defineStore } from 'pinia';\n\ninterface BasicUserInfo {\n  [key: string]: any;\n  /**\n   * 头像\n   */\n  avatar: string;\n  /**\n   * 用户昵称\n   */\n  realName: string;\n  /**\n   * 用户角色\n   */\n  roles?: string[];\n  /**\n   * 用户id\n   */\n  userId: string;\n  /**\n   * 用户名\n   */\n  username: string;\n}\n\ninterface AccessState {\n  /**\n   * 用户信息\n   */\n  userInfo: BasicUserInfo | null;\n  /**\n   * 用户角色\n   */\n  userRoles: string[];\n}\n\n/**\n * @zh_CN 用户信息相关\n */\nexport const useUserStore = defineStore('core-user', {\n  actions: {\n    setUserInfo(userInfo: BasicUserInfo | null) {\n      // 设置用户信息\n      this.userInfo = userInfo;\n      // 设置角色信息\n      const roles = userInfo?.roles ?? [];\n      this.setUserRoles(roles);\n    },\n    setUserRoles(roles: string[]) {\n      this.userRoles = roles;\n    },\n  },\n  state: (): AccessState => ({\n    userInfo: null,\n    userRoles: [],\n  }),\n});\n\n// 解决热更新问题\nconst hot = import.meta.hot;\nif (hot) {\n  hot.accept(acceptHMRUpdate(useUserStore, hot));\n}\n"
  },
  {
    "path": "hiauth-front/packages/stores/src/setup.ts",
    "content": "import type { Pinia } from 'pinia';\n\nimport type { App } from 'vue';\n\nimport { createPinia } from 'pinia';\nimport SecureLS from 'secure-ls';\n\nlet pinia: Pinia;\n\nexport interface InitStoreOptions {\n  /**\n   * @zh_CN 应用名,由于 @vben/stores 是公用的，后续可能有多个app，为了防止多个app缓存冲突，可在这里配置应用名,应用名将被用于持久化的前缀\n   */\n  namespace: string;\n}\n\n/**\n * @zh_CN 初始化pinia\n */\nexport async function initStores(app: App, options: InitStoreOptions) {\n  const { createPersistedState } = await import('pinia-plugin-persistedstate');\n  pinia = createPinia();\n  const { namespace } = options;\n  const ls = new SecureLS({\n    encodingType: 'aes',\n    encryptionSecret: import.meta.env.VITE_APP_STORE_SECURE_KEY,\n    isCompression: true,\n    // @ts-ignore secure-ls does not have a type definition for this\n    metaKey: `${namespace}-secure-meta`,\n  });\n  pinia.use(\n    createPersistedState({\n      // key $appName-$store.id\n      key: (storeKey) => `${namespace}-${storeKey}`,\n      storage: import.meta.env.DEV\n        ? localStorage\n        : {\n            getItem(key) {\n              return ls.get(key);\n            },\n            setItem(key, value) {\n              ls.set(key, value);\n            },\n          },\n    }),\n  );\n  app.use(pinia);\n  return pinia;\n}\n\nexport function resetAllStores() {\n  if (!pinia) {\n    console.error('Pinia is not installed');\n    return;\n  }\n  const allStores = (pinia as any)._s;\n  for (const [_key, store] of allStores) {\n    store.$reset();\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/stores/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\", \"shim-pinia.d.ts\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/styles/README.md",
    "content": "# @vben/styles\n\n用于多个 `app` 公用的样式文件，继承了 `@vben-core/design` 的所有能力。业务上有通用的样式文件可以放在这里。\n\n## 用法\n\n### 添加依赖\n\n```bash\n# 进入目标应用目录，例如 apps/xxxx-app\n# cd apps/xxxx-app\npnpm add @vben/styles\n```\n\n### 使用\n\n```ts\nimport '@vben/styles';\n```\n"
  },
  {
    "path": "hiauth-front/packages/styles/package.json",
    "content": "{\n  \"name\": \"@vben/styles\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/styles\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    },\n    \"./antd\": {\n      \"default\": \"./src/antd/index.css\"\n    },\n    \"./ele\": {\n      \"default\": \"./src/ele/index.css\"\n    },\n    \"./naive\": {\n      \"default\": \"./src/naive/index.css\"\n    },\n    \"./global\": {\n      \"default\": \"./src/global/index.scss\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/design\": \"workspace:*\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/styles/src/antd/index.css",
    "content": "/* ant-design-vue 组件库的一些样式重置 */\n\n.ant-app {\n  width: 100%;\n  height: 100%;\n  overscroll-behavior: none;\n  color: inherit;\n}\n\n.ant-btn {\n  .anticon {\n    display: inline-flex;\n  }\n\n  /* * 修复按钮添加图标时的位置问题 */\n  > svg {\n    display: inline-block;\n  }\n\n  > svg + span {\n    margin-inline-start: 6px;\n  }\n}\n\n.ant-tag {\n  > svg {\n    display: inline-block;\n  }\n\n  > svg + span {\n    margin-inline-start: 4px;\n  }\n}\n\n.ant-message-notice-content,\n.ant-notification-notice {\n  @apply dark:border-border/60 dark:border;\n}\n\n.form-valid-error {\n  /** select 选择器的样式 */\n\n  .ant-select:not(.valid-success) .ant-select-selector:not(.valid-success) {\n    border-color: hsl(var(--destructive)) !important;\n  }\n\n  .ant-select-focused .ant-select-selector {\n    box-shadow: 0 0 0 2px rgb(255 38 5 / 6%) !important;\n  }\n\n  /** 数字输入框样式 */\n  .ant-input-number-focused {\n    box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);\n  }\n\n  /** 密码输入框样式 */\n  .ant-input-affix-wrapper:hover {\n    border-color: hsl(var(--destructive));\n    box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);\n  }\n\n  .ant-input:not(.valid-success) {\n    border-color: hsl(var(--destructive)) !important;\n  }\n}\n\n/** 区间选择器下面来回切换时的样式 */\n.ant-app .form-valid-error .ant-picker-active-bar {\n  background-color: hsl(var(--destructive));\n}\n\n/** 时间选择器的样式 */\n.ant-app .form-valid-error .ant-picker-focused {\n  box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);\n}\n"
  },
  {
    "path": "hiauth-front/packages/styles/src/ele/index.css",
    "content": ".el-card {\n  --el-card-border-radius: var(--radius) !important;\n}\n\n.form-valid-error {\n  /** select 选择器的样式 */\n  .el-select .el-select__wrapper {\n    box-shadow: 0 0 0 1px var(--el-color-danger) inset;\n  }\n\n  /** input 选择器的样式 */\n  .el-input .el-input__wrapper {\n    box-shadow: 0 0 0 1px var(--el-color-danger) inset;\n  }\n\n  /** radio和checkbox 选择器的样式 */\n  .el-radio .el-radio__inner,\n  .el-checkbox .el-checkbox__inner {\n    border: 1px solid var(--el-color-danger);\n  }\n\n  .el-checkbox-button .el-checkbox-button__inner,\n  .el-radio-button .el-radio-button__inner {\n    border: 1px solid var(--el-color-danger);\n  }\n\n  .el-checkbox-button:first-child .el-checkbox-button__inner,\n  .el-radio-button:first-child .el-radio-button__inner {\n    border-left: 1px solid var(--el-color-danger);\n  }\n\n  .el-checkbox-button:not(:first-child) .el-checkbox-button__inner,\n  .el-radio-button:not(:first-child) .el-radio-button__inner {\n    border-left: none;\n  }\n\n  .el-textarea .el-textarea__inner {\n    border: 1px solid var(--el-color-danger);\n  }\n}\n\nhtml .el-loading-mask {\n  z-index: 1000;\n}\n"
  },
  {
    "path": "hiauth-front/packages/styles/src/global/index.scss",
    "content": "@use '@vben-core/design/bem' as *;\n"
  },
  {
    "path": "hiauth-front/packages/styles/src/index.ts",
    "content": "import '@vben-core/design';\n"
  },
  {
    "path": "hiauth-front/packages/styles/src/naive/index.css",
    "content": ".form-valid-error {\n  .n-base-selection__state-border,\n  .n-input__state-border,\n  .n-radio-group__splitor {\n    border: var(--n-border-error);\n  }\n\n  .n-radio-group .n-radio-button,\n  .n-radio-group .n-radio-group__splitor {\n    --n-button-border-color: rgb(255 56 96);\n  }\n\n  .n-radio__dot {\n    --n-box-shadow: inset 0 0 0 1px rgb(255 56 96);\n  }\n\n  .n-checkbox-box__border {\n    --n-border: 1px solid rgb(255 56 96);\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/styles/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/types/README.md",
    "content": "# @vben/types\n\n用于多个 `app` 公用的工具类型，继承了 `@vben-core/typings` 的所有能力。业务上有通用的类型定义可以放在这里。\n\n## 用法\n\n### 添加依赖\n\n```bash\n# 进入目标应用目录，例如 apps/xxxx-app\n# cd apps/xxxx-app\npnpm add @vben/types\n```\n\n### 使用\n\n```ts\n// 推荐加上 type\nimport type { SelectOption } from '@vben/types';\n```\n"
  },
  {
    "path": "hiauth-front/packages/types/global.d.ts",
    "content": "import type { RouteMeta as IRouteMeta } from '@vben-core/typings';\n\nimport 'vue-router';\n\ndeclare module 'vue-router' {\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  interface RouteMeta extends IRouteMeta {}\n}\n\nexport interface VbenAdminProAppConfigRaw {\n  VITE_GLOB_API_URL: string;\n  VITE_GLOB_AUTH_DINGDING_CLIENT_ID: string;\n  VITE_GLOB_AUTH_DINGDING_CORP_ID: string;\n}\n\ninterface AuthConfig {\n  dingding?: {\n    clientId: string;\n    corpId: string;\n  };\n}\n\nexport interface ApplicationConfig {\n  apiURL: string;\n  auth: AuthConfig;\n}\n\ndeclare global {\n  interface Window {\n    _VBEN_ADMIN_PRO_APP_CONF_: VbenAdminProAppConfigRaw;\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/types/package.json",
    "content": "{\n  \"name\": \"@vben/types\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/types\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    },\n    \"./global\": {\n      \"types\": \"./global.d.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/typings\": \"workspace:*\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/types/src/index.ts",
    "content": "export type * from './user';\nexport type * from '@vben-core/typings';\n"
  },
  {
    "path": "hiauth-front/packages/types/src/user.ts",
    "content": "import type { BasicUserInfo } from '@vben-core/typings';\n\n/** 用户信息 */\ninterface UserInfo extends BasicUserInfo {\n  /**\n   * 用户描述\n   */\n  desc: string;\n  /**\n   * 首页地址\n   */\n  homePath: string;\n\n  /**\n   * accessToken\n   */\n  token: string;\n}\n\nexport type { UserInfo };\n"
  },
  {
    "path": "hiauth-front/packages/types/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/packages/utils/README.md",
    "content": "# @vben/utils\n\n用于多个 `app` 公用的工具包，继承了 `@vben-core/shared/utils` 的所有能力。业务上有通用的工具函数可以放在这里。\n\n## 用法\n\n### 添加依赖\n\n```bash\n# 进入目标应用目录，例如 apps/xxxx-app\n# cd apps/xxxx-app\npnpm add @vben/utils\n```\n\n### 使用\n\n```ts\nimport { isString } from '@vben/utils';\n```\n"
  },
  {
    "path": "hiauth-front/packages/utils/package.json",
    "content": "{\n  \"name\": \"@vben/utils\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://github.com/vbenjs/vue-vben-admin\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"packages/utils\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"sideEffects\": [\n    \"**/*.css\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./src/index.ts\",\n      \"default\": \"./src/index.ts\"\n    }\n  },\n  \"dependencies\": {\n    \"@vben-core/shared\": \"workspace:*\",\n    \"@vben-core/typings\": \"workspace:*\",\n    \"vue-router\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { findMenuByPath, findRootMenuByPath } from '../find-menu-by-path';\n\n// 示例菜单数据\nconst menus: any[] = [\n  { path: '/', children: [] },\n  { path: '/about', children: [] },\n  {\n    path: '/contact',\n    children: [\n      { path: '/contact/email', children: [] },\n      { path: '/contact/phone', children: [] },\n    ],\n  },\n  {\n    path: '/services',\n    children: [\n      { path: '/services/design', children: [] },\n      {\n        path: '/services/development',\n        children: [{ path: '/services/development/web', children: [] }],\n      },\n    ],\n  },\n];\n\ndescribe('menu Finder Tests', () => {\n  it('finds a top-level menu', () => {\n    const menu = findMenuByPath(menus, '/about');\n    expect(menu).toBeDefined();\n    expect(menu?.path).toBe('/about');\n  });\n\n  it('finds a nested menu', () => {\n    const menu = findMenuByPath(menus, '/services/development/web');\n    expect(menu).toBeDefined();\n    expect(menu?.path).toBe('/services/development/web');\n  });\n\n  it('returns null for a non-existent path', () => {\n    const menu = findMenuByPath(menus, '/non-existent');\n    expect(menu).toBeNull();\n  });\n\n  it('handles empty menus list', () => {\n    const menu = findMenuByPath([], '/about');\n    expect(menu).toBeNull();\n  });\n\n  it('handles menu items without children', () => {\n    const menu = findMenuByPath(\n      [{ path: '/only', children: undefined }] as any[],\n      '/only',\n    );\n    expect(menu).toBeDefined();\n    expect(menu?.path).toBe('/only');\n  });\n\n  it('finds root menu by path', () => {\n    const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(\n      menus,\n      '/services/development/web',\n    );\n\n    expect(findMenu).toBeDefined();\n    expect(rootMenu).toBeUndefined();\n    expect(rootMenuPath).toBeUndefined();\n    expect(findMenu?.path).toBe('/services/development/web');\n  });\n\n  it('returns null for undefined or empty path', () => {\n    const menuUndefinedPath = findMenuByPath(menus);\n    const menuEmptyPath = findMenuByPath(menus, '');\n    expect(menuUndefinedPath).toBeNull();\n    expect(menuEmptyPath).toBeNull();\n  });\n\n  it('checks for root menu when path does not exist', () => {\n    const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(\n      menus,\n      '/non-existent',\n    );\n    expect(findMenu).toBeNull();\n    expect(rootMenu).toBeUndefined();\n    expect(rootMenuPath).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/__tests__/generate-menus.test.ts",
    "content": "import type { Router, RouteRecordRaw } from 'vue-router';\n\nimport { createRouter, createWebHistory } from 'vue-router';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { generateMenus } from '../generate-menus';\n\n// Nested route setup to test child inclusion and hideChildrenInMenu functionality\n\ndescribe('generateMenus', () => {\n  // 模拟路由数据\n  const mockRoutes = [\n    {\n      meta: { icon: 'home-icon', title: '首页' },\n      name: 'home',\n      path: '/home',\n    },\n    {\n      meta: { hideChildrenInMenu: true, icon: 'about-icon', title: '关于' },\n      name: 'about',\n      path: '/about',\n      children: [\n        {\n          path: 'team',\n          name: 'team',\n          meta: { icon: 'team-icon', title: '团队' },\n        },\n      ],\n    },\n  ] as RouteRecordRaw[];\n\n  // 模拟 Vue 路由器实例\n  const mockRouter = {\n    getRoutes: vi.fn(() => [\n      { name: 'home', path: '/home' },\n      { name: 'about', path: '/about' },\n      { name: 'team', path: '/about/team' },\n    ]),\n  };\n\n  it('the correct menu list should be generated according to the route', async () => {\n    const expectedMenus = [\n      {\n        badge: undefined,\n        badgeType: undefined,\n        badgeVariants: undefined,\n        icon: 'home-icon',\n        name: '首页',\n        order: undefined,\n        parent: undefined,\n        parents: undefined,\n        path: '/home',\n        show: true,\n        children: [],\n      },\n      {\n        badge: undefined,\n        badgeType: undefined,\n        badgeVariants: undefined,\n        icon: 'about-icon',\n        name: '关于',\n        order: undefined,\n        parent: undefined,\n        parents: undefined,\n        path: '/about',\n        show: true,\n        children: [],\n      },\n    ];\n\n    const menus = generateMenus(mockRoutes, mockRouter as any);\n    expect(menus).toEqual(expectedMenus);\n  });\n\n  it('includes additional meta properties in menu items', async () => {\n    const mockRoutesWithMeta = [\n      {\n        meta: { icon: 'user-icon', order: 1, title: 'Profile' },\n        name: 'profile',\n        path: '/profile',\n      },\n    ] as RouteRecordRaw[];\n\n    const menus = generateMenus(mockRoutesWithMeta, mockRouter as any);\n    expect(menus).toEqual([\n      {\n        badge: undefined,\n        badgeType: undefined,\n        badgeVariants: undefined,\n        icon: 'user-icon',\n        name: 'Profile',\n        order: 1,\n        parent: undefined,\n        parents: undefined,\n        path: '/profile',\n        show: true,\n        children: [],\n      },\n    ]);\n  });\n\n  it('handles dynamic route parameters correctly', async () => {\n    const mockRoutesWithParams = [\n      {\n        meta: { icon: 'details-icon', title: 'User Details' },\n        name: 'userDetails',\n        path: '/users/:userId',\n      },\n    ] as RouteRecordRaw[];\n\n    const menus = generateMenus(mockRoutesWithParams, mockRouter as any);\n    expect(menus).toEqual([\n      {\n        badge: undefined,\n        badgeType: undefined,\n        badgeVariants: undefined,\n        icon: 'details-icon',\n        name: 'User Details',\n        order: undefined,\n        parent: undefined,\n        parents: undefined,\n        path: '/users/:userId',\n        show: true,\n        children: [],\n      },\n    ]);\n  });\n\n  it('processes routes with redirects correctly', async () => {\n    const mockRoutesWithRedirect = [\n      {\n        name: 'redirectedRoute',\n        path: '/old-path',\n        redirect: '/new-path',\n      },\n      {\n        meta: { icon: 'path-icon', title: 'New Path' },\n        name: 'newPath',\n        path: '/new-path',\n      },\n    ] as RouteRecordRaw[];\n\n    const menus = generateMenus(mockRoutesWithRedirect, mockRouter as any);\n    expect(menus).toEqual([\n      // Assuming your generateMenus function excludes redirect routes from the menu\n      {\n        badge: undefined,\n        badgeType: undefined,\n        badgeVariants: undefined,\n        icon: undefined,\n        name: 'redirectedRoute',\n        order: undefined,\n        parent: undefined,\n        parents: undefined,\n        path: '/old-path',\n        show: true,\n        children: [],\n      },\n      {\n        badge: undefined,\n        badgeType: undefined,\n        badgeVariants: undefined,\n        icon: 'path-icon',\n        name: 'New Path',\n        order: undefined,\n        parent: undefined,\n        parents: undefined,\n        path: '/new-path',\n        show: true,\n        children: [],\n      },\n    ]);\n  });\n\n  const routes: any = [\n    {\n      meta: { order: 2, title: 'Home' },\n      name: 'home',\n      path: '/',\n    },\n    {\n      meta: { order: 1, title: 'About' },\n      name: 'about',\n      path: '/about',\n    },\n  ];\n\n  const router: Router = createRouter({\n    history: createWebHistory(),\n    routes,\n  });\n\n  it('should generate menu list with correct order', async () => {\n    const menus = generateMenus(routes, router);\n    const expectedMenus = [\n      {\n        badge: undefined,\n        badgeType: undefined,\n        badgeVariants: undefined,\n        icon: undefined,\n        name: 'About',\n        order: 1,\n        parent: undefined,\n        parents: undefined,\n        path: '/about',\n        show: true,\n        children: [],\n      },\n      {\n        badge: undefined,\n        badgeType: undefined,\n        badgeVariants: undefined,\n        icon: undefined,\n        name: 'Home',\n        order: 2,\n        parent: undefined,\n        parents: undefined,\n        path: '/',\n        show: true,\n        children: [],\n      },\n    ];\n\n    expect(menus).toEqual(expectedMenus);\n  });\n\n  it('should handle empty routes', async () => {\n    const emptyRoutes: any[] = [];\n    const menus = generateMenus(emptyRoutes, router);\n    expect(menus).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { describe, expect, it } from 'vitest';\n\nimport {\n  generateRoutesByFrontend,\n  hasAuthority,\n} from '../generate-routes-frontend';\n\n// Mock 路由数据\nconst mockRoutes = [\n  {\n    meta: {\n      authority: ['admin', 'user'],\n      hideInMenu: false,\n    },\n    path: '/dashboard',\n    children: [\n      {\n        path: '/dashboard/overview',\n        meta: { authority: ['admin'], hideInMenu: false },\n      },\n      {\n        path: '/dashboard/stats',\n        meta: { authority: ['user'], hideInMenu: true },\n      },\n    ],\n  },\n  {\n    meta: { authority: ['admin'], hideInMenu: false },\n    path: '/settings',\n  },\n  {\n    meta: { hideInMenu: false },\n    path: '/profile',\n  },\n] as RouteRecordRaw[];\n\ndescribe('hasAuthority', () => {\n  it('should return true if there is no authority defined', () => {\n    expect(hasAuthority(mockRoutes[2], ['admin'])).toBe(true);\n  });\n\n  it('should return true if the user has the required authority', () => {\n    expect(hasAuthority(mockRoutes[0], ['admin'])).toBe(true);\n  });\n\n  it('should return false if the user does not have the required authority', () => {\n    expect(hasAuthority(mockRoutes[1], ['user'])).toBe(false);\n  });\n});\n\ndescribe('generateRoutesByFrontend', () => {\n  it('should handle routes without children', async () => {\n    const generatedRoutes = await generateRoutesByFrontend(mockRoutes, [\n      'user',\n    ]);\n    expect(generatedRoutes).toEqual(\n      expect.arrayContaining([\n        expect.objectContaining({\n          path: '/profile', // This route has no children and should be included\n        }),\n      ]),\n    );\n  });\n\n  it('should handle empty roles array', async () => {\n    const generatedRoutes = await generateRoutesByFrontend(mockRoutes, []);\n    expect(generatedRoutes).toEqual(\n      expect.arrayContaining([\n        // Only routes without authority should be included\n        expect.objectContaining({\n          path: '/profile',\n        }),\n      ]),\n    );\n    expect(generatedRoutes).not.toEqual(\n      expect.arrayContaining([\n        expect.objectContaining({\n          path: '/dashboard',\n        }),\n        expect.objectContaining({\n          path: '/settings',\n        }),\n      ]),\n    );\n  });\n\n  it('should handle missing meta fields', async () => {\n    const routesWithMissingMeta = [\n      { path: '/path1' }, // No meta\n      { meta: {}, path: '/path2' }, // Empty meta\n      { meta: { authority: ['admin'] }, path: '/path3' }, // Only authority\n    ];\n    const generatedRoutes = await generateRoutesByFrontend(\n      routesWithMissingMeta as RouteRecordRaw[],\n      ['admin'],\n    );\n    expect(generatedRoutes).toEqual([\n      { path: '/path1' },\n      { meta: {}, path: '/path2' },\n      { meta: { authority: ['admin'] }, path: '/path3' },\n    ]);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport type { RouteModuleType } from '../merge-route-modules';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { mergeRouteModules } from '../merge-route-modules';\n\ndescribe('mergeRouteModules', () => {\n  it('should merge route modules correctly', () => {\n    const routeModules: Record<string, RouteModuleType> = {\n      './dynamic-routes/about.ts': {\n        default: [\n          {\n            component: () => Promise.resolve({ template: '<div>About</div>' }),\n            name: 'About',\n            path: '/about',\n          },\n        ],\n      },\n      './dynamic-routes/home.ts': {\n        default: [\n          {\n            component: () => Promise.resolve({ template: '<div>Home</div>' }),\n            name: 'Home',\n            path: '/',\n          },\n        ],\n      },\n    };\n\n    const expectedRoutes: RouteRecordRaw[] = [\n      {\n        component: expect.any(Function),\n        name: 'About',\n        path: '/about',\n      },\n      {\n        component: expect.any(Function),\n        name: 'Home',\n        path: '/',\n      },\n    ];\n\n    const mergedRoutes = mergeRouteModules(routeModules);\n    expect(mergedRoutes).toEqual(expectedRoutes);\n  });\n\n  it('should handle empty modules', () => {\n    const routeModules: Record<string, RouteModuleType> = {};\n    const expectedRoutes: RouteRecordRaw[] = [];\n\n    const mergedRoutes = mergeRouteModules(routeModules);\n    expect(mergedRoutes).toEqual(expectedRoutes);\n  });\n\n  it('should handle modules with no default export', () => {\n    const routeModules: Record<string, RouteModuleType> = {\n      './dynamic-routes/empty.ts': {\n        default: [],\n      },\n    };\n    const expectedRoutes: RouteRecordRaw[] = [];\n\n    const mergedRoutes = mergeRouteModules(routeModules);\n    expect(mergedRoutes).toEqual(expectedRoutes);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/find-menu-by-path.ts",
    "content": "import type { MenuRecordRaw } from '@vben-core/typings';\n\nfunction findMenuByPath(\n  list: MenuRecordRaw[],\n  path?: string,\n): MenuRecordRaw | null {\n  for (const menu of list) {\n    if (menu.path === path) {\n      return menu;\n    }\n    const findMenu = menu.children && findMenuByPath(menu.children, path);\n    if (findMenu) {\n      return findMenu;\n    }\n  }\n  return null;\n}\n\n/**\n * 查找根菜单\n * @param menus\n * @param path\n */\nfunction findRootMenuByPath(menus: MenuRecordRaw[], path?: string, level = 0) {\n  const findMenu = findMenuByPath(menus, path);\n  const rootMenuPath = findMenu?.parents?.[level];\n  const rootMenu = rootMenuPath\n    ? menus.find((item) => item.path === rootMenuPath)\n    : undefined;\n  return {\n    findMenu,\n    rootMenu,\n    rootMenuPath,\n  };\n}\n\nexport { findMenuByPath, findRootMenuByPath };\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/generate-menus.ts",
    "content": "import type { Router, RouteRecordRaw } from 'vue-router';\n\nimport type {\n  ExRouteRecordRaw,\n  MenuRecordRaw,\n  RouteMeta,\n} from '@vben-core/typings';\n\nimport { filterTree, mapTree } from '@vben-core/shared/utils';\n\n/**\n * 根据 routes 生成菜单列表\n * @param routes - 路由配置列表\n * @param router - Vue Router 实例\n * @returns 生成的菜单列表\n */\nfunction generateMenus(\n  routes: RouteRecordRaw[],\n  router: Router,\n): MenuRecordRaw[] {\n  // 将路由列表转换为一个以 name 为键的对象映射\n  const finalRoutesMap: { [key: string]: string } = Object.fromEntries(\n    router.getRoutes().map(({ name, path }) => [name, path]),\n  );\n\n  let menus = mapTree<ExRouteRecordRaw, MenuRecordRaw>(routes, (route) => {\n    // 获取最终的路由路径\n    const path = finalRoutesMap[route.name as string] ?? route.path ?? '';\n\n    const {\n      meta = {} as RouteMeta,\n      name: routeName,\n      redirect,\n      children = [],\n    } = route;\n    const {\n      activeIcon,\n      badge,\n      badgeType,\n      badgeVariants,\n      hideChildrenInMenu = false,\n      icon,\n      link,\n      order,\n      title = '',\n    } = meta;\n\n    // 确保菜单名称不为空\n    const name = (title || routeName || '') as string;\n\n    // 处理子菜单\n    const resultChildren = hideChildrenInMenu\n      ? []\n      : ((children as MenuRecordRaw[]) ?? []);\n\n    // 设置子菜单的父子关系\n    if (resultChildren.length > 0) {\n      resultChildren.forEach((child) => {\n        child.parents = [...(route.parents ?? []), path];\n        child.parent = path;\n      });\n    }\n\n    // 确定最终路径\n    const resultPath = hideChildrenInMenu ? redirect || path : link || path;\n\n    return {\n      activeIcon,\n      badge,\n      badgeType,\n      badgeVariants,\n      icon,\n      name,\n      order,\n      parent: route.parent,\n      parents: route.parents,\n      path: resultPath,\n      show: !meta.hideInMenu,\n      children: resultChildren,\n    };\n  });\n\n  // 对菜单进行排序，避免order=0时被替换成999的问题\n  menus = menus.sort((a, b) => (a?.order ?? 999) - (b?.order ?? 999));\n\n  // 过滤掉隐藏的菜单项\n  return filterTree(menus, (menu) => !!menu.show);\n}\n\nexport { generateMenus };\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/generate-routes-backend.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport type {\n  ComponentRecordType,\n  GenerateMenuAndRoutesOptions,\n  RouteRecordStringComponent,\n} from '@vben-core/typings';\n\nimport { mapTree } from '@vben-core/shared/utils';\n\n/**\n * 动态生成路由 - 后端方式\n */\nasync function generateRoutesByBackend(\n  options: GenerateMenuAndRoutesOptions,\n): Promise<RouteRecordRaw[]> {\n  const { fetchMenuListAsync, layoutMap = {}, pageMap = {} } = options;\n\n  try {\n    const menuRoutes = await fetchMenuListAsync?.();\n    if (!menuRoutes) {\n      return [];\n    }\n\n    const normalizePageMap: ComponentRecordType = {};\n\n    for (const [key, value] of Object.entries(pageMap)) {\n      normalizePageMap[normalizeViewPath(key)] = value;\n    }\n\n    const routes = convertRoutes(menuRoutes, layoutMap, normalizePageMap);\n\n    return routes;\n  } catch (error) {\n    console.error(error);\n    throw error;\n  }\n}\n\nfunction convertRoutes(\n  routes: RouteRecordStringComponent[],\n  layoutMap: ComponentRecordType,\n  pageMap: ComponentRecordType,\n): RouteRecordRaw[] {\n  return mapTree(routes, (node) => {\n    const route = node as unknown as RouteRecordRaw;\n    const { component, name } = node;\n\n    if (!name) {\n      console.error('route name is required', route);\n    }\n\n    // layout转换\n    if (component && layoutMap[component]) {\n      route.component = layoutMap[component];\n      // 页面组件转换\n    } else if (component) {\n      const normalizePath = normalizeViewPath(component);\n      const pageKey = normalizePath.endsWith('.vue')\n        ? normalizePath\n        : `${normalizePath}.vue`;\n      if (pageMap[pageKey]) {\n        route.component = pageMap[pageKey];\n      } else {\n        console.error(`route component is invalid: ${pageKey}`, route);\n        route.component = pageMap['/_core/fallback/not-found.vue'];\n      }\n    }\n\n    return route;\n  });\n}\n\nfunction normalizeViewPath(path: string): string {\n  // 去除相对路径前缀\n  const normalizedPath = path.replace(/^(\\.\\/|\\.\\.\\/)+/, '');\n\n  // 确保路径以 '/' 开头\n  const viewPath = normalizedPath.startsWith('/')\n    ? normalizedPath\n    : `/${normalizedPath}`;\n\n  // 这里耦合了vben-admin的目录结构\n  return viewPath.replace(/^\\/views/, '');\n}\nexport { generateRoutesByBackend };\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/generate-routes-frontend.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { filterTree, mapTree } from '@vben-core/shared/utils';\n\n/**\n * 动态生成路由 - 前端方式\n */\nasync function generateRoutesByFrontend(\n  routes: RouteRecordRaw[],\n  roles: string[],\n  forbiddenComponent?: RouteRecordRaw['component'],\n): Promise<RouteRecordRaw[]> {\n  // 根据角色标识过滤路由表,判断当前用户是否拥有指定权限\n  const finalRoutes = filterTree(routes, (route) => {\n    return hasAuthority(route, roles);\n  });\n\n  if (!forbiddenComponent) {\n    return finalRoutes;\n  }\n\n  // 如果有禁止访问的页面，将禁止访问的页面替换为403页面\n  return mapTree(finalRoutes, (route) => {\n    if (menuHasVisibleWithForbidden(route)) {\n      route.component = forbiddenComponent;\n    }\n    return route;\n  });\n}\n\n/**\n * 判断路由是否有权限访问\n * @param route\n * @param access\n */\nfunction hasAuthority(route: RouteRecordRaw, access: string[]) {\n  const authority = route.meta?.authority;\n  if (!authority) {\n    return true;\n  }\n  const canAccess = access.some((value) => authority.includes(value));\n\n  return canAccess || (!canAccess && menuHasVisibleWithForbidden(route));\n}\n\n/**\n * 判断路由是否在菜单中显示，但是访问会被重定向到403\n * @param route\n */\nfunction menuHasVisibleWithForbidden(route: RouteRecordRaw) {\n  return (\n    !!route.meta?.authority &&\n    Reflect.has(route.meta || {}, 'menuVisibleWithForbidden') &&\n    !!route.meta?.menuVisibleWithForbidden\n  );\n}\n\nexport { generateRoutesByFrontend, hasAuthority };\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/get-popup-container.ts",
    "content": "/**\n * If the node is holding inside a form, return the form element,\n * otherwise return the parent node of the given element or\n * the document body if the element is not provided.\n */\nexport function getPopupContainer(node?: HTMLElement): HTMLElement {\n  return (\n    node?.closest('form') ?? (node?.parentNode as HTMLElement) ?? document.body\n  );\n}\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/index.ts",
    "content": "export * from './find-menu-by-path';\nexport * from './generate-menus';\nexport * from './generate-routes-backend';\nexport * from './generate-routes-frontend';\nexport * from './get-popup-container';\nexport * from './merge-route-modules';\nexport * from './reset-routes';\nexport * from './unmount-global-loading';\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/merge-route-modules.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\n// 定义模块类型\ninterface RouteModuleType {\n  default: RouteRecordRaw[];\n}\n\n/**\n * 合并动态路由模块的默认导出\n * @param routeModules 动态导入的路由模块对象\n * @returns 合并后的路由配置数组\n */\nfunction mergeRouteModules(\n  routeModules: Record<string, unknown>,\n): RouteRecordRaw[] {\n  const mergedRoutes: RouteRecordRaw[] = [];\n\n  for (const routeModule of Object.values(routeModules)) {\n    const moduleRoutes = (routeModule as RouteModuleType)?.default ?? [];\n    mergedRoutes.push(...moduleRoutes);\n  }\n\n  return mergedRoutes;\n}\n\nexport { mergeRouteModules };\n\nexport type { RouteModuleType };\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/reset-routes.ts",
    "content": "import type { Router, RouteRecordName, RouteRecordRaw } from 'vue-router';\n\nimport { traverseTreeValues } from '@vben-core/shared/utils';\n\n/**\n * @zh_CN 重置所有路由，如有指定白名单除外\n */\nexport function resetStaticRoutes(router: Router, routes: RouteRecordRaw[]) {\n  // 获取静态路由所有节点包含子节点的 name，并排除不存在 name 字段的路由\n  const staticRouteNames = traverseTreeValues<\n    RouteRecordRaw,\n    RouteRecordName | undefined\n  >(routes, (route) => {\n    // 这些路由需要指定 name，防止在路由重置时，不能删除没有指定 name 的路由\n    if (!route.name) {\n      console.warn(\n        `The route with the path ${route.path} needs to have the field name specified.`,\n      );\n    }\n    return route.name;\n  });\n\n  const { getRoutes, hasRoute, removeRoute } = router;\n  const allRoutes = getRoutes();\n  allRoutes.forEach(({ name }) => {\n    // 存在于路由表且非白名单才需要删除\n    if (name && !staticRouteNames.includes(name) && hasRoute(name)) {\n      removeRoute(name);\n    }\n  });\n}\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/helpers/unmount-global-loading.ts",
    "content": "/**\n * 移除并销毁loading\n * 放在这里是而不是放在 index.html 的app标签内，是因为这样比较不会生硬，渲染过快可能会有闪烁\n * 通过先添加css动画隐藏，在动画结束后在移除loading节点来改善体验\n * 不好的地方是会增加一些代码量\n * 自定义loading可以见：https://doc.vben.pro/guide/in-depth/loading.html\n */\nexport function unmountGlobalLoading() {\n  // 查找全局 loading 元素\n  const loadingElement = document.querySelector('#__app-loading__');\n\n  if (loadingElement) {\n    // 添加隐藏类，触发过渡动画\n    loadingElement.classList.add('hidden');\n\n    // 查找所有需要移除的注入 loading 元素\n    const injectLoadingElements = document.querySelectorAll(\n      '[data-app-loading^=\"inject\"]',\n    );\n\n    // 当过渡动画结束时，移除 loading 元素和所有注入的 loading 元素\n    loadingElement.addEventListener(\n      'transitionend',\n      () => {\n        loadingElement.remove(); // 移除 loading 元素\n        injectLoadingElements.forEach((el) => el.remove()); // 移除所有注入的 loading 元素\n      },\n      { once: true },\n    ); // 确保事件只触发一次\n  }\n}\n"
  },
  {
    "path": "hiauth-front/packages/utils/src/index.ts",
    "content": "export * from './helpers';\nexport * from '@vben-core/shared/cache';\nexport * from '@vben-core/shared/color';\nexport * from '@vben-core/shared/utils';\n"
  },
  {
    "path": "hiauth-front/packages/utils/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/library.json\",\n  \"compilerOptions\": {\n    \"types\": [\"@vben-core/typings/vue-router\"]\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/playground/__tests__/e2e/auth-login.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\n\nimport { authLogin } from './common/auth';\n\ntest.beforeEach(async ({ page }) => {\n  await page.goto('/');\n});\n\ntest.describe('Auth Login Page Tests', () => {\n  test('check title and page elements', async ({ page }) => {\n    // 获取页面标题并断言标题包含 'Vben Admin'\n    const title = await page.title();\n    expect(title).toContain('Vben Admin');\n  });\n\n  // 测试用例: 成功登录\n  test('should successfully login with valid credentials', async ({ page }) => {\n    await authLogin(page);\n  });\n});\n"
  },
  {
    "path": "hiauth-front/playground/__tests__/e2e/common/auth.ts",
    "content": "import type { Page } from '@playwright/test';\n\nimport { expect } from '@playwright/test';\n\nexport async function authLogin(page: Page) {\n  // 确保登录表单正常\n  const usernameInput = await page.locator(`input[name='username']`);\n  await expect(usernameInput).toBeVisible();\n\n  const passwordInput = await page.locator(`input[name='password']`);\n  await expect(passwordInput).toBeVisible();\n\n  const sliderCaptcha = await page.locator(`div[name='captcha']`);\n  const sliderCaptchaAction = await page.locator(`div[name='captcha-action']`);\n  await expect(sliderCaptcha).toBeVisible();\n  await expect(sliderCaptchaAction).toBeVisible();\n\n  // 拖动验证码滑块\n  // 获取拖动按钮的位置\n  const sliderCaptchaBox = await sliderCaptcha.boundingBox();\n  if (!sliderCaptchaBox) throw new Error('滑块未找到');\n\n  const actionBoundingBox = await sliderCaptchaAction.boundingBox();\n  if (!actionBoundingBox) throw new Error('要拖动的按钮未找到');\n\n  // 计算起始位置和目标位置\n  const startX = actionBoundingBox.x + actionBoundingBox.width / 2; // div 中心的 x 坐标\n  const startY = actionBoundingBox.y + actionBoundingBox.height / 2; // div 中心的 y 坐标\n\n  const targetX = startX + sliderCaptchaBox.width + actionBoundingBox.width; // 向右拖动容器的宽度\n  const targetY = startY; // y 坐标保持不变\n\n  // 模拟鼠标拖动\n  await page.mouse.move(startX, startY); // 移动到 action 的中心\n  await page.mouse.down(); // 按下鼠标\n  await page.mouse.move(targetX, targetY, { steps: 20 }); // 拖动到目标位置\n  await page.mouse.up(); // 松开鼠标\n\n  // 在拖动后进行断言，检查action是否在预期位置,\n  const newActionBoundingBox = await sliderCaptchaAction.boundingBox();\n  expect(newActionBoundingBox?.x).toBeGreaterThan(actionBoundingBox.x);\n\n  // 到这里已经校验成功，点击进行登录\n  await page.waitForTimeout(300);\n  await page.getByRole('button', { name: 'login' }).click();\n}\n"
  },
  {
    "path": "hiauth-front/playground/index.html",
    "content": "<!doctype html>\n<html lang=\"zh\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n    <meta name=\"renderer\" content=\"webkit\" />\n    <meta name=\"description\" content=\"A Modern Back-end Management System\" />\n    <meta name=\"keywords\" content=\"Vben Admin Vue3 Vite\" />\n    <meta name=\"author\" content=\"Vben\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0\"\n    />\n    <!-- 由 vite 注入 VITE_APP_TITLE 变量，在 .env 文件内配置 -->\n    <title><%= VITE_APP_TITLE %></title>\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <script>\n      // 生产环境下注入百度统计\n      if (window._VBEN_ADMIN_PRO_APP_CONF_) {\n        var _hmt = _hmt || [];\n        (function () {\n          var hm = document.createElement('script');\n          hm.src =\n            'https://hm.baidu.com/hm.js?d20a01273820422b6aa2ee41b6c9414d';\n          var s = document.getElementsByTagName('script')[0];\n          s.parentNode.insertBefore(hm, s);\n        })();\n      }\n    </script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "hiauth-front/playground/package.json",
    "content": "{\n  \"name\": \"@vben/playground\",\n  \"version\": \"5.5.9\",\n  \"homepage\": \"https://vben.pro\",\n  \"bugs\": \"https://github.com/vbenjs/vue-vben-admin/issues\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vbenjs/vue-vben-admin.git\",\n    \"directory\": \"playground\"\n  },\n  \"license\": \"MIT\",\n  \"author\": {\n    \"name\": \"vben\",\n    \"email\": \"ann.vben@gmail.com\",\n    \"url\": \"https://github.com/anncwb\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm vite build --mode production\",\n    \"build:analyze\": \"pnpm vite build --mode analyze\",\n    \"dev\": \"pnpm vite --mode development\",\n    \"preview\": \"vite preview\",\n    \"typecheck\": \"vue-tsc --noEmit --skipLibCheck\",\n    \"test:e2e\": \"playwright test\",\n    \"test:e2e-ui\": \"playwright test --ui\",\n    \"test:e2e-codegen\": \"playwright codegen\"\n  },\n  \"imports\": {\n    \"#/*\": \"./src/*\"\n  },\n  \"dependencies\": {\n    \"@tanstack/vue-query\": \"catalog:\",\n    \"@vben-core/menu-ui\": \"workspace:*\",\n    \"@vben/access\": \"workspace:*\",\n    \"@vben/common-ui\": \"workspace:*\",\n    \"@vben/constants\": \"workspace:*\",\n    \"@vben/hooks\": \"workspace:*\",\n    \"@vben/icons\": \"workspace:*\",\n    \"@vben/layouts\": \"workspace:*\",\n    \"@vben/locales\": \"workspace:*\",\n    \"@vben/plugins\": \"workspace:*\",\n    \"@vben/preferences\": \"workspace:*\",\n    \"@vben/request\": \"workspace:*\",\n    \"@vben/stores\": \"workspace:*\",\n    \"@vben/styles\": \"workspace:*\",\n    \"@vben/types\": \"workspace:*\",\n    \"@vben/utils\": \"workspace:*\",\n    \"@vueuse/core\": \"catalog:\",\n    \"ant-design-vue\": \"catalog:\",\n    \"dayjs\": \"catalog:\",\n    \"json-bigint\": \"catalog:\",\n    \"pinia\": \"catalog:\",\n    \"vue\": \"catalog:\",\n    \"vue-router\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"@types/json-bigint\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/playwright.config.ts",
    "content": "import type { PlaywrightTestConfig } from '@playwright/test';\n\nimport { devices } from '@playwright/test';\n\n/**\n * Read environment variables from file.\n * https://github.com/motdotla/dotenv\n */\n// require('dotenv').config();\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\nconst config: PlaywrightTestConfig = {\n  expect: {\n    /**\n     * Maximum time expect() should wait for the condition to be met.\n     * For example in `await expect(locator).toHaveText();`\n     */\n    timeout: 5000,\n  },\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!process.env.CI,\n  /* Folder for test artifacts such as screenshots, videos, traces, etc. */\n  outputDir: 'node_modules/.e2e/test-results/',\n  /* Configure projects for major browsers */\n  projects: [\n    {\n      name: 'chromium',\n      use: {\n        ...devices['Desktop Chrome'],\n      },\n    },\n    // {\n    //   name: 'firefox',\n    //   use: {\n    //     ...devices['Desktop Firefox'],\n    //   },\n    // },\n    // {\n    //   name: 'webkit',\n    //   use: {\n    //     ...devices['Desktop Safari'],\n    //   },\n    // },\n\n    /* Test against mobile viewports. */\n    // {\n    //   name: 'Mobile Chrome',\n    //   use: {\n    //     ...devices['Pixel 5'],\n    //   },\n    // },\n    // {\n    //   name: 'Mobile Safari',\n    //   use: {\n    //     ...devices['iPhone 12'],\n    //   },\n    // },\n\n    /* Test against branded browsers. */\n    // {\n    //   name: 'Microsoft Edge',\n    //   use: {\n    //     channel: 'msedge',\n    //   },\n    // },\n    // {\n    //   name: 'Google Chrome',\n    //   use: {\n    //     channel: 'chrome',\n    //   },\n    // },\n  ],\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  reporter: [\n    ['list'],\n    ['html', { outputFolder: 'node_modules/.e2e/test-results' }],\n  ],\n  /* Retry on CI only */\n  retries: process.env.CI ? 2 : 0,\n  testDir: './__tests__/e2e',\n  /* Maximum time one test can run for. */\n  timeout: 30 * 1000,\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */\n    actionTimeout: 0,\n    /* Base URL to use in actions like `await page.goto('/')`. */\n    baseURL: 'http://localhost:5555',\n    /* Only on CI systems run the tests headless */\n    headless: !!process.env.CI,\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: 'retain-on-failure',\n  },\n\n  /* Run your local dev server before starting the tests */\n  webServer: {\n    command: process.env.CI ? 'pnpm preview --port 5555' : 'pnpm dev',\n    port: 5555,\n    reuseExistingServer: !process.env.CI,\n  },\n\n  /* Opt out of parallel tests on CI. */\n  workers: process.env.CI ? 1 : undefined,\n};\n\nexport default config;\n"
  },
  {
    "path": "hiauth-front/playground/postcss.config.mjs",
    "content": "export { default } from '@vben/tailwind-config/postcss';\n"
  },
  {
    "path": "hiauth-front/playground/src/adapter/component/index.ts",
    "content": "/**\n * 通用组件共同的使用的基础组件，原先放在 adapter/form 内部，限制了使用范围，这里提取出来，方便其他地方使用\n * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,\n */\n\nimport type { Component } from 'vue';\n\nimport type { BaseFormComponentType } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { defineAsyncComponent, defineComponent, h, ref } from 'vue';\n\nimport { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { notification } from 'ant-design-vue';\n\nconst AutoComplete = defineAsyncComponent(\n  () => import('ant-design-vue/es/auto-complete'),\n);\nconst Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));\nconst Checkbox = defineAsyncComponent(\n  () => import('ant-design-vue/es/checkbox'),\n);\nconst CheckboxGroup = defineAsyncComponent(() =>\n  import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),\n);\nconst DatePicker = defineAsyncComponent(\n  () => import('ant-design-vue/es/date-picker'),\n);\nconst Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));\nconst Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));\nconst InputNumber = defineAsyncComponent(\n  () => import('ant-design-vue/es/input-number'),\n);\nconst InputPassword = defineAsyncComponent(() =>\n  import('ant-design-vue/es/input').then((res) => res.InputPassword),\n);\nconst Mentions = defineAsyncComponent(\n  () => import('ant-design-vue/es/mentions'),\n);\nconst Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));\nconst RadioGroup = defineAsyncComponent(() =>\n  import('ant-design-vue/es/radio').then((res) => res.RadioGroup),\n);\nconst RangePicker = defineAsyncComponent(() =>\n  import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),\n);\nconst Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));\nconst Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));\nconst Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));\nconst Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));\nconst Textarea = defineAsyncComponent(() =>\n  import('ant-design-vue/es/input').then((res) => res.Textarea),\n);\nconst TimePicker = defineAsyncComponent(\n  () => import('ant-design-vue/es/time-picker'),\n);\nconst TreeSelect = defineAsyncComponent(\n  () => import('ant-design-vue/es/tree-select'),\n);\nconst Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));\n\nconst withDefaultPlaceholder = <T extends Component>(\n  component: T,\n  type: 'input' | 'select',\n  componentProps: Recordable<any> = {},\n) => {\n  return defineComponent({\n    name: component.name,\n    inheritAttrs: false,\n    setup: (props: any, { attrs, expose, slots }) => {\n      const placeholder =\n        props?.placeholder ||\n        attrs?.placeholder ||\n        $t(`ui.placeholder.${type}`);\n      // 透传组件暴露的方法\n      const innerRef = ref();\n      // const publicApi: Recordable<any> = {};\n      expose(\n        new Proxy(\n          {},\n          {\n            get: (_target, key) => innerRef.value?.[key],\n            has: (_target, key) => key in (innerRef.value || {}),\n          },\n        ),\n      );\n      // const instance = getCurrentInstance();\n      // instance?.proxy?.$nextTick(() => {\n      //   for (const key in innerRef.value) {\n      //     if (typeof innerRef.value[key] === 'function') {\n      //       publicApi[key] = innerRef.value[key];\n      //     }\n      //   }\n      // });\n      return () =>\n        h(\n          component,\n          { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },\n          slots,\n        );\n    },\n  });\n};\n\n// 这里需要自行根据业务组件库进行适配，需要用到的组件都需要在这里类型说明\nexport type ComponentType =\n  | 'ApiSelect'\n  | 'ApiTreeSelect'\n  | 'AutoComplete'\n  | 'Checkbox'\n  | 'CheckboxGroup'\n  | 'DatePicker'\n  | 'DefaultButton'\n  | 'Divider'\n  | 'IconPicker'\n  | 'Input'\n  | 'InputNumber'\n  | 'InputPassword'\n  | 'Mentions'\n  | 'PrimaryButton'\n  | 'Radio'\n  | 'RadioGroup'\n  | 'RangePicker'\n  | 'Rate'\n  | 'Select'\n  | 'Space'\n  | 'Switch'\n  | 'Textarea'\n  | 'TimePicker'\n  | 'TreeSelect'\n  | 'Upload'\n  | BaseFormComponentType;\n\nasync function initComponentAdapter() {\n  const components: Partial<Record<ComponentType, Component>> = {\n    // 如果你的组件体积比较大，可以使用异步加载\n    // Button: () =>\n    // import('xxx').then((res) => res.Button),\n\n    ApiSelect: withDefaultPlaceholder(ApiComponent, 'select', {\n      component: Select,\n      loadingSlot: 'suffixIcon',\n      modelPropName: 'value',\n      visibleEvent: 'onVisibleChange',\n    }),\n    ApiTreeSelect: withDefaultPlaceholder(ApiComponent, 'select', {\n      component: TreeSelect,\n      fieldNames: { label: 'label', value: 'value', children: 'children' },\n      loadingSlot: 'suffixIcon',\n      modelPropName: 'value',\n      optionsPropName: 'treeData',\n      visibleEvent: 'onVisibleChange',\n    }),\n    AutoComplete,\n    Checkbox,\n    CheckboxGroup,\n    DatePicker,\n    // 自定义默认按钮\n    DefaultButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'default' }, slots);\n    },\n    Divider,\n    IconPicker: withDefaultPlaceholder(IconPicker, 'select', {\n      iconSlot: 'addonAfter',\n      inputComponent: Input,\n      modelValueProp: 'value',\n    }),\n    Input: withDefaultPlaceholder(Input, 'input'),\n    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),\n    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),\n    Mentions: withDefaultPlaceholder(Mentions, 'input'),\n    // 自定义主要按钮\n    PrimaryButton: (props, { attrs, slots }) => {\n      return h(Button, { ...props, attrs, type: 'primary' }, slots);\n    },\n    Radio,\n    RadioGroup,\n    RangePicker,\n    Rate,\n    Select: withDefaultPlaceholder(Select, 'select'),\n    Space,\n    Switch,\n    Textarea: withDefaultPlaceholder(Textarea, 'input'),\n    TimePicker,\n    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),\n    Upload,\n  };\n\n  // 将组件注册到全局共享状态中\n  globalShareState.setComponents(components);\n\n  // 定义全局共享状态中的消息提示\n  globalShareState.defineMessage({\n    // 复制成功消息提示\n    copyPreferencesSuccess: (title, content) => {\n      notification.success({\n        description: content,\n        message: title,\n        placement: 'bottomRight',\n      });\n    },\n  });\n}\n\nexport { initComponentAdapter };\n"
  },
  {
    "path": "hiauth-front/playground/src/adapter/form.ts",
    "content": "import type {\n  VbenFormSchema as FormSchema,\n  VbenFormProps,\n} from '@vben/common-ui';\n\nimport type { ComponentType } from './component';\n\nimport { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nasync function initSetupVbenForm() {\n  setupVbenForm<ComponentType>({\n    config: {\n      // ant design vue组件库默认都是 v-model:value\n      baseModelPropName: 'value',\n      // 一些组件是 v-model:checked 或者 v-model:fileList\n      modelPropNameMap: {\n        Checkbox: 'checked',\n        Radio: 'checked',\n        Switch: 'checked',\n        Upload: 'fileList',\n      },\n    },\n    defineRules: {\n      // 输入项目必填国际化适配\n      required: (value, _params, ctx) => {\n        if (value === undefined || value === null || value.length === 0) {\n          return $t('ui.formRules.required', [ctx.label]);\n        }\n        return true;\n      },\n      // 选择项目必填国际化适配\n      selectRequired: (value, _params, ctx) => {\n        if (value === undefined || value === null) {\n          return $t('ui.formRules.selectRequired', [ctx.label]);\n        }\n        return true;\n      },\n    },\n  });\n}\n\nconst useVbenForm = useForm<ComponentType>;\n\nexport { initSetupVbenForm, useVbenForm, z };\nexport type VbenFormSchema = FormSchema<ComponentType>;\nexport type { VbenFormProps };\n"
  },
  {
    "path": "hiauth-front/playground/src/adapter/vxe-table.ts",
    "content": "import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';\nimport type { Recordable } from '@vben/types';\n\nimport type { ComponentType } from './component';\n\nimport { h } from 'vue';\n\nimport { IconifyIcon } from '@vben/icons';\nimport { $te } from '@vben/locales';\nimport {\n  setupVbenVxeTable,\n  useVbenVxeGrid as useGrid,\n} from '@vben/plugins/vxe-table';\nimport { get, isFunction, isString } from '@vben/utils';\n\nimport { objectOmit } from '@vueuse/core';\nimport { Button, Image, Popconfirm, Switch, Tag } from 'ant-design-vue';\n\nimport { $t } from '#/locales';\n\nimport { useVbenForm } from './form';\n\nsetupVbenVxeTable({\n  configVxeTable: (vxeUI) => {\n    vxeUI.setConfig({\n      grid: {\n        align: 'center',\n        border: false,\n        columnConfig: {\n          resizable: true,\n        },\n\n        formConfig: {\n          // 全局禁用vxe-table的表单配置，使用formOptions\n          enabled: false,\n        },\n        minHeight: 180,\n        proxyConfig: {\n          autoLoad: true,\n          response: {\n            result: 'items',\n            total: 'total',\n            list: '',\n          },\n          showActiveMsg: true,\n          showResponseMsg: false,\n        },\n        round: true,\n        showOverflow: true,\n        size: 'small',\n      } as VxeTableGridOptions,\n    });\n\n    /**\n     * 解决vxeTable在热更新时可能会出错的问题\n     */\n    vxeUI.renderer.forEach((_item, key) => {\n      if (key.startsWith('Cell')) {\n        vxeUI.renderer.delete(key);\n      }\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellImage' },\n    vxeUI.renderer.add('CellImage', {\n      renderTableDefault(_renderOpts, params) {\n        const { column, row } = params;\n        return h(Image, { src: row[column.field] });\n      },\n    });\n\n    // 表格配置项可以用 cellRender: { name: 'CellLink' },\n    vxeUI.renderer.add('CellLink', {\n      renderTableDefault(renderOpts) {\n        const { props } = renderOpts;\n        return h(\n          Button,\n          { size: 'small', type: 'link' },\n          { default: () => props?.text },\n        );\n      },\n    });\n\n    // 单元格渲染： Tag\n    vxeUI.renderer.add('CellTag', {\n      renderTableDefault({ options, props }, { column, row }) {\n        const value = get(row, column.field);\n        const tagOptions = options ?? [\n          { color: 'success', label: $t('common.enabled'), value: 1 },\n          { color: 'error', label: $t('common.disabled'), value: 0 },\n        ];\n        const tagItem = tagOptions.find((item) => item.value === value);\n        return h(\n          Tag,\n          {\n            ...props,\n            ...objectOmit(tagItem ?? {}, ['label']),\n          },\n          { default: () => tagItem?.label ?? value },\n        );\n      },\n    });\n\n    vxeUI.renderer.add('CellSwitch', {\n      renderTableDefault({ attrs, props }, { column, row }) {\n        const loadingKey = `__loading_${column.field}`;\n        const finallyProps = {\n          checkedChildren: $t('common.enabled'),\n          checkedValue: 1,\n          unCheckedChildren: $t('common.disabled'),\n          unCheckedValue: 0,\n          ...props,\n          checked: row[column.field],\n          loading: row[loadingKey] ?? false,\n          'onUpdate:checked': onChange,\n        };\n        async function onChange(newVal: any) {\n          row[loadingKey] = true;\n          try {\n            const result = await attrs?.beforeChange?.(newVal, row);\n            if (result !== false) {\n              row[column.field] = newVal;\n            }\n          } finally {\n            row[loadingKey] = false;\n          }\n        }\n        return h(Switch, finallyProps);\n      },\n    });\n\n    /**\n     * 注册表格的操作按钮渲染器\n     */\n    vxeUI.renderer.add('CellOperation', {\n      renderTableDefault({ attrs, options, props }, { column, row }) {\n        const defaultProps = { size: 'small', type: 'link', ...props };\n        let align = 'end';\n        switch (column.align) {\n          case 'center': {\n            align = 'center';\n            break;\n          }\n          case 'left': {\n            align = 'start';\n            break;\n          }\n          default: {\n            align = 'end';\n            break;\n          }\n        }\n        const presets: Recordable<Recordable<any>> = {\n          delete: {\n            danger: true,\n            text: $t('common.delete'),\n          },\n          edit: {\n            text: $t('common.edit'),\n          },\n        };\n        const operations: Array<Recordable<any>> = (\n          options || ['edit', 'delete']\n        )\n          .map((opt) => {\n            if (isString(opt)) {\n              return presets[opt]\n                ? { code: opt, ...presets[opt], ...defaultProps }\n                : {\n                    code: opt,\n                    text: $te(`common.${opt}`) ? $t(`common.${opt}`) : opt,\n                    ...defaultProps,\n                  };\n            } else {\n              return { ...defaultProps, ...presets[opt.code], ...opt };\n            }\n          })\n          .map((opt) => {\n            const optBtn: Recordable<any> = {};\n            Object.keys(opt).forEach((key) => {\n              optBtn[key] = isFunction(opt[key]) ? opt[key](row) : opt[key];\n            });\n            return optBtn;\n          })\n          .filter((opt) => opt.show !== false);\n\n        function renderBtn(opt: Recordable<any>, listen = true) {\n          return h(\n            Button,\n            {\n              ...props,\n              ...opt,\n              icon: undefined,\n              onClick: listen\n                ? () =>\n                    attrs?.onClick?.({\n                      code: opt.code,\n                      row,\n                    })\n                : undefined,\n            },\n            {\n              default: () => {\n                const content = [];\n                if (opt.icon) {\n                  content.push(\n                    h(IconifyIcon, { class: 'size-5', icon: opt.icon }),\n                  );\n                }\n                content.push(opt.text);\n                return content;\n              },\n            },\n          );\n        }\n\n        function renderConfirm(opt: Recordable<any>) {\n          let viewportWrapper: HTMLElement | null = null;\n          return h(\n            Popconfirm,\n            {\n              /**\n               * 当popconfirm用在固定列中时，将固定列作为弹窗的容器时可能会因为固定列较窄而无法容纳弹窗\n               * 将表格主体区域作为弹窗容器时又会因为固定列的层级较高而遮挡弹窗\n               * 将body或者表格视口区域作为弹窗容器时又会导致弹窗无法跟随表格滚动。\n               * 鉴于以上各种情况，一种折中的解决方案是弹出层展示时，禁止操作表格的滚动条。\n               * 这样既解决了弹窗的遮挡问题，又不至于让弹窗随着表格的滚动而跑出视口区域。\n               */\n              getPopupContainer(el) {\n                viewportWrapper = el.closest('.vxe-table--viewport-wrapper');\n                return document.body;\n              },\n              placement: 'topLeft',\n              title: $t('ui.actionTitle.delete', [attrs?.nameTitle || '']),\n              ...props,\n              ...opt,\n              icon: undefined,\n              onOpenChange: (open: boolean) => {\n                // 当弹窗打开时，禁止表格的滚动\n                if (open) {\n                  viewportWrapper?.style.setProperty('pointer-events', 'none');\n                } else {\n                  viewportWrapper?.style.removeProperty('pointer-events');\n                }\n              },\n              onConfirm: () => {\n                attrs?.onClick?.({\n                  code: opt.code,\n                  row,\n                });\n              },\n            },\n            {\n              default: () => renderBtn({ ...opt }, false),\n              description: () =>\n                h(\n                  'div',\n                  { class: 'truncate' },\n                  $t('ui.actionMessage.deleteConfirm', [\n                    row[attrs?.nameField || 'name'],\n                  ]),\n                ),\n            },\n          );\n        }\n\n        const btns = operations.map((opt) =>\n          opt.code === 'delete' ? renderConfirm(opt) : renderBtn(opt),\n        );\n        return h(\n          'div',\n          {\n            class: 'flex table-operations',\n            style: { justifyContent: align },\n          },\n          btns,\n        );\n      },\n    });\n\n    // 这里可以自行扩展 vxe-table 的全局配置，比如自定义格式化\n    // vxeUI.formats.add\n  },\n  useVbenForm,\n});\n\nexport const useVbenVxeGrid = <T extends Record<string, any>>(\n  ...rest: Parameters<typeof useGrid<T, ComponentType>>\n) => useGrid<T, ComponentType>(...rest);\n\nexport type OnActionClickParams<T = Recordable<any>> = {\n  code: string;\n  row: T;\n};\nexport type OnActionClickFn<T = Recordable<any>> = (\n  params: OnActionClickParams<T>,\n) => void;\nexport type * from '@vben/plugins/vxe-table';\n"
  },
  {
    "path": "hiauth-front/playground/src/api/core/auth.ts",
    "content": "import { baseRequestClient, requestClient } from '#/api/request';\n\nexport namespace AuthApi {\n  /** 登录接口参数 */\n  export interface LoginParams {\n    password?: string;\n    username?: string;\n  }\n\n  /** 登录接口返回值 */\n  export interface LoginResult {\n    accessToken: string;\n  }\n\n  export interface RefreshTokenResult {\n    data: string;\n    status: number;\n  }\n}\n\n/**\n * 登录\n */\nexport async function loginApi(data: AuthApi.LoginParams) {\n  return requestClient.post<AuthApi.LoginResult>('/auth/login', data, {\n    withCredentials: true,\n  });\n}\n\n/**\n * 刷新accessToken\n */\nexport async function refreshTokenApi() {\n  return baseRequestClient.post<AuthApi.RefreshTokenResult>(\n    '/auth/refresh',\n    null,\n    {\n      withCredentials: true,\n    },\n  );\n}\n\n/**\n * 退出登录\n */\nexport async function logoutApi() {\n  return baseRequestClient.post('/auth/logout', null, {\n    withCredentials: true,\n  });\n}\n\n/**\n * 获取用户权限码\n */\nexport async function getAccessCodesApi() {\n  return requestClient.get<string[]>('/auth/codes');\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/api/core/index.ts",
    "content": "export * from './auth';\nexport * from './menu';\nexport * from './user';\n"
  },
  {
    "path": "hiauth-front/playground/src/api/core/menu.ts",
    "content": "import type { RouteRecordStringComponent } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户所有菜单\n */\nexport async function getAllMenusApi() {\n  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/api/core/user.ts",
    "content": "import type { UserInfo } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 获取用户信息\n */\nexport async function getUserInfoApi() {\n  return requestClient.get<UserInfo>('/user/info');\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/api/examples/download.ts",
    "content": "import type { RequestResponse } from '@vben/request';\n\nimport { requestClient } from '../request';\n\n/**\n * 下载文件，获取Blob\n * @returns Blob\n */\nasync function downloadFile1() {\n  return requestClient.download<Blob>(\n    'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n  );\n}\n\n/**\n * 下载文件，获取完整的Response\n * @returns RequestResponse<Blob>\n */\nasync function downloadFile2() {\n  return requestClient.download<RequestResponse<Blob>>(\n    'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n    {\n      responseReturn: 'raw',\n    },\n  );\n}\n\nexport { downloadFile1, downloadFile2 };\n"
  },
  {
    "path": "hiauth-front/playground/src/api/examples/index.ts",
    "content": "export * from './status';\nexport * from './table';\n"
  },
  {
    "path": "hiauth-front/playground/src/api/examples/json-bigint.ts",
    "content": "import { requestClient } from '#/api/request';\n\n/**\n * 发起请求\n */\nasync function getBigIntData() {\n  return requestClient.get('/demo/bigint');\n}\n\nexport { getBigIntData };\n"
  },
  {
    "path": "hiauth-front/playground/src/api/examples/params.ts",
    "content": "import type { Recordable } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\n/**\n * 发起数组请求\n */\nasync function getParamsData(\n  params: Recordable<any>,\n  type: 'brackets' | 'comma' | 'indices' | 'repeat',\n) {\n  return requestClient.get('/status', {\n    params,\n    paramsSerializer: type,\n    responseReturn: 'raw',\n  });\n}\n\nexport { getParamsData };\n"
  },
  {
    "path": "hiauth-front/playground/src/api/examples/status.ts",
    "content": "import { requestClient } from '#/api/request';\n\n/**\n * 模拟任意状态码\n */\nasync function getMockStatusApi(status: string) {\n  return requestClient.get('/status', { params: { status } });\n}\n\nexport { getMockStatusApi };\n"
  },
  {
    "path": "hiauth-front/playground/src/api/examples/table.ts",
    "content": "import { requestClient } from '#/api/request';\n\nexport namespace DemoTableApi {\n  export interface PageFetchParams {\n    [key: string]: any;\n    page: number;\n    pageSize: number;\n  }\n}\n\n/**\n * 获取示例表格数据\n */\nasync function getExampleTableApi(params: DemoTableApi.PageFetchParams) {\n  return requestClient.get('/table/list', { params });\n}\n\nexport { getExampleTableApi };\n"
  },
  {
    "path": "hiauth-front/playground/src/api/examples/upload.ts",
    "content": "import { requestClient } from '#/api/request';\n\ninterface UploadFileParams {\n  file: File;\n  onError?: (error: Error) => void;\n  onProgress?: (progress: { percent: number }) => void;\n  onSuccess?: (data: any, file: File) => void;\n}\nexport async function upload_file({\n  file,\n  onError,\n  onProgress,\n  onSuccess,\n}: UploadFileParams) {\n  try {\n    onProgress?.({ percent: 0 });\n\n    const data = await requestClient.upload('/upload', { file });\n\n    onProgress?.({ percent: 100 });\n    onSuccess?.(data, file);\n  } catch (error) {\n    onError?.(error instanceof Error ? error : new Error(String(error)));\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/api/index.ts",
    "content": "export * from './core';\nexport * from './examples';\nexport * from './system';\n"
  },
  {
    "path": "hiauth-front/playground/src/api/request.ts",
    "content": "/**\n * 该文件可自行根据业务逻辑进行调整\n */\nimport type { AxiosResponseHeaders, RequestClientOptions } from '@vben/request';\n\nimport { useAppConfig } from '@vben/hooks';\nimport { preferences } from '@vben/preferences';\nimport {\n  authenticateResponseInterceptor,\n  defaultResponseInterceptor,\n  errorMessageResponseInterceptor,\n  RequestClient,\n} from '@vben/request';\nimport { useAccessStore } from '@vben/stores';\nimport { cloneDeep } from '@vben/utils';\n\nimport { message } from 'ant-design-vue';\nimport JSONBigInt from 'json-bigint';\n\nimport { useAuthStore } from '#/store';\n\nimport { refreshTokenApi } from './core';\n\nconst { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);\n\nfunction createRequestClient(baseURL: string, options?: RequestClientOptions) {\n  const client = new RequestClient({\n    ...options,\n    baseURL,\n    transformResponse: (data: any, header: AxiosResponseHeaders) => {\n      // storeAsString指示将BigInt存储为字符串，设为false则会存储为内置的BigInt类型\n      return header.getContentType()?.toString().includes('application/json')\n        ? cloneDeep(\n            JSONBigInt({ storeAsString: true, strict: true }).parse(data),\n          )\n        : data;\n    },\n  });\n\n  /**\n   * 重新认证逻辑\n   */\n  async function doReAuthenticate() {\n    console.warn('Access token or refresh token is invalid or expired. ');\n    const accessStore = useAccessStore();\n    const authStore = useAuthStore();\n    accessStore.setAccessToken(null);\n    if (\n      preferences.app.loginExpiredMode === 'modal' &&\n      accessStore.isAccessChecked\n    ) {\n      accessStore.setLoginExpired(true);\n    } else {\n      await authStore.logout();\n    }\n  }\n\n  /**\n   * 刷新token逻辑\n   */\n  async function doRefreshToken() {\n    const accessStore = useAccessStore();\n    const resp = await refreshTokenApi();\n    const newToken = resp.data;\n    accessStore.setAccessToken(newToken);\n    return newToken;\n  }\n\n  function formatToken(token: null | string) {\n    return token ? `Bearer ${token}` : null;\n  }\n\n  // 请求头处理\n  client.addRequestInterceptor({\n    fulfilled: async (config) => {\n      const accessStore = useAccessStore();\n\n      config.headers.Authorization = formatToken(accessStore.accessToken);\n      config.headers['Accept-Language'] = preferences.app.locale;\n      return config;\n    },\n  });\n\n  // 处理返回的响应数据格式\n  client.addResponseInterceptor(\n    defaultResponseInterceptor({\n      codeField: 'code',\n      dataField: 'data',\n      successCode: 0,\n    }),\n  );\n\n  // token过期的处理\n  client.addResponseInterceptor(\n    authenticateResponseInterceptor({\n      client,\n      doReAuthenticate,\n      doRefreshToken,\n      enableRefreshToken: preferences.app.enableRefreshToken,\n      formatToken,\n    }),\n  );\n\n  // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里\n  client.addResponseInterceptor(\n    errorMessageResponseInterceptor((msg: string, error) => {\n      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg\n      // 当前mock接口返回的错误字段是 error 或者 message\n      const responseData = error?.response?.data ?? {};\n      const errorMessage = responseData?.error ?? responseData?.message ?? '';\n      // 如果没有错误信息，则会根据状态码进行提示\n      message.error(errorMessage || msg);\n    }),\n  );\n\n  return client;\n}\n\nexport const requestClient = createRequestClient(apiURL, {\n  responseReturn: 'data',\n});\n\nexport const baseRequestClient = new RequestClient({ baseURL: apiURL });\n\nexport interface PageFetchParams {\n  [key: string]: any;\n  pageNo?: number;\n  pageSize?: number;\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/api/system/dept.ts",
    "content": "import { requestClient } from '#/api/request';\n\nexport namespace SystemDeptApi {\n  export interface SystemDept {\n    [key: string]: any;\n    children?: SystemDept[];\n    id: string;\n    name: string;\n    remark?: string;\n    status: 0 | 1;\n  }\n}\n\n/**\n * 获取部门列表数据\n */\nasync function getDeptList() {\n  return requestClient.get<Array<SystemDeptApi.SystemDept>>(\n    '/system/dept/list',\n  );\n}\n\n/**\n * 创建部门\n * @param data 部门数据\n */\nasync function createDept(\n  data: Omit<SystemDeptApi.SystemDept, 'children' | 'id'>,\n) {\n  return requestClient.post('/system/dept', data);\n}\n\n/**\n * 更新部门\n *\n * @param id 部门 ID\n * @param data 部门数据\n */\nasync function updateDept(\n  id: string,\n  data: Omit<SystemDeptApi.SystemDept, 'children' | 'id'>,\n) {\n  return requestClient.put(`/system/dept/${id}`, data);\n}\n\n/**\n * 删除部门\n * @param id 部门 ID\n */\nasync function deleteDept(id: string) {\n  return requestClient.delete(`/system/dept/${id}`);\n}\n\nexport { createDept, deleteDept, getDeptList, updateDept };\n"
  },
  {
    "path": "hiauth-front/playground/src/api/system/index.ts",
    "content": "export * from './dept';\nexport * from './menu';\nexport * from './role';\n"
  },
  {
    "path": "hiauth-front/playground/src/api/system/menu.ts",
    "content": "import type { Recordable } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\nexport namespace SystemMenuApi {\n  /** 徽标颜色集合 */\n  export const BadgeVariants = [\n    'default',\n    'destructive',\n    'primary',\n    'success',\n    'warning',\n  ] as const;\n  /** 徽标类型集合 */\n  export const BadgeTypes = ['dot', 'normal'] as const;\n  /** 菜单类型集合 */\n  export const MenuTypes = [\n    'catalog',\n    'menu',\n    'embedded',\n    'link',\n    'button',\n  ] as const;\n  /** 系统菜单 */\n  export interface SystemMenu {\n    [key: string]: any;\n    /** 后端权限标识 */\n    authCode: string;\n    /** 子级 */\n    children?: SystemMenu[];\n    /** 组件 */\n    component?: string;\n    /** 菜单ID */\n    id: string;\n    /** 菜单元数据 */\n    meta?: {\n      /** 激活时显示的图标 */\n      activeIcon?: string;\n      /** 作为路由时，需要激活的菜单的Path */\n      activePath?: string;\n      /** 固定在标签栏 */\n      affixTab?: boolean;\n      /** 在标签栏固定的顺序 */\n      affixTabOrder?: number;\n      /** 徽标内容(当徽标类型为normal时有效) */\n      badge?: string;\n      /** 徽标类型 */\n      badgeType?: (typeof BadgeTypes)[number];\n      /** 徽标颜色 */\n      badgeVariants?: (typeof BadgeVariants)[number];\n      /** 在菜单中隐藏下级 */\n      hideChildrenInMenu?: boolean;\n      /** 在面包屑中隐藏 */\n      hideInBreadcrumb?: boolean;\n      /** 在菜单中隐藏 */\n      hideInMenu?: boolean;\n      /** 在标签栏中隐藏 */\n      hideInTab?: boolean;\n      /** 菜单图标 */\n      icon?: string;\n      /** 内嵌Iframe的URL */\n      iframeSrc?: string;\n      /** 是否缓存页面 */\n      keepAlive?: boolean;\n      /** 外链页面的URL */\n      link?: string;\n      /** 同一个路由最大打开的标签数 */\n      maxNumOfOpenTab?: number;\n      /** 无需基础布局 */\n      noBasicLayout?: boolean;\n      /** 是否在新窗口打开 */\n      openInNewWindow?: boolean;\n      /** 菜单排序 */\n      order?: number;\n      /** 额外的路由参数 */\n      query?: Recordable<any>;\n      /** 菜单标题 */\n      title?: string;\n    };\n    /** 菜单名称 */\n    name: string;\n    /** 路由路径 */\n    path: string;\n    /** 父级ID */\n    pid: string;\n    /** 重定向 */\n    redirect?: string;\n    /** 菜单类型 */\n    type: (typeof MenuTypes)[number];\n  }\n}\n\n/**\n * 获取菜单数据列表\n */\nasync function getMenuList() {\n  return requestClient.get<Array<SystemMenuApi.SystemMenu>>(\n    '/system/menu/list',\n  );\n}\n\nasync function isMenuNameExists(\n  name: string,\n  id?: SystemMenuApi.SystemMenu['id'],\n) {\n  return requestClient.get<boolean>('/system/menu/name-exists', {\n    params: { id, name },\n  });\n}\n\nasync function isMenuPathExists(\n  path: string,\n  id?: SystemMenuApi.SystemMenu['id'],\n) {\n  return requestClient.get<boolean>('/system/menu/path-exists', {\n    params: { id, path },\n  });\n}\n\n/**\n * 创建菜单\n * @param data 菜单数据\n */\nasync function createMenu(\n  data: Omit<SystemMenuApi.SystemMenu, 'children' | 'id'>,\n) {\n  return requestClient.post('/system/menu', data);\n}\n\n/**\n * 更新菜单\n *\n * @param id 菜单 ID\n * @param data 菜单数据\n */\nasync function updateMenu(\n  id: string,\n  data: Omit<SystemMenuApi.SystemMenu, 'children' | 'id'>,\n) {\n  return requestClient.put(`/system/menu/${id}`, data);\n}\n\n/**\n * 删除菜单\n * @param id 菜单 ID\n */\nasync function deleteMenu(id: string) {\n  return requestClient.delete(`/system/menu/${id}`);\n}\n\nexport {\n  createMenu,\n  deleteMenu,\n  getMenuList,\n  isMenuNameExists,\n  isMenuPathExists,\n  updateMenu,\n};\n"
  },
  {
    "path": "hiauth-front/playground/src/api/system/role.ts",
    "content": "import type { Recordable } from '@vben/types';\n\nimport { requestClient } from '#/api/request';\n\nexport namespace SystemRoleApi {\n  export interface SystemRole {\n    [key: string]: any;\n    id: string;\n    name: string;\n    permissions: string[];\n    remark?: string;\n    status: 0 | 1;\n  }\n}\n\n/**\n * 获取角色列表数据\n */\nasync function getRoleList(params: Recordable<any>) {\n  return requestClient.get<Array<SystemRoleApi.SystemRole>>(\n    '/system/role/list',\n    { params },\n  );\n}\n\n/**\n * 创建角色\n * @param data 角色数据\n */\nasync function createRole(data: Omit<SystemRoleApi.SystemRole, 'id'>) {\n  return requestClient.post('/system/role', data);\n}\n\n/**\n * 更新角色\n *\n * @param id 角色 ID\n * @param data 角色数据\n */\nasync function updateRole(\n  id: string,\n  data: Omit<SystemRoleApi.SystemRole, 'id'>,\n) {\n  return requestClient.put(`/system/role/${id}`, data);\n}\n\n/**\n * 删除角色\n * @param id 角色 ID\n */\nasync function deleteRole(id: string) {\n  return requestClient.delete(`/system/role/${id}`);\n}\n\nexport { createRole, deleteRole, getRoleList, updateRole };\n"
  },
  {
    "path": "hiauth-front/playground/src/app.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { useAntdDesignTokens } from '@vben/hooks';\nimport { preferences, usePreferences } from '@vben/preferences';\n\nimport { App, ConfigProvider, theme } from 'ant-design-vue';\n\nimport { antdLocale } from '#/locales';\n\ndefineOptions({ name: 'App' });\n\nconst { isDark } = usePreferences();\nconst { tokens } = useAntdDesignTokens();\n\nconst tokenTheme = computed(() => {\n  const algorithm = isDark.value\n    ? [theme.darkAlgorithm]\n    : [theme.defaultAlgorithm];\n\n  // antd 紧凑模式算法\n  if (preferences.app.compact) {\n    algorithm.push(theme.compactAlgorithm);\n  }\n\n  return {\n    algorithm,\n    token: tokens,\n  };\n});\n</script>\n\n<template>\n  <ConfigProvider :locale=\"antdLocale\" :theme=\"tokenTheme\">\n    <App>\n      <RouterView />\n    </App>\n  </ConfigProvider>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/bootstrap.ts",
    "content": "import { createApp, watchEffect } from 'vue';\n\nimport { registerAccessDirective } from '@vben/access';\nimport { registerLoadingDirective } from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { initStores } from '@vben/stores';\nimport '@vben/styles';\nimport '@vben/styles/antd';\n\nimport { useTitle } from '@vueuse/core';\n\nimport { $t, setupI18n } from '#/locales';\nimport { router } from '#/router';\n\nimport { initComponentAdapter } from './adapter/component';\nimport { initSetupVbenForm } from './adapter/form';\nimport App from './app.vue';\n\nasync function bootstrap(namespace: string) {\n  // 初始化组件适配器\n  await initComponentAdapter();\n\n  // 初始化表单组件\n  await initSetupVbenForm();\n\n  // 设置弹窗的默认配置\n  // setDefaultModalProps({\n  //   fullscreenButton: false,\n  // });\n  // 设置抽屉的默认配置\n  // setDefaultDrawerProps({\n  //   zIndex: 1020,\n  // });\n\n  const app = createApp(App);\n\n  // 注册v-loading指令\n  registerLoadingDirective(app, {\n    loading: 'loading', // 在这里可以自定义指令名称，也可以明确提供false表示不注册这个指令\n    spinning: 'spinning',\n  });\n\n  // 国际化 i18n 配置\n  await setupI18n(app);\n\n  // 配置 pinia-tore\n  await initStores(app, { namespace });\n\n  // 安装权限指令\n  registerAccessDirective(app);\n\n  // 初始化 tippy\n  const { initTippy } = await import('@vben/common-ui/es/tippy');\n  initTippy(app);\n\n  // 配置路由及路由守卫\n  app.use(router);\n\n  // 配置@tanstack/vue-query\n  const { VueQueryPlugin } = await import('@tanstack/vue-query');\n  app.use(VueQueryPlugin);\n\n  // 配置Motion插件\n  const { MotionPlugin } = await import('@vben/plugins/motion');\n  app.use(MotionPlugin);\n\n  // 动态更新标题\n  watchEffect(() => {\n    if (preferences.app.dynamicTitle) {\n      const routeTitle = router.currentRoute.value.meta?.title;\n      const pageTitle =\n        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;\n      useTitle(pageTitle);\n    }\n  });\n\n  app.mount('#app');\n}\n\nexport { bootstrap };\n"
  },
  {
    "path": "hiauth-front/playground/src/layouts/auth.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport { AuthPageLayout } from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst appName = computed(() => preferences.app.name);\nconst logo = computed(() => preferences.logo.source);\nconst clickLogo = () => {};\n</script>\n\n<template>\n  <AuthPageLayout\n    :app-name=\"appName\"\n    :logo=\"logo\"\n    :page-description=\"$t('authentication.pageDesc')\"\n    :page-title=\"$t('authentication.pageTitle')\"\n    :click-logo=\"clickLogo\"\n  >\n    <!-- 自定义工具栏 -->\n    <!-- <template #toolbar></template> -->\n  </AuthPageLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/layouts/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { NotificationItem } from '@vben/layouts';\n\nimport { computed, onBeforeMount, ref, watch } from 'vue';\n\nimport { AuthenticationLoginExpiredModal } from '@vben/common-ui';\nimport { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';\nimport { useWatermark } from '@vben/hooks';\nimport { BookOpenText, CircleHelp, SvgGithubIcon } from '@vben/icons';\nimport {\n  BasicLayout,\n  LockScreen,\n  Notification,\n  UserDropdown,\n} from '@vben/layouts';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useTabbarStore, useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport { $t } from '#/locales';\nimport { useAuthStore } from '#/store';\nimport LoginForm from '#/views/_core/authentication/login.vue';\n\nconst { setMenuList } = useTabbarStore();\nsetMenuList([\n  'close',\n  'affix',\n  'maximize',\n  'reload',\n  'open-in-new-window',\n  'close-left',\n  'close-right',\n  'close-other',\n  'close-all',\n]);\n\nconst notifications = ref<NotificationItem[]>([\n  {\n    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',\n    date: '3小时前',\n    isRead: true,\n    message: '描述信息描述信息描述信息',\n    title: '收到了 14 份新周报',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '刚刚',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '朱偏右 回复了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/1',\n    date: '2024-01-01',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '曲丽丽 评论了你',\n  },\n  {\n    avatar: 'https://avatar.vercel.sh/satori',\n    date: '1天前',\n    isRead: false,\n    message: '描述信息描述信息描述信息',\n    title: '代办提醒',\n  },\n]);\n\nconst userStore = useUserStore();\nconst authStore = useAuthStore();\nconst accessStore = useAccessStore();\nconst { destroyWatermark, updateWatermark } = useWatermark();\nconst showDot = computed(() =>\n  notifications.value.some((item) => !item.isRead),\n);\n\nconst menus = computed(() => [\n  {\n    handler: () => {\n      openWindow(VBEN_DOC_URL, {\n        target: '_blank',\n      });\n    },\n    icon: BookOpenText,\n    text: $t('ui.widgets.document'),\n  },\n  {\n    handler: () => {\n      openWindow(VBEN_GITHUB_URL, {\n        target: '_blank',\n      });\n    },\n    icon: SvgGithubIcon,\n    text: 'GitHub',\n  },\n  {\n    handler: () => {\n      openWindow(`${VBEN_GITHUB_URL}/issues`, {\n        target: '_blank',\n      });\n    },\n    icon: CircleHelp,\n    text: $t('ui.widgets.qa'),\n  },\n]);\n\nconst avatar = computed(() => {\n  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;\n});\n\nasync function handleLogout() {\n  await authStore.logout(false);\n}\n\nfunction handleNoticeClear() {\n  notifications.value = [];\n}\n\nfunction handleMakeAll() {\n  notifications.value.forEach((item) => (item.isRead = true));\n}\n\nfunction handleClickLogo() {}\n\nwatch(\n  () => ({\n    enable: preferences.app.watermark,\n    content: preferences.app.watermarkContent,\n  }),\n  async ({ enable, content }) => {\n    if (enable) {\n      await updateWatermark({\n        content:\n          content ||\n          `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,\n      });\n    } else {\n      destroyWatermark();\n    }\n  },\n  {\n    immediate: true,\n  },\n);\n\nonBeforeMount(() => {\n  if (preferences.app.watermark) {\n    destroyWatermark();\n  }\n});\n</script>\n\n<template>\n  <BasicLayout\n    @clear-preferences-and-logout=\"handleLogout\"\n    @click-logo=\"handleClickLogo\"\n  >\n    <template #user-dropdown>\n      <UserDropdown\n        :avatar\n        :menus\n        :text=\"userStore.userInfo?.realName\"\n        description=\"ann.vben@gmail.com\"\n        tag-text=\"Pro\"\n        trigger=\"both\"\n        @logout=\"handleLogout\"\n      />\n    </template>\n    <template #notification>\n      <Notification\n        :dot=\"showDot\"\n        :notifications=\"notifications\"\n        @clear=\"handleNoticeClear\"\n        @make-all=\"handleMakeAll\"\n      />\n    </template>\n    <template #extra>\n      <AuthenticationLoginExpiredModal\n        v-model:open=\"accessStore.loginExpired\"\n        :avatar\n      >\n        <LoginForm />\n      </AuthenticationLoginExpiredModal>\n    </template>\n    <template #lock-screen>\n      <LockScreen :avatar @to-login=\"handleLogout\" />\n    </template>\n  </BasicLayout>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/layouts/index.ts",
    "content": "const BasicLayout = () => import('./basic.vue');\nconst AuthPageLayout = () => import('./auth.vue');\n\nconst IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);\n\nexport { AuthPageLayout, BasicLayout, IFrameView };\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/README.md",
    "content": "# locale\n\n每个app使用的国际化可能不同，这里用于扩展国际化的功能，例如扩展 dayjs、antd组件库的多语言切换，以及app本身的国际化文件。\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/index.ts",
    "content": "import type { Locale } from 'ant-design-vue/es/locale';\n\nimport type { App } from 'vue';\n\nimport type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';\n\nimport { ref } from 'vue';\n\nimport {\n  $t,\n  setupI18n as coreSetup,\n  loadLocalesMapFromDir,\n} from '@vben/locales';\nimport { preferences } from '@vben/preferences';\n\nimport antdEnLocale from 'ant-design-vue/es/locale/en_US';\nimport antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN';\nimport dayjs from 'dayjs';\n\nconst antdLocale = ref<Locale>(antdDefaultLocale);\n\nconst modules = import.meta.glob('./langs/**/*.json');\n\nconst localesMap = loadLocalesMapFromDir(\n  /\\.\\/langs\\/([^/]+)\\/(.*)\\.json$/,\n  modules,\n);\n/**\n * 加载应用特有的语言包\n * 这里也可以改造为从服务端获取翻译数据\n * @param lang\n */\nasync function loadMessages(lang: SupportedLanguagesType) {\n  const [appLocaleMessages] = await Promise.all([\n    localesMap[lang]?.(),\n    loadThirdPartyMessage(lang),\n  ]);\n  return appLocaleMessages?.default;\n}\n\n/**\n * 加载第三方组件库的语言包\n * @param lang\n */\nasync function loadThirdPartyMessage(lang: SupportedLanguagesType) {\n  await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);\n}\n\n/**\n * 加载dayjs的语言包\n * @param lang\n */\nasync function loadDayjsLocale(lang: SupportedLanguagesType) {\n  let locale;\n  switch (lang) {\n    case 'en-US': {\n      locale = await import('dayjs/locale/en');\n      break;\n    }\n    case 'zh-CN': {\n      locale = await import('dayjs/locale/zh-cn');\n      break;\n    }\n    // 默认使用英语\n    default: {\n      locale = await import('dayjs/locale/en');\n    }\n  }\n  if (locale) {\n    dayjs.locale(locale);\n  } else {\n    console.error(`Failed to load dayjs locale for ${lang}`);\n  }\n}\n\n/**\n * 加载antd的语言包\n * @param lang\n */\nasync function loadAntdLocale(lang: SupportedLanguagesType) {\n  switch (lang) {\n    case 'en-US': {\n      antdLocale.value = antdEnLocale;\n      break;\n    }\n    case 'zh-CN': {\n      antdLocale.value = antdDefaultLocale;\n      break;\n    }\n  }\n}\n\nasync function setupI18n(app: App, options: LocaleSetupOptions = {}) {\n  await coreSetup(app, {\n    defaultLocale: preferences.app.locale,\n    loadMessages,\n    missingWarn: !import.meta.env.PROD,\n    ...options,\n  });\n}\n\nexport { $t, antdLocale, setupI18n };\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/langs/en-US/demos.json",
    "content": "{\n  \"title\": \"Demos\",\n  \"access\": {\n    \"frontendPermissions\": \"Frontend Permissions\",\n    \"backendPermissions\": \"Backend Permissions\",\n    \"pageAccess\": \"Page Access\",\n    \"buttonControl\": \"Button Control\",\n    \"menuVisible403\": \"Menu Visible(403)\",\n    \"superVisible\": \"Visible to Super\",\n    \"adminVisible\": \"Visible to Admin\",\n    \"userVisible\": \"Visible to User\"\n  },\n  \"nested\": {\n    \"title\": \"Nested Menu\",\n    \"menu1\": \"Menu 1\",\n    \"menu2\": \"Menu 2\",\n    \"menu2_1\": \"Menu 2-1\",\n    \"menu3\": \"Menu 3\",\n    \"menu3_1\": \"Menu 3-1\",\n    \"menu3_2\": \"Menu 3-2\",\n    \"menu3_2_1\": \"Menu 3-2-1\"\n  },\n  \"outside\": {\n    \"title\": \"External Pages\",\n    \"embedded\": \"Embedded\",\n    \"externalLink\": \"External Link\"\n  },\n  \"badge\": {\n    \"title\": \"Menu Badge\",\n    \"dot\": \"Dot Badge\",\n    \"text\": \"Text Badge\",\n    \"color\": \"Badge Color\"\n  },\n  \"activeIcon\": {\n    \"title\": \"Active Menu Icon\",\n    \"children\": \"Children Active Icon\"\n  },\n  \"fallback\": {\n    \"title\": \"Fallback Page\"\n  },\n  \"features\": {\n    \"title\": \"Features\",\n    \"hideChildrenInMenu\": \"Hide Menu Children\",\n    \"loginExpired\": \"Login Expired\",\n    \"icons\": \"Icons\",\n    \"watermark\": \"Watermark\",\n    \"tabs\": \"Tabs\",\n    \"tabDetail\": \"Tab Detail Page\",\n    \"fullScreen\": \"FullScreen\",\n    \"clipboard\": \"Clipboard\",\n    \"menuWithQuery\": \"Menu With Query\",\n    \"openInNewWindow\": \"Open in New Window\",\n    \"fileDownload\": \"File Download\"\n  },\n  \"breadcrumb\": {\n    \"navigation\": \"Breadcrumb Navigation\",\n    \"lateral\": \"Lateral Mode\",\n    \"lateralDetail\": \"Lateral Mode Detail\",\n    \"level\": \"Level Mode\",\n    \"levelDetail\": \"Level Mode Detail\"\n  },\n  \"vben\": {\n    \"title\": \"Project\",\n    \"about\": \"About\",\n    \"document\": \"Document\",\n    \"antdv\": \"Ant Design Vue Version\",\n    \"naive-ui\": \"Naive UI Version\",\n    \"element-plus\": \"Element Plus Version\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/langs/en-US/examples.json",
    "content": "{\n  \"title\": \"Examples\",\n  \"modal\": {\n    \"title\": \"Modal\"\n  },\n  \"drawer\": {\n    \"title\": \"Drawer\"\n  },\n  \"ellipsis\": {\n    \"title\": \"EllipsisText\"\n  },\n  \"form\": {\n    \"title\": \"Form\",\n    \"basic\": \"Basic Form\",\n    \"layout\": \"Custom Layout\",\n    \"query\": \"Query Form\",\n    \"rules\": \"Form Rules\",\n    \"dynamic\": \"Dynamic Form\",\n    \"custom\": \"Custom Component\",\n    \"api\": \"Api\",\n    \"merge\": \"Merge Form\",\n    \"scrollToError\": \"Scroll to Error Field\",\n    \"upload-error\": \"Partial file upload failed\",\n    \"upload-urls\": \"Urls after file upload\",\n    \"file\": \"file\",\n    \"upload-image\": \"Click to upload image\"\n  },\n  \"vxeTable\": {\n    \"title\": \"Vxe Table\",\n    \"basic\": \"Basic Table\",\n    \"remote\": \"Remote Load\",\n    \"tree\": \"Tree Table\",\n    \"fixed\": \"Fixed Header/Column\",\n    \"virtual\": \"Virtual Scroll\",\n    \"editCell\": \"Edit Cell\",\n    \"editRow\": \"Edit Row\",\n    \"custom-cell\": \"Custom Cell\",\n    \"form\": \"Form Table\"\n  },\n  \"captcha\": {\n    \"title\": \"Captcha\",\n    \"pointSelection\": \"Point Selection Captcha\",\n    \"sliderCaptcha\": \"Slider Captcha\",\n    \"sliderRotateCaptcha\": \"Rotate Captcha\",\n    \"sliderTranslateCaptcha\": \"Translate Captcha\",\n    \"captchaCardTitle\": \"Please complete the security verification\",\n    \"pageDescription\": \"Verify user identity by clicking on specific locations in the image.\",\n    \"pageTitle\": \"Captcha Component Example\",\n    \"basic\": \"Basic Usage\",\n    \"titlePlaceholder\": \"Captcha Title Text\",\n    \"captchaImageUrlPlaceholder\": \"Captcha Image (supports img tag src attribute value)\",\n    \"hintImage\": \"Hint Image\",\n    \"hintText\": \"Hint Text\",\n    \"hintImagePlaceholder\": \"Hint Image (supports img tag src attribute value)\",\n    \"hintTextPlaceholder\": \"Hint Text\",\n    \"showConfirm\": \"Show Confirm\",\n    \"hideConfirm\": \"Hide Confirm\",\n    \"widthPlaceholder\": \"Captcha Image Width Default 300px\",\n    \"heightPlaceholder\": \"Captcha Image Height Default 220px\",\n    \"paddingXPlaceholder\": \"Horizontal Padding Default 12px\",\n    \"paddingYPlaceholder\": \"Vertical Padding Default 16px\",\n    \"index\": \"Index:\",\n    \"timestamp\": \"Timestamp:\",\n    \"x\": \"x:\",\n    \"y\": \"y:\"\n  },\n  \"resize\": {\n    \"title\": \"Resize\"\n  },\n  \"layout\": {\n    \"col-page\": \"ColPage Layout\"\n  },\n  \"button-group\": {\n    \"title\": \"Button Group\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/langs/en-US/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"Login\",\n    \"register\": \"Register\",\n    \"codeLogin\": \"Code Login\",\n    \"qrcodeLogin\": \"Qr Code Login\",\n    \"forgetPassword\": \"Forget Password\",\n    \"sendingCode\": \"SMS Code is sending...\",\n    \"codeSentTo\": \"Code has been sent to {0}\"\n  },\n  \"dashboard\": {\n    \"title\": \"Dashboard\",\n    \"analytics\": \"Analytics\",\n    \"workspace\": \"Workspace\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/langs/en-US/system.json",
    "content": "{\n  \"title\": \"System Management\",\n  \"dept\": {\n    \"name\": \"Department\",\n    \"title\": \"Department Management\",\n    \"deptName\": \"Department Name\",\n    \"status\": \"Status\",\n    \"createTime\": \"Create Time\",\n    \"remark\": \"Remark\",\n    \"operation\": \"Operation\",\n    \"parentDept\": \"Parent Department\"\n  },\n  \"menu\": {\n    \"title\": \"Menu Management\",\n    \"parent\": \"Parent Menu\",\n    \"menuTitle\": \"Title\",\n    \"menuName\": \"Menu Name\",\n    \"name\": \"Menu\",\n    \"type\": \"Type\",\n    \"typeCatalog\": \"Catalog\",\n    \"typeMenu\": \"Menu\",\n    \"typeButton\": \"Button\",\n    \"typeLink\": \"Link\",\n    \"typeEmbedded\": \"Embedded\",\n    \"icon\": \"Icon\",\n    \"activeIcon\": \"Active Icon\",\n    \"activePath\": \"Active Path\",\n    \"path\": \"Route Path\",\n    \"component\": \"Component\",\n    \"status\": \"Status\",\n    \"authCode\": \"Auth Code\",\n    \"badge\": \"Badge\",\n    \"operation\": \"Operation\",\n    \"linkSrc\": \"Link Address\",\n    \"affixTab\": \"Affix In Tabs\",\n    \"keepAlive\": \"Keep Alive\",\n    \"hideInMenu\": \"Hide In Menu\",\n    \"hideInTab\": \"Hide In Tabbar\",\n    \"hideChildrenInMenu\": \"Hide Children In Menu\",\n    \"hideInBreadcrumb\": \"Hide In Breadcrumb\",\n    \"advancedSettings\": \"Other Settings\",\n    \"activePathMustExist\": \"The path could not find a valid menu\",\n    \"activePathHelp\": \"When jumping to the current route, \\nthe menu path that needs to be activated must be specified when it does not display in the navigation menu.\",\n    \"badgeType\": {\n      \"title\": \"Badge Type\",\n      \"dot\": \"Dot\",\n      \"normal\": \"Text\",\n      \"none\": \"None\"\n    },\n    \"badgeVariants\": \"Badge Style\"\n  },\n  \"role\": {\n    \"title\": \"Role Management\",\n    \"list\": \"Role List\",\n    \"name\": \"Role\",\n    \"roleName\": \"Role Name\",\n    \"id\": \"Role ID\",\n    \"status\": \"Status\",\n    \"remark\": \"Remark\",\n    \"createTime\": \"Creation Time\",\n    \"operation\": \"Operation\",\n    \"permissions\": \"Permissions\",\n    \"setPermissions\": \"Permissions\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/langs/zh-CN/demos.json",
    "content": "{\n  \"title\": \"演示\",\n  \"access\": {\n    \"frontendPermissions\": \"前端权限\",\n    \"backendPermissions\": \"后端权限\",\n    \"pageAccess\": \"页面访问\",\n    \"buttonControl\": \"按钮控制\",\n    \"menuVisible403\": \"菜单可见(403)\",\n    \"superVisible\": \"Super 可见\",\n    \"adminVisible\": \"Admin 可见\",\n    \"userVisible\": \"User 可见\"\n  },\n  \"nested\": {\n    \"title\": \"嵌套菜单\",\n    \"menu1\": \"菜单 1\",\n    \"menu2\": \"菜单 2\",\n    \"menu2_1\": \"菜单 2-1\",\n    \"menu3\": \"菜单 3\",\n    \"menu3_1\": \"菜单 3-1\",\n    \"menu3_2\": \"菜单 3-2\",\n    \"menu3_2_1\": \"菜单 3-2-1\"\n  },\n  \"outside\": {\n    \"title\": \"外部页面\",\n    \"embedded\": \"内嵌\",\n    \"externalLink\": \"外链\"\n  },\n  \"badge\": {\n    \"title\": \"菜单徽标\",\n    \"dot\": \"点徽标\",\n    \"text\": \"文本徽标\",\n    \"color\": \"徽标颜色\"\n  },\n  \"activeIcon\": {\n    \"title\": \"菜单激活图标\",\n    \"children\": \"子级激活图标\"\n  },\n  \"fallback\": {\n    \"title\": \"缺省页\"\n  },\n  \"features\": {\n    \"title\": \"功能\",\n    \"hideChildrenInMenu\": \"隐藏子菜单\",\n    \"loginExpired\": \"登录过期\",\n    \"icons\": \"图标\",\n    \"watermark\": \"水印\",\n    \"tabs\": \"标签页\",\n    \"tabDetail\": \"标签详情页\",\n    \"fullScreen\": \"全屏\",\n    \"clipboard\": \"剪贴板\",\n    \"menuWithQuery\": \"带参菜单\",\n    \"openInNewWindow\": \"新窗口打开\",\n    \"fileDownload\": \"文件下载\",\n    \"requestParamsSerializer\": \"参数序列化\"\n  },\n  \"breadcrumb\": {\n    \"navigation\": \"面包屑导航\",\n    \"lateral\": \"平级模式\",\n    \"level\": \"层级模式\",\n    \"levelDetail\": \"层级模式详情\",\n    \"lateralDetail\": \"平级模式详情\"\n  },\n  \"vben\": {\n    \"title\": \"项目\",\n    \"about\": \"关于\",\n    \"document\": \"文档\",\n    \"antdv\": \"Ant Design Vue 版本\",\n    \"naive-ui\": \"Naive UI 版本\",\n    \"element-plus\": \"Element Plus 版本\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/langs/zh-CN/examples.json",
    "content": "{\n  \"title\": \"示例\",\n  \"modal\": {\n    \"title\": \"弹窗\"\n  },\n  \"drawer\": {\n    \"title\": \"抽屉\"\n  },\n  \"ellipsis\": {\n    \"title\": \"文本省略\"\n  },\n  \"resize\": {\n    \"title\": \"拖动调整\"\n  },\n  \"form\": {\n    \"title\": \"表单\",\n    \"basic\": \"基础表单\",\n    \"layout\": \"自定义布局\",\n    \"query\": \"查询表单\",\n    \"rules\": \"表单校验\",\n    \"dynamic\": \"动态表单\",\n    \"custom\": \"自定义组件\",\n    \"api\": \"Api\",\n    \"merge\": \"合并表单\",\n    \"scrollToError\": \"滚动到错误字段\",\n    \"upload-error\": \"部分文件上传失败\",\n    \"upload-urls\": \"文件上传后的网址\",\n    \"file\": \"文件\",\n    \"upload-image\": \"点击上传图片\"\n  },\n  \"vxeTable\": {\n    \"title\": \"Vxe 表格\",\n    \"basic\": \"基础表格\",\n    \"remote\": \"远程加载\",\n    \"tree\": \"树形表格\",\n    \"fixed\": \"固定表头/列\",\n    \"virtual\": \"虚拟滚动\",\n    \"editCell\": \"单元格编辑\",\n    \"editRow\": \"行编辑\",\n    \"custom-cell\": \"自定义单元格\",\n    \"form\": \"搜索表单\"\n  },\n  \"captcha\": {\n    \"title\": \"验证码\",\n    \"pointSelection\": \"点选验证\",\n    \"sliderCaptcha\": \"滑块验证\",\n    \"sliderRotateCaptcha\": \"旋转验证\",\n    \"sliderTranslateCaptcha\": \"拼图滑块验证\",\n    \"captchaCardTitle\": \"请完成安全验证\",\n    \"pageDescription\": \"通过点击图片中的特定位置来验证用户身份。\",\n    \"pageTitle\": \"验证码组件示例\",\n    \"basic\": \"基本使用\",\n    \"titlePlaceholder\": \"验证码标题文案\",\n    \"captchaImageUrlPlaceholder\": \"验证码图片（支持img标签src属性值）\",\n    \"hintImage\": \"提示图片\",\n    \"hintText\": \"提示文本\",\n    \"hintImagePlaceholder\": \"提示图片（支持img标签src属性值）\",\n    \"hintTextPlaceholder\": \"提示文本\",\n    \"showConfirm\": \"展示确认\",\n    \"hideConfirm\": \"隐藏确认\",\n    \"widthPlaceholder\": \"验证码图片宽度 默认300px\",\n    \"heightPlaceholder\": \"验证码图片高度 默认220px\",\n    \"paddingXPlaceholder\": \"水平内边距 默认12px\",\n    \"paddingYPlaceholder\": \"垂直内边距 默认16px\",\n    \"index\": \"索引：\",\n    \"timestamp\": \"时间戳：\",\n    \"x\": \"x：\",\n    \"y\": \"y：\"\n  },\n  \"layout\": {\n    \"col-page\": \"双列布局\"\n  },\n  \"button-group\": {\n    \"title\": \"按钮组\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/langs/zh-CN/page.json",
    "content": "{\n  \"auth\": {\n    \"login\": \"登录\",\n    \"register\": \"注册\",\n    \"codeLogin\": \"验证码登录\",\n    \"qrcodeLogin\": \"二维码登录\",\n    \"forgetPassword\": \"忘记密码\",\n    \"sendingCode\": \"正在发送验证码\",\n    \"codeSentTo\": \"验证码已发送至{0}\"\n  },\n  \"dashboard\": {\n    \"title\": \"概览\",\n    \"analytics\": \"分析页\",\n    \"workspace\": \"工作台\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/locales/langs/zh-CN/system.json",
    "content": "{\n  \"dept\": {\n    \"list\": \"部门列表\",\n    \"createTime\": \"创建时间\",\n    \"deptName\": \"部门名称\",\n    \"name\": \"部门\",\n    \"operation\": \"操作\",\n    \"parentDept\": \"上级部门\",\n    \"remark\": \"备注\",\n    \"status\": \"状态\",\n    \"title\": \"部门管理\"\n  },\n  \"menu\": {\n    \"list\": \"菜单列表\",\n    \"activeIcon\": \"激活图标\",\n    \"activePath\": \"激活路径\",\n    \"activePathHelp\": \"跳转到当前路由时，需要激活的菜单路径。\\n当不在导航菜单中显示时，需要指定激活路径\",\n    \"activePathMustExist\": \"该路径未能找到有效的菜单\",\n    \"advancedSettings\": \"其它设置\",\n    \"affixTab\": \"固定在标签\",\n    \"authCode\": \"权限标识\",\n    \"badge\": \"徽章内容\",\n    \"badgeVariants\": \"徽标样式\",\n    \"badgeType\": {\n      \"dot\": \"点\",\n      \"none\": \"无\",\n      \"normal\": \"文字\",\n      \"title\": \"徽标类型\"\n    },\n    \"component\": \"页面组件\",\n    \"hideChildrenInMenu\": \"隐藏子菜单\",\n    \"hideInBreadcrumb\": \"在面包屑中隐藏\",\n    \"hideInMenu\": \"隐藏菜单\",\n    \"hideInTab\": \"在标签栏中隐藏\",\n    \"icon\": \"图标\",\n    \"keepAlive\": \"缓存标签页\",\n    \"linkSrc\": \"链接地址\",\n    \"menuName\": \"菜单名称\",\n    \"menuTitle\": \"标题\",\n    \"name\": \"菜单\",\n    \"operation\": \"操作\",\n    \"parent\": \"上级菜单\",\n    \"path\": \"路由地址\",\n    \"status\": \"状态\",\n    \"title\": \"菜单管理\",\n    \"type\": \"类型\",\n    \"typeButton\": \"按钮\",\n    \"typeCatalog\": \"目录\",\n    \"typeEmbedded\": \"内嵌\",\n    \"typeLink\": \"外链\",\n    \"typeMenu\": \"菜单\"\n  },\n  \"role\": {\n    \"title\": \"角色管理\",\n    \"list\": \"角色列表\",\n    \"name\": \"角色\",\n    \"roleName\": \"角色名称\",\n    \"id\": \"角色ID\",\n    \"status\": \"状态\",\n    \"remark\": \"备注\",\n    \"createTime\": \"创建时间\",\n    \"operation\": \"操作\",\n    \"permissions\": \"权限\",\n    \"setPermissions\": \"授权\"\n  },\n  \"title\": \"系统管理\"\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/main.ts",
    "content": "import { initPreferences } from '@vben/preferences';\nimport { unmountGlobalLoading } from '@vben/utils';\n\nimport { overridesPreferences } from './preferences';\n\n/**\n * 应用初始化完成之后再进行页面加载渲染\n */\nasync function initApplication() {\n  // name用于指定项目唯一标识\n  // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据\n  const env = import.meta.env.PROD ? 'prod' : 'dev';\n  const appVersion = import.meta.env.VITE_APP_VERSION;\n  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;\n\n  // app偏好设置初始化\n  await initPreferences({\n    namespace,\n    overrides: overridesPreferences,\n  });\n\n  // 启动应用并挂载\n  // vue应用主要逻辑及视图\n  const { bootstrap } = await import('./bootstrap');\n  await bootstrap(namespace);\n\n  // 移除并销毁loading\n  unmountGlobalLoading();\n}\n\ninitApplication();\n"
  },
  {
    "path": "hiauth-front/playground/src/preferences.ts",
    "content": "import { defineOverridesPreferences } from '@vben/preferences';\n\n/**\n * @description 项目配置文件\n * 只需要覆盖项目中的一部分配置，不需要的配置不用覆盖，会自动使用默认配置\n * !!! 更改配置后请清空缓存，否则可能不生效\n */\nexport const overridesPreferences = defineOverridesPreferences({\n  // overrides\n  app: {\n    name: import.meta.env.VITE_APP_TITLE,\n  },\n});\n"
  },
  {
    "path": "hiauth-front/playground/src/router/access.ts",
    "content": "import type {\n  ComponentRecordType,\n  GenerateMenuAndRoutesOptions,\n} from '@vben/types';\n\nimport { generateAccessible } from '@vben/access';\nimport { preferences } from '@vben/preferences';\n\nimport { message } from 'ant-design-vue';\n\nimport { getAllMenusApi } from '#/api';\nimport { BasicLayout, IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');\n\nasync function generateAccess(options: GenerateMenuAndRoutesOptions) {\n  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');\n\n  const layoutMap: ComponentRecordType = {\n    BasicLayout,\n    IFrameView,\n  };\n\n  return await generateAccessible(preferences.app.accessMode, {\n    ...options,\n    fetchMenuListAsync: async () => {\n      message.loading({\n        content: `${$t('common.loadingMenu')}...`,\n        duration: 1.5,\n      });\n      return await getAllMenusApi();\n    },\n    // 可以指定没有权限跳转403页面\n    forbiddenComponent,\n    // 如果 route.meta.menuVisibleWithForbidden = true\n    layoutMap,\n    pageMap,\n  });\n}\n\nexport { generateAccess };\n"
  },
  {
    "path": "hiauth-front/playground/src/router/guard.ts",
    "content": "import type { Router } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { useAccessStore, useUserStore } from '@vben/stores';\nimport { startProgress, stopProgress } from '@vben/utils';\n\nimport { accessRoutes, coreRouteNames } from '#/router/routes';\nimport { useAuthStore } from '#/store';\n\nimport { generateAccess } from './access';\n\n/**\n * 通用守卫配置\n * @param router\n */\nfunction setupCommonGuard(router: Router) {\n  // 记录已经加载的页面\n  const loadedPaths = new Set<string>();\n\n  router.beforeEach((to) => {\n    to.meta.loaded = loadedPaths.has(to.path);\n\n    // 页面加载进度条\n    if (!to.meta.loaded && preferences.transition.progress) {\n      startProgress();\n    }\n    return true;\n  });\n\n  router.afterEach((to) => {\n    // 记录页面是否加载,如果已经加载，后续的页面切换动画等效果不在重复执行\n    loadedPaths.add(to.path);\n\n    // 关闭页面加载进度条\n    if (preferences.transition.progress) {\n      stopProgress();\n    }\n  });\n}\n\n/**\n * 权限访问守卫配置\n * @param router\n */\nfunction setupAccessGuard(router: Router) {\n  router.beforeEach(async (to, from) => {\n    const accessStore = useAccessStore();\n    const userStore = useUserStore();\n    const authStore = useAuthStore();\n    // 基本路由，这些路由不需要进入权限拦截\n    if (coreRouteNames.includes(to.name as string)) {\n      if (to.path === LOGIN_PATH && accessStore.accessToken) {\n        return decodeURIComponent(\n          (to.query?.redirect as string) ||\n            userStore.userInfo?.homePath ||\n            preferences.app.defaultHomePath,\n        );\n      }\n      return true;\n    }\n\n    // accessToken 检查\n    if (!accessStore.accessToken) {\n      // 明确声明忽略权限访问权限，则可以访问\n      if (to.meta.ignoreAccess) {\n        return true;\n      }\n\n      // 没有访问权限，跳转登录页面\n      if (to.fullPath !== LOGIN_PATH) {\n        return {\n          path: LOGIN_PATH,\n          // 如不需要，直接删除 query\n          query:\n            to.fullPath === preferences.app.defaultHomePath\n              ? {}\n              : { redirect: encodeURIComponent(to.fullPath) },\n          // 携带当前跳转的页面，登录后重新跳转该页面\n          replace: true,\n        };\n      }\n      return to;\n    }\n\n    // 是否已经生成过动态路由\n    if (accessStore.isAccessChecked) {\n      return true;\n    }\n\n    // 生成路由表\n    // 当前登录用户拥有的角色标识列表\n    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());\n    const userRoles = userInfo.roles ?? [];\n\n    // 生成菜单和路由\n    const { accessibleMenus, accessibleRoutes } = await generateAccess({\n      roles: userRoles,\n      router,\n      // 则会在菜单中显示，但是访问会被重定向到403\n      routes: accessRoutes,\n    });\n\n    // 保存菜单信息和路由信息\n    accessStore.setAccessMenus(accessibleMenus);\n    accessStore.setAccessRoutes(accessibleRoutes);\n    accessStore.setIsAccessChecked(true);\n    let redirectPath: string;\n    if (from.query.redirect) {\n      redirectPath = from.query.redirect as string;\n    } else if (to.path === preferences.app.defaultHomePath) {\n      redirectPath = preferences.app.defaultHomePath;\n    } else if (userInfo.homePath && to.path === userInfo.homePath) {\n      redirectPath = userInfo.homePath;\n    } else {\n      redirectPath = to.fullPath;\n    }\n    return {\n      ...router.resolve(decodeURIComponent(redirectPath)),\n      replace: true,\n    };\n  });\n}\n\n/**\n * 项目守卫配置\n * @param router\n */\nfunction createRouterGuard(router: Router) {\n  /** 通用 */\n  setupCommonGuard(router);\n  /** 权限访问 */\n  setupAccessGuard(router);\n}\n\nexport { createRouterGuard };\n"
  },
  {
    "path": "hiauth-front/playground/src/router/index.ts",
    "content": "import {\n  createRouter,\n  createWebHashHistory,\n  createWebHistory,\n} from 'vue-router';\n\nimport { resetStaticRoutes } from '@vben/utils';\n\nimport { createRouterGuard } from './guard';\nimport { routes } from './routes';\n\n/**\n *  @zh_CN 创建vue-router实例\n */\nconst router = createRouter({\n  history:\n    import.meta.env.VITE_ROUTER_HISTORY === 'hash'\n      ? createWebHashHistory(import.meta.env.VITE_BASE)\n      : createWebHistory(import.meta.env.VITE_BASE),\n  // 应该添加到路由的初始路由列表。\n  routes,\n  scrollBehavior: (to, _from, savedPosition) => {\n    if (savedPosition) {\n      return savedPosition;\n    }\n    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };\n  },\n  // 是否应该禁止尾部斜杠。\n  // strict: true,\n});\n\nconst resetRoutes = () => resetStaticRoutes(router, routes);\n\n// 创建路由守卫\ncreateRouterGuard(router);\n\nexport { resetRoutes, router };\n"
  },
  {
    "path": "hiauth-front/playground/src/router/routes/core.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\n\nimport { $t } from '#/locales';\n\nconst BasicLayout = () => import('#/layouts/basic.vue');\nconst AuthPageLayout = () => import('#/layouts/auth.vue');\n/** 全局404页面 */\nconst fallbackNotFoundRoute: RouteRecordRaw = {\n  component: () => import('#/views/_core/fallback/not-found.vue'),\n  meta: {\n    hideInBreadcrumb: true,\n    hideInMenu: true,\n    hideInTab: true,\n    title: '404',\n  },\n  name: 'FallbackNotFound',\n  path: '/:path(.*)*',\n};\n\n/** 基本路由，这些路由是必须存在的 */\nconst coreRoutes: RouteRecordRaw[] = [\n  /**\n   * 根路由\n   * 使用基础布局，作为所有页面的父级容器，子级就不必配置BasicLayout。\n   * 此路由必须存在，且不应修改\n   */\n  {\n    component: BasicLayout,\n    meta: {\n      hideInBreadcrumb: true,\n      title: 'Root',\n    },\n    name: 'Root',\n    path: '/',\n    redirect: preferences.app.defaultHomePath,\n    children: [],\n  },\n  {\n    component: AuthPageLayout,\n    meta: {\n      hideInTab: true,\n      title: 'Authentication',\n    },\n    name: 'Authentication',\n    path: '/auth',\n    redirect: LOGIN_PATH,\n    children: [\n      {\n        name: 'Login',\n        path: 'login',\n        component: () => import('#/views/_core/authentication/login.vue'),\n        meta: {\n          title: $t('page.auth.login'),\n        },\n      },\n      {\n        name: 'CodeLogin',\n        path: 'code-login',\n        component: () => import('#/views/_core/authentication/code-login.vue'),\n        meta: {\n          title: $t('page.auth.codeLogin'),\n        },\n      },\n      {\n        name: 'QrCodeLogin',\n        path: 'qrcode-login',\n        component: () =>\n          import('#/views/_core/authentication/qrcode-login.vue'),\n        meta: {\n          title: $t('page.auth.qrcodeLogin'),\n        },\n      },\n      {\n        name: 'ForgetPassword',\n        path: 'forget-password',\n        component: () =>\n          import('#/views/_core/authentication/forget-password.vue'),\n        meta: {\n          title: $t('page.auth.forgetPassword'),\n        },\n      },\n      {\n        name: 'Register',\n        path: 'register',\n        component: () => import('#/views/_core/authentication/register.vue'),\n        meta: {\n          title: $t('page.auth.register'),\n        },\n      },\n    ],\n  },\n];\n\nexport { coreRoutes, fallbackNotFoundRoute };\n"
  },
  {
    "path": "hiauth-front/playground/src/router/routes/index.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { mergeRouteModules, traverseTreeValues } from '@vben/utils';\n\nimport { coreRoutes, fallbackNotFoundRoute } from './core';\n\nconst dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {\n  eager: true,\n});\n\n// 有需要可以自行打开注释，并创建文件夹\n// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });\n// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });\n\n/** 动态路由 */\nconst dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);\n\n/** 外部路由列表，访问这些页面可以不需要Layout，可能用于内嵌在别的系统(不会显示在菜单中) */\n// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);\n// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);\nconst staticRoutes: RouteRecordRaw[] = [];\nconst externalRoutes: RouteRecordRaw[] = [];\n\n/** 路由列表，由基本路由、外部路由和404兜底路由组成\n *  无需走权限验证（会一直显示在菜单中） */\nconst routes: RouteRecordRaw[] = [\n  ...coreRoutes,\n  ...externalRoutes,\n  fallbackNotFoundRoute,\n];\n\n/** 基本路由列表，这些路由不需要进入权限拦截 */\nconst coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);\n\n/** 有权限校验的路由列表，包含动态路由和静态路由 */\nconst accessRoutes = [...dynamicRoutes, ...staticRoutes];\n\nconst componentKeys: string[] = Object.keys(\n  import.meta.glob('../../views/**/*.vue'),\n)\n  .filter((item) => !item.includes('/modules/'))\n  .map((v) => {\n    const path = v.replace('../../views/', '/');\n    return path.endsWith('.vue') ? path.slice(0, -4) : path;\n  });\n\nexport { accessRoutes, componentKeys, coreRouteNames, routes };\n"
  },
  {
    "path": "hiauth-front/playground/src/router/routes/modules/dashboard.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'lucide:layout-dashboard',\n      order: -1,\n      title: $t('page.dashboard.title'),\n    },\n    name: 'Dashboard',\n    path: '/dashboard',\n    children: [\n      {\n        name: 'Analytics',\n        path: '/analytics',\n        component: () => import('#/views/dashboard/analytics/index.vue'),\n        meta: {\n          affixTab: true,\n          icon: 'lucide:area-chart',\n          title: $t('page.dashboard.analytics'),\n        },\n      },\n      {\n        name: 'Workspace',\n        path: '/workspace',\n        component: () => import('#/views/dashboard/workspace/index.vue'),\n        meta: {\n          icon: 'carbon:workspace',\n          title: $t('page.dashboard.workspace'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/playground/src/router/routes/modules/demos.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'ic:baseline-view-in-ar',\n      keepAlive: true,\n      order: 1000,\n      title: $t('demos.title'),\n    },\n    name: 'Demos',\n    path: '/demos',\n    children: [\n      // 权限控制\n      {\n        meta: {\n          icon: 'mdi:shield-key-outline',\n          title: $t('demos.access.frontendPermissions'),\n        },\n        name: 'AccessDemos',\n        path: '/demos/access',\n        children: [\n          {\n            name: 'AccessPageControlDemo',\n            path: '/demos/access/page-control',\n            component: () => import('#/views/demos/access/index.vue'),\n            meta: {\n              icon: 'mdi:page-previous-outline',\n              title: $t('demos.access.pageAccess'),\n            },\n          },\n          {\n            name: 'AccessButtonControlDemo',\n            path: '/demos/access/button-control',\n            component: () => import('#/views/demos/access/button-control.vue'),\n            meta: {\n              icon: 'mdi:button-cursor',\n              title: $t('demos.access.buttonControl'),\n            },\n          },\n          {\n            name: 'AccessMenuVisible403Demo',\n            path: '/demos/access/menu-visible-403',\n            component: () =>\n              import('#/views/demos/access/menu-visible-403.vue'),\n            meta: {\n              authority: ['no-body'],\n              icon: 'mdi:button-cursor',\n              menuVisibleWithForbidden: true,\n              title: $t('demos.access.menuVisible403'),\n            },\n          },\n          {\n            name: 'AccessSuperVisibleDemo',\n            path: '/demos/access/super-visible',\n            component: () => import('#/views/demos/access/super-visible.vue'),\n            meta: {\n              authority: ['super'],\n              icon: 'mdi:button-cursor',\n              title: $t('demos.access.superVisible'),\n            },\n          },\n          {\n            name: 'AccessAdminVisibleDemo',\n            path: '/demos/access/admin-visible',\n            component: () => import('#/views/demos/access/admin-visible.vue'),\n            meta: {\n              authority: ['admin'],\n              icon: 'mdi:button-cursor',\n              title: $t('demos.access.adminVisible'),\n            },\n          },\n          {\n            name: 'AccessUserVisibleDemo',\n            path: '/demos/access/user-visible',\n            component: () => import('#/views/demos/access/user-visible.vue'),\n            meta: {\n              authority: ['user'],\n              icon: 'mdi:button-cursor',\n              title: $t('demos.access.userVisible'),\n            },\n          },\n        ],\n      },\n      // 功能\n      {\n        meta: {\n          icon: 'mdi:feature-highlight',\n          title: $t('demos.features.title'),\n        },\n        name: 'FeaturesDemos',\n        path: '/demos/features',\n        children: [\n          {\n            name: 'LoginExpiredDemo',\n            path: '/demos/features/login-expired',\n            component: () =>\n              import('#/views/demos/features/login-expired/index.vue'),\n            meta: {\n              icon: 'mdi:encryption-expiration',\n              title: $t('demos.features.loginExpired'),\n            },\n          },\n          {\n            name: 'IconsDemo',\n            path: '/demos/features/icons',\n            component: () => import('#/views/demos/features/icons/index.vue'),\n            meta: {\n              icon: 'lucide:annoyed',\n              title: $t('demos.features.icons'),\n            },\n          },\n          {\n            name: 'WatermarkDemo',\n            path: '/demos/features/watermark',\n            component: () =>\n              import('#/views/demos/features/watermark/index.vue'),\n            meta: {\n              icon: 'lucide:tags',\n              title: $t('demos.features.watermark'),\n            },\n          },\n          {\n            name: 'FeatureTabsDemo',\n            path: '/demos/features/tabs',\n            component: () => import('#/views/demos/features/tabs/index.vue'),\n            meta: {\n              icon: 'lucide:app-window',\n              title: $t('demos.features.tabs'),\n            },\n          },\n          {\n            name: 'FeatureTabDetailDemo',\n            path: '/demos/features/tabs/detail/:id',\n            component: () =>\n              import('#/views/demos/features/tabs/tab-detail.vue'),\n            meta: {\n              activePath: '/demos/features/tabs',\n              hideInMenu: true,\n              maxNumOfOpenTab: 3,\n              title: $t('demos.features.tabDetail'),\n            },\n          },\n          {\n            name: 'HideChildrenInMenuParentDemo',\n            path: '/demos/features/hide-menu-children',\n            meta: {\n              hideChildrenInMenu: true,\n              icon: 'ic:round-menu',\n              title: $t('demos.features.hideChildrenInMenu'),\n            },\n            children: [\n              {\n                name: 'HideChildrenInMenuDemo',\n                path: '',\n                component: () =>\n                  import(\n                    '#/views/demos/features/hide-menu-children/parent.vue'\n                  ),\n                meta: {\n                  // hideInMenu: true,\n                  title: $t('demos.features.hideChildrenInMenu'),\n                },\n              },\n              {\n                name: 'HideChildrenInMenuChildrenDemo',\n                path: '/demos/features/hide-menu-children/children',\n                component: () =>\n                  import(\n                    '#/views/demos/features/hide-menu-children/children.vue'\n                  ),\n                meta: {\n                  activePath: '/demos/features/hide-menu-children',\n                  title: $t('demos.features.hideChildrenInMenu'),\n                },\n              },\n            ],\n          },\n          {\n            name: 'FullScreenDemo',\n            path: '/demos/features/full-screen',\n            component: () =>\n              import('#/views/demos/features/full-screen/index.vue'),\n            meta: {\n              icon: 'lucide:fullscreen',\n              title: $t('demos.features.fullScreen'),\n            },\n          },\n          {\n            name: 'FileDownloadDemo',\n            path: '/demos/features/file-download',\n            component: () =>\n              import('#/views/demos/features/file-download/index.vue'),\n            meta: {\n              icon: 'lucide:hard-drive-download',\n              title: $t('demos.features.fileDownload'),\n            },\n          },\n          {\n            name: 'ClipboardDemo',\n            path: '/demos/features/clipboard',\n            component: () =>\n              import('#/views/demos/features/clipboard/index.vue'),\n            meta: {\n              icon: 'lucide:copy',\n              title: $t('demos.features.clipboard'),\n            },\n          },\n          {\n            name: 'MenuQueryDemo',\n            path: '/demos/menu-query',\n            component: () =>\n              import('#/views/demos/features/menu-query/index.vue'),\n            meta: {\n              icon: 'lucide:curly-braces',\n              query: {\n                id: 1,\n              },\n              title: $t('demos.features.menuWithQuery'),\n            },\n          },\n          {\n            name: 'NewWindowDemo',\n            path: '/demos/new-window',\n            component: () =>\n              import('#/views/demos/features/new-window/index.vue'),\n            meta: {\n              icon: 'lucide:app-window',\n              openInNewWindow: true,\n              title: $t('demos.features.openInNewWindow'),\n            },\n          },\n          {\n            name: 'VueQueryDemo',\n            path: '/demos/features/vue-query',\n            component: () =>\n              import('#/views/demos/features/vue-query/index.vue'),\n            meta: {\n              icon: 'lucide:git-pull-request-arrow',\n              title: 'Tanstack Query',\n            },\n          },\n          {\n            name: 'RequestParamsSerializerDemo',\n            path: '/demos/features/request-params-serializer',\n            component: () =>\n              import(\n                '#/views/demos/features/request-params-serializer/index.vue'\n              ),\n            meta: {\n              icon: 'lucide:git-pull-request-arrow',\n              title: $t('demos.features.requestParamsSerializer'),\n            },\n          },\n          {\n            name: 'BigIntDemo',\n            path: '/demos/features/json-bigint',\n            component: () =>\n              import('#/views/demos/features/json-bigint/index.vue'),\n            meta: {\n              icon: 'lucide:grape',\n              title: 'JSON BigInt',\n            },\n          },\n        ],\n      },\n      // 面包屑导航\n      {\n        name: 'BreadcrumbDemos',\n        path: '/demos/breadcrumb',\n        meta: {\n          icon: 'lucide:navigation',\n          title: $t('demos.breadcrumb.navigation'),\n        },\n        children: [\n          {\n            name: 'BreadcrumbLateralDemo',\n            path: '/demos/breadcrumb/lateral',\n            component: () => import('#/views/demos/breadcrumb/lateral.vue'),\n            meta: {\n              icon: 'lucide:navigation',\n              title: $t('demos.breadcrumb.lateral'),\n            },\n          },\n          {\n            name: 'BreadcrumbLateralDetailDemo',\n            path: '/demos/breadcrumb/lateral-detail',\n            component: () =>\n              import('#/views/demos/breadcrumb/lateral-detail.vue'),\n            meta: {\n              activePath: '/demos/breadcrumb/lateral',\n              hideInMenu: true,\n              title: $t('demos.breadcrumb.lateralDetail'),\n            },\n          },\n          {\n            name: 'BreadcrumbLevelDemo',\n            path: '/demos/breadcrumb/level',\n            meta: {\n              icon: 'lucide:navigation',\n              title: $t('demos.breadcrumb.level'),\n            },\n            children: [\n              {\n                name: 'BreadcrumbLevelDetailDemo',\n                path: '/demos/breadcrumb/level/detail',\n                component: () =>\n                  import('#/views/demos/breadcrumb/level-detail.vue'),\n                meta: {\n                  title: $t('demos.breadcrumb.levelDetail'),\n                },\n              },\n            ],\n          },\n        ],\n      },\n      // 缺省页\n      {\n        meta: {\n          icon: 'mdi:lightbulb-error-outline',\n          title: $t('demos.fallback.title'),\n        },\n        name: 'FallbackDemos',\n        path: '/demos/fallback',\n        children: [\n          {\n            name: 'Fallback403Demo',\n            path: '/demos/fallback/403',\n            component: () => import('#/views/_core/fallback/forbidden.vue'),\n            meta: {\n              icon: 'mdi:do-not-disturb-alt',\n              title: '403',\n            },\n          },\n          {\n            name: 'Fallback404Demo',\n            path: '/demos/fallback/404',\n            component: () => import('#/views/_core/fallback/not-found.vue'),\n            meta: {\n              icon: 'mdi:table-off',\n              title: '404',\n            },\n          },\n          {\n            name: 'Fallback500Demo',\n            path: '/demos/fallback/500',\n            component: () =>\n              import('#/views/_core/fallback/internal-error.vue'),\n            meta: {\n              icon: 'mdi:server-network-off',\n              title: '500',\n            },\n          },\n          {\n            name: 'FallbackOfflineDemo',\n            path: '/demos/fallback/offline',\n            component: () => import('#/views/_core/fallback/offline.vue'),\n            meta: {\n              icon: 'mdi:offline',\n              title: $t('ui.fallback.offline'),\n            },\n          },\n        ],\n      },\n      // 菜单徽标\n      {\n        meta: {\n          badgeType: 'dot',\n          badgeVariants: 'destructive',\n          icon: 'lucide:circle-dot',\n          title: $t('demos.badge.title'),\n        },\n        name: 'BadgeDemos',\n        path: '/demos/badge',\n        children: [\n          {\n            name: 'BadgeDotDemo',\n            component: () => import('#/views/demos/badge/index.vue'),\n            path: '/demos/badge/dot',\n            meta: {\n              badgeType: 'dot',\n              icon: 'lucide:square-dot',\n              title: $t('demos.badge.dot'),\n            },\n          },\n          {\n            name: 'BadgeTextDemo',\n            component: () => import('#/views/demos/badge/index.vue'),\n            path: '/demos/badge/text',\n            meta: {\n              badge: '10',\n              icon: 'lucide:square-dot',\n              title: $t('demos.badge.text'),\n            },\n          },\n          {\n            name: 'BadgeColorDemo',\n            component: () => import('#/views/demos/badge/index.vue'),\n            path: '/demos/badge/color',\n            meta: {\n              badge: 'Hot',\n              badgeVariants: 'destructive',\n              icon: 'lucide:square-dot',\n              title: $t('demos.badge.color'),\n            },\n          },\n        ],\n      },\n      // 菜单激活图标\n      {\n        meta: {\n          activeIcon: 'fluent-emoji:radioactive',\n          icon: 'bi:radioactive',\n          title: $t('demos.activeIcon.title'),\n        },\n        name: 'ActiveIconDemos',\n        path: '/demos/active-icon',\n        children: [\n          {\n            name: 'ActiveIconDemo',\n            component: () => import('#/views/demos/active-icon/index.vue'),\n            path: '/demos/active-icon/children',\n            meta: {\n              activeIcon: 'fluent-emoji:radioactive',\n              icon: 'bi:radioactive',\n              title: $t('demos.activeIcon.children'),\n            },\n          },\n        ],\n      },\n      // 外部链接\n      {\n        meta: {\n          icon: 'ic:round-settings-input-composite',\n          title: $t('demos.outside.title'),\n        },\n        name: 'OutsideDemos',\n        path: '/demos/outside',\n        children: [\n          {\n            name: 'IframeDemos',\n            path: '/demos/outside/iframe',\n            meta: {\n              icon: 'mdi:newspaper-variant-outline',\n              title: $t('demos.outside.embedded'),\n            },\n            children: [\n              {\n                name: 'VueDocumentDemo',\n                path: '/demos/outside/iframe/vue-document',\n                component: IFrameView,\n                meta: {\n                  icon: 'logos:vue',\n                  iframeSrc: 'https://cn.vuejs.org/',\n                  keepAlive: true,\n                  title: 'Vue',\n                },\n              },\n              {\n                name: 'TailwindcssDemo',\n                path: '/demos/outside/iframe/tailwindcss',\n                component: IFrameView,\n                meta: {\n                  icon: 'devicon:tailwindcss',\n                  iframeSrc: 'https://tailwindcss.com/',\n                  // keepAlive: true,\n                  title: 'Tailwindcss',\n                },\n              },\n            ],\n          },\n          {\n            name: 'ExternalLinkDemos',\n            path: '/demos/outside/external-link',\n            meta: {\n              icon: 'mdi:newspaper-variant-multiple-outline',\n              title: $t('demos.outside.externalLink'),\n            },\n            children: [\n              {\n                name: 'ViteDemo',\n                path: '/demos/outside/external-link/vite',\n                component: IFrameView,\n                meta: {\n                  icon: 'logos:vitejs',\n                  link: 'https://vitejs.dev/',\n                  title: 'Vite',\n                },\n              },\n              {\n                name: 'VueUseDemo',\n                path: '/demos/outside/external-link/vue-use',\n                component: IFrameView,\n                meta: {\n                  icon: 'logos:vueuse',\n                  link: 'https://vueuse.org',\n                  title: 'VueUse',\n                },\n              },\n            ],\n          },\n        ],\n      },\n      // 嵌套菜单\n      {\n        meta: {\n          icon: 'ic:round-menu',\n          title: $t('demos.nested.title'),\n        },\n        name: 'NestedDemos',\n        path: '/demos/nested',\n        children: [\n          {\n            name: 'Menu1Demo',\n            path: '/demos/nested/menu1',\n            component: () => import('#/views/demos/nested/menu-1.vue'),\n            meta: {\n              icon: 'ic:round-menu',\n              keepAlive: true,\n              title: $t('demos.nested.menu1'),\n            },\n          },\n          {\n            name: 'Menu2Demo',\n            path: '/demos/nested/menu2',\n            meta: {\n              icon: 'ic:round-menu',\n              keepAlive: true,\n              title: $t('demos.nested.menu2'),\n            },\n            children: [\n              {\n                name: 'Menu21Demo',\n                path: '/demos/nested/menu2/menu2-1',\n                component: () => import('#/views/demos/nested/menu-2-1.vue'),\n                meta: {\n                  icon: 'ic:round-menu',\n                  keepAlive: true,\n                  title: $t('demos.nested.menu2_1'),\n                },\n              },\n            ],\n          },\n          {\n            name: 'Menu3Demo',\n            path: '/demos/nested/menu3',\n            meta: {\n              icon: 'ic:round-menu',\n              title: $t('demos.nested.menu3'),\n            },\n            children: [\n              {\n                name: 'Menu31Demo',\n                path: '/demos/nested/menu3/menu3-1',\n                component: () => import('#/views/demos/nested/menu-3-1.vue'),\n                meta: {\n                  icon: 'ic:round-menu',\n                  keepAlive: true,\n                  title: $t('demos.nested.menu3_1'),\n                },\n              },\n              {\n                name: 'Menu32Demo',\n                path: '/demos/nested/menu3/menu3-2',\n                meta: {\n                  icon: 'ic:round-menu',\n                  title: $t('demos.nested.menu3_2'),\n                },\n                children: [\n                  {\n                    name: 'Menu321Demo',\n                    path: '/demos/nested/menu3/menu3-2/menu3-2-1',\n                    component: () =>\n                      import('#/views/demos/nested/menu-3-2-1.vue'),\n                    meta: {\n                      icon: 'ic:round-menu',\n                      keepAlive: true,\n                      title: $t('demos.nested.menu3_2_1'),\n                    },\n                  },\n                ],\n              },\n            ],\n          },\n        ],\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/playground/src/router/routes/modules/examples.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'ion:layers-outline',\n      keepAlive: true,\n      order: 1000,\n      title: $t('examples.title'),\n    },\n    name: 'Examples',\n    path: '/examples',\n    children: [\n      {\n        name: 'FormExample',\n        path: '/examples/form',\n        meta: {\n          icon: 'mdi:form-select',\n          title: $t('examples.form.title'),\n        },\n        children: [\n          {\n            name: 'FormBasicExample',\n            path: '/examples/form/basic',\n            component: () => import('#/views/examples/form/basic.vue'),\n            meta: {\n              title: $t('examples.form.basic'),\n            },\n          },\n          {\n            name: 'FormQueryExample',\n            path: '/examples/form/query',\n            component: () => import('#/views/examples/form/query.vue'),\n            meta: {\n              title: $t('examples.form.query'),\n            },\n          },\n          {\n            name: 'FormRulesExample',\n            path: '/examples/form/rules',\n            component: () => import('#/views/examples/form/rules.vue'),\n            meta: {\n              title: $t('examples.form.rules'),\n            },\n          },\n          {\n            name: 'FormDynamicExample',\n            path: '/examples/form/dynamic',\n            component: () => import('#/views/examples/form/dynamic.vue'),\n            meta: {\n              title: $t('examples.form.dynamic'),\n            },\n          },\n          {\n            name: 'FormLayoutExample',\n            path: '/examples/form/custom-layout',\n            component: () => import('#/views/examples/form/custom-layout.vue'),\n            meta: {\n              title: $t('examples.form.layout'),\n            },\n          },\n          {\n            name: 'FormCustomExample',\n            path: '/examples/form/custom',\n            component: () => import('#/views/examples/form/custom.vue'),\n            meta: {\n              title: $t('examples.form.custom'),\n            },\n          },\n          {\n            name: 'FormApiExample',\n            path: '/examples/form/api',\n            component: () => import('#/views/examples/form/api.vue'),\n            meta: {\n              title: $t('examples.form.api'),\n            },\n          },\n          {\n            name: 'FormMergeExample',\n            path: '/examples/form/merge',\n            component: () => import('#/views/examples/form/merge.vue'),\n            meta: {\n              title: $t('examples.form.merge'),\n            },\n          },\n          {\n            name: 'FormScrollToErrorExample',\n            path: '/examples/form/scroll-to-error-test',\n            component: () =>\n              import('#/views/examples/form/scroll-to-error-test.vue'),\n            meta: {\n              title: $t('examples.form.scrollToError'),\n            },\n          },\n        ],\n      },\n      {\n        name: 'VxeTableExample',\n        path: '/examples/vxe-table',\n        meta: {\n          icon: 'lucide:table',\n          title: $t('examples.vxeTable.title'),\n        },\n        children: [\n          {\n            name: 'VxeTableBasicExample',\n            path: '/examples/vxe-table/basic',\n            component: () => import('#/views/examples/vxe-table/basic.vue'),\n            meta: {\n              title: $t('examples.vxeTable.basic'),\n            },\n          },\n          {\n            name: 'VxeTableRemoteExample',\n            path: '/examples/vxe-table/remote',\n            component: () => import('#/views/examples/vxe-table/remote.vue'),\n            meta: {\n              title: $t('examples.vxeTable.remote'),\n            },\n          },\n          {\n            name: 'VxeTableTreeExample',\n            path: '/examples/vxe-table/tree',\n            component: () => import('#/views/examples/vxe-table/tree.vue'),\n            meta: {\n              title: $t('examples.vxeTable.tree'),\n            },\n          },\n          {\n            name: 'VxeTableFixedExample',\n            path: '/examples/vxe-table/fixed',\n            component: () => import('#/views/examples/vxe-table/fixed.vue'),\n            meta: {\n              title: $t('examples.vxeTable.fixed'),\n            },\n          },\n          {\n            name: 'VxeTableCustomCellExample',\n            path: '/examples/vxe-table/custom-cell',\n            component: () =>\n              import('#/views/examples/vxe-table/custom-cell.vue'),\n            meta: {\n              title: $t('examples.vxeTable.custom-cell'),\n            },\n          },\n          {\n            name: 'VxeTableFormExample',\n            path: '/examples/vxe-table/form',\n            component: () => import('#/views/examples/vxe-table/form.vue'),\n            meta: {\n              title: $t('examples.vxeTable.form'),\n            },\n          },\n          {\n            name: 'VxeTableEditCellExample',\n            path: '/examples/vxe-table/edit-cell',\n            component: () => import('#/views/examples/vxe-table/edit-cell.vue'),\n            meta: {\n              title: $t('examples.vxeTable.editCell'),\n            },\n          },\n          {\n            name: 'VxeTableEditRowExample',\n            path: '/examples/vxe-table/edit-row',\n            component: () => import('#/views/examples/vxe-table/edit-row.vue'),\n            meta: {\n              title: $t('examples.vxeTable.editRow'),\n            },\n          },\n          {\n            name: 'VxeTableVirtualExample',\n            path: '/examples/vxe-table/virtual',\n            component: () => import('#/views/examples/vxe-table/virtual.vue'),\n            meta: {\n              title: $t('examples.vxeTable.virtual'),\n            },\n          },\n        ],\n      },\n      {\n        name: 'CaptchaExample',\n        path: '/examples/captcha',\n        meta: {\n          icon: 'logos:recaptcha',\n          title: $t('examples.captcha.title'),\n        },\n        children: [\n          {\n            name: 'DragVerifyExample',\n            path: '/examples/captcha/slider',\n            component: () =>\n              import('#/views/examples/captcha/slider-captcha.vue'),\n            meta: {\n              title: $t('examples.captcha.sliderCaptcha'),\n            },\n          },\n          {\n            name: 'RotateVerifyExample',\n            path: '/examples/captcha/slider-rotate',\n            component: () =>\n              import('#/views/examples/captcha/slider-rotate-captcha.vue'),\n            meta: {\n              title: $t('examples.captcha.sliderRotateCaptcha'),\n            },\n          },\n          {\n            name: 'TranslateVerifyExample',\n            path: '/examples/captcha/slider-translate',\n            component: () =>\n              import('#/views/examples/captcha/slider-translate-captcha.vue'),\n            meta: {\n              title: $t('examples.captcha.sliderTranslateCaptcha'),\n            },\n          },\n          {\n            name: 'CaptchaPointSelectionExample',\n            path: '/examples/captcha/point-selection',\n            component: () =>\n              import('#/views/examples/captcha/point-selection-captcha.vue'),\n            meta: {\n              title: $t('examples.captcha.pointSelection'),\n            },\n          },\n        ],\n      },\n      {\n        name: 'ModalExample',\n        path: '/examples/modal',\n        component: () => import('#/views/examples/modal/index.vue'),\n        meta: {\n          icon: 'system-uicons:window-content',\n          keepAlive: true,\n          title: $t('examples.modal.title'),\n        },\n      },\n      {\n        name: 'DrawerExample',\n        path: '/examples/drawer',\n        component: () => import('#/views/examples/drawer/index.vue'),\n        meta: {\n          icon: 'iconoir:drawer',\n          keepAlive: true,\n          title: $t('examples.drawer.title'),\n        },\n      },\n      {\n        name: 'EllipsisExample',\n        path: '/examples/ellipsis',\n        component: () => import('#/views/examples/ellipsis/index.vue'),\n        meta: {\n          icon: 'ion:ellipsis-horizontal',\n          title: $t('examples.ellipsis.title'),\n        },\n      },\n      {\n        name: 'VueResizeDemo',\n        path: '/demos/resize/basic',\n        component: () => import('#/views/examples/resize/basic.vue'),\n        meta: {\n          icon: 'material-symbols:resize',\n          title: $t('examples.resize.title'),\n        },\n      },\n      {\n        name: 'ColPageDemo',\n        path: '/examples/layout/col-page',\n        component: () => import('#/views/examples/layout/col-page.vue'),\n        meta: {\n          badge: 'Alpha',\n          badgeVariants: 'destructive',\n          icon: 'material-symbols:horizontal-distribute',\n          title: $t('examples.layout.col-page'),\n        },\n      },\n      {\n        name: 'TippyDemo',\n        path: '/examples/tippy',\n        component: () => import('#/views/examples/tippy/index.vue'),\n        meta: {\n          icon: 'mdi:message-settings-outline',\n          title: 'Tippy',\n        },\n      },\n      {\n        name: 'JsonViewer',\n        path: '/examples/json-viewer',\n        component: () => import('#/views/examples/json-viewer/index.vue'),\n        meta: {\n          icon: 'tabler:json',\n          title: 'JsonViewer',\n        },\n      },\n      {\n        name: 'Motion',\n        path: '/examples/motion',\n        component: () => import('#/views/examples/motion/index.vue'),\n        meta: {\n          icon: 'mdi:animation-play',\n          title: 'Motion',\n        },\n      },\n      {\n        name: 'CountTo',\n        path: '/examples/count-to',\n        component: () => import('#/views/examples/count-to/index.vue'),\n        meta: {\n          icon: 'mdi:animation-play',\n          title: 'CountTo',\n        },\n      },\n      {\n        name: 'Loading',\n        path: '/examples/loading',\n        component: () => import('#/views/examples/loading/index.vue'),\n        meta: {\n          icon: 'mdi:circle-double',\n          title: 'Loading',\n        },\n      },\n      {\n        name: 'ButtonGroup',\n        path: '/examples/button-group',\n        component: () => import('#/views/examples/button-group/index.vue'),\n        meta: {\n          icon: 'mdi:check-circle',\n          title: $t('examples.button-group.title'),\n        },\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/playground/src/router/routes/modules/system.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      icon: 'ion:settings-outline',\n      order: 9997,\n      title: $t('system.title'),\n    },\n    name: 'System',\n    path: '/system',\n    children: [\n      {\n        path: '/system/role',\n        name: 'SystemRole',\n        meta: {\n          icon: 'mdi:account-group',\n          title: $t('system.role.title'),\n        },\n        component: () => import('#/views/system/role/list.vue'),\n      },\n      {\n        path: '/system/menu',\n        name: 'SystemMenu',\n        meta: {\n          icon: 'mdi:menu',\n          title: $t('system.menu.title'),\n        },\n        component: () => import('#/views/system/menu/list.vue'),\n      },\n      {\n        path: '/system/dept',\n        name: 'SystemDept',\n        meta: {\n          icon: 'charm:organisation',\n          title: $t('system.dept.title'),\n        },\n        component: () => import('#/views/system/dept/list.vue'),\n      },\n    ],\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/playground/src/router/routes/modules/vben.ts",
    "content": "import type { RouteRecordRaw } from 'vue-router';\n\nimport {\n  VBEN_ANT_PREVIEW_URL,\n  VBEN_DOC_URL,\n  VBEN_ELE_PREVIEW_URL,\n  VBEN_GITHUB_URL,\n  VBEN_LOGO_URL,\n  VBEN_NAIVE_PREVIEW_URL,\n} from '@vben/constants';\nimport { SvgAntdvLogoIcon } from '@vben/icons';\n\nimport { IFrameView } from '#/layouts';\nimport { $t } from '#/locales';\n\nconst routes: RouteRecordRaw[] = [\n  {\n    meta: {\n      badgeType: 'dot',\n      icon: VBEN_LOGO_URL,\n      order: 9998,\n      title: $t('demos.vben.title'),\n    },\n    name: 'VbenProject',\n    path: '/vben-admin',\n    children: [\n      {\n        name: 'VbenDocument',\n        path: '/vben-admin/document',\n        component: IFrameView,\n        meta: {\n          icon: 'lucide:book-open-text',\n          link: VBEN_DOC_URL,\n          title: $t('demos.vben.document'),\n        },\n      },\n      {\n        name: 'VbenGithub',\n        path: '/vben-admin/github',\n        component: IFrameView,\n        meta: {\n          icon: 'mdi:github',\n          link: VBEN_GITHUB_URL,\n          title: 'Github',\n        },\n      },\n      {\n        name: 'VbenAntdv',\n        path: '/vben-admin/antdv',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: SvgAntdvLogoIcon,\n          link: VBEN_ANT_PREVIEW_URL,\n          title: $t('demos.vben.antdv'),\n        },\n      },\n      {\n        name: 'VbenNaive',\n        path: '/vben-admin/naive',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: 'logos:naiveui',\n          link: VBEN_NAIVE_PREVIEW_URL,\n          title: $t('demos.vben.naive-ui'),\n        },\n      },\n      {\n        name: 'VbenElementPlus',\n        path: '/vben-admin/ele',\n        component: IFrameView,\n        meta: {\n          badgeType: 'dot',\n          icon: 'logos:element',\n          link: VBEN_ELE_PREVIEW_URL,\n          title: $t('demos.vben.element-plus'),\n        },\n      },\n    ],\n  },\n  {\n    component: () => import('#/views/_core/about/index.vue'),\n    meta: {\n      icon: 'lucide:copyright',\n      order: 9999,\n      title: $t('demos.vben.about'),\n    },\n    name: 'VbenAbout',\n    path: '/vben-admin/about',\n  },\n];\n\nexport default routes;\n"
  },
  {
    "path": "hiauth-front/playground/src/store/auth.ts",
    "content": "import type { Recordable, UserInfo } from '@vben/types';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { LOGIN_PATH } from '@vben/constants';\nimport { preferences } from '@vben/preferences';\nimport { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';\n\nimport { notification } from 'ant-design-vue';\nimport { defineStore } from 'pinia';\n\nimport { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';\nimport { $t } from '#/locales';\n\nexport const useAuthStore = defineStore('auth', () => {\n  const accessStore = useAccessStore();\n  const userStore = useUserStore();\n  const router = useRouter();\n\n  const loginLoading = ref(false);\n\n  /**\n   * 异步处理登录操作\n   * Asynchronously handle the login process\n   * @param params 登录表单数据\n   * @param onSuccess 成功之后的回调函数\n   */\n  async function authLogin(\n    params: Recordable<any>,\n    onSuccess?: () => Promise<void> | void,\n  ) {\n    // 异步处理用户登录操作并获取 accessToken\n    let userInfo: null | UserInfo = null;\n    try {\n      loginLoading.value = true;\n      const { accessToken } = await loginApi(params);\n\n      // 如果成功获取到 accessToken\n      if (accessToken) {\n        accessStore.setAccessToken(accessToken);\n\n        // 获取用户信息并存储到 accessStore 中\n        const [fetchUserInfoResult, accessCodes] = await Promise.all([\n          fetchUserInfo(),\n          getAccessCodesApi(),\n        ]);\n\n        userInfo = fetchUserInfoResult;\n\n        userStore.setUserInfo(userInfo);\n        accessStore.setAccessCodes(accessCodes);\n\n        if (accessStore.loginExpired) {\n          accessStore.setLoginExpired(false);\n        } else {\n          onSuccess\n            ? await onSuccess?.()\n            : await router.push(\n                userInfo.homePath || preferences.app.defaultHomePath,\n              );\n        }\n\n        if (userInfo?.realName) {\n          notification.success({\n            description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,\n            duration: 3,\n            message: $t('authentication.loginSuccess'),\n          });\n        }\n      }\n    } finally {\n      loginLoading.value = false;\n    }\n\n    return {\n      userInfo,\n    };\n  }\n\n  async function logout(redirect: boolean = true) {\n    try {\n      await logoutApi();\n    } catch {\n      // 不做任何处理\n    }\n\n    resetAllStores();\n    accessStore.setLoginExpired(false);\n\n    // 回登录页带上当前路由地址\n    await router.replace({\n      path: LOGIN_PATH,\n      query: redirect\n        ? {\n            redirect: encodeURIComponent(router.currentRoute.value.fullPath),\n          }\n        : {},\n    });\n  }\n\n  async function fetchUserInfo() {\n    let userInfo: null | UserInfo = null;\n    userInfo = await getUserInfoApi();\n    userStore.setUserInfo(userInfo);\n    return userInfo;\n  }\n\n  function $reset() {\n    loginLoading.value = false;\n  }\n\n  return {\n    $reset,\n    authLogin,\n    fetchUserInfo,\n    loginLoading,\n    logout,\n  };\n});\n"
  },
  {
    "path": "hiauth-front/playground/src/store/index.ts",
    "content": "export * from './auth';\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/README.md",
    "content": "# \\_core\n\n此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/about/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { About } from '@vben/common-ui';\n\ndefineOptions({ name: 'About' });\n</script>\n\n<template>\n  <About />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/authentication/code-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, ref, useTemplateRef } from 'vue';\n\nimport { AuthenticationCodeLogin, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { message } from 'ant-design-vue';\n\ndefineOptions({ name: 'CodeLogin' });\n\nconst loading = ref(false);\nconst CODE_LENGTH = 6;\nconst loginRef =\n  useTemplateRef<InstanceType<typeof AuthenticationCodeLogin>>('loginRef');\nfunction sendCodeApi(phoneNumber: string) {\n  message.loading({\n    content: $t('page.auth.sendingCode'),\n    duration: 0,\n    key: 'sending-code',\n  });\n  return new Promise((resolve) => {\n    setTimeout(() => {\n      message.success({\n        content: $t('page.auth.codeSentTo', [phoneNumber]),\n        duration: 3,\n        key: 'sending-code',\n      });\n      resolve({ code: '123456', phoneNumber });\n    }, 3000);\n  });\n}\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.mobile'),\n      },\n      fieldName: 'phoneNumber',\n      label: $t('authentication.mobile'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.mobileTip') })\n        .refine((v) => /^\\d{11}$/.test(v), {\n          message: $t('authentication.mobileErrortip'),\n        }),\n    },\n    {\n      component: 'VbenPinInput',\n      componentProps: {\n        codeLength: CODE_LENGTH,\n        createText: (countdown: number) => {\n          const text =\n            countdown > 0\n              ? $t('authentication.sendText', [countdown])\n              : $t('authentication.sendCode');\n          return text;\n        },\n        handleSendCode: async () => {\n          // 模拟发送验证码\n          // Simulate sending verification code\n          loading.value = true;\n          const formApi = loginRef.value?.getFormApi();\n          if (!formApi) {\n            loading.value = false;\n            throw new Error('formApi is not ready');\n          }\n          await formApi.validateField('phoneNumber');\n          const isPhoneReady = await formApi.isFieldValid('phoneNumber');\n          if (!isPhoneReady) {\n            loading.value = false;\n            throw new Error('Phone number is not Ready');\n          }\n          const { phoneNumber } = await formApi.getValues();\n          await sendCodeApi(phoneNumber);\n          loading.value = false;\n        },\n        placeholder: $t('authentication.code'),\n      },\n      fieldName: 'code',\n      label: $t('authentication.code'),\n      rules: z.string().length(CODE_LENGTH, {\n        message: $t('authentication.codeTip', [CODE_LENGTH]),\n      }),\n    },\n  ];\n});\n/**\n * 异步处理登录操作\n * Asynchronously handle the login process\n * @param values 登录表单数据\n */\nasync function handleLogin(values: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log(values);\n}\n</script>\n\n<template>\n  <AuthenticationCodeLogin\n    ref=\"loginRef\"\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleLogin\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/authentication/forget-password.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\n\nimport { computed, ref } from 'vue';\n\nimport { AuthenticationForgetPassword, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'ForgetPassword' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: 'example@example.com',\n      },\n      fieldName: 'email',\n      label: $t('authentication.email'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.emailTip') })\n        .email($t('authentication.emailValidErrorTip')),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Record<string, any>) {\n  // eslint-disable-next-line no-console\n  console.log('reset email:', value);\n}\n</script>\n\n<template>\n  <AuthenticationForgetPassword\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/authentication/login.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { BasicOption, Recordable } from '@vben/types';\n\nimport { computed, markRaw, useTemplateRef } from 'vue';\n\nimport { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\nimport { useAuthStore } from '#/store';\n\ndefineOptions({ name: 'Login' });\n\nconst authStore = useAuthStore();\n\nconst MOCK_USER_OPTIONS: BasicOption[] = [\n  {\n    label: 'Super',\n    value: 'vben',\n  },\n  {\n    label: 'Admin',\n    value: 'admin',\n  },\n  {\n    label: 'User',\n    value: 'jack',\n  },\n];\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenSelect',\n      // componentProps(_values, form) {\n      //   return {\n      //     'onUpdate:modelValue': (value: string) => {\n      //       const findItem = MOCK_USER_OPTIONS.find(\n      //         (item) => item.value === value,\n      //       );\n      //       if (findItem) {\n      //         form.setValues({\n      //           password: '123456',\n      //           username: findItem.label,\n      //         });\n      //       }\n      //     },\n      //     options: MOCK_USER_OPTIONS,\n      //     placeholder: $t('authentication.selectAccount'),\n      //   };\n      // },\n      componentProps: {\n        options: MOCK_USER_OPTIONS,\n        placeholder: $t('authentication.selectAccount'),\n      },\n      fieldName: 'selectAccount',\n      label: $t('authentication.selectAccount'),\n      rules: z\n        .string()\n        .min(1, { message: $t('authentication.selectAccount') })\n        .optional()\n        .default('vben'),\n    },\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.usernameTip'),\n      },\n      dependencies: {\n        trigger(values, form) {\n          if (values.selectAccount) {\n            const findUser = MOCK_USER_OPTIONS.find(\n              (item) => item.value === values.selectAccount,\n            );\n            if (findUser) {\n              form.setValues({\n                password: '123456',\n                username: findUser.value,\n              });\n            }\n          }\n        },\n        triggerFields: ['selectAccount'],\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: markRaw(SliderCaptcha),\n      fieldName: 'captcha',\n      rules: z.boolean().refine((value) => value, {\n        message: $t('authentication.verifyRequiredTip'),\n      }),\n    },\n  ];\n});\n\nconst loginRef =\n  useTemplateRef<InstanceType<typeof AuthenticationLogin>>('loginRef');\n\nasync function onSubmit(params: Recordable<any>) {\n  authStore.authLogin(params).catch(() => {\n    // 登陆失败，刷新验证码的演示\n    const formApi = loginRef.value?.getFormApi();\n    // 重置验证码组件的值\n    formApi?.setFieldValue('captcha', false, false);\n    // 使用表单API获取验证码组件实例，并调用其resume方法来重置验证码\n    formApi\n      ?.getFieldComponentRef<InstanceType<typeof SliderCaptcha>>('captcha')\n      ?.resume();\n  });\n}\n</script>\n\n<template>\n  <AuthenticationLogin\n    ref=\"loginRef\"\n    :form-schema=\"formSchema\"\n    :loading=\"authStore.loginLoading\"\n    @submit=\"onSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/authentication/qrcode-login.vue",
    "content": "<script lang=\"ts\" setup>\nimport { AuthenticationQrCodeLogin } from '@vben/common-ui';\nimport { LOGIN_PATH } from '@vben/constants';\n\ndefineOptions({ name: 'QrCodeLogin' });\n</script>\n\n<template>\n  <AuthenticationQrCodeLogin :login-path=\"LOGIN_PATH\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/authentication/register.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormSchema } from '@vben/common-ui';\nimport type { Recordable } from '@vben/types';\n\nimport { computed, h, ref } from 'vue';\n\nimport { AuthenticationRegister, z } from '@vben/common-ui';\nimport { $t } from '@vben/locales';\n\ndefineOptions({ name: 'Register' });\n\nconst loading = ref(false);\n\nconst formSchema = computed((): VbenFormSchema[] => {\n  return [\n    {\n      component: 'VbenInput',\n      componentProps: {\n        placeholder: $t('authentication.usernameTip'),\n      },\n      fieldName: 'username',\n      label: $t('authentication.username'),\n      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        passwordStrength: true,\n        placeholder: $t('authentication.password'),\n      },\n      fieldName: 'password',\n      label: $t('authentication.password'),\n      renderComponentContent() {\n        return {\n          strengthText: () => $t('authentication.passwordStrength'),\n        };\n      },\n      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),\n    },\n    {\n      component: 'VbenInputPassword',\n      componentProps: {\n        placeholder: $t('authentication.confirmPassword'),\n      },\n      dependencies: {\n        rules(values) {\n          const { password } = values;\n          return z\n            .string({ required_error: $t('authentication.passwordTip') })\n            .min(1, { message: $t('authentication.passwordTip') })\n            .refine((value) => value === password, {\n              message: $t('authentication.confirmPasswordTip'),\n            });\n        },\n        triggerFields: ['password'],\n      },\n      fieldName: 'confirmPassword',\n      label: $t('authentication.confirmPassword'),\n    },\n    {\n      component: 'VbenCheckbox',\n      fieldName: 'agreePolicy',\n      renderComponentContent: () => ({\n        default: () =>\n          h('span', [\n            $t('authentication.agree'),\n            h(\n              'a',\n              {\n                class: 'vben-link ml-1 ',\n                href: '',\n              },\n              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,\n            ),\n          ]),\n      }),\n      rules: z.boolean().refine((value) => !!value, {\n        message: $t('authentication.agreeTip'),\n      }),\n    },\n  ];\n});\n\nfunction handleSubmit(value: Recordable<any>) {\n  // eslint-disable-next-line no-console\n  console.log('register submit:', value);\n}\n</script>\n\n<template>\n  <AuthenticationRegister\n    :form-schema=\"formSchema\"\n    :loading=\"loading\"\n    @submit=\"handleSubmit\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/fallback/coming-soon.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/fallback/forbidden.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback403Demo' });\n</script>\n\n<template>\n  <Fallback status=\"403\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/fallback/internal-error.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback500Demo' });\n</script>\n\n<template>\n  <Fallback status=\"500\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/fallback/not-found.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'Fallback404Demo' });\n</script>\n\n<template>\n  <Fallback status=\"404\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/_core/fallback/offline.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n\ndefineOptions({ name: 'FallbackOfflineDemo' });\n</script>\n\n<template>\n  <Fallback status=\"offline\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/dashboard/analytics/analytics-trends.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        areaStyle: {},\n        data: [\n          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,\n          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,\n          111,\n        ],\n        itemStyle: {\n          color: '#5ab1ef',\n        },\n        smooth: true,\n        type: 'line',\n      },\n      {\n        areaStyle: {},\n        data: [\n          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,\n          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,\n        ],\n        itemStyle: {\n          color: '#019680',\n        },\n        smooth: true,\n        type: 'line',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          color: '#019680',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    // xAxis: {\n    //   axisTick: {\n    //     show: false,\n    //   },\n    //   boundaryGap: false,\n    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n    //   type: 'category',\n    // },\n    xAxis: {\n      axisTick: {\n        show: false,\n      },\n      boundaryGap: false,\n      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),\n      splitLine: {\n        lineStyle: {\n          type: 'solid',\n          width: 1,\n        },\n        show: true,\n      },\n      type: 'category',\n    },\n    yAxis: [\n      {\n        axisTick: {\n          show: false,\n        },\n        max: 80_000,\n        splitArea: {\n          show: true,\n        },\n        splitNumber: 4,\n        type: 'value',\n      },\n    ],\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/dashboard/analytics/analytics-visits-data.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: 0,\n      data: ['访问', '趋势'],\n    },\n    radar: {\n      indicator: [\n        {\n          name: '网页',\n        },\n        {\n          name: '移动端',\n        },\n        {\n          name: 'Ipad',\n        },\n        {\n          name: '客户端',\n        },\n        {\n          name: '第三方',\n        },\n        {\n          name: '其它',\n        },\n      ],\n      radius: '60%',\n      splitNumber: 8,\n    },\n    series: [\n      {\n        areaStyle: {\n          opacity: 1,\n          shadowBlur: 0,\n          shadowColor: 'rgba(0,0,0,.2)',\n          shadowOffsetX: 0,\n          shadowOffsetY: 10,\n        },\n        data: [\n          {\n            itemStyle: {\n              color: '#b6a2de',\n            },\n            name: '访问',\n            value: [90, 50, 86, 40, 50, 20],\n          },\n          {\n            itemStyle: {\n              color: '#5ab1ef',\n            },\n            name: '趋势',\n            value: [70, 75, 70, 76, 20, 85],\n          },\n        ],\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        symbolSize: 0,\n        type: 'radar',\n      },\n    ],\n    tooltip: {},\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/dashboard/analytics/analytics-visits-sales.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 400;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        center: ['50%', '50%'],\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '外包', value: 500 },\n          { name: '定制', value: 310 },\n          { name: '技术支持', value: 274 },\n          { name: '远程', value: 400 },\n        ].sort((a, b) => {\n          return a.value - b.value;\n        }),\n        name: '商业占比',\n        radius: '80%',\n        roseType: 'radius',\n        type: 'pie',\n      },\n    ],\n\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/dashboard/analytics/analytics-visits-source.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    legend: {\n      bottom: '2%',\n      left: 'center',\n    },\n    series: [\n      {\n        animationDelay() {\n          return Math.random() * 100;\n        },\n        animationEasing: 'exponentialInOut',\n        animationType: 'scale',\n        avoidLabelOverlap: false,\n        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],\n        data: [\n          { name: '搜索引擎', value: 1048 },\n          { name: '直接访问', value: 735 },\n          { name: '邮件营销', value: 580 },\n          { name: '联盟广告', value: 484 },\n        ],\n        emphasis: {\n          label: {\n            fontSize: '12',\n            fontWeight: 'bold',\n            show: true,\n          },\n        },\n        itemStyle: {\n          // borderColor: '#fff',\n          borderRadius: 10,\n          borderWidth: 2,\n        },\n        label: {\n          position: 'center',\n          show: false,\n        },\n        labelLine: {\n          show: false,\n        },\n        name: '访问来源',\n        radius: ['40%', '65%'],\n        type: 'pie',\n      },\n    ],\n    tooltip: {\n      trigger: 'item',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/dashboard/analytics/analytics-visits.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { EchartsUIType } from '@vben/plugins/echarts';\n\nimport { onMounted, ref } from 'vue';\n\nimport { EchartsUI, useEcharts } from '@vben/plugins/echarts';\n\nconst chartRef = ref<EchartsUIType>();\nconst { renderEcharts } = useEcharts(chartRef);\n\nonMounted(() => {\n  renderEcharts({\n    grid: {\n      bottom: 0,\n      containLabel: true,\n      left: '1%',\n      right: '1%',\n      top: '2 %',\n    },\n    series: [\n      {\n        barMaxWidth: 80,\n        // color: '#4f69fd',\n        data: [\n          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,\n          3200, 4800,\n        ],\n        type: 'bar',\n      },\n    ],\n    tooltip: {\n      axisPointer: {\n        lineStyle: {\n          // color: '#4f69fd',\n          width: 1,\n        },\n      },\n      trigger: 'axis',\n    },\n    xAxis: {\n      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}月`),\n      type: 'category',\n    },\n    yAxis: {\n      max: 8000,\n      splitNumber: 4,\n      type: 'value',\n    },\n  });\n});\n</script>\n\n<template>\n  <EchartsUI ref=\"chartRef\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/dashboard/analytics/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { AnalysisOverviewItem } from '@vben/common-ui';\nimport type { TabOption } from '@vben/types';\n\nimport {\n  AnalysisChartCard,\n  AnalysisChartsTabs,\n  AnalysisOverview,\n} from '@vben/common-ui';\nimport {\n  SvgBellIcon,\n  SvgCakeIcon,\n  SvgCardIcon,\n  SvgDownloadIcon,\n} from '@vben/icons';\n\nimport AnalyticsTrends from './analytics-trends.vue';\nimport AnalyticsVisitsData from './analytics-visits-data.vue';\nimport AnalyticsVisitsSales from './analytics-visits-sales.vue';\nimport AnalyticsVisitsSource from './analytics-visits-source.vue';\nimport AnalyticsVisits from './analytics-visits.vue';\n\nconst overviewItems: AnalysisOverviewItem[] = [\n  {\n    icon: SvgCardIcon,\n    title: '用户量',\n    totalTitle: '总用户量',\n    totalValue: 120_000,\n    value: 2000,\n  },\n  {\n    icon: SvgCakeIcon,\n    title: '访问量',\n    totalTitle: '总访问量',\n    totalValue: 500_000,\n    value: 20_000,\n  },\n  {\n    icon: SvgDownloadIcon,\n    title: '下载量',\n    totalTitle: '总下载量',\n    totalValue: 120_000,\n    value: 8000,\n  },\n  {\n    icon: SvgBellIcon,\n    title: '使用量',\n    totalTitle: '总使用量',\n    totalValue: 50_000,\n    value: 5000,\n  },\n];\n\nconst chartTabs: TabOption[] = [\n  {\n    label: '流量趋势',\n    value: 'trends',\n  },\n  {\n    label: '月访问量',\n    value: 'visits',\n  },\n];\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <AnalysisOverview :items=\"overviewItems\" />\n    <AnalysisChartsTabs :tabs=\"chartTabs\" class=\"mt-5\">\n      <template #trends>\n        <AnalyticsTrends />\n      </template>\n      <template #visits>\n        <AnalyticsVisits />\n      </template>\n    </AnalysisChartsTabs>\n\n    <div class=\"mt-5 w-full md:flex\">\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问数量\">\n        <AnalyticsVisitsData />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mr-4 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSource />\n      </AnalysisChartCard>\n      <AnalysisChartCard class=\"mt-5 md:mt-0 md:w-1/3\" title=\"访问来源\">\n        <AnalyticsVisitsSales />\n      </AnalysisChartCard>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/dashboard/workspace/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  WorkbenchProjectItem,\n  WorkbenchQuickNavItem,\n  WorkbenchTodoItem,\n  WorkbenchTrendItem,\n} from '@vben/common-ui';\n\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport {\n  AnalysisChartCard,\n  WorkbenchHeader,\n  WorkbenchProject,\n  WorkbenchQuickNav,\n  WorkbenchTodo,\n  WorkbenchTrends,\n} from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { useUserStore } from '@vben/stores';\nimport { openWindow } from '@vben/utils';\n\nimport AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';\n\nconst userStore = useUserStore();\n\n// 这是一个示例数据，实际项目中需要根据实际情况进行调整\n// url 也可以是内部路由，在 navTo 方法中识别处理，进行内部跳转\n// 例如：url: /dashboard/workspace\nconst projectItems: WorkbenchProjectItem[] = [\n  {\n    color: '',\n    content: '不要等待机会，而要创造机会。',\n    date: '2021-04-01',\n    group: '开源组',\n    icon: 'carbon:logo-github',\n    title: 'Github',\n    url: 'https://github.com',\n  },\n  {\n    color: '#3fb27f',\n    content: '现在的你决定将来的你。',\n    date: '2021-04-01',\n    group: '算法组',\n    icon: 'ion:logo-vue',\n    title: 'Vue',\n    url: 'https://vuejs.org',\n  },\n  {\n    color: '#e18525',\n    content: '没有什么才能比努力更重要。',\n    date: '2021-04-01',\n    group: '上班摸鱼',\n    icon: 'ion:logo-html5',\n    title: 'Html5',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',\n  },\n  {\n    color: '#bf0c2c',\n    content: '热情和欲望可以突破一切难关。',\n    date: '2021-04-01',\n    group: 'UI',\n    icon: 'ion:logo-angular',\n    title: 'Angular',\n    url: 'https://angular.io',\n  },\n  {\n    color: '#00d8ff',\n    content: '健康的身体是实现目标的基石。',\n    date: '2021-04-01',\n    group: '技术牛',\n    icon: 'bx:bxl-react',\n    title: 'React',\n    url: 'https://reactjs.org',\n  },\n  {\n    color: '#EBD94E',\n    content: '路是走出来的，而不是空想出来的。',\n    date: '2021-04-01',\n    group: '架构组',\n    icon: 'ion:logo-javascript',\n    title: 'Js',\n    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',\n  },\n];\n\n// 同样，这里的 url 也可以使用以 http 开头的外部链接\nconst quickNavItems: WorkbenchQuickNavItem[] = [\n  {\n    color: '#1fdaca',\n    icon: 'ion:home-outline',\n    title: '首页',\n    url: '/',\n  },\n  {\n    color: '#bf0c2c',\n    icon: 'ion:grid-outline',\n    title: '仪表盘',\n    url: '/dashboard',\n  },\n  {\n    color: '#e18525',\n    icon: 'ion:layers-outline',\n    title: '组件',\n    url: '/demos/features/icons',\n  },\n  {\n    color: '#3fb27f',\n    icon: 'ion:settings-outline',\n    title: '系统管理',\n    url: '/demos/features/login-expired', // 这里的 URL 是示例，实际项目中需要根据实际情况进行调整\n  },\n  {\n    color: '#4daf1bc9',\n    icon: 'ion:key-outline',\n    title: '权限管理',\n    url: '/demos/access/page-control',\n  },\n  {\n    color: '#00d8ff',\n    icon: 'ion:bar-chart-outline',\n    title: '图表',\n    url: '/analytics',\n  },\n];\n\nconst todoItems = ref<WorkbenchTodoItem[]>([\n  {\n    completed: false,\n    content: `审查最近提交到Git仓库的前端代码，确保代码质量和规范。`,\n    date: '2024-07-30 11:00:00',\n    title: '审查前端代码提交',\n  },\n  {\n    completed: true,\n    content: `检查并优化系统性能，降低CPU使用率。`,\n    date: '2024-07-30 11:00:00',\n    title: '系统性能优化',\n  },\n  {\n    completed: false,\n    content: `进行系统安全检查，确保没有安全漏洞或未授权的访问。 `,\n    date: '2024-07-30 11:00:00',\n    title: '安全检查',\n  },\n  {\n    completed: false,\n    content: `更新项目中的所有npm依赖包，确保使用最新版本。`,\n    date: '2024-07-30 11:00:00',\n    title: '更新项目依赖',\n  },\n  {\n    completed: false,\n    content: `修复用户报告的页面UI显示问题，确保在不同浏览器中显示一致。 `,\n    date: '2024-07-30 11:00:00',\n    title: '修复UI显示问题',\n  },\n]);\nconst trendItems: WorkbenchTrendItem[] = [\n  {\n    avatar: 'svg:avatar-1',\n    content: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,\n    date: '刚刚',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关注了 <a>威廉</a> `,\n    date: '1个小时前',\n    title: '艾文',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1天前',\n    title: '克里斯',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写一个Vite插件</a> `,\n    date: '2天前',\n    title: 'Vben',\n  },\n  {\n    avatar: 'svg:avatar-1',\n    content: `回复了 <a>杰克</a> 的问题 <a>如何进行项目优化？</a>`,\n    date: '3天前',\n    title: '皮特',\n  },\n  {\n    avatar: 'svg:avatar-2',\n    content: `关闭了问题 <a>如何运行项目</a> `,\n    date: '1周前',\n    title: '杰克',\n  },\n  {\n    avatar: 'svg:avatar-3',\n    content: `发布了 <a>个人动态</a> `,\n    date: '1周前',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `推送了代码到 <a>Github</a>`,\n    date: '2021-04-01 20:00',\n    title: '威廉',\n  },\n  {\n    avatar: 'svg:avatar-4',\n    content: `发表文章 <a>如何编写使用 Admin Vben</a> `,\n    date: '2021-03-01 20:00',\n    title: 'Vben',\n  },\n];\n\nconst router = useRouter();\n\n// 这是一个示例方法，实际项目中需要根据实际情况进行调整\n// This is a sample method, adjust according to the actual project requirements\nfunction navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {\n  if (nav.url?.startsWith('http')) {\n    openWindow(nav.url);\n    return;\n  }\n  if (nav.url?.startsWith('/')) {\n    router.push(nav.url).catch((error) => {\n      console.error('Navigation failed:', error);\n    });\n  } else {\n    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);\n  }\n}\n</script>\n\n<template>\n  <div class=\"p-5\">\n    <WorkbenchHeader\n      :avatar=\"userStore.userInfo?.avatar || preferences.app.defaultAvatar\"\n    >\n      <template #title>\n        早安, {{ userStore.userInfo?.realName }}, 开始您一天的工作吧！\n      </template>\n      <template #description> 今日晴，20℃ - 32℃！ </template>\n    </WorkbenchHeader>\n\n    <div class=\"mt-5 flex flex-col lg:flex-row\">\n      <div class=\"mr-4 w-full lg:w-3/5\">\n        <WorkbenchProject :items=\"projectItems\" title=\"项目\" @click=\"navTo\" />\n        <WorkbenchTrends :items=\"trendItems\" class=\"mt-5\" title=\"最新动态\" />\n      </div>\n      <div class=\"w-full lg:w-2/5\">\n        <WorkbenchQuickNav\n          :items=\"quickNavItems\"\n          class=\"mt-5 lg:mt-0\"\n          title=\"快捷导航\"\n          @click=\"navTo\"\n        />\n        <WorkbenchTodo :items=\"todoItems\" class=\"mt-5\" title=\"待办事项\" />\n        <AnalysisChartCard class=\"mt-5\" title=\"访问来源\">\n          <AnalyticsVisitsSource />\n        </AnalysisChartCard>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/access/admin-visible.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    description=\"当前页面仅 Admin 账号可见\"\n    status=\"coming-soon\"\n    title=\"页面访问测试\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/access/button-control.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Recordable } from '@vben/types';\n\nimport { useRouter } from 'vue-router';\n\nimport { AccessControl, useAccess } from '@vben/access';\nimport { Page } from '@vben/common-ui';\nimport { resetAllStores, useUserStore } from '@vben/stores';\n\nimport { Button, Card } from 'ant-design-vue';\n\nimport { useAuthStore } from '#/store';\n\nconst accounts: Record<string, Recordable<any>> = {\n  admin: {\n    password: '123456',\n    username: 'admin',\n  },\n  super: {\n    password: '123456',\n    username: 'vben',\n  },\n  user: {\n    password: '123456',\n    username: 'jack',\n  },\n};\n\nconst { accessMode, hasAccessByCodes } = useAccess();\nconst authStore = useAuthStore();\nconst userStore = useUserStore();\nconst router = useRouter();\n\nfunction roleButtonType(role: string) {\n  return userStore.userRoles.includes(role) ? 'primary' : 'default';\n}\n\nasync function changeAccount(role: string) {\n  if (userStore.userRoles.includes(role)) {\n    return;\n  }\n\n  const account = accounts[role];\n  resetAllStores();\n  if (account) {\n    await authStore.authLogin(account, async () => {\n      router.go(0);\n    });\n  }\n}\n</script>\n\n<template>\n  <Page\n    :title=\"`${accessMode === 'frontend' ? '前端' : '后端'}按钮访问权限演示`\"\n    description=\"切换不同的账号，观察按钮变化。\"\n  >\n    <Card class=\"mb-5\">\n      <template #title>\n        <span class=\"font-semibold\">当前角色:</span>\n        <span class=\"text-primary mx-4 text-lg\">\n          {{ userStore.userRoles?.[0] }}\n        </span>\n      </template>\n\n      <Button :type=\"roleButtonType('super')\" @click=\"changeAccount('super')\">\n        切换为 Super 账号\n      </Button>\n\n      <Button\n        :type=\"roleButtonType('admin')\"\n        class=\"mx-4\"\n        @click=\"changeAccount('admin')\"\n      >\n        切换为 Admin 账号\n      </Button>\n      <Button :type=\"roleButtonType('user')\" @click=\"changeAccount('user')\">\n        切换为 User 账号\n      </Button>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"组件形式控制 - 权限码\">\n      <AccessControl :codes=\"['AC_100100']\" type=\"code\">\n        <Button class=\"mr-4\"> Super 账号可见 [\"AC_100100\"] </Button>\n      </AccessControl>\n      <AccessControl :codes=\"['AC_100030']\" type=\"code\">\n        <Button class=\"mr-4\"> Admin 账号可见 [\"AC_100030\"] </Button>\n      </AccessControl>\n      <AccessControl :codes=\"['AC_1000001']\" type=\"code\">\n        <Button class=\"mr-4\"> User 账号可见 [\"AC_1000001\"] </Button>\n      </AccessControl>\n      <AccessControl :codes=\"['AC_100100', 'AC_100030']\" type=\"code\">\n        <Button class=\"mr-4\">\n          Super & Admin 账号可见 [\"AC_100100\",\"AC_100030\"]\n        </Button>\n      </AccessControl>\n    </Card>\n\n    <Card\n      v-if=\"accessMode === 'frontend'\"\n      class=\"mb-5\"\n      title=\"组件形式控制 - 角色\"\n    >\n      <AccessControl :codes=\"['super']\" type=\"role\">\n        <Button class=\"mr-4\"> Super 角色可见 </Button>\n      </AccessControl>\n      <AccessControl :codes=\"['admin']\" type=\"role\">\n        <Button class=\"mr-4\"> Admin 角色可见 </Button>\n      </AccessControl>\n      <AccessControl :codes=\"['user']\" type=\"role\">\n        <Button class=\"mr-4\"> User 角色可见 </Button>\n      </AccessControl>\n      <AccessControl :codes=\"['super', 'admin']\" type=\"role\">\n        <Button class=\"mr-4\"> Super & Admin 角色可见 </Button>\n      </AccessControl>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"函数形式控制\">\n      <Button v-if=\"hasAccessByCodes(['AC_100100'])\" class=\"mr-4\">\n        Super 账号可见 [\"AC_100100\"]\n      </Button>\n      <Button v-if=\"hasAccessByCodes(['AC_100030'])\" class=\"mr-4\">\n        Admin 账号可见 [\"AC_100030\"]\n      </Button>\n      <Button v-if=\"hasAccessByCodes(['AC_1000001'])\" class=\"mr-4\">\n        User 账号可见 [\"AC_1000001\"]\n      </Button>\n      <Button v-if=\"hasAccessByCodes(['AC_100100', 'AC_100030'])\" class=\"mr-4\">\n        Super & Admin 账号可见 [\"AC_100100\",\"AC_100030\"]\n      </Button>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"指令方式 - 权限码\">\n      <Button class=\"mr-4\" v-access:code=\"['AC_100100']\">\n        Super 账号可见 [\"AC_100100\"]\n      </Button>\n      <Button class=\"mr-4\" v-access:code=\"['AC_100030']\">\n        Admin 账号可见 [\"AC_100030\"]\n      </Button>\n      <Button class=\"mr-4\" v-access:code=\"['AC_1000001']\">\n        User 账号可见 [\"AC_1000001\"]\n      </Button>\n      <Button class=\"mr-4\" v-access:code=\"['AC_100100', 'AC_100030']\">\n        Super & Admin 账号可见 [\"AC_100100\",\"AC_100030\"]\n      </Button>\n    </Card>\n\n    <Card v-if=\"accessMode === 'frontend'\" class=\"mb-5\" title=\"指令方式 - 角色\">\n      <Button class=\"mr-4\" v-access:role=\"['super']\"> Super 角色可见 </Button>\n      <Button class=\"mr-4\" v-access:role=\"['admin']\"> Admin 角色可见 </Button>\n      <Button class=\"mr-4\" v-access:role=\"['user']\"> User 角色可见 </Button>\n      <Button class=\"mr-4\" v-access:role=\"['super', 'admin']\">\n        Super & Admin 角色可见\n      </Button>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/access/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Recordable } from '@vben/types';\n\nimport { useRouter } from 'vue-router';\n\nimport { useAccess } from '@vben/access';\nimport { Page } from '@vben/common-ui';\nimport { resetAllStores, useUserStore } from '@vben/stores';\n\nimport { Button, Card } from 'ant-design-vue';\n\nimport { useAuthStore } from '#/store';\n\nconst accounts: Record<string, Recordable<any>> = {\n  admin: {\n    password: '123456',\n    username: 'admin',\n  },\n  super: {\n    password: '123456',\n    username: 'vben',\n  },\n  user: {\n    password: '123456',\n    username: 'jack',\n  },\n};\n\nconst { accessMode, toggleAccessMode } = useAccess();\nconst userStore = useUserStore();\nconst accessStore = useAuthStore();\nconst router = useRouter();\n\nfunction roleButtonType(role: string) {\n  return userStore.userRoles.includes(role) ? 'primary' : 'default';\n}\n\nasync function changeAccount(role: string) {\n  if (userStore.userRoles.includes(role)) {\n    return;\n  }\n\n  const account = accounts[role];\n  resetAllStores();\n  if (account) {\n    await accessStore.authLogin(account, async () => {\n      router.go(0);\n    });\n  }\n}\n\nasync function handleToggleAccessMode() {\n  if (!accounts.super) {\n    return;\n  }\n  await toggleAccessMode();\n  resetAllStores();\n\n  await accessStore.authLogin(accounts.super, async () => {\n    setTimeout(() => {\n      router.go(0);\n    }, 150);\n  });\n}\n</script>\n\n<template>\n  <Page\n    :title=\"`${accessMode === 'frontend' ? '前端' : '后端'}页面访问权限演示`\"\n    description=\"切换不同的账号，观察左侧菜单变化。\"\n  >\n    <Card class=\"mb-5\" title=\"权限模式\">\n      <span class=\"font-semibold\">当前权限模式:</span>\n      <span class=\"text-primary mx-4\">{{\n        accessMode === 'frontend' ? '前端权限控制' : '后端权限控制'\n      }}</span>\n      <Button type=\"primary\" @click=\"handleToggleAccessMode\">\n        切换为{{ accessMode === 'frontend' ? '后端' : '前端' }}权限模式\n      </Button>\n    </Card>\n    <Card title=\"账号切换\">\n      <Button :type=\"roleButtonType('super')\" @click=\"changeAccount('super')\">\n        切换为 Super 账号\n      </Button>\n\n      <Button\n        :type=\"roleButtonType('admin')\"\n        class=\"mx-4\"\n        @click=\"changeAccount('admin')\"\n      >\n        切换为 Admin 账号\n      </Button>\n      <Button :type=\"roleButtonType('user')\" @click=\"changeAccount('user')\">\n        切换为 User 账号\n      </Button>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/access/menu-visible-403.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    description=\"当前页面用户不可见，会被重定向到403页面\"\n    status=\"coming-soon\"\n    title=\"页面访问测试\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/access/super-visible.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    description=\"当前页面仅 Super 账号可见\"\n    status=\"coming-soon\"\n    title=\"页面访问测试\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/access/user-visible.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    description=\"当前页面仅 User 账号可见\"\n    status=\"coming-soon\"\n    title=\"页面访问测试\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/active-icon/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    description=\"用于菜单激活显示不同的图标\"\n    status=\"coming-soon\"\n    title=\"激活图标示例\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/badge/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { reactive } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { Page } from '@vben/common-ui';\nimport { useAccessStore } from '@vben/stores';\n\nimport { MenuBadge } from '@vben-core/menu-ui';\n\nimport { Button, Card, Radio, RadioGroup } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst colors = [\n  { label: '预设：默认', value: 'default' },\n  { label: '预设：关键', value: 'destructive' },\n  { label: '预设：主要', value: 'primary' },\n  { label: '预设：成功', value: 'success' },\n  { label: '自定义', value: 'bg-gray-200 text-black' },\n];\n\nconst route = useRoute();\nconst accessStore = useAccessStore();\nconst menu = accessStore.getMenuByPath(route.path);\nconst badgeProps = reactive({\n  badge: menu?.badge as string,\n  badgeType: menu?.badge ? 'normal' : (menu?.badgeType as 'dot' | 'normal'),\n  badgeVariants: menu?.badgeVariants as string,\n});\n\nconst [Form] = useVbenForm({\n  handleValuesChange(values) {\n    badgeProps.badge = values.badge;\n    badgeProps.badgeType = values.badgeType;\n    badgeProps.badgeVariants = values.badgeVariants;\n  },\n  schema: [\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        buttonStyle: 'solid',\n        options: [\n          { label: '点徽标', value: 'dot' },\n          { label: '文字徽标', value: 'normal' },\n        ],\n        optionType: 'button',\n      },\n      defaultValue: badgeProps.badgeType,\n      fieldName: 'badgeType',\n      label: '类型',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        maxLength: 4,\n        placeholder: '请输入徽标内容',\n        style: { width: '200px' },\n      },\n      defaultValue: badgeProps.badge,\n      fieldName: 'badge',\n      label: '徽标内容',\n    },\n    {\n      component: 'RadioGroup',\n      defaultValue: badgeProps.badgeVariants,\n      fieldName: 'badgeVariants',\n      label: '颜色',\n    },\n    {\n      component: 'Input',\n      fieldName: 'action',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nfunction updateMenuBadge() {\n  if (menu) {\n    menu.badge = badgeProps.badge;\n    menu.badgeType = badgeProps.badgeType;\n    menu.badgeVariants = badgeProps.badgeVariants;\n  }\n}\n</script>\n\n<template>\n  <Page\n    description=\"菜单项上可以显示徽标，这些徽标可以主动更新\"\n    title=\"菜单徽标\"\n  >\n    <Card title=\"徽标更新\">\n      <Form>\n        <template #badgeVariants=\"slotProps\">\n          <RadioGroup v-bind=\"slotProps\">\n            <Radio\n              v-for=\"color in colors\"\n              :key=\"color.value\"\n              :value=\"color.value\"\n            >\n              <div\n                :title=\"color.label\"\n                class=\"flex h-[14px] w-[50px] items-center justify-start\"\n              >\n                <MenuBadge\n                  v-bind=\"{ ...badgeProps, badgeVariants: color.value }\"\n                />\n              </div>\n            </Radio>\n          </RadioGroup>\n        </template>\n        <template #action>\n          <Button type=\"primary\" @click=\"updateMenuBadge\">更新徽标</Button>\n        </template>\n      </Form>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/breadcrumb/lateral-detail.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useRouter } from 'vue-router';\n\nimport { Fallback } from '@vben/common-ui';\n\nimport { Button } from 'ant-design-vue';\n\nconst router = useRouter();\n</script>\n\n<template>\n  <Fallback\n    description=\"面包屑导航-平级模式-详情页\"\n    status=\"coming-soon\"\n    title=\"注意观察面包屑导航变化\"\n  >\n    <template #action>\n      <Button @click=\"router.go(-1)\">返回</Button>\n    </template>\n  </Fallback>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/breadcrumb/lateral.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useRouter } from 'vue-router';\n\nimport { Fallback } from '@vben/common-ui';\n\nimport { Button } from 'ant-design-vue';\n\nconst router = useRouter();\n\nfunction details() {\n  router.push({ name: 'BreadcrumbLateralDetailDemo' });\n}\n</script>\n\n<template>\n  <Fallback\n    description=\"点击查看详情，并观察面包屑导航变化\"\n    status=\"coming-soon\"\n    title=\"面包屑导航-平级模式\"\n  >\n    <template #action>\n      <Button type=\"primary\" @click=\"details\">点击查看详情</Button>\n    </template>\n  </Fallback>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/breadcrumb/level-detail.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    description=\"面包屑导航-层级模式-详情页\"\n    status=\"coming-soon\"\n    title=\"注意观察面包屑导航变化\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/clipboard/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { useClipboard } from '@vueuse/core';\nimport { Button, Card, Input } from 'ant-design-vue';\n\nconst source = ref('Hello');\nconst { copy, text } = useClipboard({ legacy: true, source });\n</script>\n\n<template>\n  <Page title=\"剪切板示例\">\n    <Card title=\"基本使用\">\n      <p class=\"mb-3\">\n        Current copied: <code>{{ text || 'none' }}</code>\n      </p>\n      <div class=\"flex\">\n        <Input v-model:value=\"source\" class=\"mr-3 flex w-[200px]\" />\n        <Button type=\"primary\" @click=\"copy(source)\"> Copy </Button>\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/file-download/base64.ts",
    "content": "export default `data:image/png;base64,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`;\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/file-download/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\nimport {\n  downloadFileFromBase64,\n  downloadFileFromBlobPart,\n  downloadFileFromImageUrl,\n  downloadFileFromUrl,\n} from '@vben/utils';\n\nimport { Button, Card } from 'ant-design-vue';\n\nimport { downloadFile1, downloadFile2 } from '#/api/examples/download';\n\nimport imageBase64 from './base64';\n\nconst downloadResult = ref('');\n\nfunction getBlob() {\n  downloadFile1().then((res) => {\n    downloadResult.value = `获取Blob成功，长度：${res.size}`;\n  });\n}\n\nfunction getResponse() {\n  downloadFile2().then((res) => {\n    downloadResult.value = `获取Response成功，headers：${JSON.stringify(res.headers)},长度：${res.data.size}`;\n  });\n}\n</script>\n\n<template>\n  <Page title=\"文件下载示例\">\n    <Card title=\"根据文件地址下载文件\">\n      <Button\n        type=\"primary\"\n        @click=\"\n          downloadFileFromUrl({\n            source:\n              'https://codeload.github.com/vbenjs/vue-vben-admin-doc/zip/main',\n            target: '_self',\n          })\n        \"\n      >\n        Download File\n      </Button>\n    </Card>\n\n    <Card class=\"my-5\" title=\"根据地址下载图片\">\n      <Button\n        type=\"primary\"\n        @click=\"\n          downloadFileFromImageUrl({\n            source:\n              'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n            fileName: 'vben-logo.png',\n          })\n        \"\n      >\n        Download File\n      </Button>\n    </Card>\n\n    <Card class=\"my-5\" title=\"base64流下载\">\n      <Button\n        type=\"primary\"\n        @click=\"\n          downloadFileFromBase64({\n            source: imageBase64,\n            fileName: 'image.png',\n          })\n        \"\n      >\n        Download Image\n      </Button>\n    </Card>\n    <Card class=\"my-5\" title=\"文本下载\">\n      <Button\n        type=\"primary\"\n        @click=\"\n          downloadFileFromBlobPart({\n            source: 'text content',\n            fileName: 'test.txt',\n          })\n        \"\n      >\n        Download TxT\n      </Button>\n    </Card>\n\n    <Card class=\"my-5\" title=\"Request download\">\n      <Button type=\"primary\" @click=\"getBlob\"> 获取Blob </Button>\n      <Button type=\"primary\" class=\"ml-4\" @click=\"getResponse\">\n        获取Response\n      </Button>\n      <div class=\"mt-4\">{{ downloadResult }}</div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/full-screen/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { useFullscreen } from '@vueuse/core';\nimport { Button, Card } from 'ant-design-vue';\n\nconst domRef = ref<HTMLElement>();\n\nconst { enter, exit, isFullscreen, toggle } = useFullscreen();\n\nconst { isFullscreen: isDomFullscreen, toggle: toggleDom } =\n  useFullscreen(domRef);\n</script>\n\n<template>\n  <Page title=\"全屏示例\">\n    <Card title=\"Window Full Screen\">\n      <div class=\"flex flex-wrap items-center gap-4\">\n        <Button :disabled=\"isFullscreen\" type=\"primary\" @click=\"enter\">\n          Enter Window Full Screen\n        </Button>\n        <Button @click=\"toggle\"> Toggle Window Full Screen </Button>\n\n        <Button :disabled=\"!isFullscreen\" danger @click=\"exit\">\n          Exit Window Full Screen\n        </Button>\n\n        <span class=\"text-nowrap\"> Current State: {{ isFullscreen }} </span>\n      </div>\n    </Card>\n\n    <Card class=\"mt-5\" title=\"Dom Full Screen\">\n      <Button type=\"primary\" @click=\"toggleDom\"> Enter Dom Full Screen </Button>\n    </Card>\n\n    <div\n      ref=\"domRef\"\n      class=\"mx-auto mt-10 flex h-64 w-1/2 items-center justify-center rounded-md bg-yellow-400\"\n    >\n      <Button class=\"mr-2\" type=\"primary\" @click=\"toggleDom\">\n        {{ isDomFullscreen ? 'Exit Dom Full Screen' : 'Enter Dom Full Screen' }}\n      </Button>\n    </div>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/hide-menu-children/children.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback, VbenButton } from '@vben/common-ui';\nimport { useTabs } from '@vben/hooks';\nimport { X } from '@vben/icons';\n\nconst { closeCurrentTab } = useTabs();\n</script>\n\n<template>\n  <Fallback\n    description=\"当前路由在菜单中不可见\"\n    status=\"coming-soon\"\n    title=\"被隐藏的子菜单\"\n    show-back\n  >\n    <template #action>\n      <VbenButton size=\"lg\" @click=\"closeCurrentTab()\">\n        <X class=\"mr-2 size-4\" />\n        关闭当前标签页\n      </VbenButton>\n    </template>\n  </Fallback>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/hide-menu-children/parent.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    :description=\"`当前路由：${String($route.name)}，子菜单不可见`\"\n    status=\"coming-soon\"\n    title=\"隐藏子菜单\"\n  >\n    <template #action>\n      <RouterLink to=\"/demos/features/hide-menu-children/children\">\n        打开子路由\n      </RouterLink>\n    </template>\n  </Fallback>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/icons/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h, ref } from 'vue';\n\nimport { IconPicker, Page } from '@vben/common-ui';\nimport {\n  MdiKeyboardEsc,\n  SvgAvatar1Icon,\n  SvgAvatar2Icon,\n  SvgAvatar3Icon,\n  SvgAvatar4Icon,\n  SvgBellIcon,\n  SvgCakeIcon,\n  SvgCardIcon,\n  SvgDownloadIcon,\n  SvgGithubIcon,\n  SvgGoogleIcon,\n  SvgQQChatIcon,\n  SvgWeChatIcon,\n} from '@vben/icons';\n\nimport { Card, Input } from 'ant-design-vue';\n\nconst iconValue1 = ref('ant-design:trademark-outlined');\nconst iconValue2 = ref('svg:avatar-1');\nconst iconValue3 = ref('mdi:alien-outline');\nconst iconValue4 = ref('mdi-light:book-multiple');\n\nconst inputComponent = h(Input);\n</script>\n\n<template>\n  <Page title=\"图标\">\n    <template #description>\n      <div class=\"text-foreground/80 mt-2\">\n        图标可在\n        <a\n          class=\"text-primary\"\n          href=\"https://icon-sets.iconify.design/\"\n          target=\"_blank\"\n        >\n          Iconify\n        </a>\n        中查找，支持多种图标库，如 Material Design, Font Awesome, Jam Icons 等。\n      </div>\n    </template>\n\n    <Card class=\"mb-5\" title=\"Iconify\">\n      <div class=\"flex items-center gap-5\">\n        <SvgGithubIcon class=\"size-8\" />\n        <SvgGoogleIcon class=\"size-8\" />\n        <SvgQQChatIcon class=\"size-8\" />\n        <SvgWeChatIcon class=\"size-8\" />\n        <MdiKeyboardEsc class=\"size-8\" />\n      </div>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"Svg Icons\">\n      <div class=\"flex items-center gap-5\">\n        <SvgAvatar1Icon class=\"size-8\" />\n        <SvgAvatar2Icon class=\"size-8 text-red-500\" />\n        <SvgAvatar3Icon class=\"size-8 text-green-500\" />\n        <SvgAvatar4Icon class=\"size-8\" />\n        <SvgCakeIcon class=\"size-8\" />\n        <SvgBellIcon class=\"size-8\" />\n        <SvgCardIcon class=\"size-8\" />\n        <SvgDownloadIcon class=\"size-8\" />\n      </div>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"Tailwind CSS\">\n      <div class=\"flex items-center gap-5 text-3xl\">\n        <span class=\"icon-[ant-design--alipay-circle-outlined]\"></span>\n        <span class=\"icon-[ant-design--account-book-filled]\"></span>\n        <span class=\"icon-[ant-design--container-outlined]\"></span>\n        <span class=\"icon-[svg-spinners--wind-toy]\"></span>\n        <span class=\"icon-[svg-spinners--blocks-wave]\"></span>\n        <span class=\"icon-[line-md--compass-filled-loop]\"></span>\n      </div>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"图标选择器\">\n      <div class=\"mb-5 flex items-center gap-5\">\n        <span>原始样式(Iconify):</span>\n        <IconPicker v-model=\"iconValue1\" class=\"w-[200px]\" />\n      </div>\n      <div class=\"mb-5 flex items-center gap-5\">\n        <span>原始样式(svg):</span>\n        <IconPicker v-model=\"iconValue2\" class=\"w-[200px]\" prefix=\"svg\" />\n      </div>\n      <div class=\"mb-5 flex items-center gap-5\">\n        <span>自定义Input:</span>\n        <IconPicker\n          :input-component=\"inputComponent\"\n          v-model=\"iconValue3\"\n          icon-slot=\"addonAfter\"\n          model-value-prop=\"value\"\n          prefix=\"mdi\"\n        />\n      </div>\n      <div class=\"flex items-center gap-5\">\n        <span>显示为一个Icon:</span>\n        <Input\n          v-model:value=\"iconValue4\"\n          allow-clear\n          placeholder=\"点击这里选择图标\"\n          style=\"width: 300px\"\n        >\n          <template #addonAfter>\n            <IconPicker v-model=\"iconValue4\" prefix=\"mdi-light\" type=\"icon\" />\n          </template>\n        </Input>\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/json-bigint/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Alert, Button, Card } from 'ant-design-vue';\n\nimport { getBigIntData } from '#/api/examples/json-bigint';\n\nconst response = ref('');\nfunction fetchData() {\n  getBigIntData().then((res) => {\n    response.value = res;\n  });\n}\n</script>\n<template>\n  <Page\n    title=\"JSON BigInt Support\"\n    description=\"解析后端返回的长整数（long/bigInt）。代码位置：playground/src/api/request.ts中的transformResponse\"\n  >\n    <Card>\n      <Alert>\n        <template #message>\n          有些后端接口返回的ID是长整数，但javascript原生的JSON解析是不支持超过2^53-1的长整数的。\n          这种情况可以建议后端返回数据前将长整数转换为字符串类型。如果后端不接受我们的建议😡……\n          <br />\n          下面的按钮点击后会发起请求，接口返回的JSON数据中的id字段是超出整数范围的数字，已自动将其解析为字符串\n        </template>\n      </Alert>\n      <Button class=\"mt-4\" type=\"primary\" @click=\"fetchData\">发起请求</Button>\n      <div>\n        <pre>\n        {{ response }}\n        </pre>\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/login-expired/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { LoginExpiredModeType } from '@vben/types';\n\nimport { Page } from '@vben/common-ui';\nimport { preferences, updatePreferences } from '@vben/preferences';\n\nimport { Button, Card } from 'ant-design-vue';\n\nimport { getMockStatusApi } from '#/api';\n\nasync function handleClick(type: LoginExpiredModeType) {\n  const loginExpiredMode = preferences.app.loginExpiredMode;\n\n  updatePreferences({ app: { loginExpiredMode: type } });\n  await getMockStatusApi('401');\n  updatePreferences({ app: { loginExpiredMode } });\n}\n</script>\n\n<template>\n  <Page title=\"登录过期演示\">\n    <template #description>\n      <div class=\"text-foreground/80 mt-2\">\n        接口请求遇到401状态码时，需要重新登录。有两种方式：\n        <p>1.转到登录页，登录成功后跳转回原页面</p>\n        <p>\n          2.弹出重新登录弹窗，登录后关闭弹窗，不进行任何页面跳转（刷新后还是会跳转登录页面）\n        </p>\n      </div>\n    </template>\n\n    <Card class=\"mb-5\" title=\"跳转登录页面方式\">\n      <Button type=\"primary\" @click=\"handleClick('page')\"> 点击触发 </Button>\n    </Card>\n    <Card class=\"mb-5\" title=\"登录弹窗方式\">\n      <Button type=\"primary\" @click=\"handleClick('modal')\"> 点击触发 </Button>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/menu-query/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    description=\"点击菜单，将会带上参数\"\n    status=\"coming-soon\"\n    title=\"菜单带参示例\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/new-window/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback\n    description=\"当前页面已在新窗口内打开\"\n    status=\"coming-soon\"\n    title=\"新窗口打开页面\"\n  />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/request-params-serializer/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed, ref, watchEffect } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Card, Radio, RadioGroup } from 'ant-design-vue';\n\nimport { getParamsData } from '#/api/examples/params';\n\nconst params = { ids: [2512, 3241, 4255] };\nconst paramsSerializer = ref<'brackets' | 'comma' | 'indices' | 'repeat'>(\n  'brackets',\n);\nconst response = ref('');\nconst paramsStr = computed(() => {\n  // 写一段代码，从完整的URL中提取参数部分\n  const url = response.value;\n  return new URL(url).searchParams.toString();\n});\n\nwatchEffect(() => {\n  getParamsData(params, paramsSerializer.value).then((res) => {\n    response.value = res.request.responseURL;\n  });\n});\n</script>\n<template>\n  <Page\n    title=\"请求参数序列化\"\n    description=\"不同的后台接口可能对数组类型的GET参数的解析方式不同，我们预置了几种数组序列化方式，通过配置 paramsSerializer 来实现不同的序列化方式\"\n  >\n    <Card>\n      <RadioGroup v-model:value=\"paramsSerializer\" name=\"paramsSerializer\">\n        <Radio value=\"brackets\">brackets</Radio>\n        <Radio value=\"comma\">comma</Radio>\n        <Radio value=\"indices\">indices</Radio>\n        <Radio value=\"repeat\">repeat</Radio>\n      </RadioGroup>\n      <div class=\"mt-4 flex flex-col gap-4\">\n        <div>\n          <h3>需要提交的参数</h3>\n          <div>{{ JSON.stringify(params, null, 2) }}</div>\n        </div>\n        <template v-if=\"response\">\n          <div>\n            <h3>访问地址</h3>\n            <pre>{{ response }}</pre>\n          </div>\n          <div>\n            <h3>参数字符串</h3>\n            <pre>{{ paramsStr }}</pre>\n          </div>\n          <div>\n            <h3>参数解码</h3>\n            <pre>{{ decodeURIComponent(paramsStr) }}</pre>\n          </div>\n        </template>\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/tabs/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\nimport { useRouter } from 'vue-router';\n\nimport { Page } from '@vben/common-ui';\nimport { useTabs } from '@vben/hooks';\n\nimport { Button, Card, Input } from 'ant-design-vue';\n\nconst router = useRouter();\nconst newTabTitle = ref('');\n\nconst {\n  closeAllTabs,\n  closeCurrentTab,\n  closeLeftTabs,\n  closeOtherTabs,\n  closeRightTabs,\n  closeTabByKey,\n  refreshTab,\n  resetTabTitle,\n  setTabTitle,\n} = useTabs();\n\nfunction openTab() {\n  // 这里就是路由跳转，也可以用path\n  router.push({ name: 'VbenAbout' });\n}\n\nfunction openTabWithParams(id: number) {\n  // 这里就是路由跳转，也可以用path\n  router.push({ name: 'FeatureTabDetailDemo', params: { id } });\n}\n\nfunction reset() {\n  newTabTitle.value = '';\n  resetTabTitle();\n}\n</script>\n\n<template>\n  <Page description=\"用于需要操作标签页的场景\" title=\"标签页\">\n    <Card class=\"mb-5\" title=\"打开/关闭标签页\">\n      <div class=\"text-foreground/80 mb-3\">\n        如果标签页存在，直接跳转切换。如果标签页不存在，则打开新的标签页。\n      </div>\n      <div class=\"flex flex-wrap gap-3\">\n        <Button type=\"primary\" @click=\"openTab\"> 打开 \"关于\" 标签页 </Button>\n        <Button type=\"primary\" @click=\"closeTabByKey('/vben-admin/about')\">\n          关闭 \"关于\" 标签页\n        </Button>\n      </div>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"标签页操作\">\n      <div class=\"text-foreground/80 mb-3\">用于动态控制标签页的各种操作</div>\n      <div class=\"flex flex-wrap gap-3\">\n        <Button type=\"primary\" @click=\"closeCurrentTab()\">\n          关闭当前标签页\n        </Button>\n        <Button type=\"primary\" @click=\"closeLeftTabs()\">\n          关闭左侧标签页\n        </Button>\n        <Button type=\"primary\" @click=\"closeRightTabs()\">\n          关闭右侧标签页\n        </Button>\n        <Button type=\"primary\" @click=\"closeAllTabs()\"> 关闭所有标签页 </Button>\n        <Button type=\"primary\" @click=\"closeOtherTabs()\">\n          关闭其他标签页\n        </Button>\n        <Button type=\"primary\" @click=\"refreshTab()\"> 刷新当前标签页 </Button>\n      </div>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"动态标题\">\n      <div class=\"text-foreground/80 mb-3\">\n        该操作不会影响页面标题，仅修改Tab标题\n      </div>\n      <div class=\"flex flex-wrap items-center gap-3\">\n        <Input\n          v-model:value=\"newTabTitle\"\n          class=\"w-40\"\n          placeholder=\"请输入新标题\"\n        />\n        <Button type=\"primary\" @click=\"() => setTabTitle(newTabTitle)\">\n          修改\n        </Button>\n        <Button @click=\"reset\"> 重置 </Button>\n      </div>\n    </Card>\n\n    <Card class=\"mb-5\" title=\"最大打开数量\">\n      <div class=\"text-foreground/80 mb-3\">\n        限制带参数的tab打开的最大数量，由 `route.meta.maxNumOfOpenTab` 控制\n      </div>\n      <div class=\"flex flex-wrap items-center gap-3\">\n        <template v-for=\"item in 5\" :key=\"item\">\n          <Button type=\"primary\" @click=\"openTabWithParams(item)\">\n            打开{{ item }}详情页\n          </Button>\n        </template>\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/tabs/tab-detail.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { Page } from '@vben/common-ui';\nimport { useTabs } from '@vben/hooks';\n\nconst route = useRoute();\n\nconst { setTabTitle } = useTabs();\n\nconst index = computed(() => {\n  return route.params?.id ?? -1;\n});\n\nsetTabTitle(`No.${index.value} - 详情信息`);\n</script>\n\n<template>\n  <Page :title=\"`标签页${index}详情页`\">\n    <template #description> {{ index }} - 详情页内容在此 </template>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/vue-query/concurrency-caching.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Recordable } from '@vben/types';\n\nimport { useQuery } from '@tanstack/vue-query';\n\nimport { useVbenForm } from '#/adapter/form';\nimport { getMenuList } from '#/api';\n\nconst queryKey = ['demo', 'api', 'options'];\nconst count = 4;\n\nconst { dataUpdatedAt, promise: fetchDataFn } = useQuery({\n  // 在组件渲染期间预取数据\n  experimental_prefetchInRender: true,\n  // 获取接口数据的函数\n  queryFn: getMenuList,\n  queryKey,\n  // 每次组件挂载时都重新获取数据。如果不需要每次都重新获取就不要设置为always\n  refetchOnMount: 'always',\n  // 缓存时间\n  staleTime: 1000 * 60 * 5,\n});\n\nasync function fetchOptions() {\n  return await fetchDataFn.value;\n}\n\nconst schema = [];\n\nfor (let i = 0; i < count; i++) {\n  schema.push({\n    component: 'ApiSelect',\n    componentProps: {\n      api: fetchOptions,\n      class: 'w-full',\n      filterOption: (input: string, option: Recordable<any>) => {\n        return option.label.toLowerCase().includes(input.toLowerCase());\n      },\n      labelField: 'name',\n      showSearch: true,\n      valueField: 'id',\n    },\n    fieldName: `field${i}`,\n    label: `Select ${i}`,\n  });\n}\n\nconst [Form] = useVbenForm({\n  schema,\n  showDefaultActions: false,\n});\n</script>\n<template>\n  <div>\n    <div class=\"mb-2 flex gap-2\">\n      <div>以下{{ count }}个组件共用一个数据源。</div>\n      <div>缓存更新时间：{{ new Date(dataUpdatedAt).toLocaleString() }}</div>\n    </div>\n    <Form />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/vue-query/index.vue",
    "content": "<script setup lang=\"ts\">\nimport { Page } from '@vben/common-ui';\n\nimport { refAutoReset } from '@vueuse/core';\nimport { Button, Card, Empty } from 'ant-design-vue';\n\nimport ConcurrencyCaching from './concurrency-caching.vue';\nimport InfiniteQueries from './infinite-queries.vue';\nimport PaginatedQueries from './paginated-queries.vue';\nimport QueryRetries from './query-retries.vue';\n\nconst showCaching = refAutoReset(true, 1000);\n</script>\n\n<template>\n  <Page title=\"Vue Query示例\">\n    <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n      <Card title=\"分页查询\">\n        <PaginatedQueries />\n      </Card>\n      <Card title=\"无限滚动\">\n        <InfiniteQueries class=\"h-[300px] overflow-auto\" />\n      </Card>\n      <Card title=\"错误重试\">\n        <QueryRetries />\n      </Card>\n      <Card\n        title=\"并发和缓存\"\n        v-spinning=\"!showCaching\"\n        :body-style=\"{ minHeight: '330px' }\"\n      >\n        <template #extra>\n          <Button @click=\"showCaching = false\">重新加载</Button>\n        </template>\n        <ConcurrencyCaching v-if=\"showCaching\" />\n        <Empty v-else description=\"正在加载...\" />\n      </Card>\n    </div>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/vue-query/infinite-queries.vue",
    "content": "<script setup lang=\"ts\">\nimport type { IProducts } from './typing';\n\nimport { useInfiniteQuery } from '@tanstack/vue-query';\nimport { Button } from 'ant-design-vue';\n\nconst LIMIT = 10;\nconst fetchProducts = async ({ pageParam = 0 }): Promise<IProducts> => {\n  const res = await fetch(\n    `https://dummyjson.com/products?limit=${LIMIT}&skip=${pageParam * LIMIT}`,\n  );\n  return res.json();\n};\n\nconst {\n  data,\n  error,\n  fetchNextPage,\n  hasNextPage,\n  isError,\n  isFetching,\n  isFetchingNextPage,\n  isPending,\n} = useInfiniteQuery({\n  getNextPageParam: (current, allPages) => {\n    const nextPage = allPages.length + 1;\n    const lastPage = current.skip + current.limit;\n    if (lastPage === current.total) return;\n    return nextPage;\n  },\n  initialPageParam: 0,\n  queryFn: fetchProducts,\n  queryKey: ['products'],\n});\n</script>\n\n<template>\n  <div>\n    <span v-if=\"isPending\">加载...</span>\n    <span v-else-if=\"isError\">出错了: {{ error }}</span>\n    <div v-else-if=\"data\">\n      <span v-if=\"isFetching && !isFetchingNextPage\">Fetching...</span>\n      <ul v-for=\"(group, index) in data.pages\" :key=\"index\">\n        <li v-for=\"product in group.products\" :key=\"product.id\">\n          {{ product.title }}\n        </li>\n      </ul>\n      <Button\n        :disabled=\"!hasNextPage || isFetchingNextPage\"\n        @click=\"() => fetchNextPage()\"\n      >\n        <span v-if=\"isFetchingNextPage\">加载中...</span>\n        <span v-else-if=\"hasNextPage\">加载更多</span>\n        <span v-else>没有更多了</span>\n      </Button>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/vue-query/paginated-queries.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Ref } from 'vue';\n\nimport type { IProducts } from './typing';\n\nimport { ref } from 'vue';\n\nimport { keepPreviousData, useQuery } from '@tanstack/vue-query';\nimport { Button } from 'ant-design-vue';\n\nconst LIMIT = 10;\nconst fetcher = async (page: Ref<number>): Promise<IProducts> => {\n  const res = await fetch(\n    `https://dummyjson.com/products?limit=${LIMIT}&skip=${(page.value - 1) * LIMIT}`,\n  );\n  return res.json();\n};\n\nconst page = ref(1);\nconst { data, error, isError, isPending, isPlaceholderData } = useQuery({\n  // The data from the last successful fetch is available while new data is being requested.\n  placeholderData: keepPreviousData,\n  queryFn: () => fetcher(page),\n  queryKey: ['products', page],\n});\nconst prevPage = () => {\n  page.value = Math.max(page.value - 1, 1);\n};\nconst nextPage = () => {\n  if (!isPlaceholderData.value) {\n    page.value = page.value + 1;\n  }\n};\n</script>\n\n<template>\n  <div class=\"flex gap-4\">\n    <Button size=\"small\" @click=\"prevPage\">上一页</Button>\n    <p>当前页: {{ page }}</p>\n    <Button size=\"small\" @click=\"nextPage\">下一页</Button>\n  </div>\n  <div class=\"p-4\">\n    <div v-if=\"isPending\">加载中...</div>\n    <div v-else-if=\"isError\">出错了: {{ error }}</div>\n    <div v-else-if=\"data\">\n      <ul>\n        <li v-for=\"item in data.products\" :key=\"item.id\">\n          {{ item.title }}\n        </li>\n      </ul>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/vue-query/query-retries.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue';\n\nimport { useQuery } from '@tanstack/vue-query';\nimport { Button } from 'ant-design-vue';\n\nconst count = ref(-1);\nasync function fetchApi() {\n  count.value += 1;\n  return new Promise((_resolve, reject) => {\n    setTimeout(() => {\n      reject(new Error('something went wrong!'));\n    }, 1000);\n  });\n}\n\nconst { error, isFetching, refetch } = useQuery({\n  enabled: false, // Disable automatic refetching when the query mounts\n  queryFn: fetchApi,\n  queryKey: ['queryKey'],\n  retry: 3, // Will retry failed requests 3 times before displaying an error\n});\n\nconst onClick = async () => {\n  count.value = -1;\n  await refetch();\n};\n</script>\n\n<template>\n  <Button :loading=\"isFetching\" @click=\"onClick\"> 发起错误重试 </Button>\n  <p v-if=\"count > 0\" class=\"my-3\">重试次数{{ count }}</p>\n  <p>{{ error }}</p>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/vue-query/typing.ts",
    "content": "export interface IProducts {\n  limit: number;\n  products: {\n    brand: string;\n    category: string;\n    description: string;\n    discountPercentage: string;\n    id: string;\n    images: string[];\n    price: string;\n    rating: string;\n    stock: string;\n    thumbnail: string;\n    title: string;\n  }[];\n  skip: number;\n  total: number;\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/features/watermark/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Page } from '@vben/common-ui';\nimport { useWatermark } from '@vben/hooks';\n\nimport { Button, Card } from 'ant-design-vue';\n\nconst { destroyWatermark, updateWatermark, watermark } = useWatermark();\n\nasync function recreateWaterMark() {\n  destroyWatermark();\n  await createWaterMark();\n}\n\nasync function createWaterMark() {\n  await updateWatermark({\n    advancedStyle: {\n      colorStops: [\n        {\n          color: 'red',\n          offset: 0,\n        },\n        {\n          color: 'blue',\n          offset: 1,\n        },\n      ],\n      type: 'linear',\n    },\n    content: `hello my watermark\\n${new Date().toLocaleString()}`,\n    globalAlpha: 0.5,\n    gridLayoutOptions: {\n      cols: 2,\n      gap: [20, 20],\n      matrix: [\n        [1, 0],\n        [0, 1],\n      ],\n      rows: 2,\n    },\n    height: 200,\n    layout: 'grid',\n    rotate: 22,\n    width: 200,\n  });\n}\n</script>\n\n<template>\n  <Page title=\"水印\">\n    <template #description>\n      <div class=\"text-foreground/80 mt-2\">\n        水印使用了\n        <a\n          class=\"text-primary\"\n          href=\"https://zhensherlock.github.io/watermark-js-plus/\"\n          target=\"_blank\"\n        >\n          watermark-js-plus\n        </a>\n        开源插件，详细配置可见插件配置。\n      </div>\n    </template>\n\n    <Card title=\"使用\">\n      <Button\n        :disabled=\"!!watermark\"\n        class=\"mr-2\"\n        type=\"primary\"\n        @click=\"recreateWaterMark\"\n      >\n        创建水印\n      </Button>\n      <Button\n        :disabled=\"!watermark\"\n        class=\"mr-2\"\n        type=\"primary\"\n        @click=\"createWaterMark\"\n      >\n        更新水印\n      </Button>\n      <Button :disabled=\"!watermark\" danger @click=\"destroyWatermark\">\n        移除水印\n      </Button>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/nested/menu-1.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/nested/menu-2-1.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/nested/menu-3-1.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/demos/nested/menu-3-2-1.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Fallback } from '@vben/common-ui';\n</script>\n\n<template>\n  <Fallback status=\"coming-soon\" />\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/button-group/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Recordable } from '@vben/types';\n\nimport { reactive, ref } from 'vue';\n\nimport {\n  Page,\n  VbenButton,\n  VbenButtonGroup,\n  VbenCheckButtonGroup,\n} from '@vben/common-ui';\nimport { LoaderCircle, Square, SquareCheckBig } from '@vben/icons';\n\nimport { Button, Card, message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst radioValue = ref<string | undefined>('a');\nconst checkValue = ref(['a', 'b']);\n\nconst options = [\n  { label: '选项1', value: 'a' },\n  { label: '选项2', value: 'b', num: 999 },\n  { label: '选项3', value: 'c' },\n  { label: '选项4', value: 'd' },\n  { label: '选项5', value: 'e' },\n  { label: '选项6', value: 'f' },\n];\n\nfunction resetValues() {\n  radioValue.value = undefined;\n  checkValue.value = [];\n}\n\nfunction beforeChange(v: any, isChecked: boolean) {\n  return new Promise((resolve) => {\n    message.loading({\n      content: `正在设置${v}为${isChecked ? '选中' : '未选中'}...`,\n      duration: 0,\n      key: 'beforeChange',\n    });\n    setTimeout(() => {\n      message.success({ content: `${v} 已设置成功`, key: 'beforeChange' });\n      resolve(true);\n    }, 2000);\n  });\n}\n\nconst compProps = reactive({\n  beforeChange: undefined,\n  disabled: false,\n  gap: 0,\n  showIcon: true,\n  size: 'middle',\n  allowClear: false,\n} as Recordable<any>);\n\nconst [Form] = useVbenForm({\n  handleValuesChange(values) {\n    Object.keys(values).forEach((k) => {\n      if (k === 'beforeChange') {\n        compProps[k] = values[k] ? beforeChange : undefined;\n      } else {\n        compProps[k] = values[k];\n      }\n    });\n  },\n  commonConfig: {\n    labelWidth: 150,\n  },\n  schema: [\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        options: [\n          { label: '大', value: 'large' },\n          { label: '中', value: 'middle' },\n          { label: '小', value: 'small' },\n        ],\n      },\n      defaultValue: compProps.size,\n      fieldName: 'size',\n      label: '尺寸',\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        options: [\n          { label: '无', value: 0 },\n          { label: '小', value: 5 },\n          { label: '中', value: 15 },\n          { label: '大', value: 30 },\n        ],\n      },\n      defaultValue: compProps.gap,\n      fieldName: 'gap',\n      label: '间距',\n    },\n    {\n      component: 'Switch',\n      defaultValue: compProps.showIcon,\n      fieldName: 'showIcon',\n      label: '显示图标',\n    },\n    {\n      component: 'Switch',\n      defaultValue: compProps.disabled,\n      fieldName: 'disabled',\n      label: '禁用',\n    },\n    {\n      component: 'Switch',\n      defaultValue: false,\n      fieldName: 'beforeChange',\n      label: '前置回调',\n    },\n    {\n      component: 'Switch',\n      defaultValue: false,\n      fieldName: 'allowClear',\n      label: '允许清除',\n      help: '单选时是否允许取消选中（值为undefined）',\n    },\n    {\n      component: 'InputNumber',\n      defaultValue: 0,\n      fieldName: 'maxCount',\n      label: '最大选中数量',\n      help: '多选时有效，0表示不限制',\n    },\n  ],\n  showDefaultActions: false,\n  submitOnChange: true,\n});\n\nfunction onBtnClick(value: any) {\n  const opt = options.find((o) => o.value === value);\n  if (opt) {\n    message.success(`点击了按钮${opt.label}，value = ${value}`);\n  }\n}\n</script>\n<template>\n  <Page\n    title=\"VbenButtonGroup 按钮组\"\n    description=\"VbenButtonGroup是一个按钮容器，用于包裹一组按钮，协调整体样式。VbenCheckButtonGroup则可以作为一个表单组件，提供单选或多选功能\"\n  >\n    <Card title=\"基本用法\">\n      <template #extra>\n        <Button type=\"primary\" @click=\"resetValues\">清空值</Button>\n      </template>\n      <p class=\"mt-4\">按钮组：</p>\n      <div class=\"mt-2 flex flex-col gap-2\">\n        <VbenButtonGroup v-bind=\"compProps\" border>\n          <VbenButton\n            v-for=\"btn in options\"\n            :key=\"btn.value\"\n            variant=\"link\"\n            @click=\"onBtnClick(btn.value)\"\n          >\n            {{ btn.label }}\n          </VbenButton>\n        </VbenButtonGroup>\n        <VbenButtonGroup v-bind=\"compProps\" border>\n          <VbenButton\n            v-for=\"btn in options\"\n            :key=\"btn.value\"\n            variant=\"outline\"\n            @click=\"onBtnClick(btn.value)\"\n          >\n            {{ btn.label }}\n          </VbenButton>\n        </VbenButtonGroup>\n      </div>\n      <p class=\"mt-4\">单选：{{ radioValue }}</p>\n      <div class=\"mt-2 flex flex-col gap-2\">\n        <VbenCheckButtonGroup\n          v-model=\"radioValue\"\n          :options=\"options\"\n          v-bind=\"compProps\"\n        />\n      </div>\n      <p class=\"mt-4\">单选插槽：{{ radioValue }}</p>\n      <div class=\"mt-2 flex flex-col gap-2\">\n        <VbenCheckButtonGroup\n          v-model=\"radioValue\"\n          :options=\"options\"\n          v-bind=\"compProps\"\n        >\n          <template #option=\"{ label, value, data }\">\n            <div class=\"flex items-center\">\n              <span>{{ label }}</span>\n              <span class=\"ml-2 text-gray-400\">{{ value }}</span>\n              <span v-if=\"data.num\" class=\"white ml-2\">{{ data.num }}</span>\n            </div>\n          </template>\n        </VbenCheckButtonGroup>\n      </div>\n      <p class=\"mt-4\">多选{{ checkValue }}</p>\n      <div class=\"mt-2 flex flex-col gap-2\">\n        <VbenCheckButtonGroup\n          v-model=\"checkValue\"\n          multiple\n          :options=\"options\"\n          v-bind=\"compProps\"\n        />\n      </div>\n      <p class=\"mt-4\">自定义图标{{ checkValue }}</p>\n      <div class=\"mt-2 flex flex-col gap-2\">\n        <VbenCheckButtonGroup\n          v-model=\"checkValue\"\n          multiple\n          :options=\"options\"\n          v-bind=\"compProps\"\n        >\n          <template #icon=\"{ loading, checked }\">\n            <LoaderCircle class=\"animate-spin\" v-if=\"loading\" />\n            <SquareCheckBig v-else-if=\"checked\" />\n            <Square v-else />\n          </template>\n        </VbenCheckButtonGroup>\n      </div>\n    </Card>\n\n    <Card title=\"设置\" class=\"mt-4\">\n      <Form />\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/captcha/point-selection-captcha.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { CaptchaPoint } from '@vben/common-ui';\n\nimport { reactive, ref } from 'vue';\n\nimport { Page, PointSelectionCaptcha } from '@vben/common-ui';\n\nimport { Card, Input, InputNumber, message, Switch } from 'ant-design-vue';\n\nimport { $t } from '#/locales';\n\nconst DEFAULT_CAPTCHA_IMAGE =\n  'https://unpkg.com/@vbenjs/static-source@0.1.7/source/default-captcha-image.jpeg';\n\nconst DEFAULT_HINT_IMAGE =\n  'https://unpkg.com/@vbenjs/static-source@0.1.7/source/default-hint-image.png';\n\nconst selectedPoints = ref<CaptchaPoint[]>([]);\nconst params = reactive({\n  captchaImage: '',\n  captchaImageUrl: DEFAULT_CAPTCHA_IMAGE,\n  height: undefined,\n  hintImage: '',\n  hintImageUrl: DEFAULT_HINT_IMAGE,\n  hintText: '唇，燕，碴，找',\n  paddingX: undefined,\n  paddingY: undefined,\n  showConfirm: true,\n  showHintImage: false,\n  title: '',\n  width: undefined,\n});\nconst handleConfirm = (points: CaptchaPoint[], clear: () => void) => {\n  message.success({\n    content: `captcha points: ${JSON.stringify(points)}`,\n  });\n  clear();\n  selectedPoints.value = [];\n};\nconst handleRefresh = () => {\n  selectedPoints.value = [];\n};\nconst handleClick = (point: CaptchaPoint) => {\n  selectedPoints.value.push(point);\n};\n</script>\n\n<template>\n  <Page\n    :description=\"$t('examples.captcha.pageDescription')\"\n    :title=\"$t('examples.captcha.pageTitle')\"\n  >\n    <Card :title=\"$t('examples.captcha.basic')\" class=\"mb-4 overflow-x-auto\">\n      <div class=\"mb-3 flex items-center justify-start\">\n        <Input\n          v-model:value=\"params.title\"\n          :placeholder=\"$t('examples.captcha.titlePlaceholder')\"\n          class=\"w-64\"\n        />\n        <Input\n          v-model:value=\"params.captchaImageUrl\"\n          :placeholder=\"$t('examples.captcha.captchaImageUrlPlaceholder')\"\n          class=\"ml-8 w-64\"\n        />\n        <div class=\"ml-8 flex w-96 items-center\">\n          <Switch\n            v-model:checked=\"params.showHintImage\"\n            :checked-children=\"$t('examples.captcha.hintImage')\"\n            :un-checked-children=\"$t('examples.captcha.hintText')\"\n            class=\"mr-4 w-40\"\n          />\n          <Input\n            v-show=\"params.showHintImage\"\n            v-model:value=\"params.hintImageUrl\"\n            :placeholder=\"$t('examples.captcha.hintImagePlaceholder')\"\n          />\n          <Input\n            v-show=\"!params.showHintImage\"\n            v-model:value=\"params.hintText\"\n            :placeholder=\"$t('examples.captcha.hintTextPlaceholder')\"\n          />\n        </div>\n\n        <Switch\n          v-model:checked=\"params.showConfirm\"\n          :checked-children=\"$t('examples.captcha.showConfirm')\"\n          :un-checked-children=\"$t('examples.captcha.hideConfirm')\"\n          class=\"ml-8 w-28\"\n        />\n      </div>\n      <div class=\"mb-3 flex items-center justify-start\">\n        <div>\n          <InputNumber\n            v-model:value=\"params.width\"\n            :min=\"1\"\n            :placeholder=\"$t('examples.captcha.widthPlaceholder')\"\n            :precision=\"0\"\n            :step=\"1\"\n            class=\"w-64\"\n          >\n            <template #addonAfter>px</template>\n          </InputNumber>\n        </div>\n        <div class=\"ml-8\">\n          <InputNumber\n            v-model:value=\"params.height\"\n            :min=\"1\"\n            :placeholder=\"$t('examples.captcha.heightPlaceholder')\"\n            :precision=\"0\"\n            :step=\"1\"\n            class=\"w-64\"\n          >\n            <template #addonAfter>px</template>\n          </InputNumber>\n        </div>\n        <div class=\"ml-8\">\n          <InputNumber\n            v-model:value=\"params.paddingX\"\n            :min=\"1\"\n            :placeholder=\"$t('examples.captcha.paddingXPlaceholder')\"\n            :precision=\"0\"\n            :step=\"1\"\n            class=\"w-64\"\n          >\n            <template #addonAfter>px</template>\n          </InputNumber>\n        </div>\n        <div class=\"ml-8\">\n          <InputNumber\n            v-model:value=\"params.paddingY\"\n            :min=\"1\"\n            :placeholder=\"$t('examples.captcha.paddingYPlaceholder')\"\n            :precision=\"0\"\n            :step=\"1\"\n            class=\"w-64\"\n          >\n            <template #addonAfter>px</template>\n          </InputNumber>\n        </div>\n      </div>\n\n      <PointSelectionCaptcha\n        :captcha-image=\"params.captchaImageUrl || params.captchaImage\"\n        :height=\"params.height || 220\"\n        :hint-image=\"\n          params.showHintImage ? params.hintImageUrl || params.hintImage : ''\n        \"\n        :hint-text=\"params.hintText\"\n        :padding-x=\"params.paddingX\"\n        :padding-y=\"params.paddingY\"\n        :show-confirm=\"params.showConfirm\"\n        :width=\"params.width || 300\"\n        class=\"float-left\"\n        @click=\"handleClick\"\n        @confirm=\"handleConfirm\"\n        @refresh=\"handleRefresh\"\n      >\n        <template #title>\n          {{ params.title || $t('examples.captcha.captchaCardTitle') }}\n        </template>\n      </PointSelectionCaptcha>\n\n      <ol class=\"float-left p-5\">\n        <li v-for=\"point in selectedPoints\" :key=\"point.i\" class=\"flex\">\n          <span class=\"mr-3 w-16\">{{\n            $t('examples.captcha.index') + point.i\n          }}</span>\n          <span class=\"mr-3 w-52\">{{\n            $t('examples.captcha.timestamp') + point.t\n          }}</span>\n          <span class=\"mr-3 w-16\">{{\n            $t('examples.captcha.x') + point.x\n          }}</span>\n          <span class=\"mr-3 w-16\">{{\n            $t('examples.captcha.y') + point.y\n          }}</span>\n        </li>\n      </ol>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/captcha/slider-captcha.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  CaptchaVerifyPassingData,\n  SliderCaptchaActionType,\n} from '@vben/common-ui';\n\nimport { ref } from 'vue';\n\nimport { Page, SliderCaptcha } from '@vben/common-ui';\nimport { Bell, Sun } from '@vben/icons';\n\nimport { Button, Card, message } from 'ant-design-vue';\n\nfunction handleSuccess(data: CaptchaVerifyPassingData) {\n  const { time } = data;\n  message.success(`校验成功,耗时${time}秒`);\n}\nfunction handleBtnClick(elRef?: SliderCaptchaActionType) {\n  if (!elRef) {\n    return;\n  }\n  elRef.resume();\n}\n\nconst el1 = ref<SliderCaptchaActionType>();\nconst el2 = ref<SliderCaptchaActionType>();\nconst el3 = ref<SliderCaptchaActionType>();\nconst el4 = ref<SliderCaptchaActionType>();\nconst el5 = ref<SliderCaptchaActionType>();\nconst el6 = ref<SliderCaptchaActionType>();\n</script>\n\n<template>\n  <Page description=\"用于前端简单的拖动校验场景\" title=\"滑块校验\">\n    <Card class=\"mb-5\" title=\"基础示例\">\n      <div class=\"flex items-center justify-center p-4 px-[30%]\">\n        <SliderCaptcha ref=\"el1\" @success=\"handleSuccess\" />\n        <Button class=\"ml-2\" type=\"primary\" @click=\"handleBtnClick(el1)\">\n          还原\n        </Button>\n      </div>\n    </Card>\n    <Card class=\"mb-5\" title=\"自定义圆角\">\n      <div class=\"flex items-center justify-center p-4 px-[30%]\">\n        <SliderCaptcha\n          ref=\"el2\"\n          class=\"rounded-full\"\n          @success=\"handleSuccess\"\n        />\n        <Button class=\"ml-2\" type=\"primary\" @click=\"handleBtnClick(el2)\">\n          还原\n        </Button>\n      </div>\n    </Card>\n    <Card class=\"mb-5\" title=\"自定义背景色\">\n      <div class=\"flex items-center justify-center p-4 px-[30%]\">\n        <SliderCaptcha\n          ref=\"el3\"\n          :bar-style=\"{\n            backgroundColor: '#018ffb',\n          }\"\n          success-text=\"校验成功\"\n          text=\"拖动以进行校验\"\n          @success=\"handleSuccess\"\n        />\n        <Button class=\"ml-2\" type=\"primary\" @click=\"handleBtnClick(el3)\">\n          还原\n        </Button>\n      </div>\n    </Card>\n    <Card class=\"mb-5\" title=\"自定义拖拽图标\">\n      <div class=\"flex items-center justify-center p-4 px-[30%]\">\n        <SliderCaptcha ref=\"el4\" @success=\"handleSuccess\">\n          <template #actionIcon=\"{ isPassing }\">\n            <Bell v-if=\"isPassing\" />\n            <Sun v-else />\n          </template>\n        </SliderCaptcha>\n        <Button class=\"ml-2\" type=\"primary\" @click=\"handleBtnClick(el4)\">\n          还原\n        </Button>\n      </div>\n    </Card>\n    <Card class=\"mb-5\" title=\"自定义文本\">\n      <div class=\"flex items-center justify-center p-4 px-[30%]\">\n        <SliderCaptcha\n          ref=\"el5\"\n          success-text=\"成功\"\n          text=\"拖动\"\n          @success=\"handleSuccess\"\n        />\n        <Button class=\"ml-2\" type=\"primary\" @click=\"handleBtnClick(el5)\">\n          还原\n        </Button>\n      </div>\n    </Card>\n    <Card class=\"mb-5\" title=\"自定义内容(slot)\">\n      <div class=\"flex items-center justify-center p-4 px-[30%]\">\n        <SliderCaptcha ref=\"el6\" @success=\"handleSuccess\">\n          <template #text=\"{ isPassing }\">\n            <template v-if=\"isPassing\">\n              <Bell class=\"mr-2 size-4\" />\n              成功\n            </template>\n            <template v-else>\n              拖动\n              <Sun class=\"ml-2 size-4\" />\n            </template>\n          </template>\n        </SliderCaptcha>\n        <Button class=\"ml-2\" type=\"primary\" @click=\"handleBtnClick(el6)\">\n          还原\n        </Button>\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/captcha/slider-rotate-captcha.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\nimport { Page, SliderRotateCaptcha } from '@vben/common-ui';\nimport { preferences } from '@vben/preferences';\nimport { useUserStore } from '@vben/stores';\n\nimport { Card, message } from 'ant-design-vue';\n\nconst userStore = useUserStore();\nfunction handleSuccess() {\n  message.success('success!');\n}\n\nconst avatar = computed(() => {\n  return userStore.userInfo?.avatar || preferences.app.defaultAvatar;\n});\n</script>\n\n<template>\n  <Page description=\"用于前端简单的拖动校验场景\" title=\"滑块旋转校验\">\n    <Card class=\"mb-5\" title=\"基本示例\">\n      <div class=\"flex items-center justify-center p-4\">\n        <SliderRotateCaptcha :src=\"avatar\" @success=\"handleSuccess\" />\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/captcha/slider-translate-captcha.vue",
    "content": "<script setup lang=\"ts\">\nimport { Page, SliderTranslateCaptcha } from '@vben/common-ui';\n\nimport { Card, message } from 'ant-design-vue';\n\nfunction handleSuccess() {\n  message.success('success!');\n}\n</script>\n\n<template>\n  <Page\n    description=\"用于前端简单的拼图滑块水平拖动校验场景\"\n    title=\"拼图滑块校验\"\n  >\n    <Card class=\"mb-5\" title=\"基本示例\">\n      <div class=\"flex items-center justify-center p-4\">\n        <SliderTranslateCaptcha\n          src=\"https://unpkg.com/@vbenjs/static-source@0.1.7/source/pro-avatar.webp\"\n          :canvas-width=\"420\"\n          :canvas-height=\"420\"\n          @success=\"handleSuccess\"\n        />\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/count-to/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { CountToProps, TransitionPresets } from '@vben/common-ui';\n\nimport { reactive } from 'vue';\n\nimport { CountTo, Page, TransitionPresetsKeys } from '@vben/common-ui';\nimport { IconifyIcon } from '@vben/icons';\n\nimport {\n  Button,\n  Card,\n  Col,\n  Form,\n  FormItem,\n  Input,\n  InputNumber,\n  message,\n  Row,\n  Select,\n  Switch,\n} from 'ant-design-vue';\n\nconst props = reactive<CountToProps & { transition: TransitionPresets }>({\n  decimal: '.',\n  decimals: 2,\n  decimalStyle: {\n    fontSize: 'small',\n    fontStyle: 'italic',\n  },\n  delay: 0,\n  disabled: false,\n  duration: 2000,\n  endVal: 100_000,\n  mainStyle: {\n    color: 'hsl(var(--primary))',\n    fontSize: 'xx-large',\n    fontWeight: 'bold',\n  },\n  prefix: '￥',\n  prefixStyle: {\n    paddingRight: '0.5rem',\n  },\n  separator: ',',\n  startVal: 0,\n  suffix: '元',\n  suffixStyle: {\n    paddingLeft: '0.5rem',\n  },\n  transition: 'easeOutQuart',\n});\n\nfunction changeNumber() {\n  props.endVal =\n    Math.floor(Math.random() * 100_000_000) / 10 ** (props.decimals || 0);\n}\n\nfunction openDocumentation() {\n  window.open('https://vueuse.org/core/useTransition/', '_blank');\n}\n\nfunction onStarted() {\n  message.loading({\n    content: '动画已开始',\n    duration: 0,\n    key: 'animator-info',\n  });\n}\n\nfunction onFinished() {\n  message.success({\n    content: '动画已结束',\n    duration: 2,\n    key: 'animator-info',\n  });\n}\n</script>\n<template>\n  <Page title=\"CountTo\" description=\"数字滚动动画组件。使用\">\n    <template #description>\n      <span>\n        使用useTransition封装的数字滚动动画组件，每次改变当前值都会产生过渡动画。\n      </span>\n      <Button type=\"link\" @click=\"openDocumentation\">\n        查看useTransition文档\n      </Button>\n    </template>\n    <Card title=\"基本用法\">\n      <div class=\"flex w-full items-center justify-center pb-4\">\n        <CountTo v-bind=\"props\" @started=\"onStarted\" @finished=\"onFinished\" />\n      </div>\n      <Form :model=\"props\">\n        <Row :gutter=\"20\">\n          <Col :span=\"8\">\n            <FormItem label=\"初始值\" name=\"startVal\">\n              <InputNumber v-model:value=\"props.startVal\" />\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"当前值\" name=\"endVal\">\n              <InputNumber\n                v-model:value=\"props.endVal\"\n                class=\"w-full\"\n                :precision=\"props.decimals\"\n              >\n                <template #addonAfter>\n                  <IconifyIcon\n                    v-tippy=\"`设置一个随机值`\"\n                    class=\"size-5 cursor-pointer outline-none\"\n                    icon=\"ix:random-filled\"\n                    @click=\"changeNumber\"\n                  />\n                </template>\n              </InputNumber>\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"禁用动画\" name=\"disabled\">\n              <Switch v-model:checked=\"props.disabled\" />\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"延迟动画\" name=\"delay\">\n              <InputNumber v-model:value=\"props.delay\" :min=\"0\" />\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"持续时间\" name=\"duration\">\n              <InputNumber v-model:value=\"props.duration\" :min=\"0\" />\n            </FormItem>\n          </Col>\n\n          <Col :span=\"8\">\n            <FormItem label=\"小数位数\" name=\"decimals\">\n              <InputNumber\n                v-model:value=\"props.decimals\"\n                :min=\"0\"\n                :precision=\"0\"\n              />\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"分隔符\" name=\"separator\">\n              <Input v-model:value=\"props.separator\" />\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"小数点\" name=\"decimal\">\n              <Input v-model:value=\"props.decimal\" />\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"动画\" name=\"transition\">\n              <Select v-model:value=\"props.transition\">\n                <Select.Option\n                  v-for=\"preset in TransitionPresetsKeys\"\n                  :key=\"preset\"\n                  :value=\"preset\"\n                >\n                  {{ preset }}\n                </Select.Option>\n              </Select>\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"前缀\" name=\"prefix\">\n              <Input v-model:value=\"props.prefix\" />\n            </FormItem>\n          </Col>\n          <Col :span=\"8\">\n            <FormItem label=\"后缀\" name=\"suffix\">\n              <Input v-model:value=\"props.suffix\" />\n            </FormItem>\n          </Col>\n        </Row>\n      </Form>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/doc-button.vue",
    "content": "<script lang=\"ts\" setup>\nimport { VBEN_DOC_URL } from '@vben/constants';\nimport { openWindow } from '@vben/utils';\n\nimport { Button } from 'ant-design-vue';\n\nconst props = defineProps<{ path: string }>();\n\nfunction handleClick() {\n  // 如果没有.html，打开页面时可能会出现404\n  const path =\n    VBEN_DOC_URL +\n    (props.path.toLowerCase().endsWith('.html')\n      ? props.path\n      : `${props.path}.html`);\n  openWindow(path);\n}\n</script>\n\n<template>\n  <Button @click=\"handleClick\">查看组件文档</Button>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/drawer/auto-height-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nconst list = ref<number[]>([]);\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // drawerApi.close();\n  },\n  onOpenChange(isOpen) {\n    if (isOpen) {\n      handleUpdate(10);\n    }\n  },\n});\n\nfunction handleUpdate(len: number) {\n  drawerApi.setState({ loading: true });\n  setTimeout(() => {\n    list.value = Array.from({ length: len }, (_v, k) => k + 1);\n    drawerApi.setState({ loading: false });\n  }, 2000);\n}\n</script>\n<template>\n  <Drawer title=\"自动计算高度\">\n    <div\n      v-for=\"item in list\"\n      :key=\"item\"\n      class=\"even:bg-heavy bg-muted flex-center h-[220px] w-full\"\n    >\n      {{ item }}\n    </div>\n\n    <template #prepend-footer>\n      <Button type=\"link\" @click=\"handleUpdate(6)\">点击更新数据</Button>\n    </template>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/drawer/base-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onClosed() {\n    drawerApi.setState({ overlayBlur: 0, placement: 'right' });\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // drawerApi.close();\n  },\n});\n\nfunction lockDrawer() {\n  drawerApi.lock();\n  setTimeout(() => {\n    drawerApi.unlock();\n  }, 3000);\n}\n</script>\n<template>\n  <Drawer title=\"基础抽屉示例\" title-tooltip=\"标题提示内容\">\n    <template #extra> extra </template>\n    base demo\n    <Button type=\"primary\" @click=\"lockDrawer\">锁定抽屉状态</Button>\n    <!-- <template #prepend-footer> slot </template> -->\n    <!-- <template #append-footer> prepend slot </template> -->\n    <!-- <template #center-footer> center slot </template> -->\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/drawer/dynamic-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // drawerApi.close();\n  },\n  title: '动态修改配置示例',\n});\n\n// const state = drawerApi.useStore();\n\nfunction handleUpdateTitle() {\n  drawerApi.setState({ title: '内部动态标题' });\n}\n</script>\n<template>\n  <Drawer>\n    <div class=\"flex-col-center\">\n      <Button class=\"mb-3\" type=\"primary\" @click=\"handleUpdateTitle()\">\n        内部动态修改标题\n      </Button>\n    </div>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/drawer/form-drawer-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { useVbenForm } from '#/adapter/form';\n\ndefineOptions({\n  name: 'FormDrawerDemo',\n});\n\nconst [Form, formApi] = useVbenForm({\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field1',\n      label: '字段1',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field2',\n      label: '字段2',\n      rules: 'required',\n    },\n  ],\n  showDefaultActions: false,\n});\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.submitForm();\n    drawerApi.close();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      const { values } = drawerApi.getData<Record<string, any>>();\n      if (values) {\n        formApi.setValues(values);\n      }\n    }\n  },\n  title: '内嵌表单示例',\n});\n</script>\n<template>\n  <Drawer>\n    <Form />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/drawer/in-content-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { Input, message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst value = ref('');\n\nconst [Form] = useVbenForm({\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: 'KeepAlive测试：内部组件',\n      },\n      fieldName: 'field1',\n      hideLabel: true,\n      label: '字段1',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  destroyOnClose: false,\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // drawerApi.close();\n  },\n});\n</script>\n<template>\n  <Drawer append-to-main title=\"基础抽屉示例\" title-tooltip=\"标题提示内容\">\n    <template #extra> extra </template>\n    此弹窗指定在内容区域打开，并且在关闭之后弹窗内容不会被销毁\n    <Input\n      v-model:value=\"value\"\n      placeholder=\"KeepAlive测试:connectedComponent\"\n    />\n    <Form />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/drawer/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DrawerPlacement, DrawerState } from '@vben/common-ui';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\n\nimport { Button, Card } from 'ant-design-vue';\n\nimport DocButton from '../doc-button.vue';\nimport AutoHeightDemo from './auto-height-demo.vue';\nimport BaseDemo from './base-demo.vue';\nimport DynamicDemo from './dynamic-demo.vue';\nimport FormDrawerDemo from './form-drawer-demo.vue';\nimport inContentDemo from './in-content-demo.vue';\nimport SharedDataDemo from './shared-data-demo.vue';\n\ndefineOptions({ name: 'DrawerExample' });\nconst [BaseDrawer, baseDrawerApi] = useVbenDrawer({\n  // 连接抽离的组件\n  connectedComponent: BaseDemo,\n  // placement: 'left',\n});\n\nconst [InContentDrawer, inContentDrawerApi] = useVbenDrawer({\n  // 连接抽离的组件\n  connectedComponent: inContentDemo,\n  // placement: 'left',\n});\n\nconst [AutoHeightDrawer, autoHeightDrawerApi] = useVbenDrawer({\n  connectedComponent: AutoHeightDemo,\n});\n\nconst [DynamicDrawer, dynamicDrawerApi] = useVbenDrawer({\n  connectedComponent: DynamicDemo,\n});\n\nconst [SharedDataDrawer, sharedDrawerApi] = useVbenDrawer({\n  connectedComponent: SharedDataDemo,\n});\n\nconst [FormDrawer, formDrawerApi] = useVbenDrawer({\n  connectedComponent: FormDrawerDemo,\n});\n\nfunction openBaseDrawer(placement: DrawerPlacement = 'right') {\n  baseDrawerApi.setState({ placement }).open();\n}\n\nfunction openBlurDrawer() {\n  baseDrawerApi.setState({ overlayBlur: 5 }).open();\n}\n\nfunction openInContentDrawer(placement: DrawerPlacement = 'right') {\n  const state: Partial<DrawerState> = { class: '', placement };\n  if (placement === 'top') {\n    // 页面顶部区域的层级只有200，所以设置一个低于200的值，抽屉从顶部滑出来的时候才比较合适\n    state.zIndex = 199;\n  }\n  inContentDrawerApi.setState(state).open();\n}\n\nfunction openMaxContentDrawer() {\n  // 这里只是用来演示方便。实际上自己使用的时候可以直接将这些配置卸载Drawer的属性里\n  inContentDrawerApi.setState({ class: 'w-full', placement: 'right' }).open();\n}\n\nfunction openAutoHeightDrawer() {\n  autoHeightDrawerApi.open();\n}\n\nfunction openDynamicDrawer() {\n  dynamicDrawerApi.open();\n}\n\nfunction handleUpdateTitle() {\n  dynamicDrawerApi.setState({ title: '外部动态标题' }).open();\n}\n\nfunction openSharedDrawer() {\n  sharedDrawerApi\n    .setData({\n      content: '外部传递的数据 content',\n      payload: '外部传递的数据 payload',\n    })\n    .open();\n}\n\nfunction openFormDrawer() {\n  formDrawerApi\n    .setData({\n      // 表单值\n      values: { field1: 'abc', field2: '123' },\n    })\n    .open();\n}\n</script>\n\n<template>\n  <Page\n    auto-content-height\n    description=\"抽屉组件通常用于在当前页面上显示一个覆盖层，用以展示重要信息或提供用户交互界面。\"\n    title=\"抽屉组件示例\"\n  >\n    <template #extra>\n      <DocButton path=\"/components/common-ui/vben-drawer\" />\n    </template>\n    <BaseDrawer />\n    <InContentDrawer />\n    <AutoHeightDrawer />\n    <DynamicDrawer />\n    <SharedDataDrawer />\n    <FormDrawer />\n\n    <Card class=\"mb-4\" title=\"基本使用\">\n      <p class=\"mb-3\">一个基础的抽屉示例</p>\n      <Button class=\"mb-2\" type=\"primary\" @click=\"openBaseDrawer('right')\">\n        右侧打开\n      </Button>\n      <Button\n        class=\"mb-2 ml-2\"\n        type=\"primary\"\n        @click=\"openBaseDrawer('bottom')\"\n      >\n        底部打开\n      </Button>\n      <Button class=\"mb-2 ml-2\" type=\"primary\" @click=\"openBaseDrawer('left')\">\n        左侧打开\n      </Button>\n      <Button class=\"mb-2 ml-2\" type=\"primary\" @click=\"openBaseDrawer('top')\">\n        顶部打开\n      </Button>\n      <Button class=\"mb-2 ml-2\" type=\"primary\" @click=\"openBlurDrawer\">\n        遮罩层模糊效果\n      </Button>\n    </Card>\n\n    <Card class=\"mb-4\" title=\"在内容区域打开\">\n      <p class=\"mb-3\">指定抽屉在内容区域打开，不会覆盖顶部和左侧菜单等区域</p>\n      <Button class=\"mb-2\" type=\"primary\" @click=\"openInContentDrawer('right')\">\n        右侧打开\n      </Button>\n      <Button\n        class=\"mb-2 ml-2\"\n        type=\"primary\"\n        @click=\"openInContentDrawer('bottom')\"\n      >\n        底部打开\n      </Button>\n      <Button\n        class=\"mb-2 ml-2\"\n        type=\"primary\"\n        @click=\"openInContentDrawer('left')\"\n      >\n        左侧打开\n      </Button>\n      <Button\n        class=\"mb-2 ml-2\"\n        type=\"primary\"\n        @click=\"openInContentDrawer('top')\"\n      >\n        顶部打开\n      </Button>\n      <Button class=\"mb-2 ml-2\" type=\"primary\" @click=\"openMaxContentDrawer\">\n        内容区域全屏打开\n      </Button>\n    </Card>\n\n    <Card class=\"mb-4\" title=\"内容高度自适应滚动\">\n      <p class=\"mb-3\">可根据内容自动计算滚动高度</p>\n      <Button type=\"primary\" @click=\"openAutoHeightDrawer\">打开抽屉</Button>\n    </Card>\n\n    <Card class=\"mb-4\" title=\"动态配置示例\">\n      <p class=\"mb-3\">通过 setState 动态调整抽屉数据</p>\n      <Button type=\"primary\" @click=\"openDynamicDrawer\">打开抽屉</Button>\n      <Button class=\"ml-2\" type=\"primary\" @click=\"handleUpdateTitle\">\n        从外部修改标题并打开\n      </Button>\n    </Card>\n\n    <Card class=\"mb-4\" title=\"内外数据共享示例\">\n      <p class=\"mb-3\">通过共享 sharedData 来进行数据交互</p>\n      <Button type=\"primary\" @click=\"openSharedDrawer\">\n        打开抽屉并传递数据\n      </Button>\n    </Card>\n\n    <Card class=\"mb-4\" title=\"表单抽屉示例\">\n      <p class=\"mb-3\">打开抽屉并设置表单schema以及数据</p>\n      <Button type=\"primary\" @click=\"openFormDrawer\">\n        打开抽屉并设置表单schema以及数据\n      </Button>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/drawer/shared-data-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\n\nimport { message } from 'ant-design-vue';\n\nconst data = ref();\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onCancel() {\n    drawerApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // drawerApi.close();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      data.value = drawerApi.getData<Record<string, any>>();\n    }\n  },\n});\n</script>\n<template>\n  <Drawer title=\"数据共享示例\">\n    <div class=\"flex-col-center\">外部传递数据： {{ data }}</div>\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/ellipsis/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { EllipsisText, Page } from '@vben/common-ui';\n\nimport { Card } from 'ant-design-vue';\n\nimport DocButton from '../doc-button.vue';\n\nconst longText = `Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案，目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈，可以作为项目的启动模版，以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例，用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术，并将其应用在项目中。`;\n\nconst text = ref(longText);\n</script>\n\n<template>\n  <Page\n    description=\"用于多行文本省略，支持点击展开和自定义内容。\"\n    title=\"文本省略组件示例\"\n  >\n    <template #extra>\n      <DocButton class=\"mb-2\" path=\"/components/common-ui/vben-ellipsis-text\" />\n    </template>\n    <Card class=\"mb-4\" title=\"基本使用\">\n      <EllipsisText :max-width=\"500\">{{ text }}</EllipsisText>\n    </Card>\n\n    <Card class=\"mb-4\" title=\"多行省略\">\n      <EllipsisText :line=\"2\">{{ text }}</EllipsisText>\n    </Card>\n\n    <Card class=\"mb-4\" title=\"点击展开\">\n      <EllipsisText :line=\"3\" expand>{{ text }}</EllipsisText>\n    </Card>\n    <Card class=\"mb-4\" title=\"自定义内容\">\n      <EllipsisText :max-width=\"240\">\n        住在我心里孤独的 孤独的海怪 痛苦之王 开始厌倦 深海的光 停滞的海浪\n        <template #tooltip>\n          <div style=\"text-align: center\">\n            《秦皇岛》<br />住在我心里孤独的<br />孤独的海怪 痛苦之王<br />开始厌倦\n            深海的光 停滞的海浪\n          </div>\n        </template>\n      </EllipsisText>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/api.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { RefSelectProps } from 'ant-design-vue/es/select';\n\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button, Card, message, Space } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst isReverseActionButtons = ref(false);\n\nconst [BaseForm, formApi] = useVbenForm({\n  // 翻转操作按钮的位置\n  actionButtonsReverse: isReverseActionButtons.value,\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 使用 tailwindcss grid布局\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  layout: 'horizontal',\n  // 水平布局，label和input在同一行\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      // 字段名\n      fieldName: 'field1',\n      // 界面显示的label\n      label: 'field1',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field2',\n      label: 'field2',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      fieldName: 'fieldOptions',\n      label: '下拉选',\n    },\n  ],\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n\nfunction handleClick(\n  action:\n    | 'batchAddSchema'\n    | 'batchDeleteSchema'\n    | 'componentRef'\n    | 'disabled'\n    | 'hiddenAction'\n    | 'hiddenResetButton'\n    | 'hiddenSubmitButton'\n    | 'labelWidth'\n    | 'resetDisabled'\n    | 'resetLabelWidth'\n    | 'reverseActionButtons'\n    | 'showAction'\n    | 'showResetButton'\n    | 'showSubmitButton'\n    | 'updateActionAlign'\n    | 'updateResetButton'\n    | 'updateSchema'\n    | 'updateSubmitButton',\n) {\n  switch (action) {\n    case 'batchAddSchema': {\n      formApi.setState((prev) => {\n        const currentSchema = prev?.schema ?? [];\n        const newSchema = [];\n        for (let i = 0; i < 3; i++) {\n          newSchema.push({\n            component: 'Input',\n            componentProps: {\n              placeholder: '请输入',\n            },\n            fieldName: `field${i}${Date.now()}`,\n            label: `field+`,\n          });\n        }\n        return {\n          schema: [...currentSchema, ...newSchema],\n        };\n      });\n      break;\n    }\n\n    case 'batchDeleteSchema': {\n      formApi.setState((prev) => {\n        const currentSchema = prev?.schema ?? [];\n        return {\n          schema: currentSchema.slice(0, -3),\n        };\n      });\n      break;\n    }\n    case 'componentRef': {\n      // 获取下拉组件的实例，并调用它的focus方法\n      formApi.getFieldComponentRef<RefSelectProps>('fieldOptions')?.focus?.();\n      break;\n    }\n    case 'disabled': {\n      formApi.setState({ commonConfig: { disabled: true } });\n      break;\n    }\n    case 'hiddenAction': {\n      formApi.setState({ showDefaultActions: false });\n      break;\n    }\n    case 'hiddenResetButton': {\n      formApi.setState({ resetButtonOptions: { show: false } });\n      break;\n    }\n    case 'hiddenSubmitButton': {\n      formApi.setState({ submitButtonOptions: { show: false } });\n      break;\n    }\n    case 'labelWidth': {\n      formApi.setState({\n        commonConfig: {\n          labelWidth: 150,\n        },\n      });\n      break;\n    }\n    case 'resetDisabled': {\n      formApi.setState({ commonConfig: { disabled: false } });\n      break;\n    }\n    case 'resetLabelWidth': {\n      formApi.setState({\n        commonConfig: {\n          labelWidth: 100,\n        },\n      });\n      break;\n    }\n    case 'reverseActionButtons': {\n      isReverseActionButtons.value = !isReverseActionButtons.value;\n      formApi.setState({ actionButtonsReverse: isReverseActionButtons.value });\n      break;\n    }\n    case 'showAction': {\n      formApi.setState({ showDefaultActions: true });\n      break;\n    }\n    case 'showResetButton': {\n      formApi.setState({ resetButtonOptions: { show: true } });\n      break;\n    }\n    case 'showSubmitButton': {\n      formApi.setState({ submitButtonOptions: { show: true } });\n      break;\n    }\n\n    case 'updateActionAlign': {\n      formApi.setState({\n        // 可以自行调整class\n        actionWrapperClass: 'text-center',\n      });\n      break;\n    }\n    case 'updateResetButton': {\n      formApi.setState({\n        resetButtonOptions: { disabled: true },\n      });\n      break;\n    }\n    case 'updateSchema': {\n      formApi.updateSchema([\n        {\n          componentProps: {\n            options: [\n              {\n                label: '选项1',\n                value: '1',\n              },\n              {\n                label: '选项2',\n                value: '2',\n              },\n              {\n                label: '选项3',\n                value: '3',\n              },\n            ],\n          },\n          fieldName: 'fieldOptions',\n        },\n      ]);\n      message.success('字段 `fieldOptions` 下拉选项更新成功。');\n      break;\n    }\n    case 'updateSubmitButton': {\n      formApi.setState({\n        submitButtonOptions: { loading: true },\n      });\n      break;\n    }\n  }\n}\n</script>\n\n<template>\n  <Page description=\"表单组件api操作示例。\" title=\"表单组件\">\n    <Space class=\"mb-5 flex-wrap\">\n      <Button @click=\"handleClick('updateSchema')\">updateSchema</Button>\n      <Button @click=\"handleClick('labelWidth')\">更改labelWidth</Button>\n      <Button @click=\"handleClick('resetLabelWidth')\">还原labelWidth</Button>\n      <Button @click=\"handleClick('disabled')\">禁用表单</Button>\n      <Button @click=\"handleClick('resetDisabled')\">解除禁用</Button>\n      <Button @click=\"handleClick('reverseActionButtons')\">\n        翻转操作按钮位置\n      </Button>\n      <Button @click=\"handleClick('hiddenAction')\">隐藏操作按钮</Button>\n      <Button @click=\"handleClick('showAction')\">显示操作按钮</Button>\n      <Button @click=\"handleClick('hiddenResetButton')\">隐藏重置按钮</Button>\n      <Button @click=\"handleClick('showResetButton')\">显示重置按钮</Button>\n      <Button @click=\"handleClick('hiddenSubmitButton')\">隐藏提交按钮</Button>\n      <Button @click=\"handleClick('showSubmitButton')\">显示提交按钮</Button>\n      <Button @click=\"handleClick('updateResetButton')\">修改重置按钮</Button>\n      <Button @click=\"handleClick('updateSubmitButton')\">修改提交按钮</Button>\n      <Button @click=\"handleClick('updateActionAlign')\">\n        调整操作按钮位置\n      </Button>\n      <Button @click=\"handleClick('batchAddSchema')\"> 批量添加表单项 </Button>\n      <Button @click=\"handleClick('batchDeleteSchema')\">\n        批量删除表单项\n      </Button>\n      <Button @click=\"handleClick('componentRef')\">下拉组件获取焦点</Button>\n    </Space>\n    <Card title=\"操作示例\">\n      <BaseForm />\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { UploadFile } from 'ant-design-vue';\n\nimport { h, ref, toRaw } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { useDebounceFn } from '@vueuse/core';\nimport { Button, Card, message, Spin, Tag } from 'ant-design-vue';\nimport dayjs from 'dayjs';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport { getAllMenusApi } from '#/api';\nimport { upload_file } from '#/api/examples/upload';\nimport { $t } from '#/locales';\n\nimport DocButton from '../doc-button.vue';\n\nconst keyword = ref('');\nconst fetching = ref(false);\n// 模拟远程获取数据\nfunction fetchRemoteOptions({ keyword = '选项' }: Record<string, any>) {\n  fetching.value = true;\n  return new Promise((resolve) => {\n    setTimeout(() => {\n      const options = Array.from({ length: 10 }).map((_, index) => ({\n        label: `${keyword}-${index}`,\n        value: `${keyword}-${index}`,\n      }));\n      resolve(options);\n      fetching.value = false;\n    }, 1000);\n  });\n}\n\nconst [BaseForm, baseFormApi] = useVbenForm({\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 在label后显示一个冒号\n    colon: true,\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  fieldMappingTime: [['rangePicker', ['startTime', 'endTime'], 'YYYY-MM-DD']],\n  // 提交函数\n  handleSubmit: onSubmit,\n  handleValuesChange(_values, fieldsChanged) {\n    message.info(`表单以下字段发生变化：${fieldsChanged.join('，')}`);\n  },\n\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'horizontal',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      // 字段名\n      fieldName: 'username',\n      // 界面显示的label\n      label: '字符串',\n      rules: 'required',\n    },\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'ApiSelect',\n      // 对应组件的参数\n      componentProps: {\n        // 菜单接口转options格式\n        afterFetch: (data: { name: string; path: string }[]) => {\n          return data.map((item: any) => ({\n            label: item.name,\n            value: item.path,\n          }));\n        },\n        // 菜单接口\n        api: getAllMenusApi,\n        autoSelect: 'first',\n      },\n      // 字段名\n      fieldName: 'api',\n      // 界面显示的label\n      label: 'ApiSelect',\n    },\n    {\n      component: 'ApiSelect',\n      // 对应组件的参数\n      componentProps: () => {\n        return {\n          api: fetchRemoteOptions,\n          // 禁止本地过滤\n          filterOption: false,\n          // 如果正在获取数据，使用插槽显示一个loading\n          notFoundContent: fetching.value ? undefined : null,\n          // 搜索词变化时记录下来， 使用useDebounceFn防抖。\n          onSearch: useDebounceFn((value: string) => {\n            keyword.value = value;\n          }, 300),\n          // 远程搜索参数。当搜索词变化时，params也会更新\n          params: {\n            keyword: keyword.value || undefined,\n          },\n          showSearch: true,\n        };\n      },\n      // 字段名\n      fieldName: 'remoteSearch',\n      // 界面显示的label\n      label: '远程搜索',\n      renderComponentContent: () => {\n        return {\n          notFoundContent: fetching.value ? h(Spin) : undefined,\n        };\n      },\n      rules: 'selectRequired',\n    },\n    {\n      component: 'ApiTreeSelect',\n      // 对应组件的参数\n      componentProps: {\n        // 菜单接口\n        api: getAllMenusApi,\n        // 菜单接口转options格式\n        labelField: 'name',\n        valueField: 'path',\n        childrenField: 'children',\n      },\n      // 字段名\n      fieldName: 'apiTree',\n      // 界面显示的label\n      label: 'ApiTreeSelect',\n    },\n    {\n      component: 'InputPassword',\n      componentProps: {\n        placeholder: '请输入密码',\n      },\n      fieldName: 'password',\n      label: '密码',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'number',\n      label: '数字(带后缀)',\n      suffix: () => '¥',\n    },\n    {\n      component: 'IconPicker',\n      fieldName: 'icon',\n      label: '图标',\n    },\n    {\n      colon: false,\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      fieldName: 'options',\n      label: () => h(Tag, { color: 'warning' }, () => '😎自定义：'),\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n      },\n      fieldName: 'radioGroup',\n      label: '单选组',\n    },\n    {\n      component: 'Radio',\n      fieldName: 'radio',\n      label: '',\n      renderComponentContent: () => {\n        return {\n          default: () => ['Radio'],\n        };\n      },\n    },\n    {\n      component: 'CheckboxGroup',\n      componentProps: {\n        name: 'cname',\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n      },\n      fieldName: 'checkboxGroup',\n      label: '多选组',\n    },\n    {\n      component: 'Checkbox',\n      fieldName: 'checkbox',\n      label: '',\n      renderComponentContent: () => {\n        return {\n          default: () => ['我已阅读并同意'],\n        };\n      },\n      rules: z\n        .boolean()\n        .refine((v) => v, { message: '为什么不同意？勾上它！' }),\n    },\n    {\n      component: 'Mentions',\n      componentProps: {\n        options: [\n          {\n            label: 'afc163',\n            value: 'afc163',\n          },\n          {\n            label: 'zombieJ',\n            value: 'zombieJ',\n          },\n        ],\n        placeholder: '请输入',\n      },\n      fieldName: 'mentions',\n      label: '提及',\n    },\n    {\n      component: 'Rate',\n      fieldName: 'rate',\n      label: '评分',\n    },\n    {\n      component: 'Switch',\n      componentProps: {\n        class: 'w-auto',\n      },\n      fieldName: 'switch',\n      help: () =>\n        ['这是一个多行帮助信息', '第二行', '第三行'].map((v) => h('p', v)),\n      label: '开关',\n    },\n    {\n      component: 'DatePicker',\n      fieldName: 'datePicker',\n      label: '日期选择框',\n    },\n    {\n      component: 'RangePicker',\n      fieldName: 'rangePicker',\n      label: '范围选择器',\n    },\n    {\n      component: 'TimePicker',\n      fieldName: 'timePicker',\n      label: '时间选择框',\n    },\n    {\n      component: 'TreeSelect',\n      componentProps: {\n        allowClear: true,\n        placeholder: '请选择',\n        showSearch: true,\n        treeData: [\n          {\n            label: 'root 1',\n            value: 'root 1',\n            children: [\n              {\n                label: 'parent 1',\n                value: 'parent 1',\n                children: [\n                  {\n                    label: 'parent 1-0',\n                    value: 'parent 1-0',\n                    children: [\n                      {\n                        label: 'my leaf',\n                        value: 'leaf1',\n                      },\n                      {\n                        label: 'your leaf',\n                        value: 'leaf2',\n                      },\n                    ],\n                  },\n                  {\n                    label: 'parent 1-1',\n                    value: 'parent 1-1',\n                  },\n                ],\n              },\n              {\n                label: 'parent 2',\n                value: 'parent 2',\n              },\n            ],\n          },\n        ],\n        treeNodeFilterProp: 'label',\n      },\n      fieldName: 'treeSelect',\n      label: '树选择',\n    },\n    {\n      component: 'Upload',\n      componentProps: {\n        // 更多属性见：https://ant.design/components/upload-cn\n        accept: '.png,.jpg,.jpeg',\n        // 自动携带认证信息\n        customRequest: upload_file,\n        disabled: false,\n        maxCount: 1,\n        multiple: false,\n        showUploadList: true,\n        // 上传列表的内建样式，支持四种基本样式 text, picture, picture-card 和 picture-circle\n        listType: 'picture-card',\n      },\n      fieldName: 'files',\n      label: $t('examples.form.file'),\n      renderComponentContent: () => {\n        return {\n          default: () => $t('examples.form.upload-image'),\n        };\n      },\n      rules: 'required',\n    },\n  ],\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  const files = toRaw(values.files) as UploadFile[];\n  const doneFiles = files.filter((file) => file.status === 'done');\n  const failedFiles = files.filter((file) => file.status !== 'done');\n\n  const msg = [\n    ...doneFiles.map((file) => file.response?.url || file.url),\n    ...failedFiles.map((file) => file.name),\n  ].join(', ');\n\n  if (failedFiles.length === 0) {\n    message.success({\n      content: `${$t('examples.form.upload-urls')}: ${msg}`,\n    });\n  } else {\n    message.error({\n      content: `${$t('examples.form.upload-error')}: ${msg}`,\n    });\n    return;\n  }\n  // 如果需要可提交前替换为需要的urls\n  values.files = doneFiles.map((file) => file.response?.url || file.url);\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n\nfunction handleSetFormValue() {\n  /**\n   * 设置表单值(多个)\n   */\n  baseFormApi.setValues({\n    checkboxGroup: ['1'],\n    datePicker: dayjs('2022-01-01'),\n    files: [\n      {\n        name: 'example.png',\n        status: 'done',\n        uid: '-1',\n        url: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',\n      },\n    ],\n    mentions: '@afc163',\n    number: 3,\n    options: '1',\n    password: '2',\n    radioGroup: '1',\n    rangePicker: [dayjs('2022-01-01'), dayjs('2022-01-02')],\n    rate: 3,\n    switch: true,\n    timePicker: dayjs('2022-01-01 12:00:00'),\n    treeSelect: 'leaf1',\n    username: '1',\n  });\n\n  // 设置单个表单值\n  baseFormApi.setFieldValue('checkbox', true);\n}\n</script>\n\n<template>\n  <Page\n    content-class=\"flex flex-col gap-4\"\n    description=\"表单组件基础示例，请注意，该页面用到的参数代码会添加一些简单注释，方便理解，请仔细查看。\"\n    title=\"表单组件\"\n  >\n    <template #description>\n      <div class=\"text-muted-foreground\">\n        <p>\n          表单组件基础示例，请注意，该页面用到的参数代码会添加一些简单注释，方便理解，请仔细查看。\n        </p>\n      </div>\n    </template>\n    <template #extra>\n      <DocButton class=\"mb-2\" path=\"/components/common-ui/vben-form\" />\n    </template>\n    <Card title=\"基础示例\">\n      <template #extra>\n        <Button type=\"primary\" @click=\"handleSetFormValue\">设置表单值</Button>\n      </template>\n      <BaseForm />\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/custom-layout.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Card } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nimport DocButton from '../doc-button.vue';\n\nconst [CustomLayoutForm] = useVbenForm({\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  layout: 'horizontal',\n  schema: [\n    {\n      component: 'Select',\n      fieldName: 'field1',\n      label: '字符串',\n    },\n    {\n      component: 'TreeSelect',\n      fieldName: 'field2',\n      label: '字符串',\n    },\n    {\n      component: 'Mentions',\n      fieldName: 'field3',\n      label: '字符串',\n    },\n    {\n      component: 'Input',\n      fieldName: 'field4',\n      label: '字符串',\n    },\n    {\n      component: 'InputNumber',\n      fieldName: 'field5',\n      // 从第三列开始 相当于中间空了一列\n      formItemClass: 'col-start-3',\n      label: '前面空了一列',\n    },\n    {\n      component: 'Divider',\n      fieldName: '_divider',\n      formItemClass: 'col-span-3',\n      hideLabel: true,\n      renderComponentContent: () => {\n        return {\n          default: () => h('div', '分割线'),\n        };\n      },\n    },\n    {\n      component: 'Textarea',\n      fieldName: 'field6',\n      // 占满三列空间 基线对齐\n      formItemClass: 'col-span-3 items-baseline',\n      label: '占满三列',\n    },\n    {\n      component: 'Input',\n      fieldName: 'field7',\n      // 占满2列空间 从第二列开始 相当于前面空了一列\n      formItemClass: 'col-span-2 col-start-2',\n      label: '占满2列',\n    },\n    {\n      component: 'Input',\n      fieldName: 'field8',\n      // 左右留空\n      formItemClass: 'col-start-2',\n      label: '左右留空',\n    },\n    {\n      component: 'InputPassword',\n      fieldName: 'field9',\n      formItemClass: 'col-start-1',\n      label: '字符串',\n    },\n  ],\n  // 一共三列\n  wrapperClass: 'grid-cols-3',\n});\n</script>\n\n<template>\n  <Page\n    content-class=\"flex flex-col gap-4\"\n    description=\"使用tailwind自定义表单项的布局\"\n    title=\"表单自定义布局\"\n  >\n    <template #description>\n      <div class=\"text-muted-foreground\">\n        <p>使用tailwind自定义表单项的布局，使用Divider分割表单。</p>\n      </div>\n    </template>\n    <template #extra>\n      <DocButton class=\"mb-2\" path=\"/components/common-ui/vben-form\" />\n    </template>\n    <Card title=\"使用tailwind自定义布局\">\n      <CustomLayoutForm />\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/custom.vue",
    "content": "<script lang=\"ts\" setup>\nimport { h, markRaw } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Card, Input, message } from 'ant-design-vue';\n\nimport { useVbenForm, z } from '#/adapter/form';\n\nimport TwoFields from './modules/two-fields.vue';\n\nconst [Form] = useVbenForm({\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n    labelClass: 'w-2/6',\n  },\n  fieldMappingTime: [['field4', ['phoneType', 'phoneNumber'], null]],\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'horizontal',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      fieldName: 'field',\n      label: '自定义后缀',\n      suffix: () => h('span', { class: 'text-red-600' }, '元'),\n    },\n    {\n      component: 'Input',\n      fieldName: 'field1',\n      label: '自定义组件slot',\n      renderComponentContent: () => ({\n        prefix: () => 'prefix',\n        suffix: () => 'suffix',\n      }),\n    },\n    {\n      component: h(Input, { placeholder: '请输入Field2' }),\n      fieldName: 'field2',\n      label: '自定义组件',\n      modelPropName: 'value',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      fieldName: 'field3',\n      label: '自定义组件(slot)',\n      rules: 'required',\n    },\n    {\n      component: markRaw(TwoFields),\n      defaultValue: [undefined, ''],\n      disabledOnChangeListener: false,\n      fieldName: 'field4',\n      formItemClass: 'col-span-1',\n      label: '组合字段',\n      rules: z\n        .array(z.string().optional())\n        .length(2, '请选择类型并输入手机号码')\n        .refine((v) => !!v[0], {\n          message: '请选择类型',\n        })\n        .refine((v) => !!v[1] && v[1] !== '', {\n          message: '　　　　　　　输入手机号码',\n        })\n        .refine((v) => v[1]?.match(/^1[3-9]\\d{9}$/), {\n          // 使用全角空格占位，将错误提示文字挤到手机号码输入框的下面\n          message: '　　　　　　　号码格式不正确',\n        }),\n    },\n  ],\n  // 中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <Page description=\"表单组件自定义示例\" title=\"表单组件\">\n    <Card title=\"基础示例\">\n      <Form>\n        <template #field3=\"slotProps\">\n          <Input placeholder=\"请输入\" v-bind=\"slotProps\" />\n        </template>\n      </Form>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/dynamic.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Page } from '@vben/common-ui';\n\nimport { Button, Card, message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst [Form, formApi] = useVbenForm({\n  // 提交函数\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      defaultValue: 'hidden value',\n      dependencies: {\n        show: false,\n        // 随意一个字段改变时，都会触发\n        triggerFields: ['field1Switch'],\n      },\n      fieldName: 'hiddenField',\n      label: '隐藏字段',\n    },\n    {\n      component: 'Switch',\n      defaultValue: true,\n      fieldName: 'field1Switch',\n      help: '通过Dom控制销毁',\n      label: '显示字段1',\n    },\n    {\n      component: 'Switch',\n      defaultValue: true,\n      fieldName: 'field2Switch',\n      help: '通过css控制隐藏',\n      label: '显示字段2',\n    },\n    {\n      component: 'Switch',\n      fieldName: 'field3Switch',\n      label: '禁用字段3',\n    },\n    {\n      component: 'Switch',\n      fieldName: 'field4Switch',\n      label: '字段4必填',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        if(values) {\n          return !!values.field1Switch;\n        },\n        // 只有指定的字段改变时，才会触发\n        triggerFields: ['field1Switch'],\n      },\n      // 字段名\n      fieldName: 'field1',\n      // 界面显示的label\n      label: '字段1',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        show(values) {\n          return !!values.field2Switch;\n        },\n        triggerFields: ['field2Switch'],\n      },\n      fieldName: 'field2',\n      label: '字段2',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        disabled(values) {\n          return !!values.field3Switch;\n        },\n        triggerFields: ['field3Switch'],\n      },\n      fieldName: 'field3',\n      label: '字段3',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        required(values) {\n          return !!values.field4Switch;\n        },\n        triggerFields: ['field4Switch'],\n      },\n      fieldName: 'field4',\n      label: '字段4',\n    },\n    {\n      component: 'Input',\n      dependencies: {\n        rules(values) {\n          if (values.field1 === '123') {\n            return 'required';\n          }\n          return null;\n        },\n        triggerFields: ['field1'],\n      },\n      fieldName: 'field5',\n      help: '当字段1的值为`123`时，必填',\n      label: '动态rules',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        class: 'w-full',\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      dependencies: {\n        componentProps(values) {\n          if (values.field2 === '123') {\n            return {\n              options: [\n                {\n                  label: '选项1',\n                  value: '1',\n                },\n                {\n                  label: '选项2',\n                  value: '2',\n                },\n                {\n                  label: '选项3',\n                  value: '3',\n                },\n              ],\n            };\n          }\n          return {};\n        },\n        triggerFields: ['field2'],\n      },\n      fieldName: 'field6',\n      help: '当字段2的值为`123`时，更改下拉选项',\n      label: '动态配置',\n    },\n    {\n      component: 'Input',\n      fieldName: 'field7',\n      label: '字段7',\n    },\n  ],\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-3 lg:grid-cols-4',\n});\n\nconst [SyncForm] = useVbenForm({\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      // 字段名\n      fieldName: 'field1',\n      // 界面显示的label\n      label: '字段1',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        disabled: true,\n      },\n      dependencies: {\n        trigger(values, form) {\n          form.setFieldValue('field2', values.field1);\n        },\n        // 只有指定的字段改变时，才会触发\n        triggerFields: ['field1'],\n      },\n      // 字段名\n      fieldName: 'field2',\n      // 界面显示的label\n      label: '字段2',\n    },\n  ],\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-3 lg:grid-cols-4',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n\nfunction handleDelete() {\n  formApi.setState((prev) => {\n    return {\n      schema: prev.schema?.filter((item) => item.fieldName !== 'field7'),\n    };\n  });\n}\n\nfunction handleAdd() {\n  formApi.setState((prev) => {\n    return {\n      schema: [\n        ...(prev?.schema ?? []),\n        {\n          component: 'Input',\n          fieldName: `field${Date.now()}`,\n          label: '字段+',\n        },\n      ],\n    };\n  });\n}\n\nfunction handleUpdate() {\n  formApi.setState((prev) => {\n    return {\n      schema: prev.schema?.map((item) => {\n        if (item.fieldName === 'field3') {\n          return {\n            ...item,\n            label: '字段3-修改',\n          };\n        }\n        return item;\n      }),\n    };\n  });\n}\n</script>\n\n<template>\n  <Page\n    description=\"表单组件动态联动示例，包含了常用的场景。增删改，本质上是修改schema，你也可以通过 `setState` 动态修改schema。\"\n    title=\"表单组件\"\n  >\n    <Card title=\"表单动态联动示例\">\n      <template #extra>\n        <Button class=\"mr-2\" @click=\"handleUpdate\">修改字段3</Button>\n        <Button class=\"mr-2\" @click=\"handleDelete\">删除字段7</Button>\n        <Button @click=\"handleAdd\">添加字段</Button>\n      </template>\n      <Form />\n    </Card>\n\n    <Card class=\"mt-5\" title=\"字段同步，字段1数据与字段2数据同步\">\n      <SyncForm />\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/merge.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button, Card, message, Step, Steps, Switch } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst currentTab = ref(0);\nfunction onFirstSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form1 values: ${JSON.stringify(values)}`,\n  });\n  currentTab.value = 1;\n}\nfunction onSecondReset() {\n  currentTab.value = 0;\n}\nfunction onSecondSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form2 values: ${JSON.stringify(values)}`,\n  });\n}\n\nconst [FirstForm, firstFormApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleSubmit: onFirstSubmit,\n  layout: 'horizontal',\n  resetButtonOptions: {\n    show: false,\n  },\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'formFirst',\n      label: '表单1字段',\n      rules: 'required',\n    },\n  ],\n  submitButtonOptions: {\n    content: '下一步',\n  },\n  wrapperClass: 'grid-cols-1 md:grid-cols-1 lg:grid-cols-1',\n});\nconst [SecondForm, secondFormApi] = useVbenForm({\n  commonConfig: {\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  handleReset: onSecondReset,\n  handleSubmit: onSecondSubmit,\n  layout: 'horizontal',\n  resetButtonOptions: {\n    content: '上一步',\n  },\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'formSecond',\n      label: '表单2字段',\n      rules: 'required',\n    },\n  ],\n  wrapperClass: 'grid-cols-1 md:grid-cols-1 lg:grid-cols-1',\n});\nconst needMerge = ref(true);\nasync function handleMergeSubmit() {\n  const values = await firstFormApi\n    .merge(secondFormApi)\n    .submitAllForm(needMerge.value);\n  message.success({\n    content: `merged form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <Page\n    description=\"表单组件合并示例：在某些场景下，例如分步表单，需要合并多个表单并统一提交。默认情况下，使用 Object.assign 规则合并表单。如果需要特殊处理数据，可以传入 false。\"\n    title=\"表单组件\"\n  >\n    <Card title=\"基础示例\">\n      <template #extra>\n        <Switch\n          v-model:checked=\"needMerge\"\n          checked-children=\"开启字段合并\"\n          class=\"mr-4\"\n          un-checked-children=\"关闭字段合并\"\n        />\n        <Button type=\"primary\" @click=\"handleMergeSubmit\">合并提交</Button>\n      </template>\n      <div class=\"mx-auto max-w-lg\">\n        <Steps :current=\"currentTab\" class=\"steps\">\n          <Step title=\"表单1\" />\n          <Step title=\"表单2\" />\n        </Steps>\n        <div class=\"p-20\">\n          <FirstForm v-show=\"currentTab === 0\" />\n          <SecondForm v-show=\"currentTab === 1\" />\n        </div>\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/modules/two-fields.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Input, Select } from 'ant-design-vue';\n\nconst emit = defineEmits(['blur', 'change']);\n\nconst modelValue = defineModel<[string, string]>({\n  default: () => [undefined, undefined],\n});\n\nfunction onChange() {\n  emit('change', modelValue.value);\n}\n</script>\n<template>\n  <div class=\"flex w-full gap-1\">\n    <Select\n      v-model:value=\"modelValue[0]\"\n      class=\"w-[80px]\"\n      placeholder=\"类型\"\n      allow-clear\n      :class=\"{ 'valid-success': !!modelValue[0] }\"\n      :options=\"[\n        { label: '个人', value: 'personal' },\n        { label: '工作', value: 'work' },\n        { label: '私密', value: 'private' },\n      ]\"\n      @blur=\"emit('blur')\"\n      @change=\"onChange\"\n    />\n    <Input\n      placeholder=\"请输入11位手机号码\"\n      class=\"flex-1\"\n      allow-clear\n      :class=\"{ 'valid-success': modelValue[1]?.match(/^1[3-9]\\d{9}$/) }\"\n      v-model:value=\"modelValue[1]\"\n      :maxlength=\"11\"\n      type=\"tel\"\n      @blur=\"emit('blur')\"\n      @change=\"onChange\"\n    />\n  </div>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/query.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Page } from '@vben/common-ui';\n\nimport { Card, message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst [QueryForm] = useVbenForm({\n  // 默认展开\n  collapsed: false,\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'horizontal',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      // 字段名\n      fieldName: 'username',\n      // 界面显示的label\n      label: '字符串',\n    },\n    {\n      component: 'InputPassword',\n      componentProps: {\n        placeholder: '请输入密码',\n      },\n      fieldName: 'password',\n      label: '密码',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'number',\n      label: '数字(带后缀)',\n      suffix: () => '¥',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      fieldName: 'options',\n      label: '下拉选',\n    },\n    {\n      component: 'DatePicker',\n      fieldName: 'datePicker',\n      label: '日期选择框',\n    },\n  ],\n  // 是否可展开\n  showCollapseButton: true,\n  submitButtonOptions: {\n    content: '查询',\n  },\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n});\n\nconst [InlineForm] = useVbenForm({\n  layout: 'inline',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      // 字段名\n      fieldName: 'username',\n      // 界面显示的label\n      label: '字符串',\n    },\n    {\n      component: 'InputPassword',\n      componentProps: {\n        placeholder: '请输入密码',\n      },\n      fieldName: 'password',\n      label: '密码',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'number',\n      label: '数字(带后缀)',\n      suffix: () => '¥',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      fieldName: 'options',\n      label: '下拉选',\n    },\n  ],\n});\n\nconst [QueryForm1] = useVbenForm({\n  // 默认展开\n  collapsed: true,\n  collapsedRows: 2,\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'horizontal',\n  schema: (() => {\n    const schema = [];\n    for (let index = 0; index < 14; index++) {\n      schema.push({\n        // 组件需要在 #/adapter.ts内注册，并加上类型\n        component: 'Input',\n        // 字段名\n        fieldName: `field${index}`,\n        // 界面显示的label\n        label: `字段${index}`,\n      });\n    }\n    return schema;\n  })(),\n  // 是否可展开\n  showCollapseButton: true,\n  submitButtonOptions: {\n    content: '查询',\n  },\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n});\n\nconst [QueryForm2] = useVbenForm({\n  // 操作按钮组 newLine: 在新行显示。rowEnd: 在行内显示，靠右对齐（默认）。inline: 使用grid默认样式\n  actionLayout: 'newLine',\n  actionPosition: 'left', // 操作按钮组在左侧显示\n  // 默认折叠\n  collapsed: true,\n  collapsedRows: 3,\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'vertical',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      // 字段名\n      fieldName: 'username',\n      // 界面显示的label\n      label: '字符串',\n    },\n    {\n      component: 'InputPassword',\n      componentProps: {\n        placeholder: '请输入密码',\n      },\n      fieldName: 'password',\n      label: '密码',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'number',\n      label: '数字(带后缀)',\n      suffix: () => '¥',\n    },\n    {\n      component: 'DatePicker',\n      fieldName: 'datePicker',\n      label: '日期选择框',\n    },\n  ],\n  // 是否可展开\n  showCollapseButton: true,\n  submitButtonOptions: {\n    content: '查询',\n  },\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <Page\n    description=\"查询表单，常用语和表格组合使用，可进行收缩展开。\"\n    title=\"表单组件\"\n  >\n    <Card class=\"mb-5\" title=\"查询表单，默认展开\">\n      <QueryForm />\n    </Card>\n\n    <Card class=\"mb-5\" title=\"查询表单，单行表单\">\n      <InlineForm />\n    </Card>\n\n    <Card class=\"mb-5\" title=\"查询表单，默认展开，垂直布局\">\n      <QueryForm2 />\n    </Card>\n\n    <Card title=\"查询表单，默认折叠，折叠时保留2行\">\n      <QueryForm1 />\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/rules.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Page } from '@vben/common-ui';\n\nimport { Button, Card, message } from 'ant-design-vue';\n\nimport { useVbenForm, z } from '#/adapter/form';\n\nconst [Form, formApi] = useVbenForm({\n  // 所有表单项共用，可单独在表单内覆盖\n  commonConfig: {\n    // 所有表单项\n    componentProps: {\n      class: 'w-full',\n    },\n  },\n  // 提交函数\n  handleSubmit: onSubmit,\n  // 垂直布局，label和input在不同行，值为vertical\n  // 水平布局，label和input在同一行\n  layout: 'horizontal',\n  schema: [\n    {\n      // 组件需要在 #/adapter.ts内注册，并加上类型\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入',\n      },\n      // 字段名\n      fieldName: 'field1',\n      // 界面显示的label\n      label: '字段1',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      defaultValue: '默认值',\n      fieldName: 'field2',\n      label: '默认值(必填)',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field3',\n      label: '默认值(非必填)',\n      rules: z.string().default('默认值').optional(),\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field31',\n      label: '自定义信息',\n      rules: z.string().min(1, { message: '最少输入1个字符' }),\n    },\n    {\n      component: 'Input',\n      // 对应组件的参数\n      componentProps: {\n        placeholder: '请输入',\n      },\n      // 字段名\n      fieldName: 'field4',\n      // 界面显示的label\n      label: '邮箱',\n      rules: z.string().email('请输入正确的邮箱'),\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'number',\n      label: '数字',\n      rules: 'required',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        filterOption: true,\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n        showSearch: true,\n      },\n      defaultValue: undefined,\n      fieldName: 'options',\n      label: '下拉选',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n      },\n      fieldName: 'radioGroup',\n      label: '单选组',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'CheckboxGroup',\n      componentProps: {\n        name: 'cname',\n        options: [\n          {\n            label: '选项1',\n            value: '1',\n          },\n          {\n            label: '选项2',\n            value: '2',\n          },\n        ],\n      },\n      fieldName: 'checkboxGroup',\n      label: '多选组',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'Checkbox',\n      fieldName: 'checkbox',\n      label: '',\n      renderComponentContent: () => {\n        return {\n          default: () => ['我已阅读并同意'],\n        };\n      },\n      rules: z.boolean().refine((value) => value, {\n        message: '请勾选',\n      }),\n    },\n    {\n      component: 'DatePicker',\n      defaultValue: undefined,\n      fieldName: 'datePicker',\n      label: '日期选择框',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'RangePicker',\n      defaultValue: undefined,\n      fieldName: 'rangePicker',\n      label: '区间选择框',\n      rules: 'selectRequired',\n    },\n    {\n      component: 'InputPassword',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'password',\n      label: '密码',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'input-blur',\n      formFieldProps: {\n        validateOnChange: false,\n        validateOnModelUpdate: false,\n      },\n      help: 'blur时才会触发校验',\n      label: 'blur触发',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'input-async',\n      label: '异步校验',\n      rules: z\n        .string()\n        .min(3, '用户名至少需要3个字符')\n        .refine(\n          async (username) => {\n            // 假设这是一个异步函数，模拟检查用户名是否已存在\n            const checkUsernameExists = async (\n              username: string,\n            ): Promise<boolean> => {\n              await new Promise((resolve) => setTimeout(resolve, 1000));\n              return username === 'existingUser';\n            };\n            const exists = await checkUsernameExists(username);\n            return !exists;\n          },\n          {\n            message: '用户名已存在',\n          },\n        ),\n    },\n  ],\n  // 大屏一行显示3个，中屏一行显示2个，小屏一行显示1个\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.success({\n    content: `form values: ${JSON.stringify(values)}`,\n  });\n}\n</script>\n\n<template>\n  <Page description=\"表单校验示例\" title=\"表单组件\">\n    <Card title=\"基础组件校验示例\">\n      <template #extra>\n        <Button @click=\"() => formApi.validate()\">校验表单</Button>\n        <Button class=\"mx-2\" @click=\"() => formApi.resetValidate()\">\n          清空校验信息\n        </Button>\n      </template>\n      <Form />\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/form/scroll-to-error-test.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button, Card, Switch } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\ndefineOptions({\n  name: 'ScrollToErrorTest',\n});\n\nconst scrollEnabled = ref(true);\n\nconst [Form, formApi] = useVbenForm({\n  scrollToFirstError: scrollEnabled.value,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入用户名',\n      },\n      fieldName: 'username',\n      label: '用户名',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入邮箱',\n      },\n      fieldName: 'email',\n      label: '邮箱',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入手机号',\n      },\n      fieldName: 'phone',\n      label: '手机号',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入地址',\n      },\n      fieldName: 'address',\n      label: '地址',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入备注',\n      },\n      fieldName: 'remark',\n      label: '备注',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入公司名称',\n      },\n      fieldName: 'company',\n      label: '公司名称',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入职位',\n      },\n      fieldName: 'position',\n      label: '职位',\n      rules: 'required',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: [\n          { label: '男', value: 'male' },\n          { label: '女', value: 'female' },\n        ],\n        placeholder: '请选择性别',\n      },\n      fieldName: 'gender',\n      label: '性别',\n      rules: 'selectRequired',\n    },\n  ],\n  showDefaultActions: false,\n});\n\n// 测试 validateAndSubmitForm（验证并提交）\nasync function testValidateAndSubmit() {\n  await formApi.validateAndSubmitForm();\n}\n\n// 测试 validate（手动验证整个表单）\nasync function testValidate() {\n  await formApi.validate();\n}\n\n// 测试 validateField（验证单个字段）\nasync function testValidateField() {\n  await formApi.validateField('username');\n}\n\n// 切换滚动功能\nfunction toggleScrollToError() {\n  formApi.setState({ scrollToFirstError: scrollEnabled.value });\n}\n\n// 填充部分数据测试\nasync function fillPartialData() {\n  await formApi.resetForm();\n  await formApi.setFieldValue('username', '测试用户');\n  await formApi.setFieldValue('email', 'test@example.com');\n}\n</script>\n\n<template>\n  <Page\n    description=\"测试表单验证失败时自动滚动到错误字段的功能\"\n    title=\"滚动到错误字段测试\"\n  >\n    <Card title=\"功能测试\">\n      <template #extra>\n        <div class=\"flex items-center gap-2\">\n          <Switch\n            v-model:checked=\"scrollEnabled\"\n            @change=\"toggleScrollToError\"\n          />\n          <span>启用滚动到错误字段</span>\n        </div>\n      </template>\n\n      <div class=\"space-y-4\">\n        <div class=\"rounded bg-blue-50 p-4\">\n          <h3 class=\"mb-2 font-medium\">测试说明：</h3>\n          <ul class=\"list-inside list-disc space-y-1 text-sm\">\n            <li>所有验证方法在验证失败时都会自动滚动到第一个错误字段</li>\n            <li>可以通过右上角的开关控制是否启用自动滚动功能</li>\n          </ul>\n        </div>\n\n        <div class=\"rounded border p-4\">\n          <h4 class=\"mb-3 font-medium\">验证方法测试：</h4>\n          <div class=\"flex flex-wrap gap-2\">\n            <Button type=\"primary\" @click=\"testValidateAndSubmit\">\n              测试 validateAndSubmitForm()\n            </Button>\n            <Button @click=\"testValidate\"> 测试 validate() </Button>\n            <Button @click=\"testValidateField\"> 测试 validateField() </Button>\n          </div>\n          <div class=\"mt-2 text-xs text-gray-500\">\n            <p>• validateAndSubmitForm(): 验证表单并提交</p>\n            <p>• validate(): 手动验证整个表单</p>\n            <p>• validateField(): 验证单个字段（这里测试用户名字段）</p>\n          </div>\n        </div>\n\n        <div class=\"rounded border p-4\">\n          <h4 class=\"mb-3 font-medium\">数据填充测试：</h4>\n          <div class=\"flex flex-wrap gap-2\">\n            <Button @click=\"fillPartialData\"> 填充部分数据 </Button>\n            <Button @click=\"() => formApi.resetForm()\"> 清空表单 </Button>\n          </div>\n          <div class=\"mt-2 text-xs text-gray-500\">\n            <p>• 填充部分数据后验证，会滚动到第一个错误字段</p>\n          </div>\n        </div>\n\n        <Form />\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/json-viewer/data.ts",
    "content": "export const json1 = {\n  additionalInfo: {\n    author: 'Your Name',\n    debug: true,\n    version: '1.3.10',\n    versionCode: 132,\n  },\n  additionalNotes: 'This JSON is used for demonstration purposes',\n  tools: [\n    {\n      description: 'Description of Tool 1',\n      name: 'Tool 1',\n    },\n    {\n      description: 'Description of Tool 2',\n      name: 'Tool 2',\n    },\n    {\n      description: 'Description of Tool 3',\n      name: 'Tool 3',\n    },\n    {\n      description: 'Description of Tool 4',\n      name: 'Tool 4',\n    },\n  ],\n};\n\nexport const json2 = JSON.parse(`\n  {\n\t\"id\": \"chatcmpl-123\",\n\t\"object\": \"chat.completion\",\n\t\"created\": 1677652288,\n\t\"model\": \"gpt-3.5-turbo-0613\",\n\t\"system_fingerprint\": \"fp_44709d6fcb\",\n\t\"choices\": [{\n\t\t\"index\": 0,\n\t\t\"message\": {\n\t\t\t\"role\": \"assistant\",\n\t\t\t\"content\": \"Hello there, how may I assist you today?\"\n\t\t},\n\t\t\"finish_reason\": \"stop\"\n\t}],\n\t\"usage\": {\n\t\t\"prompt_tokens\": 9,\n\t\t\"completion_tokens\": 12,\n\t\t\"total_tokens\": 21,\n    \"debug_mode\": true\n\t},\n  \"debug\": {\n    \"startAt\": \"2021-08-01T00:00:00Z\",\n    \"logs\": [\n      {\n        \"timestamp\": \"2021-08-01T00:00:00Z\",\n        \"message\": \"This is a debug message\",\n        \"extra\":[ \"extra1\", \"extra2\" ]\n      },\n      {\n        \"timestamp\": \"2021-08-01T00:00:01Z\",\n        \"message\": \"This is another debug message\",\n        \"extra\":[ \"extra3\", \"extra4\" ]\n      }\n    ]\n  }\n}\n  `);\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/json-viewer/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { JsonViewerAction, JsonViewerValue } from '@vben/common-ui';\n\nimport { JsonViewer, Page } from '@vben/common-ui';\n\nimport { Card, message } from 'ant-design-vue';\n\nimport { json1, json2 } from './data';\n\nfunction handleKeyClick(key: string) {\n  message.info(`点击了Key ${key}`);\n}\n\nfunction handleValueClick(value: JsonViewerValue) {\n  message.info(`点击了Value ${JSON.stringify(value)}`);\n}\n\nfunction handleCopied(_event: JsonViewerAction) {\n  message.success('已复制JSON');\n}\n</script>\n<template>\n  <Page\n    title=\"Json Viewer\"\n    description=\"一个渲染 JSON 结构数据的组件，支持复制、展开等，简单易用\"\n  >\n    <Card title=\"默认配置\">\n      <JsonViewer :value=\"json1\" />\n    </Card>\n    <Card title=\"可复制、默认展开3层、显示边框、事件处理\" class=\"mt-4\">\n      <JsonViewer\n        :value=\"json2\"\n        :expand-depth=\"3\"\n        copyable\n        :sort=\"false\"\n        @key-click=\"handleKeyClick\"\n        @value-click=\"handleValueClick\"\n        @copied=\"handleCopied\"\n        boxed\n      />\n    </Card>\n    <Card title=\"预览模式\" class=\"mt-4\">\n      <JsonViewer\n        :value=\"json2\"\n        copyable\n        preview-mode\n        :show-array-index=\"false\"\n      />\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/layout/col-page.vue",
    "content": "<script lang=\"ts\" setup>\nimport { reactive, ref } from 'vue';\n\nimport { ColPage } from '@vben/common-ui';\nimport { IconifyIcon } from '@vben/icons';\n\nimport {\n  Alert,\n  Button,\n  Card,\n  Checkbox,\n  Slider,\n  Tag,\n  Tooltip,\n} from 'ant-design-vue';\n\nconst props = reactive({\n  leftCollapsedWidth: 5,\n  leftCollapsible: true,\n  leftMaxWidth: 50,\n  leftMinWidth: 20,\n  leftWidth: 30,\n  resizable: true,\n  rightWidth: 70,\n  splitHandle: false,\n  splitLine: false,\n});\nconst leftMinWidth = ref(props.leftMinWidth || 1);\nconst leftMaxWidth = ref(props.leftMaxWidth || 100);\n</script>\n<template>\n  <ColPage\n    auto-content-height\n    description=\"ColPage 是一个双列布局组件，支持左侧折叠、拖拽调整宽度等功能。\"\n    v-bind=\"props\"\n    title=\"ColPage 双列布局组件\"\n  >\n    <template #title>\n      <span class=\"mr-2 text-2xl font-bold\">ColPage 双列布局组件</span>\n      <Tag color=\"hsl(var(--destructive))\">Alpha</Tag>\n    </template>\n    <template #left=\"{ isCollapsed, expand }\">\n      <div v-if=\"isCollapsed\" @click=\"expand\">\n        <Tooltip title=\"点击展开左侧\">\n          <Button shape=\"circle\" type=\"primary\">\n            <template #icon>\n              <IconifyIcon class=\"text-2xl\" icon=\"bi:arrow-right\" />\n            </template>\n          </Button>\n        </Tooltip>\n      </div>\n      <div\n        v-else\n        :style=\"{ minWidth: '200px' }\"\n        class=\"border-border bg-card mr-2 rounded-[var(--radius)] border p-2\"\n      >\n        <p>这里是左侧内容</p>\n        <p>这里是左侧内容</p>\n        <p>这里是左侧内容</p>\n        <p>这里是左侧内容</p>\n        <p>这里是左侧内容</p>\n      </div>\n    </template>\n    <Card class=\"ml-2\" title=\"基本使用\">\n      <div class=\"flex flex-col gap-2\">\n        <div class=\"flex gap-2\">\n          <Checkbox v-model:checked=\"props.resizable\">可拖动调整宽度</Checkbox>\n          <Checkbox v-model:checked=\"props.splitLine\">显示拖动分隔线</Checkbox>\n          <Checkbox v-model:checked=\"props.splitHandle\">显示拖动手柄</Checkbox>\n          <Checkbox v-model:checked=\"props.leftCollapsible\">\n            左侧可折叠\n          </Checkbox>\n        </div>\n        <div class=\"flex items-center gap-2\">\n          <span>左侧最小宽度百分比：</span>\n          <Slider\n            v-model:value=\"leftMinWidth\"\n            :max=\"props.leftMaxWidth - 1\"\n            :min=\"1\"\n            style=\"width: 100px\"\n            @after-change=\"(value) => (props.leftMinWidth = value as number)\"\n          />\n          <span>左侧最大宽度百分比：</span>\n          <Slider\n            v-model:value=\"props.leftMaxWidth\"\n            :max=\"100\"\n            :min=\"leftMaxWidth + 1\"\n            style=\"width: 100px\"\n            @after-change=\"(value) => (props.leftMaxWidth = value as number)\"\n          />\n        </div>\n        <Alert message=\"实验性的组件\" show-icon type=\"warning\">\n          <template #description>\n            <p>\n              双列布局组件是一个在Page组件上扩展的相对基础的布局组件，支持左侧折叠（当拖拽导致左侧宽度比最小宽度还要小时，还可以进入折叠状态）、拖拽调整宽度等功能。\n            </p>\n            <p>以上宽度设置的数值是百分比，最小值为1，最大值为100。</p>\n            <p class=\"font-bold text-red-600\">\n              这是一个实验性的组件，用法可能会发生变动，也可能最终不会被采用。在其用法正式出现在文档中之前，不建议在生产环境中使用。\n            </p>\n          </template>\n        </Alert>\n      </div>\n    </Card>\n  </ColPage>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/loading/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { Loading, Page, Spinner } from '@vben/common-ui';\nimport { IconifyIcon } from '@vben/icons';\n\nimport { refAutoReset } from '@vueuse/core';\nimport { Button, Card, Spin } from 'ant-design-vue';\n\nconst spinning = refAutoReset(false, 3000);\nconst loading = refAutoReset(false, 3000);\n\nconst spinningV = refAutoReset(false, 3000);\nconst loadingV = refAutoReset(false, 3000);\n</script>\n<template>\n  <Page\n    title=\"Vben Loading\"\n    description=\"加载中状态组件。这个组件可以为其它作为容器的组件添加一个加载中的遮罩层。使用它们时，容器需要relative定位。\"\n  >\n    <Card title=\"Antd Spin\">\n      <template #actions>这是Antd 组件库自带的Spin组件演示</template>\n      <Spin :spinning=\"spinning\" tip=\"加载中...\">\n        <Button type=\"primary\" @click=\"spinning = true\">显示Spin</Button>\n      </Spin>\n    </Card>\n\n    <Card title=\"Vben Loading\" v-loading=\"loadingV\" class=\"mt-4\">\n      <template #extra>\n        <Button type=\"primary\" @click=\"loadingV = true\">\n          v-loading 指令\n        </Button>\n      </template>\n      <template #actions>\n        Loading组件可以设置文字，并且也提供了icon插槽用于替换加载图标。\n      </template>\n      <div class=\"flex gap-4\">\n        <div class=\"size-40\">\n          <Loading\n            :spinning=\"loading\"\n            text=\"正在加载...\"\n            class=\"flex h-full w-full items-center justify-center\"\n          >\n            <Button type=\"primary\" @click=\"loading = true\">默认动画</Button>\n          </Loading>\n        </div>\n        <div class=\"size-40\">\n          <Loading\n            :spinning=\"loading\"\n            class=\"flex h-full w-full items-center justify-center\"\n          >\n            <Button type=\"primary\" @click=\"loading = true\">自定义动画1</Button>\n            <template #icon>\n              <IconifyIcon\n                icon=\"svg-spinners:ring-resize\"\n                class=\"text-primary size-10\"\n              />\n            </template>\n          </Loading>\n        </div>\n        <div class=\"size-40\">\n          <Loading\n            :spinning=\"loading\"\n            class=\"flex h-full w-full items-center justify-center\"\n          >\n            <Button type=\"primary\" @click=\"loading = true\">自定义动画2</Button>\n            <template #icon>\n              <IconifyIcon\n                icon=\"svg-spinners:bars-scale\"\n                class=\"text-primary size-10\"\n              />\n            </template>\n          </Loading>\n        </div>\n      </div>\n    </Card>\n\n    <Card\n      title=\"Vben Spinner\"\n      v-spinning=\"spinningV\"\n      class=\"mt-4 overflow-hidden\"\n      :body-style=\"{\n        position: 'relative',\n        overflow: 'hidden',\n      }\"\n    >\n      <template #extra>\n        <Button type=\"primary\" @click=\"spinningV = true\">\n          v-spinning 指令\n        </Button>\n      </template>\n      <template #actions>\n        Spinner组件是Loading组件的一个特例，只有一个固定的统一样式。\n      </template>\n      <Spinner\n        :spinning=\"spinning\"\n        class=\"flex size-40 items-center justify-center\"\n      >\n        <Button type=\"primary\" @click=\"spinning = true\">显示Spinner</Button>\n      </Spinner>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/auto-height-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nconst list = ref<number[]>([]);\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n  },\n  onOpenChange(isOpen) {\n    if (isOpen) {\n      handleUpdate();\n    }\n  },\n});\n\nfunction handleUpdate(len?: number) {\n  modalApi.setState({ confirmDisabled: true, loading: true });\n  setTimeout(() => {\n    list.value = Array.from(\n      { length: len ?? Math.floor(Math.random() * 10) + 1 },\n      (_v, k) => k + 1,\n    );\n    modalApi.setState({ confirmDisabled: false, loading: false });\n  }, 2000);\n}\n</script>\n\n<template>\n  <Modal title=\"自动计算高度\">\n    <div\n      v-for=\"item in list\"\n      :key=\"item\"\n      class=\"even:bg-heavy bg-muted flex-center h-[220px] w-full\"\n    >\n      {{ item }}\n    </div>\n    <template #prepend-footer>\n      <Button type=\"link\" @click=\"handleUpdate()\">点击更新数据</Button>\n    </template>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/base-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onClosed() {\n    message.info('onClosed：关闭动画结束');\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // modalApi.close();\n  },\n  onOpened() {\n    message.info('onOpened：打开动画结束');\n  },\n});\n\nfunction lockModal() {\n  modalApi.lock();\n  setTimeout(() => {\n    modalApi.unlock();\n  }, 3000);\n}\n</script>\n<template>\n  <Modal class=\"w-[600px]\" title=\"基础弹窗示例\" title-tooltip=\"标题提示内容\">\n    base demo\n    <Button type=\"primary\" @click=\"lockModal\">锁定弹窗</Button>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/blur-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref, watch } from 'vue';\n\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Slider } from 'ant-design-vue';\n\nconst blur = ref(5);\nconst [Modal, modalApi] = useVbenModal({\n  overlayBlur: blur.value,\n});\nwatch(blur, (val) => {\n  modalApi.setState({\n    overlayBlur: val,\n  });\n});\n</script>\n<template>\n  <Modal title=\"遮罩层模糊\">\n    <p>调整滑块来改变遮罩层模糊程度：{{ blur }}</p>\n    <Slider v-model:value=\"blur\" :max=\"30\" :min=\"0\" />\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/drag-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { message } from 'ant-design-vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  draggable: true,\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // modalApi.close();\n  },\n});\n</script>\n<template>\n  <Modal title=\"可拖拽示例\"> 鼠标移动到 header 上，可拖拽弹窗 </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/dynamic-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  draggable: true,\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // modalApi.close();\n  },\n  title: '动态修改配置示例',\n});\n\nconst state = modalApi.useStore();\n\nfunction handleUpdateTitle() {\n  modalApi.setState({ title: '内部动态标题' });\n}\n\nfunction handleToggleFullscreen() {\n  modalApi.setState((prev) => {\n    return { ...prev, fullscreen: !prev.fullscreen };\n  });\n}\n</script>\n<template>\n  <Modal>\n    <div class=\"flex-col-center\">\n      <Button class=\"mb-3\" type=\"primary\" @click=\"handleUpdateTitle()\">\n        内部动态修改标题\n      </Button>\n      <Button class=\"mb-3\" type=\"primary\" @click=\"handleToggleFullscreen()\">\n        {{ state.fullscreen ? '退出全屏' : '打开全屏' }}\n      </Button>\n    </div>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/form-modal-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { message } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\ndefineOptions({\n  name: 'FormModelDemo',\n});\n\nconst [Form, formApi] = useVbenForm({\n  handleSubmit: onSubmit,\n  schema: [\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field1',\n      label: '字段1',\n      rules: 'required',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        placeholder: '请输入',\n      },\n      fieldName: 'field2',\n      label: '字段2',\n      rules: 'required',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        options: [\n          { label: '选项1', value: '1' },\n          { label: '选项2', value: '2' },\n        ],\n        placeholder: '请输入',\n      },\n      fieldName: 'field3',\n      label: '字段3',\n      rules: 'required',\n    },\n  ],\n  showDefaultActions: false,\n});\n\nconst [Modal, modalApi] = useVbenModal({\n  fullscreenButton: false,\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm: async () => {\n    await formApi.validateAndSubmitForm();\n    // modalApi.close();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      const { values } = modalApi.getData<Record<string, any>>();\n      if (values) {\n        formApi.setValues(values);\n      }\n    }\n  },\n  title: '内嵌表单示例',\n});\n\nfunction onSubmit(values: Record<string, any>) {\n  message.loading({\n    content: '正在提交中...',\n    duration: 0,\n    key: 'is-form-submitting',\n  });\n  modalApi.lock();\n  setTimeout(() => {\n    modalApi.close();\n    message.success({\n      content: `提交成功：${JSON.stringify(values)}`,\n      duration: 2,\n      key: 'is-form-submitting',\n    });\n  }, 3000);\n}\n</script>\n<template>\n  <Modal>\n    <Form />\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/in-content-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Input, message } from 'ant-design-vue';\n\nconst [Modal, modalApi] = useVbenModal({\n  destroyOnClose: false,\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // modalApi.close();\n  },\n});\nconst value = ref();\n</script>\n<template>\n  <Modal\n    append-to-main\n    class=\"w-[600px]\"\n    title=\"基础弹窗示例\"\n    title-tooltip=\"标题提示内容\"\n  >\n    此弹窗指定在内容区域打开，并且在关闭之后弹窗内容不会被销毁\n    <Input v-model:value=\"value\" placeholder=\"KeepAlive测试\" />\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { onBeforeUnmount } from 'vue';\n\nimport {\n  alert,\n  clearAllAlerts,\n  confirm,\n  Page,\n  prompt,\n  useVbenModal,\n} from '@vben/common-ui';\n\nimport { Button, Card, Flex, message } from 'ant-design-vue';\n\nimport DocButton from '../doc-button.vue';\nimport AutoHeightDemo from './auto-height-demo.vue';\nimport BaseDemo from './base-demo.vue';\nimport BlurDemo from './blur-demo.vue';\nimport DragDemo from './drag-demo.vue';\nimport DynamicDemo from './dynamic-demo.vue';\nimport FormModalDemo from './form-modal-demo.vue';\nimport InContentModalDemo from './in-content-demo.vue';\nimport NestedDemo from './nested-demo.vue';\nimport SharedDataDemo from './shared-data-demo.vue';\n\ndefineOptions({ name: 'ModalExample' });\n\nconst [BaseModal, baseModalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: BaseDemo,\n});\n\nconst [InContentModal, inContentModalApi] = useVbenModal({\n  // 连接抽离的组件\n  connectedComponent: InContentModalDemo,\n});\n\nconst [AutoHeightModal, autoHeightModalApi] = useVbenModal({\n  connectedComponent: AutoHeightDemo,\n});\n\nconst [DragModal, dragModalApi] = useVbenModal({\n  connectedComponent: DragDemo,\n});\n\nconst [DynamicModal, dynamicModalApi] = useVbenModal({\n  connectedComponent: DynamicDemo,\n});\n\nconst [SharedDataModal, sharedModalApi] = useVbenModal({\n  connectedComponent: SharedDataDemo,\n});\n\nconst [FormModal, formModalApi] = useVbenModal({\n  connectedComponent: FormModalDemo,\n});\n\nconst [NestedModal, nestedModalApi] = useVbenModal({\n  connectedComponent: NestedDemo,\n});\n\nconst [BlurModal, blurModalApi] = useVbenModal({\n  connectedComponent: BlurDemo,\n});\n\nfunction openBaseModal() {\n  baseModalApi.open();\n}\n\nfunction openInContentModal() {\n  inContentModalApi.open();\n}\n\nfunction openAutoHeightModal() {\n  autoHeightModalApi.open();\n}\n\nfunction openDragModal() {\n  dragModalApi.open();\n}\n\nfunction openDynamicModal() {\n  dynamicModalApi.open();\n}\n\nfunction openSharedModal() {\n  sharedModalApi\n    .setData({\n      content: '外部传递的数据 content',\n      payload: '外部传递的数据 payload',\n    })\n    .open();\n}\n\nfunction openNestedModal() {\n  nestedModalApi.open();\n}\n\nfunction openBlurModal() {\n  blurModalApi.open();\n}\n\nfunction handleUpdateTitle() {\n  dynamicModalApi.setState({ title: '外部动态标题' }).open();\n}\n\nfunction openFormModal() {\n  formModalApi\n    .setData({\n      // 表单值\n      values: { field1: 'abc', field2: '123' },\n    })\n    .open();\n}\n\nfunction openAlert() {\n  alert({\n    content: '这是一个弹窗',\n    icon: 'success',\n  }).then(() => {\n    message.info('用户关闭了弹窗');\n  });\n}\n\nonBeforeUnmount(() => {\n  // 清除所有弹窗\n  clearAllAlerts();\n});\n\nfunction openConfirm() {\n  confirm({\n    beforeClose({ isConfirm }) {\n      if (!isConfirm) return;\n      // 这里可以做一些异步操作\n      return new Promise((resolve) => {\n        setTimeout(() => {\n          resolve(true);\n        }, 1000);\n      });\n    },\n    centered: false,\n    content: '这是一个确认弹窗',\n    icon: 'question',\n  })\n    .then(() => {\n      message.success('用户确认了操作');\n    })\n    .catch(() => {\n      message.error('用户取消了操作');\n    });\n}\n\nasync function openPrompt() {\n  prompt<string>({\n    async beforeClose({ isConfirm, value }) {\n      if (isConfirm && value === '芝士') {\n        message.error('不能吃芝士');\n        return false;\n      }\n    },\n    componentProps: { placeholder: '不能吃芝士...' },\n    content: '中午吃了什么？',\n    icon: 'question',\n    overlayBlur: 3,\n  })\n    .then((res) => {\n      message.success(`用户输入了：${res}`);\n    })\n    .catch(() => {\n      message.error('用户取消了输入');\n    });\n}\n</script>\n\n<template>\n  <Page\n    auto-content-height\n    description=\"弹窗组件常用于在不离开当前页面的情况下，显示额外的信息、表单或操作提示，更多api请查看组件文档。\"\n    title=\"弹窗组件示例\"\n  >\n    <template #extra>\n      <DocButton path=\"/components/common-ui/vben-modal\" />\n    </template>\n    <BaseModal />\n    <InContentModal />\n    <AutoHeightModal />\n    <DragModal />\n    <DynamicModal />\n    <SharedDataModal />\n    <FormModal />\n    <NestedModal />\n    <BlurModal />\n    <Flex wrap=\"wrap\" class=\"w-full\" gap=\"10\">\n      <Card class=\"w-[300px]\" title=\"基本使用\">\n        <p>一个基础的弹窗示例</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openBaseModal\">打开弹窗</Button>\n        </template>\n      </Card>\n\n      <Card class=\"w-[300px]\" title=\"指定容器+关闭后不销毁\">\n        <p>在内容区域打开弹窗的示例</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openInContentModal\">打开弹窗</Button>\n        </template>\n      </Card>\n\n      <Card class=\"w-[300px]\" title=\"内容高度自适应\">\n        <p>可根据内容并自动调整高度</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openAutoHeightModal\">\n            打开弹窗\n          </Button>\n        </template>\n      </Card>\n\n      <Card class=\"w-[300px]\" title=\"可拖拽示例\">\n        <p>配置 draggable 可开启拖拽功能</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openDragModal\"> 打开弹窗 </Button>\n        </template>\n      </Card>\n\n      <Card class=\"w-[300px]\" title=\"动态配置示例\">\n        <p>通过 setState 动态调整弹窗数据</p>\n        <template #extra>\n          <Button type=\"link\" @click=\"openDynamicModal\">打开弹窗</Button>\n        </template>\n        <template #actions>\n          <Button type=\"primary\" @click=\"handleUpdateTitle\">\n            外部修改标题并打开\n          </Button>\n        </template>\n      </Card>\n\n      <Card class=\"w-[300px]\" title=\"内外数据共享示例\">\n        <p>通过共享 sharedData 来进行数据交互</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openSharedModal\">\n            打开弹窗并传递数据\n          </Button>\n        </template>\n      </Card>\n\n      <Card class=\"w-[300px]\" title=\"表单弹窗示例\">\n        <p>弹窗与表单结合</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openFormModal\"> 打开表单弹窗 </Button>\n        </template>\n      </Card>\n\n      <Card class=\"w-[300px]\" title=\"嵌套弹窗示例\">\n        <p>在已经打开的弹窗中再次打开弹窗</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openNestedModal\">打开嵌套弹窗</Button>\n        </template>\n      </Card>\n\n      <Card class=\"w-[300px]\" title=\"遮罩模糊示例\">\n        <p>遮罩层应用类似毛玻璃的模糊效果</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openBlurModal\">打开弹窗</Button>\n        </template>\n      </Card>\n      <Card class=\"w-[300px]\" title=\"轻量提示弹窗\">\n        <template #extra>\n          <DocButton path=\"/components/common-ui/vben-alert\" />\n        </template>\n        <p>通过快捷方法创建动态提示弹窗，适合一些轻量的提示和确认、输入等</p>\n        <template #actions>\n          <Button type=\"primary\" @click=\"openAlert\">Alert</Button>\n          <Button type=\"primary\" @click=\"openConfirm\">Confirm</Button>\n          <Button type=\"primary\" @click=\"openPrompt\">Prompt</Button>\n        </template>\n      </Card>\n    </Flex>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/nested-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Button } from 'ant-design-vue';\n\nimport DragDemo from './drag-demo.vue';\n\nconst [Modal] = useVbenModal({\n  destroyOnClose: true,\n});\nconst [BaseModal, baseModalApi] = useVbenModal({\n  connectedComponent: DragDemo,\n});\n\nfunction openNestedModal() {\n  baseModalApi.open();\n}\n</script>\n<template>\n  <Modal title=\"嵌套弹窗示例\">\n    <Button @click=\"openNestedModal\" type=\"primary\">打开子弹窗</Button>\n    <BaseModal />\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/modal/shared-data-demo.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { message } from 'ant-design-vue';\n\nconst data = ref();\n\nconst [Modal, modalApi] = useVbenModal({\n  onCancel() {\n    modalApi.close();\n  },\n  onConfirm() {\n    message.info('onConfirm');\n    // modalApi.close();\n  },\n  onOpenChange(isOpen: boolean) {\n    if (isOpen) {\n      data.value = modalApi.getData<Record<string, any>>();\n    }\n  },\n});\n</script>\n<template>\n  <Modal title=\"数据共享示例\">\n    <div class=\"flex-col-center\">外部传递数据： {{ data }}</div>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/motion/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport { reactive } from 'vue';\n\nimport { Page } from '@vben/common-ui';\nimport { Motion, MotionGroup, MotionPresets } from '@vben/plugins/motion';\n\nimport { refAutoReset, watchDebounced } from '@vueuse/core';\nimport {\n  Button,\n  Card,\n  Col,\n  Form,\n  FormItem,\n  InputNumber,\n  Row,\n  Select,\n} from 'ant-design-vue';\n// 本例子用不到visible类型的动画。带有VisibleOnce和Visible的类型会在组件进入视口被显示时执行动画，\nconst presets = MotionPresets.filter((v) => !v.includes('Visible'));\nconst showCard1 = refAutoReset(true, 100);\nconst showCard2 = refAutoReset(true, 100);\nconst showCard3 = refAutoReset(true, 100);\nconst motionProps = reactive({\n  delay: 0,\n  duration: 300,\n  enter: { scale: 1 },\n  hovered: { scale: 1.1, transition: { delay: 0, duration: 50 } },\n  preset: 'fade',\n  tapped: { scale: 0.9, transition: { delay: 0, duration: 50 } },\n});\n\nconst motionGroupProps = reactive({\n  delay: 0,\n  duration: 300,\n  enter: { scale: 1 },\n  hovered: { scale: 1.1, transition: { delay: 0, duration: 50 } },\n  preset: 'fade',\n  tapped: { scale: 0.9, transition: { delay: 0, duration: 50 } },\n});\n\nwatchDebounced(\n  motionProps,\n  () => {\n    showCard2.value = false;\n  },\n  { debounce: 200, deep: true },\n);\n\nwatchDebounced(\n  motionGroupProps,\n  () => {\n    showCard3.value = false;\n  },\n  { debounce: 200, deep: true },\n);\n\nfunction openDocPage() {\n  window.open('https://motion.vueuse.org/', '_blank');\n}\n</script>\n<template>\n  <Page title=\"Motion\">\n    <template #description>\n      <span>一个易于使用的为其它组件赋予动画效果的组件。</span>\n      <Button type=\"link\" @click=\"openDocPage\">查看文档</Button>\n    </template>\n    <Card title=\"使用指令\" :body-style=\"{ minHeight: '5rem' }\">\n      <template #extra>\n        <Button type=\"primary\" @click=\"showCard1 = false\">重载</Button>\n      </template>\n      <div>\n        <div class=\"relative flex gap-2 overflow-hidden\" v-if=\"showCard1\">\n          <Button v-motion-fade-visible>fade</Button>\n          <Button v-motion-pop-visible :duration=\"500\">pop</Button>\n          <Button v-motion-slide-left>slide-left</Button>\n          <Button v-motion-slide-right>slide-right</Button>\n          <Button v-motion-slide-bottom>slide-bottom</Button>\n          <Button v-motion-slide-top>slide-top</Button>\n        </div>\n      </div>\n    </Card>\n    <Card\n      class=\"mt-2\"\n      title=\"使用组件（将内部作为一个整体添加动画）\"\n      :body-style=\"{ padding: 0 }\"\n    >\n      <div\n        class=\"relative flex min-h-32 items-center justify-center gap-2 overflow-hidden\"\n      >\n        <Motion\n          v-bind=\"motionProps\"\n          v-if=\"showCard2\"\n          class=\"flex items-center gap-2\"\n        >\n          <Button size=\"large\">这个按钮在显示时会有动画效果</Button>\n          <span>附属组件，会作为整体处理动画</span>\n        </Motion>\n      </div>\n      <div\n        class=\"relative flex min-h-32 items-center justify-center gap-2 overflow-hidden\"\n      >\n        <div v-if=\"showCard2\" class=\"flex items-center gap-2\">\n          <span>顺序延迟</span>\n          <Motion\n            v-bind=\"{\n              ...motionProps,\n              delay: motionProps.delay + 100 * i,\n            }\"\n            v-for=\"i in 5\"\n            :key=\"i\"\n          >\n            <Button size=\"large\">按钮{{ i }}</Button>\n          </Motion>\n        </div>\n      </div>\n      <div>\n        <Form :model=\"motionProps\" :label-col=\"{ span: 10 }\">\n          <Row>\n            <Col :span=\"8\">\n              <FormItem prop=\"preset\" label=\"动画效果\">\n                <Select v-model:value=\"motionProps.preset\">\n                  <Select.Option\n                    :value=\"preset\"\n                    v-for=\"preset in presets\"\n                    :key=\"preset\"\n                  >\n                    {{ preset }}\n                  </Select.Option>\n                </Select>\n              </FormItem>\n            </Col>\n            <Col :span=\"8\">\n              <FormItem prop=\"duration\" label=\"持续时间\">\n                <InputNumber v-model:value=\"motionProps.duration\" />\n              </FormItem>\n            </Col>\n            <Col :span=\"8\">\n              <FormItem prop=\"delay\" label=\"延迟动画\">\n                <InputNumber v-model:value=\"motionProps.delay\" />\n              </FormItem>\n            </Col>\n            <Col :span=\"8\">\n              <FormItem prop=\"hovered.scale\" label=\"Hover缩放\">\n                <InputNumber v-model:value=\"motionProps.hovered.scale\" />\n              </FormItem>\n            </Col>\n            <Col :span=\"8\">\n              <FormItem prop=\"hovered.tapped\" label=\"按下时缩放\">\n                <InputNumber v-model:value=\"motionProps.tapped.scale\" />\n              </FormItem>\n            </Col>\n          </Row>\n        </Form>\n      </div>\n    </Card>\n    <Card\n      class=\"mt-2\"\n      title=\"分组动画（每个子元素都会应用相同的独立动画）\"\n      :body-style=\"{ padding: 0 }\"\n    >\n      <div\n        class=\"relative flex min-h-32 items-center justify-center gap-2 overflow-hidden\"\n      >\n        <MotionGroup v-bind=\"motionGroupProps\" v-if=\"showCard3\">\n          <Button size=\"large\">按钮1</Button>\n          <Button size=\"large\">按钮2</Button>\n          <Button size=\"large\">按钮3</Button>\n          <Button size=\"large\">按钮4</Button>\n          <Button size=\"large\">按钮5</Button>\n        </MotionGroup>\n      </div>\n      <div>\n        <Form :model=\"motionGroupProps\" :label-col=\"{ span: 10 }\">\n          <Row>\n            <Col :span=\"8\">\n              <FormItem prop=\"preset\" label=\"动画效果\">\n                <Select v-model:value=\"motionGroupProps.preset\">\n                  <Select.Option\n                    :value=\"preset\"\n                    v-for=\"preset in presets\"\n                    :key=\"preset\"\n                  >\n                    {{ preset }}\n                  </Select.Option>\n                </Select>\n              </FormItem>\n            </Col>\n            <Col :span=\"8\">\n              <FormItem prop=\"duration\" label=\"持续时间\">\n                <InputNumber v-model:value=\"motionGroupProps.duration\" />\n              </FormItem>\n            </Col>\n            <Col :span=\"8\">\n              <FormItem prop=\"delay\" label=\"延迟动画\">\n                <InputNumber v-model:value=\"motionGroupProps.delay\" />\n              </FormItem>\n            </Col>\n            <Col :span=\"8\">\n              <FormItem prop=\"hovered.scale\" label=\"Hover缩放\">\n                <InputNumber v-model:value=\"motionGroupProps.hovered.scale\" />\n              </FormItem>\n            </Col>\n            <Col :span=\"8\">\n              <FormItem prop=\"hovered.tapped\" label=\"按下时缩放\">\n                <InputNumber v-model:value=\"motionGroupProps.tapped.scale\" />\n              </FormItem>\n            </Col>\n          </Row>\n        </Form>\n      </div>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/resize/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport { Page, VResize } from '@vben/common-ui';\n\nconst colorMap = ['red', 'green', 'yellow', 'gray'];\n\ntype TSize = {\n  height: number;\n  left: number;\n  top: number;\n  width: number;\n};\n\nconst sizeList = ref<TSize[]>([\n  { height: 200, left: 200, top: 200, width: 200 },\n  { height: 300, left: 300, top: 300, width: 300 },\n  { height: 400, left: 400, top: 400, width: 400 },\n  { height: 500, left: 500, top: 500, width: 500 },\n]);\n\nconst resize = (size?: TSize, rect?: TSize) => {\n  if (!size || !rect) return;\n\n  size.height = rect.height;\n  size.left = rect.left;\n  size.top = rect.top;\n  size.width = rect.width;\n};\n</script>\n\n<template>\n  <Page description=\"Resize组件基础示例\" title=\"Resize组件\">\n    <div class=\"m-4 bg-blue-500 p-48 text-xl\">\n      <div v-for=\"size in sizeList\" :key=\"size.width\">\n        {{\n          `width: ${size.width}px, height: ${size.height}px, top: ${size.top}px, left: ${size.left}px`\n        }}\n      </div>\n    </div>\n\n    <template v-for=\"(_, idx) of 4\" :key=\"idx\">\n      <VResize\n        :h=\"100 * (idx + 1)\"\n        :w=\"100 * (idx + 1)\"\n        :x=\"100 * (idx + 1)\"\n        :y=\"100 * (idx + 1)\"\n        @dragging=\"(rect) => resize(sizeList[idx], rect)\"\n        @resizing=\"(rect) => resize(sizeList[idx], rect)\"\n      >\n        <div\n          :style=\"{ backgroundColor: colorMap[idx] }\"\n          class=\"h-full w-full\"\n        ></div>\n      </VResize>\n    </template>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/tippy/index.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { TippyProps } from '@vben/common-ui';\n\nimport { reactive } from 'vue';\n\nimport { Page, Tippy } from '@vben/common-ui';\n\nimport { Button, Card, Flex } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\n\nconst tippyProps = reactive<TippyProps>({\n  animation: 'shift-away',\n  arrow: true,\n  content: '这是一个提示',\n  delay: [200, 200],\n  duration: 200,\n  followCursor: false,\n  hideOnClick: false,\n  inertia: true,\n  maxWidth: 'none',\n  placement: 'top',\n  theme: 'dark',\n  trigger: 'mouseenter focusin',\n});\n\nfunction parseBoolean(value: string) {\n  switch (value) {\n    case 'false': {\n      return false;\n    }\n    case 'true': {\n      return true;\n    }\n    default: {\n      return value;\n    }\n  }\n}\n\nconst [Form] = useVbenForm({\n  handleValuesChange(values) {\n    Object.assign(tippyProps, {\n      ...values,\n      delay: [values.delay1, values.delay2],\n      followCursor: parseBoolean(values.followCursor),\n      hideOnClick: parseBoolean(values.hideOnClick),\n      trigger: values.trigger.join(' '),\n    });\n  },\n  schema: [\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        buttonStyle: 'solid',\n        class: 'w-full',\n        options: [\n          { label: '自动', value: 'auto' },\n          { label: '暗色', value: 'dark' },\n          { label: '亮色', value: 'light' },\n        ],\n        optionType: 'button',\n      },\n      defaultValue: tippyProps.theme,\n      fieldName: 'theme',\n      label: '主题',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        class: 'w-full',\n        options: [\n          { label: '向上滑入', value: 'shift-away' },\n          { label: '向下滑入', value: 'shift-toward' },\n          { label: '缩放', value: 'scale' },\n          { label: '透视', value: 'perspective' },\n          { label: '淡入', value: 'fade' },\n        ],\n      },\n      defaultValue: tippyProps.animation,\n      fieldName: 'animation',\n      label: '动画类型',\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        buttonStyle: 'solid',\n        options: [\n          { label: '是', value: true },\n          { label: '否', value: false },\n        ],\n        optionType: 'button',\n      },\n      defaultValue: tippyProps.inertia,\n      fieldName: 'inertia',\n      label: '动画惯性',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        class: 'w-full',\n        options: [\n          { label: '顶部', value: 'top' },\n          { label: '顶左', value: 'top-start' },\n          { label: '顶右', value: 'top-end' },\n          { label: '底部', value: 'bottom' },\n          { label: '底左', value: 'bottom-start' },\n          { label: '底右', value: 'bottom-end' },\n          { label: '左侧', value: 'left' },\n          { label: '左上', value: 'left-start' },\n          { label: '左下', value: 'left-end' },\n          { label: '右侧', value: 'right' },\n          { label: '右上', value: 'right-start' },\n          { label: '右下', value: 'right-end' },\n        ],\n      },\n      defaultValue: tippyProps.placement,\n      fieldName: 'placement',\n      label: '位置',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        addonAfter: '毫秒',\n      },\n      defaultValue: tippyProps.duration,\n      fieldName: 'duration',\n      label: '动画时长',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        addonAfter: '毫秒',\n      },\n      defaultValue: 100,\n      fieldName: 'delay1',\n      label: '显示延时',\n    },\n    {\n      component: 'InputNumber',\n      componentProps: {\n        addonAfter: '毫秒',\n      },\n      defaultValue: 100,\n      fieldName: 'delay2',\n      label: '隐藏延时',\n    },\n    {\n      component: 'Input',\n      defaultValue: tippyProps.content,\n      fieldName: 'content',\n      label: '内容',\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        buttonStyle: 'solid',\n        options: [\n          { label: '是', value: true },\n          { label: '否', value: false },\n        ],\n        optionType: 'button',\n      },\n      defaultValue: tippyProps.arrow,\n      fieldName: 'arrow',\n      label: '指示箭头',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        class: 'w-full',\n        options: [\n          { label: '不跟随', value: 'false' },\n          { label: '完全跟随', value: 'true' },\n          { label: '仅横向', value: 'horizontal' },\n          { label: '仅纵向', value: 'vertical' },\n          { label: '仅初始', value: 'initial' },\n        ],\n      },\n      defaultValue: tippyProps.followCursor?.toString(),\n      fieldName: 'followCursor',\n      label: '跟随指针',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        class: 'w-full',\n        mode: 'multiple',\n        options: [\n          { label: '鼠标移入', value: 'mouseenter' },\n          { label: '被点击', value: 'click' },\n          { label: '获得焦点', value: 'focusin' },\n          { label: '无触发，仅手动', value: 'manual' },\n        ],\n      },\n      defaultValue: tippyProps.trigger?.split(' '),\n      fieldName: 'trigger',\n      label: '触发方式',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        class: 'w-full',\n        options: [\n          { label: '否', value: 'false' },\n          { label: '是', value: 'true' },\n          { label: '仅内部', value: 'toggle' },\n        ],\n      },\n      defaultValue: tippyProps.hideOnClick?.toString(),\n      dependencies: {\n        componentProps(_, formAction) {\n          return {\n            disabled: !formAction.values.trigger.includes('click'),\n          };\n        },\n        triggerFields: ['trigger'],\n      },\n      fieldName: 'hideOnClick',\n      help: '只有在触发方式为`click`时才有效',\n      label: '点击后隐藏',\n    },\n    {\n      component: 'Input',\n      componentProps: {\n        allowClear: true,\n        placeholder: 'none、200px',\n      },\n      defaultValue: tippyProps.maxWidth,\n      fieldName: 'maxWidth',\n      label: '最大宽度',\n    },\n  ],\n  showDefaultActions: false,\n  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n});\n\nfunction goDoc() {\n  window.open('https://atomiks.github.io/tippyjs/v6/all-props/');\n}\n</script>\n<template>\n  <Page title=\"Tippy\">\n    <template #description>\n      <div class=\"flex items-center\">\n        <p>\n          Tippy\n          是一个轻量级的提示工具库，它可以用来创建各种交互式提示，如工具提示、引导提示等。\n        </p>\n        <Button type=\"link\" size=\"small\" @click=\"goDoc\">查看文档</Button>\n      </div>\n    </template>\n    <Card title=\"指令形式使用\">\n      <p class=\"mb-4\">\n        指令形式使用比较简洁，直接在需要展示tooltip的组件上用v-tippy传递配置，适用于固定内容的工具提示。\n      </p>\n      <Flex warp=\"warp\" gap=\"20\" align=\"center\">\n        <Button v-tippy=\"'这是一个提示，使用了默认的配置'\">默认配置</Button>\n\n        <Button\n          v-tippy=\"{ theme: 'light', content: '这是一个提示，总是light主题' }\"\n        >\n          指定主题\n        </Button>\n        <Button\n          v-tippy=\"{\n            theme: 'light',\n            content: '这个提示将在点燃组件100毫秒后激活',\n            delay: 100,\n          }\"\n        >\n          指定延时\n        </Button>\n        <Button\n          v-tippy=\"{\n            content: '本提示的动画为`scale`',\n            animation: 'scale',\n          }\"\n        >\n          指定动画\n        </Button>\n      </Flex>\n    </Card>\n    <Card title=\"组件形式使用\" class=\"mt-4\">\n      <div class=\"flex w-full justify-center\">\n        <Tippy v-bind=\"tippyProps\">\n          <Button>鼠标移到这个组件上来体验效果</Button>\n        </Tippy>\n      </div>\n\n      <Form class=\"mt-4\" />\n      <template #actions>\n        <p\n          class=\"text-secondary-foreground hover:text-secondary-foreground cursor-default\"\n        >\n          更多配置请\n          <Button type=\"link\" size=\"small\" @click=\"goDoc\">查看文档</Button>\n          ，这里只列出了一些常用的配置\n        </p>\n      </template>\n    </Card>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/basic.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport DocButton from '../doc-button.vue';\nimport { MOCK_TABLE_DATA } from './table-data';\n\ninterface RowType {\n  address: string;\n  age: number;\n  id: number;\n  name: string;\n  nickname: string;\n  role: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'name', title: 'Name' },\n    { field: 'age', sortable: true, title: 'Age' },\n    { field: 'nickname', title: 'Nickname' },\n    { field: 'role', title: 'Role' },\n    { field: 'address', showOverflow: true, title: 'Address' },\n  ],\n  data: MOCK_TABLE_DATA,\n  pagerConfig: {\n    enabled: false,\n  },\n  sortConfig: {\n    multiple: true,\n  },\n};\n\nconst gridEvents: VxeGridListeners<RowType> = {\n  cellClick: ({ row }) => {\n    message.info(`cell-click: ${row.name}`);\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid<RowType>({\n  // 放开注释查看表单组件的类型\n  // formOptions: {\n  //   schema: [\n  //     {\n  //       component: 'Switch',\n  //       fieldName: 'name',\n  //     },\n  //   ],\n  // },\n  gridEvents,\n  gridOptions,\n});\n\n// 放开注释查看当前表格实例的类型\n// gridApi.grid\n\nconst showBorder = gridApi.useStore((state) => state.gridOptions?.border);\nconst showStripe = gridApi.useStore((state) => state.gridOptions?.stripe);\n\nfunction changeBorder() {\n  gridApi.setGridOptions({\n    border: !showBorder.value,\n  });\n}\n\nfunction changeStripe() {\n  gridApi.setGridOptions({\n    stripe: !showStripe.value,\n  });\n}\n\nfunction changeLoading() {\n  gridApi.setLoading(true);\n  setTimeout(() => {\n    gridApi.setLoading(false);\n  }, 2000);\n}\n</script>\n\n<template>\n  <Page\n    description=\"表格组件常用于快速开发数据展示与交互界面，示例数据为静态数据。该组件是对vxe-table进行简单的二次封装，大部分属性与方法与vxe-table保持一致。\"\n    title=\"表格基础示例\"\n  >\n    <template #extra>\n      <DocButton path=\"/components/common-ui/vben-vxe-table\" />\n    </template>\n    <Grid table-title=\"基础列表\" table-title-help=\"提示\">\n      <!-- <template #toolbar-actions>\n        <Button class=\"mr-2\" type=\"primary\">左侧插槽</Button>\n      </template> -->\n      <template #toolbar-tools>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"changeBorder\">\n          {{ showBorder ? '隐藏' : '显示' }}边框\n        </Button>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"changeLoading\">\n          显示loading\n        </Button>\n        <Button type=\"primary\" @click=\"changeStripe\">\n          {{ showStripe ? '隐藏' : '显示' }}斑马纹\n        </Button>\n      </template>\n    </Grid>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/custom-cell.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button, Image, Switch, Tag } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { getExampleTableApi } from '#/api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  imageUrl: string;\n  open: boolean;\n  price: string;\n  productName: string;\n  releaseDate: string;\n  status: 'error' | 'success' | 'warning';\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  checkboxConfig: {\n    highlight: true,\n    labelField: 'name',\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { field: 'category', title: 'Category', width: 100 },\n    {\n      field: 'imageUrl',\n      slots: { default: 'image-url' },\n      title: 'Image',\n      width: 100,\n    },\n    {\n      cellRender: { name: 'CellImage' },\n      field: 'imageUrl2',\n      title: 'Render Image',\n      width: 130,\n    },\n    {\n      field: 'open',\n      slots: { default: 'open' },\n      title: 'Open',\n      width: 100,\n    },\n    {\n      field: 'status',\n      slots: { default: 'status' },\n      title: 'Status',\n      width: 100,\n    },\n    { field: 'color', title: 'Color', width: 100 },\n    { field: 'productName', title: 'Product Name', width: 200 },\n    { field: 'price', title: 'Price', width: 100 },\n    {\n      field: 'releaseDate',\n      formatter: 'formatDateTime',\n      title: 'Date',\n      width: 200,\n    },\n    {\n      cellRender: { name: 'CellLink', props: { text: '编辑' } },\n      field: 'action',\n      fixed: 'right',\n      title: '操作',\n      width: 120,\n    },\n  ],\n  height: 'auto',\n  keepSource: true,\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n  showOverflow: false,\n};\n\nconst [Grid] = useVbenVxeGrid({ gridOptions });\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #image-url=\"{ row }\">\n        <Image :src=\"row.imageUrl\" height=\"30\" width=\"30\" />\n      </template>\n      <template #open=\"{ row }\">\n        <Switch v-model:checked=\"row.open\" />\n      </template>\n      <template #status=\"{ row }\">\n        <Tag :color=\"row.color\">{{ row.status }}</Tag>\n      </template>\n      <template #action>\n        <Button type=\"link\">编辑</Button>\n      </template>\n    </Grid>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/edit-cell.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Page } from '@vben/common-ui';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { getExampleTableApi } from '#/api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { editRender: { name: 'input' }, field: 'category', title: 'Category' },\n    { editRender: { name: 'input' }, field: 'color', title: 'Color' },\n    {\n      editRender: { name: 'input' },\n      field: 'productName',\n      title: 'Product Name',\n    },\n    { field: 'price', title: 'Price' },\n    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },\n  ],\n  editConfig: {\n    mode: 'cell',\n    trigger: 'click',\n  },\n  height: 'auto',\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n  showOverflow: true,\n};\n\nconst [Grid] = useVbenVxeGrid({ gridOptions });\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/edit-row.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { getExampleTableApi } from '#/api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { editRender: { name: 'input' }, field: 'category', title: 'Category' },\n    { editRender: { name: 'input' }, field: 'color', title: 'Color' },\n    {\n      editRender: { name: 'input' },\n      field: 'productName',\n      title: 'Product Name',\n    },\n    { field: 'price', title: 'Price' },\n    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },\n    { slots: { default: 'action' }, title: '操作' },\n  ],\n  editConfig: {\n    mode: 'row',\n    trigger: 'click',\n  },\n  height: 'auto',\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n  showOverflow: true,\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({ gridOptions });\n\nfunction hasEditStatus(row: RowType) {\n  return gridApi.grid?.isEditByRow(row);\n}\n\nfunction editRowEvent(row: RowType) {\n  gridApi.grid?.setEditRow(row);\n}\n\nasync function saveRowEvent(row: RowType) {\n  await gridApi.grid?.clearEdit();\n\n  gridApi.setLoading(true);\n  setTimeout(() => {\n    gridApi.setLoading(false);\n    message.success({\n      content: `保存成功！category=${row.category}`,\n    });\n  }, 600);\n}\n\nconst cancelRowEvent = (_row: RowType) => {\n  gridApi.grid?.clearEdit();\n};\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #action=\"{ row }\">\n        <template v-if=\"hasEditStatus(row)\">\n          <Button type=\"link\" @click=\"saveRowEvent(row)\">保存</Button>\n          <Button type=\"link\" @click=\"cancelRowEvent(row)\">取消</Button>\n        </template>\n        <template v-else>\n          <Button type=\"link\" @click=\"editRowEvent(row)\">编辑</Button>\n        </template>\n      </template>\n    </Grid>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/fixed.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { getExampleTableApi } from '#/api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { fixed: 'left', title: '序号', type: 'seq', width: 50 },\n    { field: 'category', title: 'Category', width: 300 },\n    { field: 'color', title: 'Color', width: 300 },\n    { field: 'productName', title: 'Product Name', width: 300 },\n    { field: 'price', title: 'Price', width: 300 },\n    {\n      field: 'releaseDate',\n      formatter: 'formatDateTime',\n      title: 'DateTime',\n      width: 500,\n    },\n    {\n      field: 'action',\n      fixed: 'right',\n      slots: { default: 'action' },\n      title: '操作',\n      width: 120,\n    },\n  ],\n  height: 'auto',\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n        });\n      },\n    },\n  },\n  rowConfig: {\n    isHover: true,\n  },\n};\n\nconst [Grid] = useVbenVxeGrid({ gridOptions });\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid>\n      <template #action>\n        <Button type=\"link\">编辑</Button>\n      </template>\n    </Grid>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/form.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VbenFormProps } from '#/adapter/form';\nimport type { VxeTableGridOptions } from '#/adapter/vxe-table';\n\nimport { Page } from '@vben/common-ui';\n\nimport { message } from 'ant-design-vue';\nimport dayjs from 'dayjs';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { getExampleTableApi } from '#/api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst formOptions: VbenFormProps = {\n  // 默认展开\n  collapsed: false,\n  fieldMappingTime: [['date', ['start', 'end']]],\n  schema: [\n    {\n      component: 'Input',\n      defaultValue: '1',\n      fieldName: 'category',\n      label: 'Category',\n    },\n    {\n      component: 'Input',\n      fieldName: 'productName',\n      label: 'ProductName',\n    },\n    {\n      component: 'Input',\n      fieldName: 'price',\n      label: 'Price',\n    },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        options: [\n          {\n            label: 'Color1',\n            value: '1',\n          },\n          {\n            label: 'Color2',\n            value: '2',\n          },\n        ],\n        placeholder: '请选择',\n      },\n      fieldName: 'color',\n      label: 'Color',\n    },\n    {\n      component: 'RangePicker',\n      defaultValue: [dayjs().subtract(7, 'days'), dayjs()],\n      fieldName: 'date',\n      label: 'Date',\n    },\n  ],\n  // 控制表单是否显示折叠按钮\n  showCollapseButton: true,\n  // 是否在字段值改变时提交表单\n  submitOnChange: true,\n  // 按下回车时是否提交表单\n  submitOnEnter: false,\n};\n\nconst gridOptions: VxeTableGridOptions<RowType> = {\n  checkboxConfig: {\n    highlight: true,\n    labelField: 'name',\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { align: 'left', title: 'Name', type: 'checkbox', width: 100 },\n    { field: 'category', title: 'Category' },\n    { field: 'color', title: 'Color' },\n    { field: 'productName', title: 'Product Name' },\n    { field: 'price', title: 'Price' },\n    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },\n  ],\n  exportConfig: {},\n  height: 'auto',\n  keepSource: true,\n  pagerConfig: {},\n  proxyConfig: {\n    ajax: {\n      query: async ({ page }, formValues) => {\n        message.success(`Query params: ${JSON.stringify(formValues)}`);\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n          ...formValues,\n        });\n      },\n    },\n  },\n  toolbarConfig: {\n    custom: true,\n    export: true,\n    refresh: true,\n    resizable: true,\n    search: true,\n    zoom: true,\n  },\n};\n\nconst [Grid] = useVbenVxeGrid({\n  formOptions,\n  gridOptions,\n});\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/remote.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { getExampleTableApi } from '#/api';\n\ninterface RowType {\n  category: string;\n  color: string;\n  id: string;\n  price: string;\n  productName: string;\n  releaseDate: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  checkboxConfig: {\n    highlight: true,\n    labelField: 'name',\n  },\n  columns: [\n    { title: '序号', type: 'seq', width: 50 },\n    { align: 'left', title: 'Name', type: 'checkbox', width: 100 },\n    { field: 'category', sortable: true, title: 'Category' },\n    { field: 'color', sortable: true, title: 'Color' },\n    { field: 'productName', sortable: true, title: 'Product Name' },\n    { field: 'price', sortable: true, title: 'Price' },\n    { field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },\n  ],\n  exportConfig: {},\n  height: 'auto',\n  keepSource: true,\n  proxyConfig: {\n    ajax: {\n      query: async ({ page, sort }) => {\n        return await getExampleTableApi({\n          page: page.currentPage,\n          pageSize: page.pageSize,\n          sortBy: sort.field,\n          sortOrder: sort.order,\n        });\n      },\n    },\n    sort: true,\n  },\n  sortConfig: {\n    defaultSort: { field: 'category', order: 'desc' },\n    remote: true,\n  },\n  toolbarConfig: {\n    custom: true,\n    export: true,\n    // import: true,\n    refresh: true,\n    zoom: true,\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions,\n});\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid table-title=\"数据列表\" table-title-help=\"提示\">\n      <template #toolbar-tools>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"() => gridApi.query()\">\n          刷新当前页面\n        </Button>\n        <Button type=\"primary\" @click=\"() => gridApi.reload()\">\n          刷新并返回第一页\n        </Button>\n      </template>\n    </Grid>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/table-data.ts",
    "content": "interface TableRowData {\n  address: string;\n  age: number;\n  id: number;\n  name: string;\n  nickname: string;\n  role: string;\n}\n\nconst roles = ['User', 'Admin', 'Manager', 'Guest'];\n\nexport const MOCK_TABLE_DATA: TableRowData[] = (() => {\n  const data: TableRowData[] = [];\n  for (let i = 0; i < 40; i++) {\n    data.push({\n      address: `New York${i}`,\n      age: i + 1,\n      id: i,\n      name: `Test${i}`,\n      nickname: `Test${i}`,\n      role: roles[Math.floor(Math.random() * roles.length)] as string,\n    });\n  }\n  return data;\n})();\n\nexport const MOCK_TREE_TABLE_DATA = [\n  {\n    date: '2020-08-01',\n    id: 10_000,\n    name: 'Test1',\n    parentId: null,\n    size: 1024,\n    type: 'mp3',\n  },\n  {\n    date: '2021-04-01',\n    id: 10_050,\n    name: 'Test2',\n    parentId: null,\n    size: 0,\n    type: 'mp4',\n  },\n  {\n    date: '2020-03-01',\n    id: 24_300,\n    name: 'Test3',\n    parentId: 10_050,\n    size: 1024,\n    type: 'avi',\n  },\n  {\n    date: '2021-04-01',\n    id: 20_045,\n    name: 'Test4',\n    parentId: 24_300,\n    size: 600,\n    type: 'html',\n  },\n  {\n    date: '2021-04-01',\n    id: 10_053,\n    name: 'Test5',\n    parentId: 24_300,\n    size: 0,\n    type: 'avi',\n  },\n  {\n    date: '2021-10-01',\n    id: 24_330,\n    name: 'Test6',\n    parentId: 10_053,\n    size: 25,\n    type: 'txt',\n  },\n  {\n    date: '2020-01-01',\n    id: 21_011,\n    name: 'Test7',\n    parentId: 10_053,\n    size: 512,\n    type: 'pdf',\n  },\n  {\n    date: '2021-06-01',\n    id: 22_200,\n    name: 'Test8',\n    parentId: 10_053,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2020-11-01',\n    id: 23_666,\n    name: 'Test9',\n    parentId: null,\n    size: 2048,\n    type: 'xlsx',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_677,\n    name: 'Test10',\n    parentId: 23_666,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_671,\n    name: 'Test11',\n    parentId: 23_677,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_672,\n    name: 'Test12',\n    parentId: 23_677,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_688,\n    name: 'Test13',\n    parentId: 23_666,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_681,\n    name: 'Test14',\n    parentId: 23_688,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 23_682,\n    name: 'Test15',\n    parentId: 23_688,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2020-10-01',\n    id: 24_555,\n    name: 'Test16',\n    parentId: null,\n    size: 224,\n    type: 'avi',\n  },\n  {\n    date: '2021-06-01',\n    id: 24_566,\n    name: 'Test17',\n    parentId: 24_555,\n    size: 1024,\n    type: 'js',\n  },\n  {\n    date: '2021-06-01',\n    id: 24_577,\n    name: 'Test18',\n    parentId: 24_555,\n    size: 1024,\n    type: 'js',\n  },\n];\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/tree.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { Page } from '@vben/common-ui';\n\nimport { Button } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\nimport { MOCK_TREE_TABLE_DATA } from './table-data';\n\ninterface RowType {\n  date: string;\n  id: number;\n  name: string;\n  parentId: null | number;\n  size: number;\n  type: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { type: 'seq', width: 70 },\n    { field: 'name', minWidth: 300, title: 'Name', treeNode: true },\n    { field: 'size', title: 'Size' },\n    { field: 'type', title: 'Type' },\n    { field: 'date', title: 'Date' },\n  ],\n  data: MOCK_TREE_TABLE_DATA,\n  pagerConfig: {\n    enabled: false,\n  },\n  treeConfig: {\n    parentField: 'parentId',\n    rowField: 'id',\n    transform: true,\n  },\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({ gridOptions });\n\nconst expandAll = () => {\n  gridApi.grid?.setAllTreeExpand(true);\n};\n\nconst collapseAll = () => {\n  gridApi.grid?.setAllTreeExpand(false);\n};\n</script>\n\n<template>\n  <Page>\n    <Grid table-title=\"数据列表\" table-title-help=\"提示\">\n      <template #toolbar-tools>\n        <Button class=\"mr-2\" type=\"primary\" @click=\"expandAll\">\n          展开全部\n        </Button>\n        <Button type=\"primary\" @click=\"collapseAll\"> 折叠全部 </Button>\n      </template>\n    </Grid>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/examples/vxe-table/virtual.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { VxeGridProps } from '#/adapter/vxe-table';\n\nimport { onMounted } from 'vue';\n\nimport { Page } from '@vben/common-ui';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\n\ninterface RowType {\n  id: number;\n  name: string;\n  role: string;\n  sex: string;\n}\n\nconst gridOptions: VxeGridProps<RowType> = {\n  columns: [\n    { type: 'seq', width: 70 },\n    { field: 'name', title: 'Name' },\n    { field: 'role', title: 'Role' },\n    { field: 'sex', title: 'Sex' },\n  ],\n  data: [],\n  height: 'auto',\n  pagerConfig: {\n    enabled: false,\n  },\n  scrollY: {\n    enabled: true,\n    gt: 0,\n  },\n  showOverflow: true,\n};\n\nconst [Grid, gridApi] = useVbenVxeGrid({ gridOptions });\n\n// 模拟行数据\nconst loadList = (size = 200) => {\n  try {\n    const dataList: RowType[] = [];\n    for (let i = 0; i < size; i++) {\n      dataList.push({\n        id: 10_000 + i,\n        name: `Test${i}`,\n        role: 'Developer',\n        sex: '男',\n      });\n    }\n    gridApi.setGridOptions({ data: dataList });\n  } catch (error) {\n    console.error('Failed to load data:', error);\n    // Implement user-friendly error handling\n  }\n};\n\nonMounted(() => {\n  loadList(1000);\n});\n</script>\n\n<template>\n  <Page auto-content-height>\n    <Grid />\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/dept/data.ts",
    "content": "import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';\n\nimport type { VbenFormSchema } from '#/adapter/form';\nimport type { OnActionClickFn } from '#/adapter/vxe-table';\nimport type { SystemDeptApi } from '#/api/system/dept';\n\nimport { z } from '#/adapter/form';\nimport { getDeptList } from '#/api/system/dept';\nimport { $t } from '#/locales';\n\n/**\n * 获取编辑表单的字段配置。如果没有使用多语言，可以直接export一个数组常量\n */\nexport function useSchema(): VbenFormSchema[] {\n  return [\n    {\n      component: 'Input',\n      fieldName: 'name',\n      label: $t('system.dept.deptName'),\n      rules: z\n        .string()\n        .min(2, $t('ui.formRules.minLength', [$t('system.dept.deptName'), 2]))\n        .max(\n          20,\n          $t('ui.formRules.maxLength', [$t('system.dept.deptName'), 20]),\n        ),\n    },\n    {\n      component: 'ApiTreeSelect',\n      componentProps: {\n        allowClear: true,\n        api: getDeptList,\n        class: 'w-full',\n        labelField: 'name',\n        valueField: 'id',\n        childrenField: 'children',\n      },\n      fieldName: 'pid',\n      label: $t('system.dept.parentDept'),\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        buttonStyle: 'solid',\n        options: [\n          { label: $t('common.enabled'), value: 1 },\n          { label: $t('common.disabled'), value: 0 },\n        ],\n        optionType: 'button',\n      },\n      defaultValue: 1,\n      fieldName: 'status',\n      label: $t('system.dept.status'),\n    },\n    {\n      component: 'Textarea',\n      componentProps: {\n        maxLength: 50,\n        rows: 3,\n        showCount: true,\n      },\n      fieldName: 'remark',\n      label: $t('system.dept.remark'),\n      rules: z\n        .string()\n        .max(50, $t('ui.formRules.maxLength', [$t('system.dept.remark'), 50]))\n        .optional(),\n    },\n  ];\n}\n\n/**\n * 获取表格列配置\n * @description 使用函数的形式返回列数据而不是直接export一个Array常量，是为了响应语言切换时重新翻译表头\n * @param onActionClick 表格操作按钮点击事件\n */\nexport function useColumns(\n  onActionClick?: OnActionClickFn<SystemDeptApi.SystemDept>,\n): VxeTableGridOptions<SystemDeptApi.SystemDept>['columns'] {\n  return [\n    {\n      align: 'left',\n      field: 'name',\n      fixed: 'left',\n      title: $t('system.dept.deptName'),\n      treeNode: true,\n      width: 150,\n    },\n    {\n      cellRender: { name: 'CellTag' },\n      field: 'status',\n      title: $t('system.dept.status'),\n      width: 100,\n    },\n    {\n      field: 'createTime',\n      title: $t('system.dept.createTime'),\n      width: 180,\n    },\n    {\n      field: 'remark',\n      title: $t('system.dept.remark'),\n    },\n    {\n      align: 'right',\n      cellRender: {\n        attrs: {\n          nameField: 'name',\n          nameTitle: $t('system.dept.name'),\n          onClick: onActionClick,\n        },\n        name: 'CellOperation',\n        options: [\n          {\n            code: 'append',\n            text: '新增下级',\n          },\n          'edit', // 默认的编辑按钮\n          {\n            code: 'delete', // 默认的删除按钮\n            disabled: (row: SystemDeptApi.SystemDept) => {\n              return !!(row.children && row.children.length > 0);\n            },\n          },\n        ],\n      },\n      field: 'operation',\n      fixed: 'right',\n      headerAlign: 'center',\n      showOverflow: false,\n      title: $t('system.dept.operation'),\n      width: 200,\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/dept/list.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  OnActionClickParams,\n  VxeTableGridOptions,\n} from '#/adapter/vxe-table';\nimport type { SystemDeptApi } from '#/api/system/dept';\n\nimport { Page, useVbenModal } from '@vben/common-ui';\nimport { Plus } from '@vben/icons';\n\nimport { Button, message } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { deleteDept, getDeptList } from '#/api/system/dept';\nimport { $t } from '#/locales';\n\nimport { useColumns } from './data';\nimport Form from './modules/form.vue';\n\nconst [FormModal, formModalApi] = useVbenModal({\n  connectedComponent: Form,\n  destroyOnClose: true,\n});\n\n/**\n * 编辑部门\n * @param row\n */\nfunction onEdit(row: SystemDeptApi.SystemDept) {\n  formModalApi.setData(row).open();\n}\n\n/**\n * 添加下级部门\n * @param row\n */\nfunction onAppend(row: SystemDeptApi.SystemDept) {\n  formModalApi.setData({ pid: row.id }).open();\n}\n\n/**\n * 创建新部门\n */\nfunction onCreate() {\n  formModalApi.setData(null).open();\n}\n\n/**\n * 删除部门\n * @param row\n */\nfunction onDelete(row: SystemDeptApi.SystemDept) {\n  const hideLoading = message.loading({\n    content: $t('ui.actionMessage.deleting', [row.name]),\n    duration: 0,\n    key: 'action_process_msg',\n  });\n  deleteDept(row.id)\n    .then(() => {\n      message.success({\n        content: $t('ui.actionMessage.deleteSuccess', [row.name]),\n        key: 'action_process_msg',\n      });\n      refreshGrid();\n    })\n    .catch(() => {\n      hideLoading();\n    });\n}\n\n/**\n * 表格操作按钮的回调函数\n */\nfunction onActionClick({\n  code,\n  row,\n}: OnActionClickParams<SystemDeptApi.SystemDept>) {\n  switch (code) {\n    case 'append': {\n      onAppend(row);\n      break;\n    }\n    case 'delete': {\n      onDelete(row);\n      break;\n    }\n    case 'edit': {\n      onEdit(row);\n      break;\n    }\n  }\n}\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridEvents: {},\n  gridOptions: {\n    columns: useColumns(onActionClick),\n    height: 'auto',\n    keepSource: true,\n    pagerConfig: {\n      enabled: false,\n    },\n    proxyConfig: {\n      ajax: {\n        query: async (_params) => {\n          return await getDeptList();\n        },\n      },\n    },\n    toolbarConfig: {\n      custom: true,\n      export: false,\n      refresh: true,\n      zoom: true,\n    },\n    treeConfig: {\n      parentField: 'pid',\n      rowField: 'id',\n      transform: false,\n    },\n  } as VxeTableGridOptions,\n});\n\n/**\n * 刷新表格\n */\nfunction refreshGrid() {\n  gridApi.query();\n}\n</script>\n<template>\n  <Page auto-content-height>\n    <FormModal @success=\"refreshGrid\" />\n    <Grid table-title=\"部门列表\">\n      <template #toolbar-tools>\n        <Button type=\"primary\" @click=\"onCreate\">\n          <Plus class=\"size-5\" />\n          {{ $t('ui.actionTitle.create', [$t('system.dept.name')]) }}\n        </Button>\n      </template>\n    </Grid>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/dept/modules/form.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { SystemDeptApi } from '#/api/system/dept';\n\nimport { computed, ref } from 'vue';\n\nimport { useVbenModal } from '@vben/common-ui';\n\nimport { Button } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\nimport { createDept, updateDept } from '#/api/system/dept';\nimport { $t } from '#/locales';\n\nimport { useSchema } from '../data';\n\nconst emit = defineEmits(['success']);\nconst formData = ref<SystemDeptApi.SystemDept>();\nconst getTitle = computed(() => {\n  return formData.value?.id\n    ? $t('ui.actionTitle.edit', [$t('system.dept.name')])\n    : $t('ui.actionTitle.create', [$t('system.dept.name')]);\n});\n\nconst [Form, formApi] = useVbenForm({\n  layout: 'vertical',\n  schema: useSchema(),\n  showDefaultActions: false,\n});\n\nfunction resetForm() {\n  formApi.resetForm();\n  formApi.setValues(formData.value || {});\n}\n\nconst [Modal, modalApi] = useVbenModal({\n  async onConfirm() {\n    const { valid } = await formApi.validate();\n    if (valid) {\n      modalApi.lock();\n      const data = await formApi.getValues();\n      try {\n        await (formData.value?.id\n          ? updateDept(formData.value.id, data)\n          : createDept(data));\n        modalApi.close();\n        emit('success');\n      } finally {\n        modalApi.lock(false);\n      }\n    }\n  },\n  onOpenChange(isOpen) {\n    if (isOpen) {\n      const data = modalApi.getData<SystemDeptApi.SystemDept>();\n      if (data) {\n        if (data.pid === 0) {\n          data.pid = undefined;\n        }\n        formData.value = data;\n        formApi.setValues(formData.value);\n      }\n    }\n  },\n});\n</script>\n\n<template>\n  <Modal :title=\"getTitle\">\n    <Form class=\"mx-4\" />\n    <template #prepend-footer>\n      <div class=\"flex-auto\">\n        <Button type=\"primary\" danger @click=\"resetForm\">\n          {{ $t('common.reset') }}\n        </Button>\n      </div>\n    </template>\n  </Modal>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/menu/data.ts",
    "content": "import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';\nimport type { SystemMenuApi } from '#/api/system/menu';\n\nimport { $t } from '#/locales';\n\nexport function getMenuTypeOptions() {\n  return [\n    {\n      color: 'processing',\n      label: $t('system.menu.typeCatalog'),\n      value: 'catalog',\n    },\n    { color: 'default', label: $t('system.menu.typeMenu'), value: 'menu' },\n    { color: 'error', label: $t('system.menu.typeButton'), value: 'button' },\n    {\n      color: 'success',\n      label: $t('system.menu.typeEmbedded'),\n      value: 'embedded',\n    },\n    { color: 'warning', label: $t('system.menu.typeLink'), value: 'link' },\n  ];\n}\n\nexport function useColumns(\n  onActionClick: OnActionClickFn<SystemMenuApi.SystemMenu>,\n): VxeTableGridOptions<SystemMenuApi.SystemMenu>['columns'] {\n  return [\n    {\n      align: 'left',\n      field: 'meta.title',\n      fixed: 'left',\n      slots: { default: 'title' },\n      title: $t('system.menu.menuTitle'),\n      treeNode: true,\n      width: 250,\n    },\n    {\n      align: 'center',\n      cellRender: { name: 'CellTag', options: getMenuTypeOptions() },\n      field: 'type',\n      title: $t('system.menu.type'),\n      width: 100,\n    },\n    {\n      field: 'authCode',\n      title: $t('system.menu.authCode'),\n      width: 200,\n    },\n    {\n      align: 'left',\n      field: 'path',\n      title: $t('system.menu.path'),\n      width: 200,\n    },\n\n    {\n      align: 'left',\n      field: 'component',\n      formatter: ({ row }) => {\n        switch (row.type) {\n          case 'catalog':\n          case 'menu': {\n            return row.component ?? '';\n          }\n          case 'embedded': {\n            return row.meta?.iframeSrc ?? '';\n          }\n          case 'link': {\n            return row.meta?.link ?? '';\n          }\n        }\n        return '';\n      },\n      minWidth: 200,\n      title: $t('system.menu.component'),\n    },\n    {\n      cellRender: { name: 'CellTag' },\n      field: 'status',\n      title: $t('system.menu.status'),\n      width: 100,\n    },\n\n    {\n      align: 'right',\n      cellRender: {\n        attrs: {\n          nameField: 'name',\n          onClick: onActionClick,\n        },\n        name: 'CellOperation',\n        options: [\n          {\n            code: 'append',\n            text: '新增下级',\n          },\n          'edit', // 默认的编辑按钮\n          'delete', // 默认的删除按钮\n        ],\n      },\n      field: 'operation',\n      fixed: 'right',\n      headerAlign: 'center',\n      showOverflow: false,\n      title: $t('system.menu.operation'),\n      width: 200,\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/menu/list.vue",
    "content": "<script lang=\"ts\" setup>\nimport type {\n  OnActionClickParams,\n  VxeTableGridOptions,\n} from '#/adapter/vxe-table';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\nimport { IconifyIcon, Plus } from '@vben/icons';\nimport { $t } from '@vben/locales';\n\nimport { MenuBadge } from '@vben-core/menu-ui';\n\nimport { Button, message } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { deleteMenu, getMenuList, SystemMenuApi } from '#/api/system/menu';\n\nimport { useColumns } from './data';\nimport Form from './modules/form.vue';\n\nconst [FormDrawer, formDrawerApi] = useVbenDrawer({\n  connectedComponent: Form,\n  destroyOnClose: true,\n});\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  gridOptions: {\n    columns: useColumns(onActionClick),\n    height: 'auto',\n    keepSource: true,\n    pagerConfig: {\n      enabled: false,\n    },\n    proxyConfig: {\n      ajax: {\n        query: async (_params) => {\n          return await getMenuList();\n        },\n      },\n    },\n    rowConfig: {\n      keyField: 'id',\n    },\n    toolbarConfig: {\n      custom: true,\n      export: false,\n      refresh: true,\n      zoom: true,\n    },\n    treeConfig: {\n      parentField: 'pid',\n      rowField: 'id',\n      transform: false,\n    },\n  } as VxeTableGridOptions,\n});\n\nfunction onActionClick({\n  code,\n  row,\n}: OnActionClickParams<SystemMenuApi.SystemMenu>) {\n  switch (code) {\n    case 'append': {\n      onAppend(row);\n      break;\n    }\n    case 'delete': {\n      onDelete(row);\n      break;\n    }\n    case 'edit': {\n      onEdit(row);\n      break;\n    }\n    default: {\n      break;\n    }\n  }\n}\n\nfunction onRefresh() {\n  gridApi.query();\n}\nfunction onEdit(row: SystemMenuApi.SystemMenu) {\n  formDrawerApi.setData(row).open();\n}\nfunction onCreate() {\n  formDrawerApi.setData({}).open();\n}\nfunction onAppend(row: SystemMenuApi.SystemMenu) {\n  formDrawerApi.setData({ pid: row.id }).open();\n}\n\nfunction onDelete(row: SystemMenuApi.SystemMenu) {\n  const hideLoading = message.loading({\n    content: $t('ui.actionMessage.deleting', [row.name]),\n    duration: 0,\n    key: 'action_process_msg',\n  });\n  deleteMenu(row.id)\n    .then(() => {\n      message.success({\n        content: $t('ui.actionMessage.deleteSuccess', [row.name]),\n        key: 'action_process_msg',\n      });\n      onRefresh();\n    })\n    .catch(() => {\n      hideLoading();\n    });\n}\n</script>\n<template>\n  <Page auto-content-height>\n    <FormDrawer @success=\"onRefresh\" />\n    <Grid>\n      <template #toolbar-tools>\n        <Button type=\"primary\" @click=\"onCreate\">\n          <Plus class=\"size-5\" />\n          {{ $t('ui.actionTitle.create', [$t('system.menu.name')]) }}\n        </Button>\n      </template>\n      <template #title=\"{ row }\">\n        <div class=\"flex w-full items-center gap-1\">\n          <div class=\"size-5 flex-shrink-0\">\n            <IconifyIcon\n              v-if=\"row.type === 'button'\"\n              icon=\"carbon:security\"\n              class=\"size-full\"\n            />\n            <IconifyIcon\n              v-else-if=\"row.meta?.icon\"\n              :icon=\"row.meta?.icon || 'carbon:circle-dash'\"\n              class=\"size-full\"\n            />\n          </div>\n          <span class=\"flex-auto\">{{ $t(row.meta?.title) }}</span>\n          <div class=\"items-center justify-end\"></div>\n        </div>\n        <MenuBadge\n          v-if=\"row.meta?.badgeType\"\n          class=\"menu-badge\"\n          :badge=\"row.meta.badge\"\n          :badge-type=\"row.meta.badgeType\"\n          :badge-variants=\"row.meta.badgeVariants\"\n        />\n      </template>\n    </Grid>\n  </Page>\n</template>\n<style lang=\"scss\" scoped>\n.menu-badge {\n  top: 50%;\n  right: 0;\n  transform: translateY(-50%);\n\n  & > :deep(div) {\n    padding-top: 0;\n    padding-bottom: 0;\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/menu/modules/form.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { ChangeEvent } from 'ant-design-vue/es/_util/EventInterface';\n\nimport type { Recordable } from '@vben/types';\n\nimport type { VbenFormSchema } from '#/adapter/form';\n\nimport { computed, h, ref } from 'vue';\n\nimport { useVbenDrawer } from '@vben/common-ui';\nimport { IconifyIcon } from '@vben/icons';\nimport { $te } from '@vben/locales';\nimport { getPopupContainer } from '@vben/utils';\n\nimport { breakpointsTailwind, useBreakpoints } from '@vueuse/core';\n\nimport { useVbenForm, z } from '#/adapter/form';\nimport {\n  createMenu,\n  getMenuList,\n  isMenuNameExists,\n  isMenuPathExists,\n  SystemMenuApi,\n  updateMenu,\n} from '#/api/system/menu';\nimport { $t } from '#/locales';\nimport { componentKeys } from '#/router/routes';\n\nimport { getMenuTypeOptions } from '../data';\n\nconst emit = defineEmits<{\n  success: [];\n}>();\nconst formData = ref<SystemMenuApi.SystemMenu>();\nconst titleSuffix = ref<string>();\nconst schema: VbenFormSchema[] = [\n  {\n    component: 'RadioGroup',\n    componentProps: {\n      buttonStyle: 'solid',\n      options: getMenuTypeOptions(),\n      optionType: 'button',\n    },\n    defaultValue: 'menu',\n    fieldName: 'type',\n    formItemClass: 'col-span-2 md:col-span-2',\n    label: $t('system.menu.type'),\n  },\n  {\n    component: 'Input',\n    fieldName: 'name',\n    label: $t('system.menu.menuName'),\n    rules: z\n      .string()\n      .min(2, $t('ui.formRules.minLength', [$t('system.menu.menuName'), 2]))\n      .max(30, $t('ui.formRules.maxLength', [$t('system.menu.menuName'), 30]))\n      .refine(\n        async (value: string) => {\n          return !(await isMenuNameExists(value, formData.value?.id));\n        },\n        (value) => ({\n          message: $t('ui.formRules.alreadyExists', [\n            $t('system.menu.menuName'),\n            value,\n          ]),\n        }),\n      ),\n  },\n  {\n    component: 'ApiTreeSelect',\n    componentProps: {\n      api: getMenuList,\n      class: 'w-full',\n      filterTreeNode(input: string, node: Recordable<any>) {\n        if (!input || input.length === 0) {\n          return true;\n        }\n        const title: string = node.meta?.title ?? '';\n        if (!title) return false;\n        return title.includes(input) || $t(title).includes(input);\n      },\n      getPopupContainer,\n      labelField: 'meta.title',\n      showSearch: true,\n      treeDefaultExpandAll: true,\n      valueField: 'id',\n      childrenField: 'children',\n    },\n    fieldName: 'pid',\n    label: $t('system.menu.parent'),\n    renderComponentContent() {\n      return {\n        title({ label, meta }: { label: string; meta: Recordable<any> }) {\n          const coms = [];\n          if (!label) return '';\n          if (meta?.icon) {\n            coms.push(h(IconifyIcon, { class: 'size-4', icon: meta.icon }));\n          }\n          coms.push(h('span', { class: '' }, $t(label || '')));\n          return h('div', { class: 'flex items-center gap-1' }, coms);\n        },\n      };\n    },\n  },\n  {\n    component: 'Input',\n    componentProps() {\n      // 不需要处理多语言时就无需这么做\n      return {\n        addonAfter: titleSuffix.value,\n        onChange({ target: { value } }: ChangeEvent) {\n          titleSuffix.value = value && $te(value) ? $t(value) : undefined;\n        },\n      };\n    },\n    fieldName: 'meta.title',\n    label: $t('system.menu.menuTitle'),\n    rules: 'required',\n  },\n  {\n    component: 'Input',\n    dependencies: {\n      show: (values) => {\n        return ['catalog', 'embedded', 'menu'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'path',\n    label: $t('system.menu.path'),\n    rules: z\n      .string()\n      .min(2, $t('ui.formRules.minLength', [$t('system.menu.path'), 2]))\n      .max(100, $t('ui.formRules.maxLength', [$t('system.menu.path'), 100]))\n      .refine(\n        (value: string) => {\n          return value.startsWith('/');\n        },\n        $t('ui.formRules.startWith', [$t('system.menu.path'), '/']),\n      )\n      .refine(\n        async (value: string) => {\n          return !(await isMenuPathExists(value, formData.value?.id));\n        },\n        (value) => ({\n          message: $t('ui.formRules.alreadyExists', [\n            $t('system.menu.path'),\n            value,\n          ]),\n        }),\n      ),\n  },\n  {\n    component: 'Input',\n    dependencies: {\n      show: (values) => {\n        return ['embedded', 'menu'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'activePath',\n    help: $t('system.menu.activePathHelp'),\n    label: $t('system.menu.activePath'),\n    rules: z\n      .string()\n      .min(2, $t('ui.formRules.minLength', [$t('system.menu.path'), 2]))\n      .max(100, $t('ui.formRules.maxLength', [$t('system.menu.path'), 100]))\n      .refine(\n        (value: string) => {\n          return value.startsWith('/');\n        },\n        $t('ui.formRules.startWith', [$t('system.menu.path'), '/']),\n      )\n      .refine(async (value: string) => {\n        return await isMenuPathExists(value, formData.value?.id);\n      }, $t('system.menu.activePathMustExist'))\n      .optional(),\n  },\n  {\n    component: 'IconPicker',\n    componentProps: {\n      prefix: 'carbon',\n    },\n    dependencies: {\n      show: (values) => {\n        return ['catalog', 'embedded', 'link', 'menu'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.icon',\n    label: $t('system.menu.icon'),\n  },\n  {\n    component: 'IconPicker',\n    componentProps: {\n      prefix: 'carbon',\n    },\n    dependencies: {\n      show: (values) => {\n        return ['catalog', 'embedded', 'menu'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.activeIcon',\n    label: $t('system.menu.activeIcon'),\n  },\n  {\n    component: 'AutoComplete',\n    componentProps: {\n      allowClear: true,\n      class: 'w-full',\n      filterOption(input: string, option: { value: string }) {\n        return option.value.toLowerCase().includes(input.toLowerCase());\n      },\n      options: componentKeys.map((v) => ({ value: v })),\n    },\n    dependencies: {\n      rules: (values) => {\n        return values.type === 'menu' ? 'required' : null;\n      },\n      show: (values) => {\n        return values.type === 'menu';\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'component',\n    label: $t('system.menu.component'),\n  },\n  {\n    component: 'Input',\n    dependencies: {\n      show: (values) => {\n        return ['embedded', 'link'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'linkSrc',\n    label: $t('system.menu.linkSrc'),\n    rules: z.string().url($t('ui.formRules.invalidURL')),\n  },\n  {\n    component: 'Input',\n    dependencies: {\n      rules: (values) => {\n        return values.type === 'button' ? 'required' : null;\n      },\n      show: (values) => {\n        return ['button', 'catalog', 'embedded', 'menu'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'authCode',\n    label: $t('system.menu.authCode'),\n  },\n  {\n    component: 'RadioGroup',\n    componentProps: {\n      buttonStyle: 'solid',\n      options: [\n        { label: $t('common.enabled'), value: 1 },\n        { label: $t('common.disabled'), value: 0 },\n      ],\n      optionType: 'button',\n    },\n    defaultValue: 1,\n    fieldName: 'status',\n    label: $t('system.menu.status'),\n  },\n  {\n    component: 'Select',\n    componentProps: {\n      allowClear: true,\n      class: 'w-full',\n      options: [\n        { label: $t('system.menu.badgeType.dot'), value: 'dot' },\n        { label: $t('system.menu.badgeType.normal'), value: 'normal' },\n      ],\n    },\n    dependencies: {\n      show: (values) => {\n        return values.type !== 'button';\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.badgeType',\n    label: $t('system.menu.badgeType.title'),\n  },\n  {\n    component: 'Input',\n    componentProps: (values) => {\n      return {\n        allowClear: true,\n        class: 'w-full',\n        disabled: values.meta?.badgeType !== 'normal',\n      };\n    },\n    dependencies: {\n      show: (values) => {\n        return values.type !== 'button';\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.badge',\n    label: $t('system.menu.badge'),\n  },\n  {\n    component: 'Select',\n    componentProps: {\n      allowClear: true,\n      class: 'w-full',\n      options: SystemMenuApi.BadgeVariants.map((v) => ({\n        label: v,\n        value: v,\n      })),\n    },\n    dependencies: {\n      show: (values) => {\n        return values.type !== 'button';\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.badgeVariants',\n    label: $t('system.menu.badgeVariants'),\n  },\n  {\n    component: 'Divider',\n    dependencies: {\n      show: (values) => {\n        return !['button', 'link'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'divider1',\n    formItemClass: 'col-span-2 md:col-span-2 pb-0',\n    hideLabel: true,\n    renderComponentContent() {\n      return {\n        default: () => $t('system.menu.advancedSettings'),\n      };\n    },\n  },\n  {\n    component: 'Checkbox',\n    dependencies: {\n      show: (values) => {\n        return ['menu'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.keepAlive',\n    renderComponentContent() {\n      return {\n        default: () => $t('system.menu.keepAlive'),\n      };\n    },\n  },\n  {\n    component: 'Checkbox',\n    dependencies: {\n      show: (values) => {\n        return ['embedded', 'menu'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.affixTab',\n    renderComponentContent() {\n      return {\n        default: () => $t('system.menu.affixTab'),\n      };\n    },\n  },\n  {\n    component: 'Checkbox',\n    dependencies: {\n      show: (values) => {\n        return !['button'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.hideInMenu',\n    renderComponentContent() {\n      return {\n        default: () => $t('system.menu.hideInMenu'),\n      };\n    },\n  },\n  {\n    component: 'Checkbox',\n    dependencies: {\n      show: (values) => {\n        return ['catalog', 'menu'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.hideChildrenInMenu',\n    renderComponentContent() {\n      return {\n        default: () => $t('system.menu.hideChildrenInMenu'),\n      };\n    },\n  },\n  {\n    component: 'Checkbox',\n    dependencies: {\n      show: (values) => {\n        return !['button', 'link'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.hideInBreadcrumb',\n    renderComponentContent() {\n      return {\n        default: () => $t('system.menu.hideInBreadcrumb'),\n      };\n    },\n  },\n  {\n    component: 'Checkbox',\n    dependencies: {\n      show: (values) => {\n        return !['button', 'link'].includes(values.type);\n      },\n      triggerFields: ['type'],\n    },\n    fieldName: 'meta.hideInTab',\n    renderComponentContent() {\n      return {\n        default: () => $t('system.menu.hideInTab'),\n      };\n    },\n  },\n];\n\nconst breakpoints = useBreakpoints(breakpointsTailwind);\nconst isHorizontal = computed(() => breakpoints.greaterOrEqual('md').value);\n\nconst [Form, formApi] = useVbenForm({\n  commonConfig: {\n    colon: true,\n    formItemClass: 'col-span-2 md:col-span-1',\n  },\n  schema,\n  showDefaultActions: false,\n  wrapperClass: 'grid-cols-2 gap-x-4',\n});\n\nconst [Drawer, drawerApi] = useVbenDrawer({\n  onConfirm: onSubmit,\n  onOpenChange(isOpen) {\n    if (isOpen) {\n      const data = drawerApi.getData<SystemMenuApi.SystemMenu>();\n      if (data?.type === 'link') {\n        data.linkSrc = data.meta?.link;\n      } else if (data?.type === 'embedded') {\n        data.linkSrc = data.meta?.iframeSrc;\n      }\n      if (data) {\n        formData.value = data;\n        formApi.setValues(formData.value);\n        titleSuffix.value = formData.value.meta?.title\n          ? $t(formData.value.meta.title)\n          : '';\n      } else {\n        formApi.resetForm();\n        titleSuffix.value = '';\n      }\n    }\n  },\n});\n\nasync function onSubmit() {\n  const { valid } = await formApi.validate();\n  if (valid) {\n    drawerApi.lock();\n    const data =\n      await formApi.getValues<\n        Omit<SystemMenuApi.SystemMenu, 'children' | 'id'>\n      >();\n    if (data.type === 'link') {\n      data.meta = { ...data.meta, link: data.linkSrc };\n    } else if (data.type === 'embedded') {\n      data.meta = { ...data.meta, iframeSrc: data.linkSrc };\n    }\n    delete data.linkSrc;\n    try {\n      await (formData.value?.id\n        ? updateMenu(formData.value.id, data)\n        : createMenu(data));\n      drawerApi.close();\n      emit('success');\n    } finally {\n      drawerApi.unlock();\n    }\n  }\n}\nconst getDrawerTitle = computed(() =>\n  formData.value?.id\n    ? $t('ui.actionTitle.edit', [$t('system.menu.name')])\n    : $t('ui.actionTitle.create', [$t('system.menu.name')]),\n);\n</script>\n<template>\n  <Drawer class=\"w-full max-w-[800px]\" :title=\"getDrawerTitle\">\n    <Form class=\"mx-4\" :layout=\"isHorizontal ? 'horizontal' : 'vertical'\" />\n  </Drawer>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/role/data.ts",
    "content": "import type { VbenFormSchema } from '#/adapter/form';\nimport type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';\nimport type { SystemRoleApi } from '#/api';\n\nimport { $t } from '#/locales';\n\nexport function useFormSchema(): VbenFormSchema[] {\n  return [\n    {\n      component: 'Input',\n      fieldName: 'name',\n      label: $t('system.role.roleName'),\n      rules: 'required',\n    },\n    {\n      component: 'RadioGroup',\n      componentProps: {\n        buttonStyle: 'solid',\n        options: [\n          { label: $t('common.enabled'), value: 1 },\n          { label: $t('common.disabled'), value: 0 },\n        ],\n        optionType: 'button',\n      },\n      defaultValue: 1,\n      fieldName: 'status',\n      label: $t('system.role.status'),\n    },\n    {\n      component: 'Textarea',\n      fieldName: 'remark',\n      label: $t('system.role.remark'),\n    },\n    {\n      component: 'Input',\n      fieldName: 'permissions',\n      formItemClass: 'items-start',\n      label: $t('system.role.setPermissions'),\n      modelPropName: 'modelValue',\n    },\n  ];\n}\n\nexport function useGridFormSchema(): VbenFormSchema[] {\n  return [\n    {\n      component: 'Input',\n      fieldName: 'name',\n      label: $t('system.role.roleName'),\n    },\n    { component: 'Input', fieldName: 'id', label: $t('system.role.id') },\n    {\n      component: 'Select',\n      componentProps: {\n        allowClear: true,\n        options: [\n          { label: $t('common.enabled'), value: 1 },\n          { label: $t('common.disabled'), value: 0 },\n        ],\n      },\n      fieldName: 'status',\n      label: $t('system.role.status'),\n    },\n    {\n      component: 'Input',\n      fieldName: 'remark',\n      label: $t('system.role.remark'),\n    },\n    {\n      component: 'RangePicker',\n      fieldName: 'createTime',\n      label: $t('system.role.createTime'),\n    },\n  ];\n}\n\nexport function useColumns<T = SystemRoleApi.SystemRole>(\n  onActionClick: OnActionClickFn<T>,\n  onStatusChange?: (newStatus: any, row: T) => PromiseLike<boolean | undefined>,\n): VxeTableGridOptions['columns'] {\n  return [\n    {\n      field: 'name',\n      title: $t('system.role.roleName'),\n      width: 200,\n    },\n    {\n      field: 'id',\n      title: $t('system.role.id'),\n      width: 200,\n    },\n    {\n      cellRender: {\n        attrs: { beforeChange: onStatusChange },\n        name: onStatusChange ? 'CellSwitch' : 'CellTag',\n      },\n      field: 'status',\n      title: $t('system.role.status'),\n      width: 100,\n    },\n    {\n      field: 'remark',\n      minWidth: 100,\n      title: $t('system.role.remark'),\n    },\n    {\n      field: 'createTime',\n      title: $t('system.role.createTime'),\n      width: 200,\n    },\n    {\n      align: 'center',\n      cellRender: {\n        attrs: {\n          nameField: 'name',\n          nameTitle: $t('system.role.name'),\n          onClick: onActionClick,\n        },\n        name: 'CellOperation',\n      },\n      field: 'operation',\n      fixed: 'right',\n      title: $t('system.role.operation'),\n      width: 130,\n    },\n  ];\n}\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/role/list.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { Recordable } from '@vben/types';\n\nimport type {\n  OnActionClickParams,\n  VxeTableGridOptions,\n} from '#/adapter/vxe-table';\nimport type { SystemRoleApi } from '#/api';\n\nimport { Page, useVbenDrawer } from '@vben/common-ui';\nimport { Plus } from '@vben/icons';\n\nimport { Button, message, Modal } from 'ant-design-vue';\n\nimport { useVbenVxeGrid } from '#/adapter/vxe-table';\nimport { deleteRole, getRoleList, updateRole } from '#/api';\nimport { $t } from '#/locales';\n\nimport { useColumns, useGridFormSchema } from './data';\nimport Form from './modules/form.vue';\n\nconst [FormDrawer, formDrawerApi] = useVbenDrawer({\n  connectedComponent: Form,\n  destroyOnClose: true,\n});\n\nconst [Grid, gridApi] = useVbenVxeGrid({\n  formOptions: {\n    fieldMappingTime: [['createTime', ['startTime', 'endTime']]],\n    schema: useGridFormSchema(),\n    submitOnChange: true,\n  },\n  gridOptions: {\n    columns: useColumns(onActionClick, onStatusChange),\n    height: 'auto',\n    keepSource: true,\n    proxyConfig: {\n      ajax: {\n        query: async ({ page }, formValues) => {\n          return await getRoleList({\n            page: page.currentPage,\n            pageSize: page.pageSize,\n            ...formValues,\n          });\n        },\n      },\n    },\n    rowConfig: {\n      keyField: 'id',\n    },\n\n    toolbarConfig: {\n      custom: true,\n      export: false,\n      refresh: true,\n      search: true,\n      zoom: true,\n    },\n  } as VxeTableGridOptions<SystemRoleApi.SystemRole>,\n});\n\nfunction onActionClick(e: OnActionClickParams<SystemRoleApi.SystemRole>) {\n  switch (e.code) {\n    case 'delete': {\n      onDelete(e.row);\n      break;\n    }\n    case 'edit': {\n      onEdit(e.row);\n      break;\n    }\n  }\n}\n\n/**\n * 将Antd的Modal.confirm封装为promise，方便在异步函数中调用。\n * @param content 提示内容\n * @param title 提示标题\n */\nfunction confirm(content: string, title: string) {\n  return new Promise((reslove, reject) => {\n    Modal.confirm({\n      content,\n      onCancel() {\n        reject(new Error('已取消'));\n      },\n      onOk() {\n        reslove(true);\n      },\n      title,\n    });\n  });\n}\n\n/**\n * 状态开关即将改变\n * @param newStatus 期望改变的状态值\n * @param row 行数据\n * @returns 返回false则中止改变，返回其他值（undefined、true）则允许改变\n */\nasync function onStatusChange(\n  newStatus: number,\n  row: SystemRoleApi.SystemRole,\n) {\n  const status: Recordable<string> = {\n    0: '禁用',\n    1: '启用',\n  };\n  try {\n    await confirm(\n      `你要将${row.name}的状态切换为 【${status[newStatus.toString()]}】 吗？`,\n      `切换状态`,\n    );\n    await updateRole(row.id, { status: newStatus });\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nfunction onEdit(row: SystemRoleApi.SystemRole) {\n  formDrawerApi.setData(row).open();\n}\n\nfunction onDelete(row: SystemRoleApi.SystemRole) {\n  const hideLoading = message.loading({\n    content: $t('ui.actionMessage.deleting', [row.name]),\n    duration: 0,\n    key: 'action_process_msg',\n  });\n  deleteRole(row.id)\n    .then(() => {\n      message.success({\n        content: $t('ui.actionMessage.deleteSuccess', [row.name]),\n        key: 'action_process_msg',\n      });\n      onRefresh();\n    })\n    .catch(() => {\n      hideLoading();\n    });\n}\n\nfunction onRefresh() {\n  gridApi.query();\n}\n\nfunction onCreate() {\n  formDrawerApi.setData({}).open();\n}\n</script>\n<template>\n  <Page auto-content-height>\n    <FormDrawer @success=\"onRefresh\" />\n    <Grid :table-title=\"$t('system.role.list')\">\n      <template #toolbar-tools>\n        <Button type=\"primary\" @click=\"onCreate\">\n          <Plus class=\"size-5\" />\n          {{ $t('ui.actionTitle.create', [$t('system.role.name')]) }}\n        </Button>\n      </template>\n    </Grid>\n  </Page>\n</template>\n"
  },
  {
    "path": "hiauth-front/playground/src/views/system/role/modules/form.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DataNode } from 'ant-design-vue/es/tree';\n\nimport type { Recordable } from '@vben/types';\n\nimport type { SystemRoleApi } from '#/api/system/role';\n\nimport { computed, nextTick, ref } from 'vue';\n\nimport { Tree, useVbenDrawer } from '@vben/common-ui';\nimport { IconifyIcon } from '@vben/icons';\n\nimport { Spin } from 'ant-design-vue';\n\nimport { useVbenForm } from '#/adapter/form';\nimport { getMenuList } from '#/api/system/menu';\nimport { createRole, updateRole } from '#/api/system/role';\nimport { $t } from '#/locales';\n\nimport { useFormSchema } from '../data';\n\nconst emits = defineEmits(['success']);\n\nconst formData = ref<SystemRoleApi.SystemRole>();\n\nconst [Form, formApi] = useVbenForm({\n  schema: useFormSchema(),\n  showDefaultActions: false,\n});\n\nconst permissions = ref<DataNode[]>([]);\nconst loadingPermissions = ref(false);\n\nconst id = ref();\nconst [Drawer, drawerApi] = useVbenDrawer({\n  async onConfirm() {\n    const { valid } = await formApi.validate();\n    if (!valid) return;\n    const values = await formApi.getValues();\n    drawerApi.lock();\n    (id.value ? updateRole(id.value, values) : createRole(values))\n      .then(() => {\n        emits('success');\n        drawerApi.close();\n      })\n      .catch(() => {\n        drawerApi.unlock();\n      });\n  },\n\n  async onOpenChange(isOpen) {\n    if (isOpen) {\n      const data = drawerApi.getData<SystemRoleApi.SystemRole>();\n      formApi.resetForm();\n\n      if (data) {\n        formData.value = data;\n        id.value = data.id;\n      } else {\n        id.value = undefined;\n      }\n\n      if (permissions.value.length === 0) {\n        await loadPermissions();\n      }\n      // Wait for Vue to flush DOM updates (form fields mounted)\n      await nextTick();\n      if (data) {\n        formApi.setValues(data);\n      }\n    }\n  },\n});\n\nasync function loadPermissions() {\n  loadingPermissions.value = true;\n  try {\n    const res = await getMenuList();\n    permissions.value = res as unknown as DataNode[];\n  } finally {\n    loadingPermissions.value = false;\n  }\n}\n\nconst getDrawerTitle = computed(() => {\n  return formData.value?.id\n    ? $t('common.edit', $t('system.role.name'))\n    : $t('common.create', $t('system.role.name'));\n});\n\nfunction getNodeClass(node: Recordable<any>) {\n  const classes: string[] = [];\n  if (node.value?.type === 'button') {\n    classes.push('inline-flex');\n  }\n\n  return classes.join(' ');\n}\n</script>\n<template>\n  <Drawer :title=\"getDrawerTitle\">\n    <Form>\n      <template #permissions=\"slotProps\">\n        <Spin :spinning=\"loadingPermissions\" wrapper-class-name=\"w-full\">\n          <Tree\n            :tree-data=\"permissions\"\n            multiple\n            bordered\n            :default-expanded-level=\"2\"\n            :get-node-class=\"getNodeClass\"\n            v-bind=\"slotProps\"\n            value-field=\"id\"\n            label-field=\"meta.title\"\n            icon-field=\"meta.icon\"\n          >\n            <template #node=\"{ value }\">\n              <IconifyIcon v-if=\"value.meta.icon\" :icon=\"value.meta.icon\" />\n              {{ $t(value.meta.title) }}\n            </template>\n          </Tree>\n        </Spin>\n      </template>\n    </Form>\n  </Drawer>\n</template>\n<style lang=\"css\" scoped>\n:deep(.ant-tree-title) {\n  .tree-actions {\n    display: none;\n    margin-left: 20px;\n  }\n}\n\n:deep(.ant-tree-title:hover) {\n  .tree-actions {\n    display: flex;\n    flex: auto;\n    justify-content: flex-end;\n    margin-left: 20px;\n  }\n}\n</style>\n"
  },
  {
    "path": "hiauth-front/playground/tailwind.config.mjs",
    "content": "export { default } from '@vben/tailwind-config';\n"
  },
  {
    "path": "hiauth-front/playground/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/web-app.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"#/*\": [\"./src/*\"]\n    }\n  },\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }],\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"]\n}\n"
  },
  {
    "path": "hiauth-front/playground/tsconfig.node.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n    \"noEmit\": false\n  },\n  \"include\": [\"vite.config.mts\"]\n}\n"
  },
  {
    "path": "hiauth-front/playground/vite.config.mts",
    "content": "import { defineConfig } from '@vben/vite-config';\n\nexport default defineConfig(async () => {\n  return {\n    application: {},\n    vite: {\n      server: {\n        proxy: {\n          '/api': {\n            changeOrigin: true,\n            rewrite: (path) => path.replace(/^\\/api/, ''),\n            // mock代理目标地址\n            target: 'http://localhost:5320/api',\n            ws: true,\n          },\n        },\n      },\n    },\n  };\n});\n"
  },
  {
    "path": "hiauth-front/pnpm-workspace.yaml",
    "content": "packages:\n  - internal/*\n  - internal/lint-configs/*\n  - packages/*\n  - packages/@core/base/*\n  - packages/@core/ui-kit/*\n  - packages/@core/forward/*\n  - packages/@core/*\n  - packages/effects/*\n  - packages/business/*\n  - apps/*\n  - scripts/*\n  - docs\n  - playground\n\ncatalog:\n  '@ast-grep/napi': ^0.37.0\n  '@changesets/changelog-github': ^0.5.1\n  '@changesets/cli': ^2.29.5\n  '@changesets/git': ^3.0.4\n  '@clack/prompts': ^0.10.1\n  '@commitlint/cli': ^19.8.1\n  '@commitlint/config-conventional': ^19.8.1\n  '@ctrl/tinycolor': ^4.1.0\n  '@eslint/js': ^9.30.1\n  '@faker-js/faker': ^9.9.0\n  '@iconify/json': ^2.2.354\n  '@iconify/tailwind': ^1.2.0\n  '@iconify/vue': ^5.0.0\n  '@intlify/core-base': ^11.1.7\n  '@intlify/unplugin-vue-i18n': ^6.0.8\n  '@jspm/generator': ^2.6.2\n  '@manypkg/get-packages': ^3.0.0\n  '@nolebase/vitepress-plugin-git-changelog': ^2.18.0\n  '@playwright/test': ^1.53.2\n  '@pnpm/workspace.read-manifest': ^1000.2.0\n  '@stylistic/stylelint-plugin': ^3.1.3\n  '@tailwindcss/nesting': 0.0.0-insiders.565cd3e\n  '@tailwindcss/typography': ^0.5.16\n  '@tanstack/vue-query': ^5.81.5\n  '@tanstack/vue-store': ^0.7.1\n  '@types/archiver': ^6.0.3\n  '@types/eslint': ^9.6.1\n  '@types/html-minifier-terser': ^7.0.2\n  '@types/json-bigint': ^1.0.4\n  '@types/jsonwebtoken': ^9.0.10\n  '@types/lodash.clonedeep': ^4.5.9\n  '@types/lodash.get': ^4.4.9\n  '@types/lodash.isequal': ^4.5.8\n  '@types/lodash.set': ^4.3.9\n  '@types/node': ^22.16.0\n  '@types/nprogress': ^0.2.3\n  '@types/postcss-import': ^14.0.3\n  '@types/qrcode': ^1.5.5\n  '@types/qs': ^6.14.0\n  '@types/sortablejs': ^1.15.8\n  '@typescript-eslint/eslint-plugin': ^8.35.1\n  '@typescript-eslint/parser': ^8.35.1\n  '@vee-validate/zod': ^4.15.1\n  '@vite-pwa/vitepress': ^1.0.0\n  '@vitejs/plugin-vue': ^6.0.1\n  '@vitejs/plugin-vue-jsx': ^5.0.1\n  '@vue/reactivity': ^3.5.17\n  '@vue/shared': ^3.5.17\n  '@vue/test-utils': ^2.4.6\n  '@vueuse/core': ^13.4.0\n  '@vueuse/integrations': ^13.4.0\n  '@vueuse/motion': ^3.0.3\n  ant-design-vue: ^4.2.6\n  archiver: ^7.0.1\n  autoprefixer: ^10.4.21\n  axios: ^1.10.0\n  axios-mock-adapter: ^2.1.0\n  cac: ^6.7.14\n  chalk: ^5.4.1\n  cheerio: ^1.1.0\n  circular-dependency-scanner: ^2.3.0\n  class-variance-authority: ^0.7.1\n  clsx: ^2.1.1\n  commitlint-plugin-function-rules: ^4.0.2\n  consola: ^3.4.2\n  cross-env: ^7.0.3\n  cspell: ^8.19.4\n  cssnano: ^7.0.7\n  cz-git: ^1.11.2\n  czg: ^1.11.1\n  dayjs: ^1.11.13\n  defu: ^6.1.4\n  depcheck: ^1.4.7\n  dotenv: ^16.6.1\n  echarts: ^5.6.0\n  element-plus: ^2.10.2\n  eslint: ^9.30.1\n  eslint-config-turbo: ^2.5.4\n  eslint-plugin-command: ^3.3.1\n  eslint-plugin-eslint-comments: ^3.2.0\n  eslint-plugin-import-x: ^4.16.1\n  eslint-plugin-jsdoc: ^50.8.0\n  eslint-plugin-jsonc: ^2.20.1\n  eslint-plugin-n: ^17.20.0\n  eslint-plugin-no-only-tests: ^3.3.0\n  eslint-plugin-perfectionist: ^4.15.0\n  eslint-plugin-prettier: ^5.5.1\n  eslint-plugin-regexp: ^2.9.0\n  eslint-plugin-unicorn: ^59.0.1\n  eslint-plugin-unused-imports: ^4.1.4\n  eslint-plugin-vitest: ^0.5.4\n  eslint-plugin-vue: ^10.2.0\n  execa: ^9.6.0\n  find-up: ^7.0.0\n  get-port: ^7.1.0\n  globals: ^16.3.0\n  h3: ^1.15.3\n  happy-dom: ^17.6.3\n  html-minifier-terser: ^7.2.0\n  is-ci: ^4.1.0\n  json-bigint: ^1.0.0\n  jsonc-eslint-parser: ^2.4.0\n  jsonwebtoken: ^9.0.2\n  lefthook: ^1.11.14\n  lodash.clonedeep: ^4.5.0\n  lodash.get: ^4.4.2\n  lodash.isequal: ^4.5.0\n  lodash.set: ^4.3.2\n  lucide-vue-next: ^0.507.0\n  medium-zoom: ^1.1.0\n  naive-ui: ^2.42.0\n  nitropack: ^2.11.13\n  nprogress: ^0.2.0\n  ora: ^8.2.0\n  pinia: ^3.0.3\n  pinia-plugin-persistedstate: ^4.4.1\n  pkg-types: ^2.2.0\n  playwright: ^1.53.2\n  postcss: ^8.5.6\n  postcss-antd-fixes: ^0.2.0\n  postcss-html: ^1.8.0\n  postcss-import: ^16.1.1\n  postcss-preset-env: ^10.2.4\n  postcss-scss: ^4.0.9\n  prettier: ^3.6.2\n  prettier-plugin-tailwindcss: ^0.6.13\n  publint: ^0.3.12\n  qrcode: ^1.5.4\n  qs: ^6.14.0\n  radix-vue: ^1.9.17\n  resolve.exports: ^2.0.3\n  rimraf: ^6.0.1\n  rollup: ^4.44.1\n  rollup-plugin-visualizer: ^5.14.0\n  sass: ^1.89.2\n  secure-ls: ^2.0.0\n  sortablejs: ^1.15.6\n  stylelint: ^16.21.0\n  stylelint-config-recess-order: ^6.1.0\n  stylelint-config-recommended: ^16.0.0\n  stylelint-config-recommended-scss: ^14.1.0\n  stylelint-config-recommended-vue: ^1.6.1\n  stylelint-config-standard: ^38.0.0\n  stylelint-order: ^7.0.0\n  stylelint-prettier: ^5.0.3\n  stylelint-scss: ^6.12.1\n  tailwind-merge: ^2.6.0\n  tailwindcss: ^3.4.17\n  tailwindcss-animate: ^1.0.7\n  theme-colors: ^0.1.0\n  tippy.js: ^6.3.7\n  turbo: ^2.5.4\n  typescript: ^5.8.3\n  unbuild: ^3.6.1\n  unplugin-element-plus: ^0.10.0\n  vee-validate: ^4.15.1\n  vite: ^7.1.2\n  vite-plugin-compression: ^0.5.1\n  vite-plugin-dts: ^4.5.4\n  vite-plugin-html: ^3.2.2\n  vite-plugin-lazy-import: ^1.0.7\n  vite-plugin-pwa: ^1.0.1\n  vite-plugin-vue-devtools: ^7.7.7\n  vitepress: ^1.6.3\n  vitepress-plugin-group-icons: ^1.6.1\n  vitest: ^3.2.4\n  vue: ^3.5.17\n  vue-eslint-parser: ^10.2.0\n  vue-i18n: ^11.1.7\n  vue-json-viewer: ^3.0.4\n  vue-router: ^4.5.1\n  vue-tippy: ^6.7.1\n  vue-tsc: 2.2.10\n  vxe-pc-ui: ^4.9.29\n  vxe-table: ^4.16.11\n  watermark-js-plus: ^1.6.2\n  zod: ^3.25.67\n  zod-defaults: ^0.1.3\n"
  },
  {
    "path": "hiauth-front/scripts/clean.mjs",
    "content": "import { promises as fs } from 'node:fs';\nimport { join, normalize } from 'node:path';\n\nconst rootDir = process.cwd();\n\n// 控制并发数量，避免创建过多的并发任务\nconst CONCURRENCY_LIMIT = 10;\n\n// 需要跳过的目录，避免进入这些目录进行清理\nconst SKIP_DIRS = new Set(['.DS_Store', '.git', '.idea', '.vscode']);\n\n/**\n * 处理单个文件/目录项\n * @param {string} currentDir - 当前目录路径\n * @param {string} item - 文件/目录名\n * @param {string[]} targets - 要删除的目标列表\n * @param {number} _depth - 当前递归深度\n * @returns {Promise<boolean>} - 是否需要进一步递归处理\n */\nasync function processItem(currentDir, item, targets, _depth) {\n  // 跳过特殊目录\n  if (SKIP_DIRS.has(item)) {\n    return false;\n  }\n\n  try {\n    const itemPath = normalize(join(currentDir, item));\n\n    if (targets.includes(item)) {\n      // 匹配到目标目录或文件时直接删除\n      await fs.rm(itemPath, { force: true, recursive: true });\n      console.log(`✅ Deleted: ${itemPath}`);\n      return false; // 已删除，无需递归\n    }\n\n    // 使用 readdir 的 withFileTypes 选项，避免额外的 lstat 调用\n    return true; // 可能需要递归，由调用方决定\n  } catch (error) {\n    // 更详细的错误信息\n    if (error.code === 'ENOENT') {\n      // 文件不存在，可能已被删除，这是正常情况\n      return false;\n    } else if (error.code === 'EPERM' || error.code === 'EACCES') {\n      console.error(`❌ Permission denied: ${item} in ${currentDir}`);\n    } else {\n      console.error(\n        `❌ Error handling item ${item} in ${currentDir}: ${error.message}`,\n      );\n    }\n    return false;\n  }\n}\n\n/**\n * 递归查找并删除目标目录（并发优化版本）\n * @param {string} currentDir - 当前遍历的目录路径\n * @param {string[]} targets - 要删除的目标列表\n * @param {number} depth - 当前递归深度，避免过深递归\n */\nasync function cleanTargetsRecursively(currentDir, targets, depth = 0) {\n  // 限制递归深度，避免无限递归\n  if (depth > 10) {\n    console.warn(`Max recursion depth reached at: ${currentDir}`);\n    return;\n  }\n\n  let dirents;\n  try {\n    // 使用 withFileTypes 选项，一次性获取文件类型信息，避免后续 lstat 调用\n    dirents = await fs.readdir(currentDir, { withFileTypes: true });\n  } catch (error) {\n    // 如果无法读取目录，可能已被删除或权限不足\n    console.warn(`Cannot read directory ${currentDir}: ${error.message}`);\n    return;\n  }\n\n  // 分批处理，控制并发数量\n  for (let i = 0; i < dirents.length; i += CONCURRENCY_LIMIT) {\n    const batch = dirents.slice(i, i + CONCURRENCY_LIMIT);\n\n    const tasks = batch.map(async (dirent) => {\n      const item = dirent.name;\n      const shouldRecurse = await processItem(currentDir, item, targets, depth);\n\n      // 如果是目录且没有被删除，则递归处理\n      if (shouldRecurse && dirent.isDirectory()) {\n        const itemPath = normalize(join(currentDir, item));\n        return cleanTargetsRecursively(itemPath, targets, depth + 1);\n      }\n\n      return null;\n    });\n\n    // 并发执行当前批次的任务\n    const results = await Promise.allSettled(tasks);\n\n    // 检查是否有失败的任务（可选：用于调试）\n    const failedTasks = results.filter(\n      (result) => result.status === 'rejected',\n    );\n    if (failedTasks.length > 0) {\n      console.warn(\n        `${failedTasks.length} tasks failed in batch starting at index ${i} in directory: ${currentDir}`,\n      );\n    }\n  }\n}\n\n(async function startCleanup() {\n  // 要删除的目录及文件名称\n  const targets = ['node_modules', 'dist', '.turbo', 'dist.zip'];\n  const deleteLockFile = process.argv.includes('--del-lock');\n  const cleanupTargets = [...targets];\n\n  if (deleteLockFile) {\n    cleanupTargets.push('pnpm-lock.yaml');\n  }\n\n  console.log(\n    `🚀 Starting cleanup of targets: ${cleanupTargets.join(', ')} from root: ${rootDir}`,\n  );\n\n  const startTime = Date.now();\n\n  try {\n    // 先统计要删除的目标数量\n    console.log('📊 Scanning for cleanup targets...');\n\n    await cleanTargetsRecursively(rootDir, cleanupTargets);\n\n    const endTime = Date.now();\n    const duration = (endTime - startTime) / 1000;\n\n    console.log(\n      `✨ Cleanup process completed successfully in ${duration.toFixed(2)}s`,\n    );\n  } catch (error) {\n    console.error(`💥 Unexpected error during cleanup: ${error.message}`);\n    process.exit(1);\n  }\n})();\n"
  },
  {
    "path": "hiauth-front/scripts/deploy/Dockerfile",
    "content": "FROM node:22-slim AS builder\n\n# --max-old-space-size\nENV PNPM_HOME=\"/pnpm\"\nENV PATH=\"$PNPM_HOME:$PATH\"\nENV NODE_OPTIONS=--max-old-space-size=8192\nENV TZ=Asia/Shanghai\n\nRUN npm i -g corepack\n\nWORKDIR /app\n\n# copy package.json and pnpm-lock.yaml to workspace\nCOPY . /app\n\n# 安装依赖\nRUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile\nRUN pnpm run build --filter=\\!./docs\n\nRUN echo \"Builder Success 🎉\"\n\nFROM nginx:stable-alpine AS production\n\n# 配置 nginx\nRUN echo \"types { application/javascript js mjs; }\" > /etc/nginx/conf.d/mjs.conf \\\n    && rm -rf /etc/nginx/conf.d/default.conf\n\n# 复制构建产物\nCOPY --from=builder /app/playground/dist /usr/share/nginx/html\n\n# 复制 nginx 配置\nCOPY --from=builder /app/scripts/deploy/nginx.conf /etc/nginx/nginx.conf\n\nEXPOSE 8080\n\n# 启动 nginx\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n"
  },
  {
    "path": "hiauth-front/scripts/deploy/build-local-docker-image.sh",
    "content": "#!/bin/bash\n\nSCRIPT_DIR=$( cd -- \"$( dirname -- \"${BASH_SOURCE[0]}\" )\" &> /dev/null && pwd )\nLOG_FILE=${SCRIPT_DIR}/build-local-docker-image.log\nERROR=\"\"\nIMAGE_NAME=\"vben-admin-local\"\n\nfunction stop_and_remove_container() {\n    # Stop and remove the existing container\n    docker stop ${IMAGE_NAME} >/dev/null 2>&1\n    docker rm ${IMAGE_NAME} >/dev/null 2>&1\n}\n\nfunction remove_image() {\n    # Remove the existing image\n    docker rmi vben-admin-pro >/dev/null 2>&1\n}\n\nfunction install_dependencies() {\n    # Install all dependencies\n    cd ${SCRIPT_DIR}\n    pnpm install || ERROR=\"install_dependencies failed\"\n}\n\nfunction build_image() {\n    # build docker\n    docker build ../../ -f Dockerfile -t ${IMAGE_NAME} || ERROR=\"build_image failed\"\n}\n\nfunction log_message() {\n    if [[ ${ERROR} != \"\" ]];\n    then\n        >&2 echo \"build failed, Please check build-local-docker-image.log for more details\"\n        >&2 echo \"ERROR: ${ERROR}\"\n        exit 1\n    else\n        echo \"docker image with tag '${IMAGE_NAME}' built sussessfully. Use below sample command to run the container\"\n        echo \"\"\n        echo \"docker run -d -p 8010:8080 --name ${IMAGE_NAME} ${IMAGE_NAME}\"\n    fi\n}\n\necho \"Info: Stopping and removing existing container and image\" | tee ${LOG_FILE}\nstop_and_remove_container\nremove_image\n\necho \"Info: Installing dependencies\" | tee -a ${LOG_FILE}\ninstall_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE}\n\nif [[ ${ERROR} == \"\" ]]; then\n    echo \"Info: Building docker image\" | tee -a ${LOG_FILE}\n    build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE}\nfi\n\nlog_message | tee -a ${LOG_FILE}\n"
  },
  {
    "path": "hiauth-front/scripts/deploy/nginx.conf",
    "content": "\n#user  nobody;\nworker_processes 1;\n\n#error_log  logs/error.log;\n#error_log  logs/error.log  notice;\n#error_log  logs/error.log  info;\n\n#pid        logs/nginx.pid;\n\n\nevents {\n  worker_connections 1024;\n}\n\n\nhttp {\n  include mime.types;\n  default_type application/octet-stream;\n\n  types {\n    application/javascript  js mjs;\n    text/css                css;\n    text/html               html;\n  }\n\n  sendfile on;\n  # tcp_nopush     on;\n\n  #keepalive_timeout  0;\n  # keepalive_timeout 65;\n\n  # gzip on;\n  # gzip_buffers 32 16k;\n  # gzip_comp_level 6;\n  # gzip_min_length 1k;\n  # gzip_static on;\n  # gzip_types text/plain\n  #   text/css\n  #   application/javascript\n  #   application/json\n  #   application/x-javascript\n  #   text/xml\n  #   application/xml\n  #   application/xml+rss\n  #   text/javascript; #设置压缩的文件类型\n  # gzip_vary on;\n\n  server {\n    listen 8080;\n    server_name localhost;\n\n    location / {\n      root /usr/share/nginx/html;\n      try_files $uri $uri/ /index.html;\n      index index.html;\n      # Enable CORS\n      add_header 'Access-Control-Allow-Origin' '*';\n      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';\n      add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';\n      if ($request_method = 'OPTIONS') {\n        add_header 'Access-Control-Max-Age' 1728000;\n        add_header 'Content-Type' 'text/plain charset=UTF-8';\n        add_header 'Content-Length' 0;\n        return 204;\n      }\n    }\n\n    error_page 500 502 503 504 /50x.html;\n\n    location = /50x.html {\n        root /usr/share/nginx/html;\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/scripts/turbo-run/README.md",
    "content": "# @vben/turbo-run\n\n`turbo-run` 是一个命令行工具，允许你在多个包中并行运行命令。它提供了一个交互式的界面，让你可以选择要运行命令的包。\n\n## 特性\n\n- 🚀 交互式选择要运行的包\n- 📦 支持 monorepo 项目结构\n- 🔍 自动检测可用的命令\n- 🎯 精确过滤目标包\n\n## 安装\n\n```bash\npnpm add -D @vben/turbo-run\n```\n\n## 使用方法\n\n基本语法：\n\n```bash\nturbo-run [script]\n```\n\n例如，如果你想运行 `dev` 命令：\n\n```bash\nturbo-run dev\n```\n\n工具会自动检测哪些包有 `dev` 命令，并提供一个交互式界面让你选择要运行的包。\n\n## 示例\n\n假设你的项目中有以下包：\n\n- `@vben/app`\n- `@vben/admin`\n- `@vben/website`\n\n当你运行：\n\n```bash\nturbo-run dev\n```\n\n工具会：\n\n1. 检测哪些包有 `dev` 命令\n2. 显示一个交互式选择界面\n3. 让你选择要运行命令的包\n4. 使用 `pnpm --filter` 在选定的包中运行命令\n\n## 注意事项\n\n- 确保你的项目使用 pnpm 作为包管理器\n- 确保目标包在 `package.json` 中定义了相应的脚本命令\n- 该工具需要在 monorepo 项目的根目录下运行\n"
  },
  {
    "path": "hiauth-front/scripts/turbo-run/bin/turbo-run.mjs",
    "content": "#!/usr/bin/env node\n\nimport('../dist/index.mjs');\n"
  },
  {
    "path": "hiauth-front/scripts/turbo-run/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/scripts/turbo-run/package.json",
    "content": "{\n  \"name\": \"@vben/turbo-run\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"stub\": \"pnpm unbuild --stub\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"bin\": {\n    \"turbo-run\": \"./bin/turbo-run.mjs\"\n  },\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"default\": \"./dist/index.mjs\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"dependencies\": {\n    \"@clack/prompts\": \"catalog:\",\n    \"@vben/node-utils\": \"workspace:*\",\n    \"cac\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/scripts/turbo-run/src/index.ts",
    "content": "import { colors, consola } from '@vben/node-utils';\n\nimport { cac } from 'cac';\n\nimport { run } from './run';\n\ntry {\n  const turboRun = cac('turbo-run');\n\n  turboRun\n    .command('[script]')\n    .usage(`Run turbo interactively.`)\n    .action(async (command: string) => {\n      run({ command });\n    });\n\n  // Invalid command\n  turboRun.on('command:*', () => {\n    consola.error(colors.red('Invalid command!'));\n    process.exit(1);\n  });\n\n  turboRun.usage('turbo-run');\n  turboRun.help();\n  turboRun.parse();\n} catch (error) {\n  consola.error(error);\n  process.exit(1);\n}\n"
  },
  {
    "path": "hiauth-front/scripts/turbo-run/src/run.ts",
    "content": "import { execaCommand, getPackages } from '@vben/node-utils';\n\nimport { cancel, isCancel, select } from '@clack/prompts';\n\ninterface RunOptions {\n  command?: string;\n}\n\nexport async function run(options: RunOptions) {\n  const { command } = options;\n  if (!command) {\n    console.error('Please enter the command to run');\n    process.exit(1);\n  }\n  const { packages } = await getPackages();\n  // const appPkgs = await findApps(process.cwd(), packages);\n  // const websitePkg = packages.find(\n  //   (item) => item.packageJson.name === '@vben/website',\n  // );\n\n  // 只显示有对应命令的包\n  const selectPkgs = packages.filter((pkg) => {\n    return (pkg?.packageJson as Record<string, any>)?.scripts?.[command];\n  });\n\n  let selectPkg: string | symbol;\n  if (selectPkgs.length > 1) {\n    selectPkg = await select<string>({\n      message: `Select the app you need to run [${command}]:`,\n      options: selectPkgs.map((item) => ({\n        label: item?.packageJson.name,\n        value: item?.packageJson.name,\n      })),\n    });\n\n    if (isCancel(selectPkg) || !selectPkg) {\n      cancel('👋 Has cancelled');\n      process.exit(0);\n    }\n  } else {\n    selectPkg = selectPkgs[0]?.packageJson?.name ?? '';\n  }\n\n  if (!selectPkg) {\n    console.error('No app found');\n    process.exit(1);\n  }\n\n  execaCommand(`pnpm --filter=${selectPkg} run ${command}`, {\n    stdio: 'inherit',\n  });\n}\n\n/**\n * 过滤app包\n * @param root\n * @param packages\n */\n// async function findApps(root: string, packages: Package[]) {\n//   // apps内的\n//   const appPackages = packages.filter((pkg) => {\n//     const viteConfigExists = fs.existsSync(join(pkg.dir, 'vite.config.mts'));\n//     return pkg.dir.startsWith(join(root, 'apps')) && viteConfigExists;\n//   });\n\n//   return appPackages;\n// }\n"
  },
  {
    "path": "hiauth-front/scripts/turbo-run/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/README.md",
    "content": "# @vben/vsh\n\n一个 Shell 脚本工具集合，用于 Vue Vben Admin 项目的开发和管理。\n\n## 功能特性\n\n- 🚀 基于 Node.js 的现代化 Shell 工具\n- 📦 支持模块化开发和按需加载\n- 🔍 提供依赖检查和分析功能\n- 🔄 支持循环依赖扫描\n- 📝 提供包发布检查功能\n\n## 安装\n\n```bash\n# 使用 pnpm 安装\npnpm add -D @vben/vsh\n\n# 或者使用 npm\nnpm install -D @vben/vsh\n\n# 或者使用 yarn\nyarn add -D @vben/vsh\n```\n\n## 使用方法\n\n### 全局安装\n\n```bash\n# 全局安装\npnpm add -g @vben/vsh\n\n# 使用 vsh 命令\nvsh [command]\n```\n\n### 本地使用\n\n```bash\n# 在 package.json 中添加脚本\n{\n  \"scripts\": {\n    \"vsh\": \"vsh\"\n  }\n}\n\n# 运行命令\npnpm vsh [command]\n```\n\n## 命令列表\n\n- `vsh check-deps`: 检查项目依赖\n- `vsh scan-circular`: 扫描循环依赖\n- `vsh publish-check`: 检查包发布配置\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/bin/vsh.mjs",
    "content": "#!/usr/bin/env node\n\nimport('../dist/index.mjs');\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n  clean: true,\n  declaration: true,\n  entries: ['src/index'],\n});\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/package.json",
    "content": "{\n  \"name\": \"@vben/vsh\",\n  \"version\": \"5.5.9\",\n  \"private\": true,\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"stub\": \"pnpm unbuild --stub\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"bin\": {\n    \"vsh\": \"./bin/vsh.mjs\"\n  },\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"default\": \"./dist/index.mjs\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"dependencies\": {\n    \"@vben/node-utils\": \"workspace:*\",\n    \"cac\": \"catalog:\",\n    \"circular-dependency-scanner\": \"catalog:\",\n    \"depcheck\": \"catalog:\",\n    \"publint\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/src/check-circular/index.ts",
    "content": "import type { CAC } from 'cac';\n\nimport { extname } from 'node:path';\n\nimport { getStagedFiles } from '@vben/node-utils';\n\nimport { circularDepsDetect } from 'circular-dependency-scanner';\n\n// 默认配置\nconst DEFAULT_CONFIG = {\n  allowedExtensions: ['.cjs', '.js', '.jsx', '.mjs', '.ts', '.tsx', '.vue'],\n  ignoreDirs: [\n    'dist',\n    '.turbo',\n    'output',\n    '.cache',\n    'scripts',\n    'internal',\n    'packages/effects/request/src/',\n    'packages/@core/ui-kit/menu-ui/src/',\n    'packages/@core/ui-kit/popup-ui/src/',\n  ],\n  threshold: 0, // 循环依赖的阈值\n} as const;\n\n// 类型定义\ntype CircularDependencyResult = string[];\n\ninterface CheckCircularConfig {\n  allowedExtensions?: string[];\n  ignoreDirs?: string[];\n  threshold?: number;\n}\n\ninterface CommandOptions {\n  config?: CheckCircularConfig;\n  staged: boolean;\n  verbose: boolean;\n}\n\n// 缓存机制\nconst cache = new Map<string, CircularDependencyResult[]>();\n\n/**\n * 格式化循环依赖的输出\n * @param circles - 循环依赖结果\n */\nfunction formatCircles(circles: CircularDependencyResult[]): void {\n  if (circles.length === 0) {\n    console.log('✅ No circular dependencies found');\n    return;\n  }\n\n  console.log('⚠️ Circular dependencies found:');\n  circles.forEach((circle, index) => {\n    console.log(`\\nCircular dependency #${index + 1}:`);\n    circle.forEach((file) => console.log(`  → ${file}`));\n  });\n}\n\n/**\n * 检查项目中的循环依赖\n * @param options - 检查选项\n * @param options.staged - 是否只检查暂存区文件\n * @param options.verbose - 是否显示详细信息\n * @param options.config - 自定义配置\n * @returns Promise<void>\n */\nasync function checkCircular({\n  config = {},\n  staged,\n  verbose,\n}: CommandOptions): Promise<void> {\n  try {\n    // 合并配置\n    const finalConfig = {\n      ...DEFAULT_CONFIG,\n      ...config,\n    };\n\n    // 生成忽略模式\n    const ignorePattern = `**/{${finalConfig.ignoreDirs.join(',')}}/**`;\n\n    // 检查缓存\n    const cacheKey = `${staged}-${process.cwd()}-${ignorePattern}`;\n    if (cache.has(cacheKey)) {\n      const cachedResults = cache.get(cacheKey);\n      if (cachedResults) {\n        verbose && formatCircles(cachedResults);\n      }\n      return;\n    }\n\n    // 检测循环依赖\n    const results = await circularDepsDetect({\n      absolute: staged,\n      cwd: process.cwd(),\n      ignore: [ignorePattern],\n    });\n\n    if (staged) {\n      let files = await getStagedFiles();\n      const allowedExtensions = new Set(finalConfig.allowedExtensions);\n\n      // 过滤文件列表\n      files = files.filter((file) => allowedExtensions.has(extname(file)));\n\n      const circularFiles: CircularDependencyResult[] = [];\n\n      for (const file of files) {\n        for (const result of results) {\n          const resultFiles = result.flat();\n          if (resultFiles.includes(file)) {\n            circularFiles.push(result);\n          }\n        }\n      }\n\n      // 更新缓存\n      cache.set(cacheKey, circularFiles);\n      verbose && formatCircles(circularFiles);\n    } else {\n      // 更新缓存\n      cache.set(cacheKey, results);\n      verbose && formatCircles(results);\n    }\n\n    // 如果发现循环依赖，只输出警告信息\n    if (results.length > 0) {\n      console.log(\n        '\\n⚠️ Warning: Circular dependencies found, please check and fix',\n      );\n    }\n  } catch (error) {\n    console.error(\n      '❌ Error checking circular dependencies:',\n      error instanceof Error ? error.message : error,\n    );\n  }\n}\n\n/**\n * 定义检查循环依赖的命令\n * @param cac - CAC实例\n */\nfunction defineCheckCircularCommand(cac: CAC): void {\n  cac\n    .command('check-circular')\n    .option('--staged', 'Only check staged files')\n    .option('--verbose', 'Show detailed information')\n    .option('--threshold <number>', 'Threshold for circular dependencies', {\n      default: 0,\n    })\n    .option('--ignore-dirs <dirs>', 'Directories to ignore, comma separated')\n    .usage('Analyze project circular dependencies')\n    .action(async ({ ignoreDirs, staged, threshold, verbose }) => {\n      const config: CheckCircularConfig = {\n        threshold: Number(threshold),\n        ...(ignoreDirs && { ignoreDirs: ignoreDirs.split(',') }),\n      };\n\n      await checkCircular({\n        config,\n        staged,\n        verbose: verbose ?? true,\n      });\n    });\n}\n\nexport { type CheckCircularConfig, defineCheckCircularCommand };\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/src/check-dep/index.ts",
    "content": "import type { CAC } from 'cac';\n\nimport { getPackages } from '@vben/node-utils';\n\nimport depcheck from 'depcheck';\n\n// 默认配置\nconst DEFAULT_CONFIG = {\n  // 需要忽略的依赖匹配\n  ignoreMatches: [\n    'vite',\n    'vitest',\n    'unbuild',\n    '@vben/tsconfig',\n    '@vben/vite-config',\n    '@vben/tailwind-config',\n    '@types/*',\n    '@vben-core/design',\n  ],\n  // 需要忽略的包\n  ignorePackages: [\n    '@vben/backend-mock',\n    '@vben/commitlint-config',\n    '@vben/eslint-config',\n    '@vben/node-utils',\n    '@vben/prettier-config',\n    '@vben/stylelint-config',\n    '@vben/tailwind-config',\n    '@vben/tsconfig',\n    '@vben/vite-config',\n    '@vben/vsh',\n  ],\n  // 需要忽略的文件模式\n  ignorePatterns: ['dist', 'node_modules', 'public'],\n};\n\ninterface DepcheckResult {\n  dependencies: string[];\n  devDependencies: string[];\n  missing: Record<string, string[]>;\n}\n\ninterface DepcheckConfig {\n  ignoreMatches?: string[];\n  ignorePackages?: string[];\n  ignorePatterns?: string[];\n}\n\ninterface PackageInfo {\n  dir: string;\n  packageJson: {\n    name: string;\n  };\n}\n\n/**\n * 清理依赖检查结果\n * @param unused - 依赖检查结果\n */\nfunction cleanDepcheckResult(unused: DepcheckResult): void {\n  // 删除file:前缀的依赖提示，该依赖是本地依赖\n  Reflect.deleteProperty(unused.missing, 'file:');\n\n  // 清理路径依赖\n  Object.keys(unused.missing).forEach((key) => {\n    unused.missing[key] = (unused.missing[key] || []).filter(\n      (item: string) => !item.startsWith('/'),\n    );\n    if (unused.missing[key].length === 0) {\n      Reflect.deleteProperty(unused.missing, key);\n    }\n  });\n}\n\n/**\n * 格式化依赖检查结果\n * @param pkgName - 包名\n * @param unused - 依赖检查结果\n */\nfunction formatDepcheckResult(pkgName: string, unused: DepcheckResult): void {\n  const hasIssues =\n    Object.keys(unused.missing).length > 0 ||\n    unused.dependencies.length > 0 ||\n    unused.devDependencies.length > 0;\n\n  if (!hasIssues) {\n    return;\n  }\n\n  console.log('\\n📦 Package:', pkgName);\n\n  if (Object.keys(unused.missing).length > 0) {\n    console.log('❌ Missing dependencies:');\n    Object.entries(unused.missing).forEach(([dep, files]) => {\n      console.log(`  - ${dep}:`);\n      files.forEach((file) => console.log(`    → ${file}`));\n    });\n  }\n\n  if (unused.dependencies.length > 0) {\n    console.log('⚠️ Unused dependencies:');\n    unused.dependencies.forEach((dep) => console.log(`  - ${dep}`));\n  }\n\n  if (unused.devDependencies.length > 0) {\n    console.log('⚠️ Unused devDependencies:');\n    unused.devDependencies.forEach((dep) => console.log(`  - ${dep}`));\n  }\n}\n\n/**\n * 运行依赖检查\n * @param config - 配置选项\n */\nasync function runDepcheck(config: DepcheckConfig = {}): Promise<void> {\n  try {\n    const finalConfig = {\n      ...DEFAULT_CONFIG,\n      ...config,\n    };\n\n    const { packages } = await getPackages();\n\n    let hasIssues = false;\n\n    await Promise.all(\n      packages.map(async (pkg: PackageInfo) => {\n        // 跳过需要忽略的包\n        if (finalConfig.ignorePackages.includes(pkg.packageJson.name)) {\n          return;\n        }\n\n        const unused = await depcheck(pkg.dir, {\n          ignoreMatches: finalConfig.ignoreMatches,\n          ignorePatterns: finalConfig.ignorePatterns,\n        });\n\n        cleanDepcheckResult(unused);\n\n        const pkgHasIssues =\n          Object.keys(unused.missing).length > 0 ||\n          unused.dependencies.length > 0 ||\n          unused.devDependencies.length > 0;\n\n        if (pkgHasIssues) {\n          hasIssues = true;\n          formatDepcheckResult(pkg.packageJson.name, unused);\n        }\n      }),\n    );\n\n    if (!hasIssues) {\n      console.log('\\n✅ Dependency check completed, no issues found');\n    }\n  } catch (error) {\n    console.error(\n      '❌ Dependency check failed:',\n      error instanceof Error ? error.message : error,\n    );\n  }\n}\n\n/**\n * 定义依赖检查命令\n * @param cac - CAC实例\n */\nfunction defineDepcheckCommand(cac: CAC): void {\n  cac\n    .command('check-dep')\n    .option(\n      '--ignore-packages <packages>',\n      'Packages to ignore, comma separated',\n    )\n    .option(\n      '--ignore-matches <matches>',\n      'Dependency patterns to ignore, comma separated',\n    )\n    .option(\n      '--ignore-patterns <patterns>',\n      'File patterns to ignore, comma separated',\n    )\n    .usage('Analyze project dependencies')\n    .action(async ({ ignoreMatches, ignorePackages, ignorePatterns }) => {\n      const config: DepcheckConfig = {\n        ...(ignorePackages && { ignorePackages: ignorePackages.split(',') }),\n        ...(ignoreMatches && { ignoreMatches: ignoreMatches.split(',') }),\n        ...(ignorePatterns && { ignorePatterns: ignorePatterns.split(',') }),\n      };\n\n      await runDepcheck(config);\n    });\n}\n\nexport { defineDepcheckCommand, type DepcheckConfig };\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/src/code-workspace/index.ts",
    "content": "import type { CAC } from 'cac';\n\nimport { join, relative } from 'node:path';\n\nimport {\n  colors,\n  consola,\n  findMonorepoRoot,\n  getPackages,\n  gitAdd,\n  outputJSON,\n  prettierFormat,\n  toPosixPath,\n} from '@vben/node-utils';\n\nconst CODE_WORKSPACE_FILE = join('vben-admin.code-workspace');\n\ninterface CodeWorkspaceCommandOptions {\n  autoCommit?: boolean;\n  spaces?: number;\n}\n\nasync function createCodeWorkspace({\n  autoCommit = false,\n  spaces = 2,\n}: CodeWorkspaceCommandOptions) {\n  const { packages, rootDir } = await getPackages();\n\n  let folders = packages.map((pkg) => {\n    const { dir, packageJson } = pkg;\n    return {\n      name: packageJson.name,\n      path: toPosixPath(relative(rootDir, dir)),\n    };\n  });\n\n  folders = folders.filter(Boolean);\n\n  const monorepoRoot = findMonorepoRoot();\n  const outputPath = join(monorepoRoot, CODE_WORKSPACE_FILE);\n  await outputJSON(outputPath, { folders }, spaces);\n\n  await prettierFormat(outputPath);\n  if (autoCommit) {\n    await gitAdd(CODE_WORKSPACE_FILE, monorepoRoot);\n  }\n}\n\nasync function runCodeWorkspace({\n  autoCommit,\n  spaces,\n}: CodeWorkspaceCommandOptions) {\n  await createCodeWorkspace({\n    autoCommit,\n    spaces,\n  });\n  if (autoCommit) {\n    return;\n  }\n  consola.log('');\n  consola.success(colors.green(`${CODE_WORKSPACE_FILE} is updated!`));\n  consola.log('');\n}\n\nfunction defineCodeWorkspaceCommand(cac: CAC) {\n  cac\n    .command('code-workspace')\n    .usage('Update the `.code-workspace` file')\n    .option('--spaces [number]', '.code-workspace JSON file spaces.', {\n      default: 2,\n    })\n    .option('--auto-commit', 'auto commit .code-workspace JSON file.', {\n      default: false,\n    })\n    .action(runCodeWorkspace);\n}\n\nexport { defineCodeWorkspaceCommand };\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/src/index.ts",
    "content": "import { colors, consola } from '@vben/node-utils';\n\nimport { cac } from 'cac';\n\nimport { version } from '../package.json';\nimport { defineCheckCircularCommand } from './check-circular';\nimport { defineDepcheckCommand } from './check-dep';\nimport { defineCodeWorkspaceCommand } from './code-workspace';\nimport { defineLintCommand } from './lint';\nimport { definePubLintCommand } from './publint';\n\n// 命令描述\nconst COMMAND_DESCRIPTIONS = {\n  'check-circular': 'Check for circular dependencies',\n  'check-dep': 'Check for unused dependencies',\n  'code-workspace': 'Manage VS Code workspace settings',\n  lint: 'Run linting on the project',\n  publint: 'Check package.json files for publishing standards',\n} as const;\n\n/**\n * Initialize and run the CLI\n */\nasync function main(): Promise<void> {\n  try {\n    const vsh = cac('vsh');\n\n    // Register commands\n    defineLintCommand(vsh);\n    definePubLintCommand(vsh);\n    defineCodeWorkspaceCommand(vsh);\n    defineCheckCircularCommand(vsh);\n    defineDepcheckCommand(vsh);\n\n    // Handle invalid commands\n    vsh.on('command:*', ([cmd]) => {\n      consola.error(\n        colors.red(`Invalid command: ${cmd}`),\n        '\\n',\n        colors.yellow('Available commands:'),\n        '\\n',\n        Object.entries(COMMAND_DESCRIPTIONS)\n          .map(([cmd, desc]) => `  ${colors.cyan(cmd)} - ${desc}`)\n          .join('\\n'),\n      );\n      process.exit(1);\n    });\n\n    // Set up CLI\n    vsh.usage('vsh <command> [options]');\n    vsh.help();\n    vsh.version(version);\n\n    // Parse arguments\n    vsh.parse();\n  } catch (error) {\n    consola.error(\n      colors.red('An unexpected error occurred:'),\n      '\\n',\n      error instanceof Error ? error.message : error,\n    );\n    process.exit(1);\n  }\n}\n\n// Run the CLI\nmain().catch((error) => {\n  consola.error(\n    colors.red('Failed to start CLI:'),\n    '\\n',\n    error instanceof Error ? error.message : error,\n  );\n  process.exit(1);\n});\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/src/lint/index.ts",
    "content": "import type { CAC } from 'cac';\n\nimport { execaCommand } from '@vben/node-utils';\n\ninterface LintCommandOptions {\n  /**\n   * Format lint problem.\n   */\n  format?: boolean;\n}\n\nasync function runLint({ format }: LintCommandOptions) {\n  // process.env.FORCE_COLOR = '3';\n\n  if (format) {\n    await execaCommand(`stylelint \"**/*.{vue,css,less,scss}\" --cache --fix`, {\n      stdio: 'inherit',\n    });\n    await execaCommand(`eslint . --cache --fix`, {\n      stdio: 'inherit',\n    });\n    await execaCommand(`prettier . --write --cache --log-level warn`, {\n      stdio: 'inherit',\n    });\n    return;\n  }\n  await Promise.all([\n    execaCommand(`eslint . --cache`, {\n      stdio: 'inherit',\n    }),\n    execaCommand(`prettier . --ignore-unknown --check --cache`, {\n      stdio: 'inherit',\n    }),\n    execaCommand(`stylelint \"**/*.{vue,css,less,scss}\" --cache`, {\n      stdio: 'inherit',\n    }),\n  ]);\n}\n\nfunction defineLintCommand(cac: CAC) {\n  cac\n    .command('lint')\n    .usage('Batch execute project lint check.')\n    .option('--format', 'Format lint problem.')\n    .action(runLint);\n}\n\nexport { defineLintCommand };\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/src/publint/index.ts",
    "content": "import type { CAC } from 'cac';\nimport type { Result } from 'publint';\n\nimport { basename, dirname, join } from 'node:path';\n\nimport {\n  colors,\n  consola,\n  ensureFile,\n  findMonorepoRoot,\n  generatorContentHash,\n  getPackages,\n  outputJSON,\n  readJSON,\n  UNICODE,\n} from '@vben/node-utils';\n\nimport { publint } from 'publint';\nimport { formatMessage } from 'publint/utils';\n\nconst CACHE_FILE = join(\n  'node_modules',\n  '.cache',\n  'publint',\n  '.pkglintcache.json',\n);\n\ninterface PubLintCommandOptions {\n  /**\n   * Only errors are checked, no program exit is performed\n   */\n  check?: boolean;\n}\n\n/**\n * Get files that require lint\n * @param files\n */\nasync function getLintFiles(files: string[] = []) {\n  const lintFiles: string[] = [];\n\n  if (files?.length > 0) {\n    return files.filter((file) => basename(file) === 'package.json');\n  }\n\n  const { packages } = await getPackages();\n\n  for (const { dir } of packages) {\n    lintFiles.push(join(dir, 'package.json'));\n  }\n  return lintFiles;\n}\n\nfunction getCacheFile() {\n  const root = findMonorepoRoot();\n  return join(root, CACHE_FILE);\n}\n\nasync function readCache(cacheFile: string) {\n  try {\n    await ensureFile(cacheFile);\n    return await readJSON(cacheFile);\n  } catch {\n    return {};\n  }\n}\n\nasync function runPublint(files: string[], { check }: PubLintCommandOptions) {\n  const lintFiles = await getLintFiles(files);\n  const cacheFile = getCacheFile();\n\n  const cacheData = await readCache(cacheFile);\n  const cache: Record<string, { hash: string; result: Result }> = cacheData;\n\n  const results = await Promise.all(\n    lintFiles.map(async (file) => {\n      try {\n        const pkgJson = await readJSON(file);\n\n        if (pkgJson.private) {\n          return null;\n        }\n\n        Reflect.deleteProperty(pkgJson, 'dependencies');\n        Reflect.deleteProperty(pkgJson, 'devDependencies');\n        Reflect.deleteProperty(pkgJson, 'peerDependencies');\n        const content = JSON.stringify(pkgJson);\n        const hash = generatorContentHash(content);\n\n        const publintResult: Result =\n          cache?.[file]?.hash === hash\n            ? (cache?.[file]?.result ?? [])\n            : await publint({\n                level: 'suggestion',\n                pkgDir: dirname(file),\n                strict: true,\n              });\n\n        cache[file] = {\n          hash,\n          result: publintResult,\n        };\n\n        return { pkgJson, pkgPath: file, publintResult };\n      } catch {\n        return null;\n      }\n    }),\n  );\n\n  await outputJSON(cacheFile, cache);\n  printResult(results, check);\n}\n\nfunction printResult(\n  results: Array<null | {\n    pkgJson: Record<string, number | string>;\n    pkgPath: string;\n    publintResult: Result;\n  }>,\n  check?: boolean,\n) {\n  let errorCount = 0;\n  let warningCount = 0;\n  let suggestionsCount = 0;\n\n  for (const result of results) {\n    if (!result) {\n      continue;\n    }\n    const { pkgJson, pkgPath, publintResult } = result;\n    const messages = publintResult?.messages ?? [];\n    if (messages?.length < 1) {\n      continue;\n    }\n\n    consola.log('');\n    consola.log(pkgPath);\n    for (const message of messages) {\n      switch (message.type) {\n        case 'error': {\n          errorCount++;\n\n          break;\n        }\n        case 'suggestion': {\n          suggestionsCount++;\n          break;\n        }\n        case 'warning': {\n          warningCount++;\n\n          break;\n        }\n        // No default\n      }\n      const ruleUrl = `https://publint.dev/rules#${message.code.toLocaleLowerCase()}`;\n      consola.log(\n        `  ${formatMessage(message, pkgJson)}${colors.dim(` ${ruleUrl}`)}`,\n      );\n    }\n  }\n\n  const totalCount = warningCount + errorCount + suggestionsCount;\n  if (totalCount > 0) {\n    consola.error(\n      colors.red(\n        `${UNICODE.FAILURE} ${totalCount} problem (${errorCount} errors, ${warningCount} warnings, ${suggestionsCount} suggestions)`,\n      ),\n    );\n    !check && process.exit(1);\n  } else {\n    consola.log(colors.green(`${UNICODE.SUCCESS} No problem`));\n  }\n}\n\nfunction definePubLintCommand(cac: CAC) {\n  cac\n    .command('publint [...files]')\n    .usage('Check if the monorepo package conforms to the publint standard.')\n    .option('--check', 'Only errors are checked, no program exit is performed.')\n    .action(runPublint);\n}\n\nexport { definePubLintCommand };\n"
  },
  {
    "path": "hiauth-front/scripts/vsh/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"extends\": \"@vben/tsconfig/node.json\",\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "hiauth-front/stylelint.config.mjs",
    "content": "export default {\n  extends: ['@vben/stylelint-config'],\n  root: true,\n};\n"
  },
  {
    "path": "hiauth-front/tea.yaml",
    "content": "# https://tea.xyz/what-is-this-file\n---\nversion: 1.0.0\ncodeOwners:\n  - '0xB33cc732DFc15Cd39eF50Fb165c876E24417E48f'\nquorum: 1\n"
  },
  {
    "path": "hiauth-front/turbo.json",
    "content": "{\n  \"$schema\": \"https://turbo.build/schema.json\",\n  \"globalDependencies\": [\n    \"pnpm-lock.yaml\",\n    \"**/.env.*local\",\n    \"**/tsconfig*.json\",\n    \"internal/node-utils/*.json\",\n    \"internal/node-utils/src/**/*.ts\",\n    \"internal/tailwind-config/src/**/*.ts\",\n    \"internal/vite-config/*.json\",\n    \"internal/vite-config/src/**/*.ts\",\n    \"scripts/*/src/**/*.ts\",\n    \"scripts/*/src/**/*.json\"\n  ],\n  \"globalEnv\": [\"NODE_ENV\"],\n  \"tasks\": {\n    \"build\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\n        \"dist/**\",\n        \"dist.zip\",\n        \".vitepress/dist.zip\",\n        \".vitepress/dist/**\"\n      ]\n    },\n    \"preview\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\"dist/**\"]\n    },\n    \"build:analyze\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\"dist/**\"]\n    },\n    \"@vben/backend-mock#build\": {\n      \"dependsOn\": [\"^build\"],\n      \"outputs\": [\".nitro/**\", \".output/**\"]\n    },\n    \"test:e2e\": {},\n    \"dev\": {\n      \"dependsOn\": [],\n      \"outputs\": [],\n      \"cache\": false,\n      \"persistent\": true\n    },\n    \"typecheck\": {\n      \"outputs\": []\n    }\n  }\n}\n"
  },
  {
    "path": "hiauth-front/vben-admin.code-workspace",
    "content": "{\n  \"folders\": [\n    {\n      \"name\": \"@vben/backend-mock\",\n      \"path\": \"apps/backend-mock\",\n    },\n    {\n      \"name\": \"@vben/web-antd\",\n      \"path\": \"apps/web-antd\",\n    },\n    {\n      \"name\": \"@vben/web-auth\",\n      \"path\": \"apps/web-auth\",\n    },\n    {\n      \"name\": \"@vben/web-ele\",\n      \"path\": \"apps/web-ele\",\n    },\n    {\n      \"name\": \"@vben/web-naive\",\n      \"path\": \"apps/web-naive\",\n    },\n    {\n      \"name\": \"@vben/docs\",\n      \"path\": \"docs\",\n    },\n    {\n      \"name\": \"@vben/commitlint-config\",\n      \"path\": \"internal/lint-configs/commitlint-config\",\n    },\n    {\n      \"name\": \"@vben/eslint-config\",\n      \"path\": \"internal/lint-configs/eslint-config\",\n    },\n    {\n      \"name\": \"@vben/prettier-config\",\n      \"path\": \"internal/lint-configs/prettier-config\",\n    },\n    {\n      \"name\": \"@vben/stylelint-config\",\n      \"path\": \"internal/lint-configs/stylelint-config\",\n    },\n    {\n      \"name\": \"@vben/node-utils\",\n      \"path\": \"internal/node-utils\",\n    },\n    {\n      \"name\": \"@vben/tailwind-config\",\n      \"path\": \"internal/tailwind-config\",\n    },\n    {\n      \"name\": \"@vben/tsconfig\",\n      \"path\": \"internal/tsconfig\",\n    },\n    {\n      \"name\": \"@vben/vite-config\",\n      \"path\": \"internal/vite-config\",\n    },\n    {\n      \"name\": \"@vben-core/design\",\n      \"path\": \"packages/@core/base/design\",\n    },\n    {\n      \"name\": \"@vben-core/icons\",\n      \"path\": \"packages/@core/base/icons\",\n    },\n    {\n      \"name\": \"@vben-core/shared\",\n      \"path\": \"packages/@core/base/shared\",\n    },\n    {\n      \"name\": \"@vben-core/typings\",\n      \"path\": \"packages/@core/base/typings\",\n    },\n    {\n      \"name\": \"@vben-core/composables\",\n      \"path\": \"packages/@core/composables\",\n    },\n    {\n      \"name\": \"@vben-core/preferences\",\n      \"path\": \"packages/@core/preferences\",\n    },\n    {\n      \"name\": \"@vben-core/form-ui\",\n      \"path\": \"packages/@core/ui-kit/form-ui\",\n    },\n    {\n      \"name\": \"@vben-core/layout-ui\",\n      \"path\": \"packages/@core/ui-kit/layout-ui\",\n    },\n    {\n      \"name\": \"@vben-core/menu-ui\",\n      \"path\": \"packages/@core/ui-kit/menu-ui\",\n    },\n    {\n      \"name\": \"@vben-core/popup-ui\",\n      \"path\": \"packages/@core/ui-kit/popup-ui\",\n    },\n    {\n      \"name\": \"@vben-core/shadcn-ui\",\n      \"path\": \"packages/@core/ui-kit/shadcn-ui\",\n    },\n    {\n      \"name\": \"@vben-core/tabs-ui\",\n      \"path\": \"packages/@core/ui-kit/tabs-ui\",\n    },\n    {\n      \"name\": \"@vben/constants\",\n      \"path\": \"packages/constants\",\n    },\n    {\n      \"name\": \"@vben/access\",\n      \"path\": \"packages/effects/access\",\n    },\n    {\n      \"name\": \"@vben/common-ui\",\n      \"path\": \"packages/effects/common-ui\",\n    },\n    {\n      \"name\": \"@vben/hooks\",\n      \"path\": \"packages/effects/hooks\",\n    },\n    {\n      \"name\": \"@vben/layouts\",\n      \"path\": \"packages/effects/layouts\",\n    },\n    {\n      \"name\": \"@vben/plugins\",\n      \"path\": \"packages/effects/plugins\",\n    },\n    {\n      \"name\": \"@vben/request\",\n      \"path\": \"packages/effects/request\",\n    },\n    {\n      \"name\": \"@vben/icons\",\n      \"path\": \"packages/icons\",\n    },\n    {\n      \"name\": \"@vben/locales\",\n      \"path\": \"packages/locales\",\n    },\n    {\n      \"name\": \"@vben/preferences\",\n      \"path\": \"packages/preferences\",\n    },\n    {\n      \"name\": \"@vben/stores\",\n      \"path\": \"packages/stores\",\n    },\n    {\n      \"name\": \"@vben/styles\",\n      \"path\": \"packages/styles\",\n    },\n    {\n      \"name\": \"@vben/types\",\n      \"path\": \"packages/types\",\n    },\n    {\n      \"name\": \"@vben/utils\",\n      \"path\": \"packages/utils\",\n    },\n    {\n      \"name\": \"@vben/playground\",\n      \"path\": \"playground\",\n    },\n    {\n      \"name\": \"@vben/turbo-run\",\n      \"path\": \"scripts/turbo-run\",\n    },\n    {\n      \"name\": \"@vben/vsh\",\n      \"path\": \"scripts/vsh\",\n    },\n  ],\n}\n"
  },
  {
    "path": "hiauth-front/vitest.config.ts",
    "content": "import Vue from '@vitejs/plugin-vue';\nimport VueJsx from '@vitejs/plugin-vue-jsx';\nimport { configDefaults, defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  plugins: [Vue(), VueJsx()],\n  test: {\n    environment: 'happy-dom',\n    exclude: [...configDefaults.exclude, '**/e2e/**'],\n  },\n});\n"
  },
  {
    "path": "hiauth-front/vitest.workspace.ts",
    "content": "import { defineWorkspace } from 'vitest/config';\n\nexport default defineWorkspace(['vitest.config.ts']);\n"
  },
  {
    "path": "hiauth-server/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>3.4.5</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>hiauth-server</artifactId>\n    <version>3.0.0-SNAPSHOT</version>\n    <name>hiauth-server</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>17</java.version>\n    </properties>\n\n    <dependencies>\n        <!-- starter自动配置和装载 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n            <scope>compile</scope>\n        </dependency>\n        <!-- actuator -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-actuator</artifactId>\n        </dependency>\n        <!-- 开发支持：热启动等 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <scope>runtime</scope>\n            <optional>true</optional>\n        </dependency>\n        <!-- web服务必选 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- authorization server -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>\n        </dependency>\n        <!-- Spring Boot验证依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n        <!-- thymeleaf -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n        <!-- redis -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        <!-- session -->\n        <dependency>\n            <groupId>org.springframework.session</groupId>\n            <artifactId>spring-session-data-redis</artifactId>\n        </dependency>\n        <!-- 单元测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.junit.jupiter</groupId>\n            <artifactId>junit-jupiter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.htmlunit</groupId>\n            <artifactId>htmlunit</artifactId>\n        </dependency>\n        <!-- API DOC -->\n        <dependency>\n            <groupId>org.springdoc</groupId>\n            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>\n            <version>2.8.8</version>\n        </dependency>\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>\n            <version>4.5.0</version>\n        </dependency>\n        <!-- hutool -->\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.38</version>\n        </dependency>\n        <!-- lombok -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <!-- webjars -->\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>webjars-locator-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>bootstrap</artifactId>\n            <version>5.3.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>jquery</artifactId>\n            <version>3.7.1</version>\n        </dependency>\n        <!-- scms -->\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>commons</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>cache-spring-boot-starter</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>mybatis-plus-spring-boot-starter</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.webestar.scms</groupId>\n            <artifactId>security-spring-boot-starter</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <!-- 数据库 -->\n        <dependency>\n            <groupId>org.postgresql</groupId>\n            <artifactId>postgresql</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.2.24</version>\n        </dependency>\n        <!-- jsonpath -->\n        <dependency>\n            <groupId>com.jayway.jsonpath</groupId>\n            <artifactId>json-path</artifactId>\n            <version>2.9.0</version>\n        </dependency>\n        <!-- 图形验证码工具 kaptcha -->\n        <dependency>\n            <groupId>com.github.penggle</groupId>\n            <artifactId>kaptcha</artifactId>\n            <version>2.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.aliyun</groupId>\n            <artifactId>dysmsapi20170525</artifactId>\n            <version>3.1.1</version>\n        </dependency>\n        <dependency>\n            <groupId>com.aliyun</groupId>\n            <artifactId>tea-openapi</artifactId>\n            <version>0.3.6</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>hiauth-server</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.graalvm.buildtools</groupId>\n                <artifactId>native-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <excludes>\n                        <exclude>\n                            <groupId>org.projectlombok</groupId>\n                            <artifactId>lombok</artifactId>\n                        </exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/ServerStarter.java",
    "content": "package cn.hiauth.server;\n\nimport cn.webestar.scms.commons.Constant;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\n\n@ComponentScan(basePackages = {\"cn.hiauth.server\", Constant.SCMS_BASIC_PKG})\n@SpringBootApplication\npublic class ServerStarter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ServerStarter.class, args);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/KeywordPageUserDto.java",
    "content": "package cn.hiauth.server.api.dto;\n\nimport cn.hiauth.server.entity.User;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class KeywordPageUserDto extends PageBody {\n\n    private String keyword;\n\n    @Override\n    public LambdaQueryWrapper<User> toQueryWapper() {\n        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.like(User::getName, keyword);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/PageDepDto.java",
    "content": "package cn.hiauth.server.api.dto;\n\nimport cn.hiauth.server.entity.Department;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport org.springframework.util.StringUtils;\n\n@Data\n@EqualsAndHashCode(callSuper = true)\npublic class PageDepDto extends PageBody {\n\n    private Long pid;\n\n    private String keyword;\n\n    @Override\n    public LambdaQueryWrapper<Department> toQueryWapper() {\n        LambdaQueryWrapper<Department> queryWrapper = new LambdaQueryWrapper<>();\n        if (pid != null) {\n            queryWrapper.eq(Department::getPid, pid);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Department::getNo, keyword).or().like(Department::getName, keyword));\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/PageEmpDto.java",
    "content": "package cn.hiauth.server.api.dto;\n\nimport cn.hiauth.server.entity.Employee;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport org.springframework.util.StringUtils;\n\n@Data\n@EqualsAndHashCode(callSuper = true)\npublic class PageEmpDto extends PageBody {\n\n    private Long depId;\n\n    private String keyword;\n\n    private Boolean isDeleted = Boolean.FALSE;\n\n    @Override\n    public LambdaQueryWrapper<Employee> toQueryWapper() {\n        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(Employee::getIsDeleted, isDeleted);\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Employee::getNo, keyword)\n                    .or().like(Employee::getName, keyword)\n                    .or().like(Employee::getEmail, keyword)\n            );\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/PageRoleDto.java",
    "content": "package cn.hiauth.server.api.dto;\n\nimport cn.hiauth.server.entity.Role;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport org.springframework.util.StringUtils;\n\n@Data\n@EqualsAndHashCode(callSuper = true)\npublic class PageRoleDto extends PageBody {\n\n    private String keyword;\n\n    @Override\n    public LambdaQueryWrapper<Role> toQueryWapper() {\n        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.like(Role::getName, keyword);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/RegisterDto.java",
    "content": "package cn.hiauth.server.api.dto;\n\nimport cn.hiauth.server.entity.Corp;\nimport cn.hiauth.server.entity.User;\nimport cn.hiauth.server.utils.Constant;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.Pattern;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\n\n@Data\npublic class RegisterDto {\n\n    @Size(min = 2, max = 20, message = \"长度必须在2到30个字符之间\")\n    @Schema(description = \"租户名称\")\n    private String corpName;\n\n    @Size(min = 5, max = 20, message = \"长度必须在2到20个字符之间\")\n    @Schema(description = \"用户名\")\n    private String username;\n\n    @Size(min = 5, max = 20, message = \"长度必须在5到20个字符之间\")\n    @Schema(description = \"密码\")\n    private String password;\n\n    @Pattern(regexp = \"^1[3-9]\\\\d{9}$\", message = \"手机号码格式不正确\")\n    @Schema(description = \"手机号码\")\n    private String phoneNum;\n\n    @Size(min = 3, max = 6, message = \"长度必须在3到6个字符之间\")\n    @Schema(description = \"短信验证码\")\n    private String smsCode;\n\n    public Corp toCorp() {\n        Corp corp = new Corp();\n        corp.setName(corpName);\n        corp.setStatus(1);\n        return corp;\n    }\n\n    public User toUser() {\n        User user = new User();\n        user.setName(username);\n        user.setUsername(username);\n        user.setPhoneNum(phoneNum);\n        user.setPwd(password);\n        user.setAvatarUrl(Constant.USER_DEFAULT_AVATAR);\n        user.setIsSysAdmin(false);\n        user.setStatus(1);\n        user.setRegtime(LocalDateTime.now());\n        user.setIsDeleted(false);\n        return user;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/app/AppCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.app;\n\nimport cn.hiauth.server.entity.App;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\npublic class AppCreateDto extends CreateBody {\n\n    @TableField(\"cid\")\n    @Schema(description = \"创建应用的企业CID\")\n    private Long cid;\n\n    @Schema(description = \"图标\")\n    @Size(max = 200, message = \"长度不能超过200\")\n    private String icon;\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 20, message = \"长度必须在5到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"主页地址\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 100, message = \"长度必须在5到100个字符之间\")\n    private String home;\n\n    @Schema(description = \"备注\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String remark;\n\n    @Override\n    public App toDO() {\n        App o = new App();\n        o.setCid(cid);\n        o.setIcon(icon);\n        o.setName(name);\n        o.setHome(home);\n        o.setRemark(remark);\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/app/AppLimitDto.java",
    "content": "package cn.hiauth.server.api.dto.app;\n\nimport cn.hiauth.server.entity.App;\nimport cn.webestar.scms.commons.api.LimitBody;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class AppLimitDto extends LimitBody {\n\n    @TableField(\"cid\")\n    @Schema(description = \"创建应用的企业CID\")\n    private Long cid;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Override\n    public LambdaQueryWrapper<App> toQueryWapper() {\n        LambdaQueryWrapper<App> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(App::getCid, cid);\n        }\n        if (StringUtils.hasText(name)) {\n            queryWrapper.eq(App::getName, name);\n        }\n        queryWrapper.last(\"OFFSET \" + this.getOffset() + \" LIMIT \" + this.getLimit());\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/app/AppPageDto.java",
    "content": "package cn.hiauth.server.api.dto.app;\n\nimport cn.hiauth.server.entity.App;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class AppPageDto extends PageBody {\n\n    @TableField(\"cid\")\n    @Schema(description = \"创建应用的企业CID\")\n    private Long cid;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Override\n    public LambdaQueryWrapper<App> toQueryWapper() {\n        LambdaQueryWrapper<App> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(App::getCid, cid);\n        }\n        if (StringUtils.hasText(name)) {\n            queryWrapper.like(App::getName, name);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/app/AppUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.app;\n\nimport cn.hiauth.server.entity.App;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\npublic class AppUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    private Long id;\n\n    @TableField(\"cid\")\n    @Schema(description = \"创建应用的企业CID\")\n    private Long cid;\n\n    @Schema(description = \"图标\")\n    @Size(max = 200, message = \"长度不能超过200\")\n    private String icon;\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 20, message = \"长度必须在5到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"主页地址\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 100, message = \"长度必须在5到100个字符之间\")\n    private String home;\n\n    @Schema(description = \"备注\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String remark;\n\n    @Override\n    public Long getId() {\n        return id;\n    }\n\n    @Override\n    public App toDO() {\n        App o = new App();\n        o.setId(id);\n        o.setCid(cid);\n        o.setIcon(icon);\n        o.setName(name);\n        o.setHome(home);\n        o.setRemark(remark);\n        return o;\n    }\n\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appClient/AppClientCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.appClient;\n\nimport cn.hiauth.server.entity.CorpApp;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotNull;\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Data\npublic class AppClientCreateDto extends CreateBody {\n\n    @Schema(description = \"租户\")\n    private Long corpId;\n\n    @Schema(description = \"应用id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long[] appIds;\n\n    @Override\n    public CorpApp toDO() {\n        return null;\n    }\n\n    public List<CorpApp> toDos() {\n        List<CorpApp> list = new ArrayList<>();\n        if (appIds != null && appIds.length > 0) {\n            for (Long appId : appIds) {\n                CorpApp o = new CorpApp();\n                o.setCorpId(corpId);\n                o.setAppId(appId);\n                list.add(o);\n            }\n        }\n        return list;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appClient/AppClientDeleteDto.java",
    "content": "package cn.hiauth.server.api.dto.appClient;\n\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotNull;\nimport lombok.Data;\n\n@Data\npublic class AppClientDeleteDto {\n\n    @Schema(description = \"租户\")\n    @NotNull(message = \"不能为NULL\")\n    private Long corpId;\n\n    @Schema(description = \"应用\")\n    @NotNull(message = \"不能为NULL\")\n    private Long[] appIds;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appClient/AppClientLimitDto.java",
    "content": "package cn.hiauth.server.api.dto.appClient;\n\nimport cn.webestar.scms.commons.api.LimitBody;\nimport cn.webestar.scms.commons.entity.Entity;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\n\n@Data\npublic class AppClientLimitDto extends LimitBody {\n\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Override\n    public <T extends Entity> LambdaQueryWrapper<T> toQueryWapper() {\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appClient/AppClientPageDto.java",
    "content": "package cn.hiauth.server.api.dto.appClient;\n\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class AppClientPageDto extends PageBody {\n\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Override\n    public LambdaQueryWrapper<Oauth2RegisteredClient> toQueryWapper() {\n        LambdaQueryWrapper<Oauth2RegisteredClient> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(Oauth2RegisteredClient::getCid, cid);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Oauth2RegisteredClient::getClientName, keyword)\n                    .or().like(Oauth2RegisteredClient::getClientId, keyword)\n                    .or().like(Oauth2RegisteredClient::getScopes, keyword)\n            );\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appClient/AppClientUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.appClient;\n\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport cn.hiauth.server.utils.Oauth2RegisteredClientUtils;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\npublic class AppClientUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    @NotNull(message = \"不能为NULL\")\n    private String id;\n\n    @Schema(description = \"clientId\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 50, message = \"长度必须在5到50个字符之间\")\n    private String clientId;\n\n    @Schema(description = \"clientSecret\")\n    @Size(min = 5, max = 50, message = \"长度必须在5到50个字符之间\")\n    private String clientSecret;\n\n    @Schema(description = \"redirectUris\")\n    @Size(max = 500, message = \"长度不能超过500个字符\")\n    private String redirectUris;\n\n    @Schema(description = \"scopes\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 100, message = \"长度必须在2到100个字符之间\")\n    private String scopes;\n\n    @Schema(description = \"accessTokenTimeToLive\")\n    @NotNull(message = \"不能为NULL\")\n    private Integer accessTokenTimeToLive;\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public Oauth2RegisteredClient toDO() {\n        Oauth2RegisteredClient o = new Oauth2RegisteredClient();\n        o.setId(id);\n        o.setClientId(clientId);\n        o.setClientSecret(clientSecret);\n        o.setRedirectUris(redirectUris);\n        o.setScopes(scopes);\n        if (accessTokenTimeToLive != null) {\n            o.setTokenSettings(Oauth2RegisteredClientUtils.getTokenSettings(accessTokenTimeToLive * 3600));\n        }\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appResource/AppResourceCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.appResource;\n\nimport cn.hiauth.server.entity.AppResource;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.util.Map;\n\n@Data\npublic class AppResourceCreateDto extends CreateBody {\n\n    @Schema(description = \"应用id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long appId;\n\n    @Schema(description = \"父节点\")\n    private Long pid;\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 20, message = \"长度必须在5到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"排序\")\n    private Integer sort;\n\n    @Schema(description = \"编码\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 100, message = \"长度必须在2到100个字符之间\")\n    private String code;\n\n    @Schema(description = \"URL\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String url;\n\n    @Schema(description = \"api\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String api;\n\n    @Schema(description = \"资源类型，1：目录、菜单，2：页面，3：功能、接口\")\n    @NotNull(message = \"不能为空\")\n    private Integer type;\n\n    @Schema(description = \"备注\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String remark;\n\n    @Schema(description = \"扩展字段\")\n    private Map<String, ?> extend;\n\n    @Override\n    public AppResource toDO() {\n        AppResource o = new AppResource();\n        o.setAppId(appId);\n        o.setPid(pid);\n        o.setName(name);\n        o.setSort(sort);\n        o.setCode(code);\n        o.setUrl(url);\n        o.setApi(api);\n        o.setType(type);\n        o.setRemark(remark);\n        o.setExtend(extend);\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appResource/AppResourcePageDto.java",
    "content": "package cn.hiauth.server.api.dto.appResource;\n\nimport cn.hiauth.server.entity.AppResource;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotNull;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class AppResourcePageDto extends PageBody {\n\n    @Schema(description = \"应用id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long appId;\n\n    @Schema(description = \"父节点\")\n    private Long pid;\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Schema(description = \"编码\")\n    private String code;\n\n    @Schema(description = \"URL\")\n    private String url;\n\n    @Schema(description = \"api\")\n    private String api;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Schema(description = \"资源类型，1：目录、菜单，2：页面，3：功能、接口\")\n    private Integer type;\n\n    @Override\n    public LambdaQueryWrapper<AppResource> toQueryWapper() {\n        LambdaQueryWrapper<AppResource> queryWrapper = new LambdaQueryWrapper<>();\n        if (appId != null) {\n            queryWrapper.eq(AppResource::getAppId, appId);\n        }\n        if (pid != null) {\n            queryWrapper.eq(AppResource::getPid, pid);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(AppResource::getCode, keyword)\n                    .or().like(AppResource::getUrl, keyword)\n                    .or().like(AppResource::getApi, keyword)\n                    .or().like(AppResource::getName, keyword)\n            );\n        }\n        if (StringUtils.hasText(code)) {\n            queryWrapper.like(AppResource::getCode, code);\n        }\n        if (StringUtils.hasText(url)) {\n            queryWrapper.like(AppResource::getUrl, url);\n        }\n        if (StringUtils.hasText(api)) {\n            queryWrapper.like(AppResource::getApi, api);\n        }\n        if (StringUtils.hasText(name)) {\n            queryWrapper.like(AppResource::getName, name);\n        }\n        if (type != null) {\n            queryWrapper.eq(AppResource::getType, type);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appResource/AppResourceUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.appResource;\n\nimport cn.hiauth.server.entity.AppResource;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.util.Map;\n\n@Data\npublic class AppResourceUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long id;\n\n    @Schema(description = \"父节点\")\n    private Long pid;\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"排序\")\n    private Integer sort;\n\n    @Schema(description = \"编码\")\n    @NotBlank(message = \"编码不能为空\")\n    @Size(min = 2, max = 100, message = \"长度必须在2到100个字符之间\")\n    private String code;\n\n    @Schema(description = \"URL\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String url;\n\n    @Schema(description = \"api\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String api;\n\n    @Schema(description = \"资源类型，1：目录、菜单，2：页面，3：功能、接口\")\n    @NotNull(message = \"不能为空\")\n    private Integer type;\n\n    @Schema(description = \"备注\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String remark;\n\n    @Schema(description = \"扩展字段\")\n    private Map<String, ?> extend;\n\n    @Override\n    public Long getId() {\n        return id;\n    }\n\n    @Override\n    public AppResource toDO() {\n        AppResource o = new AppResource();\n        o.setId(id);\n        o.setPid(pid);\n        o.setName(name);\n        o.setSort(sort);\n        o.setCode(code);\n        o.setUrl(url);\n        o.setApi(api);\n        o.setType(type);\n        o.setRemark(remark);\n        o.setExtend(extend);\n        return o;\n    }\n\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/appResource/FindAppResourceIdsByRoleAndAppDto.java",
    "content": "package cn.hiauth.server.api.dto.appResource;\n\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotNull;\nimport lombok.Data;\n\n@Data\npublic class FindAppResourceIdsByRoleAndAppDto {\n\n    @Schema(description = \"appId\")\n    @NotNull(message = \"不能为NULL\")\n    private Long appId;\n\n    @Schema(description = \"roleId\")\n    @NotNull(message = \"不能为NULL\")\n    private Long roleId;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/corp/CorpCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.corp;\n\nimport cn.hiauth.server.entity.Corp;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\n@Schema(description = \"CorpCreateDto\")\npublic class CorpCreateDto extends CreateBody {\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    @NotNull(message = \"不能为NULL\")\n    private Integer status;\n\n    @Override\n    public Corp toDO() {\n        Corp o = new Corp();\n        o.setName(name);\n        o.setAppCount(0);\n        o.setDepCount(0);\n        o.setEmpCount(0);\n        o.setStatus(status);\n        o.setIsDeleted(false);\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/corp/CorpPageDto.java",
    "content": "package cn.hiauth.server.api.dto.corp;\n\nimport cn.hiauth.server.entity.Corp;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class CorpPageDto extends PageBody {\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    private Integer status;\n\n    @Override\n    public LambdaQueryWrapper<Corp> toQueryWapper() {\n        LambdaQueryWrapper<Corp> queryWrapper = new LambdaQueryWrapper<>();\n        if (StringUtils.hasText(name)) {\n            queryWrapper.like(Corp::getName, name);\n        }\n        if (status != null) {\n            queryWrapper.eq(Corp::getStatus, status);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/corp/CorpUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.corp;\n\nimport cn.hiauth.server.entity.Corp;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\n@Schema(description = \"CorpUpdateDto\")\npublic class CorpUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long id;\n\n    @Schema(description = \"名称\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    private Integer status;\n\n    @Override\n    public Long getId() {\n        return id;\n    }\n\n    @Override\n    public Corp toDO() {\n        Corp o = new Corp();\n        o.setId(id);\n        o.setName(name);\n        o.setStatus(status);\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/dep/DepCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.dep;\n\nimport cn.hiauth.server.entity.Department;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\n\n@Data\npublic class DepCreateDto extends CreateBody {\n\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @Schema(description = \"父部门\")\n    private Long pid;\n\n    @Schema(description = \"排序号\")\n    private Integer sort;\n\n    @Schema(description = \"部门编码\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String no;\n\n    @Schema(description = \"部门名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    @NotNull(message = \"不能为NULL\")\n    private Integer status;\n\n    @Schema(description = \"备注\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String remark;\n\n    @Override\n    public Department toDO() {\n        Department o = new Department();\n        o.setCid(cid);\n        o.setPid(pid);\n        o.setSort(sort);\n        o.setNo(no);\n        o.setName(name);\n        o.setStatus(status);\n        o.setRemark(remark);\n        o.setCreateTime(LocalDateTime.now());\n        o.setUpdateTime(LocalDateTime.now());\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/dep/DepLimitDto.java",
    "content": "package cn.hiauth.server.api.dto.dep;\n\nimport cn.hiauth.server.entity.Department;\nimport cn.webestar.scms.commons.api.LimitBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class DepLimitDto extends LimitBody {\n\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Override\n    public LambdaQueryWrapper<Department> toQueryWapper() {\n        LambdaQueryWrapper<Department> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(Department::getCid, cid);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Department::getNo, keyword).or().like(Department::getName, keyword));\n        }\n        queryWrapper.last(\"OFFSET \" + this.getOffset() + \" LIMIT \" + this.getLimit());\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/dep/DepPageDto.java",
    "content": "package cn.hiauth.server.api.dto.dep;\n\nimport cn.hiauth.server.entity.Department;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class DepPageDto extends PageBody {\n\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @Schema(description = \"父部门\")\n    private Long pid;\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Schema(description = \"部门编码\")\n    private String no;\n\n    @Schema(description = \"部门名称\")\n    private String name;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    private Integer status;\n\n    @Override\n    public LambdaQueryWrapper<Department> toQueryWapper() {\n        LambdaQueryWrapper<Department> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(Department::getCid, cid);\n        }\n        if (pid != null) {\n            queryWrapper.eq(Department::getPid, pid);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Department::getNo, keyword).or().like(Department::getName, keyword));\n        }\n        if (StringUtils.hasText(no)) {\n            queryWrapper.like(Department::getNo, no);\n        }\n        if (StringUtils.hasText(name)) {\n            queryWrapper.like(Department::getName, name);\n        }\n        if (status != null) {\n            queryWrapper.eq(Department::getStatus, status);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/dep/DepUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.dep;\n\nimport cn.hiauth.server.entity.Department;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\n\n@Data\npublic class DepUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long id;\n\n    @Schema(description = \"父部门\")\n    private Long pid;\n\n    @Schema(description = \"排序号\")\n    private Integer sort;\n\n    @Schema(description = \"部门编码\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String no;\n\n    @Schema(description = \"部门名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    @NotNull(message = \"不能为NULL\")\n    private Integer status;\n\n    @Schema(description = \"备注\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String remark;\n\n    @Override\n    public Long getId() {\n        return id;\n    }\n\n    @Override\n    public Department toDO() {\n        Department o = new Department();\n        o.setId(id);\n        o.setPid(pid);\n        o.setSort(sort);\n        o.setNo(no);\n        o.setName(name);\n        o.setStatus(status);\n        o.setRemark(remark);\n        o.setUpdateTime(LocalDateTime.now());\n        return o;\n    }\n\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/dict/DictCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.dict;\n\nimport cn.hiauth.server.entity.Dict;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\n\n@Data\npublic class DictCreateDto extends CreateBody {\n\n    @Schema(description = \"cid\")\n    private Long cid;\n\n    @Schema(description = \"排序\")\n    private Integer sort;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 50, message = \"长度必须在2到50个字符之间\")\n    @Schema(description = \"编码\")\n    private String code;\n\n    @Size(min = 2, max = 50, message = \"长度必须在2到50个字符之间\")\n    @Schema(description = \"父编码\")\n    private String pcode;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 1, max = 200, message = \"长度必须在2到200个字符之间\")\n    @Schema(description = \"值\")\n    private String value;\n\n    @Override\n    public Dict toDO() {\n        Dict o = new Dict();\n        o.setSort(sort);\n        o.setCode(code);\n        o.setPCode(pcode);\n        o.setName(name);\n        o.setValue(value);\n        o.setIsEnable(true);\n        o.setHasChild(false);\n        o.setCreateTime(LocalDateTime.now());\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/dict/DictLimitDto.java",
    "content": "package cn.hiauth.server.api.dto.dict;\n\nimport cn.hiauth.server.entity.Dict;\nimport cn.webestar.scms.commons.api.LimitBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class DictLimitDto extends LimitBody {\n\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Schema(description = \"pCode\")\n    private String pcode;\n\n    @Override\n    public LambdaQueryWrapper<Dict> toQueryWapper() {\n        LambdaQueryWrapper<Dict> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(Dict::getCid, cid);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Dict::getName, keyword)\n                    .or().like(Dict::getCode, keyword)\n            );\n        }\n        if (StringUtils.hasText(pcode)) {\n            queryWrapper.eq(Dict::getPCode, pcode);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/dict/DictPageDto.java",
    "content": "package cn.hiauth.server.api.dto.dict;\n\nimport cn.hiauth.server.entity.Dict;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class DictPageDto extends PageBody {\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Schema(description = \"租户ID\")\n    private Long cid;\n\n    @Schema(description = \"员工号\")\n    private String code;\n\n    @Schema(description = \"父编码\")\n    private String pCode;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Schema(description = \"根节点\")\n    private Boolean isRoot;\n\n    @Override\n    public LambdaQueryWrapper<Dict> toQueryWapper() {\n        LambdaQueryWrapper<Dict> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(Dict::getCid, cid);\n        }\n        if (StringUtils.hasText(pCode)) {\n            // 通过父编码查询字典值\n            queryWrapper.like(Dict::getPCode, pCode);\n        } else if (isRoot) {\n            // 查询字典分类\n            queryWrapper.isNull(Dict::getPCode);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Dict::getName, keyword)\n                    .or().like(Dict::getCode, keyword)\n                    .or().like(Dict::getPCode, keyword));\n        }\n        if (StringUtils.hasText(code)) {\n            queryWrapper.like(Dict::getCode, code);\n        }\n        if (StringUtils.hasText(name)) {\n            queryWrapper.like(Dict::getName, name);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/dict/DictUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.dict;\n\nimport cn.hiauth.server.entity.Dict;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\n\n@Data\npublic class DictUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long id;\n\n    @Schema(description = \"排序\")\n    private Integer sort;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 50, message = \"长度必须在2到50个字符之间\")\n    @Schema(description = \"编码\")\n    private String code;\n\n    @Size(min = 2, max = 50, message = \"长度必须在2到50个字符之间\")\n    @Schema(description = \"父编码\")\n    private String pcode;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 1, max = 200, message = \"长度必须在2到200个字符之间\")\n    @Schema(description = \"值\")\n    private String value;\n\n    @Override\n    public Long getId() {\n        return id;\n    }\n\n    @Override\n    public Dict toDO() {\n        Dict o = new Dict();\n        o.setId(id);\n        o.setSort(sort);\n        o.setCode(code);\n        o.setPCode(pcode);\n        o.setName(name);\n        o.setIsEnable(true);\n        o.setCreateTime(LocalDateTime.now());\n        return o;\n    }\n\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/emp/EmpCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.emp;\n\nimport cn.hiauth.server.entity.Employee;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.Email;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\nimport java.util.Set;\n\n@Data\npublic class EmpCreateDto extends CreateBody {\n\n    @Schema(description = \"租户ID\")\n    private Long cid;\n\n    @Schema(description = \"用户id\")\n    private Long userId;\n\n    @Schema(description = \"部门id\")\n    private Set<Long> depIds;\n\n    @Schema(description = \"员工号\")\n    private String no;\n\n    @Schema(description = \"姓名\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 10, message = \"长度必须在2到10个字符之间\")\n    private String name;\n\n    @Schema(description = \"邮箱\")\n    @Email\n    @Size(min = 5, max = 50, message = \"长度必须在5到50个字符之间\")\n    private String email;\n\n    @Schema(description = \"是否为租户管理员\")\n    @NotNull(message = \"不能为NULL\")\n    private Boolean isCorpAdmin;\n\n    @Schema(description = \"角色id\")\n    private Set<Long> roleIds;\n\n    @Override\n    public Employee toDO() {\n        Employee o = new Employee();\n        o.setCid(cid);\n        o.setUserId(userId);\n        o.setNo(no);\n        o.setName(name);\n        o.setEmail(email);\n        o.setIsCorpAdmin(isCorpAdmin);\n        o.setCreateTime(LocalDateTime.now());\n        o.setUpdateTime(LocalDateTime.now());\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/emp/EmpPageDto.java",
    "content": "package cn.hiauth.server.api.dto.emp;\n\nimport cn.hiauth.server.entity.Employee;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\nimport java.util.Set;\n\n@Data\npublic class EmpPageDto extends PageBody {\n\n    @Schema(description = \"租户ID\")\n    private Long cid;\n\n    @Schema(description = \"部门id\")\n    private Set<Long> depIds;\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Schema(description = \"员工号\")\n    private String no;\n\n    @Schema(description = \"姓名\")\n    private String name;\n\n    @Schema(description = \"邮箱\")\n    private String email;\n\n    @Schema(description = \"是否为租户管理员\")\n    private Boolean isCorpAdmin;\n\n    @Override\n    public LambdaQueryWrapper<Employee> toQueryWapper() {\n        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(Employee::getIsDeleted, false);\n        if (cid != null) {\n            queryWrapper.eq(Employee::getCid, cid);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Employee::getNo, keyword)\n                    .or().like(Employee::getName, keyword)\n                    .or().like(Employee::getEmail, keyword));\n        }\n        if (StringUtils.hasText(no)) {\n            queryWrapper.like(Employee::getNo, no);\n        }\n        if (StringUtils.hasText(name)) {\n            queryWrapper.like(Employee::getName, name);\n        }\n        if (StringUtils.hasText(email)) {\n            queryWrapper.like(Employee::getEmail, email);\n        }\n        if (isCorpAdmin != null) {\n            queryWrapper.eq(Employee::getIsCorpAdmin, isCorpAdmin);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/emp/EmpUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.emp;\n\nimport cn.hiauth.server.entity.Employee;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.Email;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\nimport java.util.Set;\n\n@Data\npublic class EmpUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long id;\n\n    @Schema(description = \"用户id\")\n    private Long userId;\n\n    @Schema(description = \"部门id\")\n    private Set<Long> depIds;\n\n    @Schema(description = \"员工号\")\n    private String no;\n\n    @Schema(description = \"姓名\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 10, message = \"长度必须在2到10个字符之间\")\n    private String name;\n\n    @Schema(description = \"邮箱\")\n    @Email\n    @Size(min = 5, max = 50, message = \"长度必须在5到50个字符之间\")\n    private String email;\n\n    @Schema(description = \"是否为租户管理员\")\n    @NotNull(message = \"不能为NULL\")\n    private Boolean isCorpAdmin;\n\n    @Schema(description = \"最后登录时间\")\n    private LocalDateTime lastLoginTime;\n\n    @Schema(description = \"角色id\")\n    private Set<Long> roleIds;\n\n    @Override\n    public Long getId() {\n        return id;\n    }\n\n    @Override\n    public Employee toDO() {\n        Employee o = new Employee();\n        o.setId(id);\n        o.setUserId(userId);\n        o.setNo(no);\n        o.setName(name);\n        o.setEmail(email);\n        o.setIsCorpAdmin(isCorpAdmin);\n        o.setLastLoginTime(lastLoginTime);\n        o.setUpdateTime(LocalDateTime.now());\n        return o;\n    }\n\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/login/CaptchaVerifyDto.java",
    "content": "package cn.hiauth.server.api.dto.login;\n\nimport lombok.Data;\n\n@Data\npublic class CaptchaVerifyDto {\n\n    private String token;\n    private Integer startX;\n    private Integer endX;\n    private Long startTime;\n    private Long endTime;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/login/SmsCodeDto.java",
    "content": "package cn.hiauth.server.api.dto.login;\n\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.Pattern;\nimport lombok.Data;\n\n@Data\npublic class SmsCodeDto {\n\n    @NotBlank(message = \"不能为空\")\n    @Pattern(regexp = \"^1[3-9]\\\\d{9}$\", message = \"手机号码格式不正确\")\n    private String phoneNum;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/login/SmsCodeLoginDto.java",
    "content": "package cn.hiauth.server.api.dto.login;\n\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.Pattern;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\npublic class SmsCodeLoginDto {\n\n    @NotBlank(message = \"不能为空\")\n    @Pattern(regexp = \"^1[3-9]\\\\d{9}$\", message = \"手机号码格式不正确\")\n    private String phoneNum;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 3, max = 6, message = \"长度必须在3到6个字符之间\")\n    private String smsCode;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/role/RoleAuthDto.java",
    "content": "package cn.hiauth.server.api.dto.role;\n\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotNull;\nimport lombok.Data;\n\nimport java.util.Set;\n\n@Data\npublic class RoleAuthDto {\n\n    @Schema(description = \"应用id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long appId;\n\n    @Schema(description = \"角色id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long roleId;\n\n    @Schema(description = \"资源id\")\n    private Set<Long> appResourceIds;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/role/RoleCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.role;\n\nimport cn.hiauth.server.entity.Role;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\n\n@Data\npublic class RoleCreateDto extends CreateBody {\n\n    @Schema(description = \"cid\")\n    private Long cid;\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"备注\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String remark;\n\n    @Schema(description = \"是否可用\")\n    @NotNull(message = \"不能为NULL\")\n    private Boolean isEnable;\n\n    @Override\n    public Role toDO() {\n        Role o = new Role();\n        o.setCid(cid);\n        o.setName(name);\n        o.setRemark(remark);\n        o.setIsEnable(isEnable);\n        o.setCreateTime(LocalDateTime.now());\n        o.setUpdateTime(LocalDateTime.now());\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/role/RoleLimitDto.java",
    "content": "package cn.hiauth.server.api.dto.role;\n\nimport cn.hiauth.server.entity.Role;\nimport cn.webestar.scms.commons.api.LimitBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class RoleLimitDto extends LimitBody {\n\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Override\n    public LambdaQueryWrapper<Role> toQueryWapper() {\n        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(Role::getCid, cid);\n        }\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(Role::getName, keyword));\n        }\n        queryWrapper.last(\"OFFSET \" + this.getOffset() + \" LIMIT \" + this.getLimit());\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/role/RolePageDto.java",
    "content": "package cn.hiauth.server.api.dto.role;\n\nimport cn.hiauth.server.entity.Role;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class RolePageDto extends PageBody {\n\n    @Schema(description = \"cid\")\n    private Long cid;\n\n    @Schema(description = \"depId\")\n    private Long depId;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Override\n    public LambdaQueryWrapper<Role> toQueryWapper() {\n        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(Role::getCid, cid);\n        }\n        if (StringUtils.hasText(name)) {\n            queryWrapper.like(Role::getName, name);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/role/RoleUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.role;\n\nimport cn.hiauth.server.entity.Role;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\npublic class RoleUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long id;\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"备注\")\n    @Size(max = 100, message = \"长度不能超过100\")\n    private String remark;\n\n    @Schema(description = \"是否可用\")\n    @NotNull(message = \"不能为NULL\")\n    private Boolean isEnable;\n\n    @Override\n    public Long getId() {\n        return id;\n    }\n\n    @Override\n    public Role toDO() {\n        Role o = new Role();\n        o.setId(id);\n        o.setName(name);\n        o.setRemark(remark);\n        o.setIsEnable(isEnable);\n        return o;\n    }\n\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/user/UserCreateDto.java",
    "content": "package cn.hiauth.server.api.dto.user;\n\nimport cn.hiauth.server.entity.User;\nimport cn.webestar.scms.commons.api.CreateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Pattern;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Schema(description = \"UserCreateDto\")\npublic class UserCreateDto extends CreateBody {\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"头像\")\n    @Size(max = 200, message = \"长度不能超过200\")\n    private String avatar;\n\n    @Schema(description = \"用户名\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 20, message = \"长度必须在5到20个字符之间\")\n    private String username;\n\n    @Schema(description = \"手机号码\")\n    @Pattern(regexp = \"^1[3-9]\\\\d{9}$\", message = \"手机号码格式不正确\")\n    private String phoneNum;\n\n    @Schema(description = \"性别，0：未知，1：男，2：女\")\n    @NotNull(message = \"不能为NULL\")\n    private Integer gender;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    @NotNull(message = \"不能为NULL\")\n    private Integer status;\n\n    @Schema(description = \"是否为系统管理员\")\n    @NotNull(message = \"不能为NULL\")\n    private Boolean isSysAdmin;\n\n    @Override\n    public User toDO() {\n        User o = new User();\n        o.setName(name);\n        o.setAvatarUrl(avatar);\n        o.setUsername(username);\n        o.setPhoneNum(phoneNum);\n        o.setGender(gender);\n        o.setStatus(status);\n        o.setIsSysAdmin(isSysAdmin);\n        o.setRegtime(LocalDateTime.now());\n        o.setIsDeleted(false);\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/user/UserLimitDto.java",
    "content": "package cn.hiauth.server.api.dto.user;\n\nimport cn.hiauth.server.entity.User;\nimport cn.webestar.scms.commons.api.LimitBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class UserLimitDto extends LimitBody {\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Schema(description = \"用户ID\")\n    private Long userId;\n\n    @Override\n    public LambdaQueryWrapper<User> toQueryWapper() {\n        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(User::getIsDeleted, false);\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(User::getUsername, keyword)\n                    .or().like(User::getPhoneNum, keyword)\n                    .or().like(User::getName, keyword)\n            );\n            queryWrapper.orderByDesc(User::getCreateTime);\n            queryWrapper.last(\"OFFSET \" + this.getOffset() + \" LIMIT \" + this.getLimit());\n        } else {\n            // 如果没有搜索条件，说明是初始化查找，则把传过来的id排在第一位，确保前端显示没有问题\n            queryWrapper.last(\"ORDER BY CASE WHEN id = \" + userId + \" THEN 0 ELSE 1 END, create_time DESC \"\n                    + \"OFFSET \" + this.getOffset() + \" LIMIT \" + this.getLimit());\n        }\n\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/user/UserPageDto.java",
    "content": "package cn.hiauth.server.api.dto.user;\n\nimport cn.hiauth.server.entity.User;\nimport cn.webestar.scms.commons.api.PageBody;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport org.springframework.util.StringUtils;\n\n@Data\npublic class UserPageDto extends PageBody {\n\n    @Schema(description = \"关键字\")\n    private String keyword;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Schema(description = \"用户名\")\n    private String username;\n\n    @Schema(description = \"手机号码\")\n    private String phoneNum;\n\n    @Schema(description = \"性别，0：未知，1：男，2：女\")\n    private Integer gender;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    private Integer status;\n\n    @Schema(description = \"注册时间\")\n    private String[] regtime;\n\n    @Schema(description = \"是否为系统管理员\")\n    private Boolean isSysAdmin;\n\n    @Override\n    public LambdaQueryWrapper<User> toQueryWapper() {\n        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(User::getIsDeleted, false);\n        if (StringUtils.hasText(keyword)) {\n            queryWrapper.and(wrapper -> wrapper.like(User::getName, keyword)\n                    .or().like(User::getUsername, keyword)\n                    .or().like(User::getPhoneNum, keyword)\n            );\n        }\n        if (StringUtils.hasText(name)) {\n            queryWrapper.like(User::getName, name);\n        }\n        if (StringUtils.hasText(username)) {\n            queryWrapper.like(User::getUsername, username);\n        }\n        if (StringUtils.hasText(phoneNum)) {\n            queryWrapper.like(User::getPhoneNum, phoneNum);\n        }\n        if (gender != null) {\n            queryWrapper.eq(User::getGender, gender);\n        }\n        if (status != null) {\n            queryWrapper.eq(User::getStatus, status);\n        }\n        if (isSysAdmin != null) {\n            queryWrapper.eq(User::getIsSysAdmin, isSysAdmin);\n        }\n        if (regtime != null && regtime.length >= 2) {\n            queryWrapper.ge(User::getRegtime, regtime[0]);\n            queryWrapper.le(User::getRegtime, regtime[1]);\n        }\n        return queryWrapper;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/user/UserPwdUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.user;\n\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\n@Schema(description = \"UserPwdUpdateDto\")\npublic class UserPwdUpdateDto {\n\n    @Schema(description = \"用户id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long userId;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 20, message = \"长度必须在5~20之间\")\n    @Schema(description = \"pwd\")\n    private String pwd;\n\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 20, message = \"长度必须在5~20之间\")\n    @Schema(description = \"rawPwd\")\n    private String rawPwd;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/dto/user/UserUpdateDto.java",
    "content": "package cn.hiauth.server.api.dto.user;\n\nimport cn.hiauth.server.entity.User;\nimport cn.webestar.scms.commons.api.UpdateBody;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport jakarta.validation.constraints.NotBlank;\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.validation.constraints.Pattern;\nimport jakarta.validation.constraints.Size;\nimport lombok.Data;\n\n@Data\n@Schema(description = \"UserUpdateDto\")\npublic class UserUpdateDto extends UpdateBody {\n\n    @Schema(description = \"id\")\n    @NotNull(message = \"不能为NULL\")\n    private Long id;\n\n    @Schema(description = \"名称\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 2, max = 20, message = \"长度必须在2到20个字符之间\")\n    private String name;\n\n    @Schema(description = \"头像\")\n    @Size(max = 200, message = \"长度不能超过200\")\n    private String avatar;\n\n    @Schema(description = \"用户名\")\n    @NotBlank(message = \"不能为空\")\n    @Size(min = 5, max = 20, message = \"长度必须在5到20个字符之间\")\n    private String username;\n\n    @Schema(description = \"手机号码\")\n    @Pattern(regexp = \"^1[3-9]\\\\d{9}$\", message = \"手机号码格式不正确\")\n    private String phoneNum;\n\n    @Schema(description = \"性别，0：未知，1：男，2：女\")\n    @NotNull(message = \"不能为NULL\")\n    private Integer gender;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    @NotNull(message = \"不能为NULL\")\n    private Integer status;\n\n    @Schema(description = \"是否为系统管理员\")\n    @NotNull(message = \"不能为NULL\")\n    private Boolean isSysAdmin;\n\n    @Override\n    public Long getId() {\n        return id;\n    }\n\n    @Override\n    public User toDO() {\n        User o = new User();\n        o.setId(id);\n        o.setName(name);\n        o.setAvatarUrl(avatar);\n        o.setUsername(username);\n        o.setPhoneNum(phoneNum);\n        o.setGender(gender);\n        o.setStatus(status);\n        o.setIsSysAdmin(isSysAdmin);\n        o.setIsDeleted(false);\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/CommonTreeNodeVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport cn.hiauth.server.entity.AppResource;\nimport cn.hiauth.server.entity.Department;\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Data\npublic class CommonTreeNodeVo {\n\n    private Long id;\n    private String name;\n    private List<CommonTreeNodeVo> children = new ArrayList<>();\n    ;\n\n    public static CommonTreeNodeVo convertToVo(AppResource o) {\n        CommonTreeNodeVo vo = new CommonTreeNodeVo();\n        vo.setId(o.getId());\n        vo.setName(o.getName());\n        return vo;\n    }\n\n    public static CommonTreeNodeVo convertToVo(Department o) {\n        CommonTreeNodeVo vo = new CommonTreeNodeVo();\n        vo.setId(o.getId());\n        vo.setName(o.getName());\n        return vo;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/CorpAppVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport cn.webestar.scms.commons.api.PageVO;\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.jayway.jsonpath.JsonPath;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n@Data\npublic class CorpAppVo extends BasicDO<String> {\n\n    @Schema(description = \"租户ID\")\n    private Long cid;\n\n    @Schema(description = \"租户ID\")\n    private Long appId;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Schema(description = \"图标\")\n    private String icon;\n\n    @Schema(description = \"创建时间\")\n    private LocalDateTime createTime;\n\n    @Schema(description = \"说明\")\n    private String remark;\n\n\n    @Schema(description = \"clientId\")\n    private String clientId;\n\n    @Schema(description = \"\")\n    private String clientSecret;\n\n    @TableField(\"client_name\")\n    @Schema(description = \"\")\n    private String clientName;\n\n    @Schema(description = \"\")\n    private String redirectUris;\n\n    @Schema(description = \"\")\n    private String scopes;\n\n    @Schema(description = \"token有效期，分钟\")\n    private Integer accessTokenTimeToLive;\n\n    public static CorpAppVo convert(Oauth2RegisteredClient o, App app) {\n        CorpAppVo vo = new CorpAppVo();\n        vo.setId(o.getId());\n        vo.setCid(o.getCid());\n        vo.setAppId(o.getAppId());\n        vo.setClientId(o.getClientId());\n//        vo.setClientSecret(o.getClientSecret());\n//        if(!StringUtils.isBlank(o.getClientSecret())){\n//            vo.setClientSecret(\"**********\");\n//        }\n        vo.setClientName(o.getClientName());\n        vo.setRedirectUris(o.getRedirectUris());\n        vo.setScopes(o.getScopes());\n        vo.setName(app.getName());\n        vo.setIcon(app.getIcon());\n        vo.setRemark(app.getRemark());\n        try {\n            Integer accessTokenTimeToLive = JsonPath.read(o.getTokenSettings(), \"$.['settings\\\\.token\\\\.access-token-time-to-live'][1]\");\n            vo.setAccessTokenTimeToLive(accessTokenTimeToLive / 3600);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return vo;\n    }\n\n    public static List<CorpAppVo> convert(List<Oauth2RegisteredClient> os, Map<Long, App> apps) {\n        List<CorpAppVo> vos = new ArrayList<>();\n        os.forEach(i -> {\n            App app = apps.get(i.getAppId());\n            if (app != null) {\n                vos.add(convert(i, app));\n            }\n        });\n        return vos;\n    }\n\n    public static PageVO<CorpAppVo> toPageVo(IPage<Oauth2RegisteredClient> page, Map<Long, App> apps) {\n        List<CorpAppVo> vos = convert(page.getRecords(), apps);\n        PageVO<CorpAppVo> pageVo = new PageVO<>(page.getCurrent(), page.getSize(), page.getTotal(), vos);\n        return pageVo;\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/CorpResourceTreeNodeVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.entity.AppResource;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Data\npublic class CorpResourceTreeNodeVo {\n\n    @Schema(description = \"应用id\")\n    private Long appId;\n    @Schema(description = \"资源id\")\n    private Long rid;\n    @Schema(description = \"1:应用，2：资源\")\n    private Integer type;\n    private String name;\n    private List<CorpResourceTreeNodeVo> children = new ArrayList<>();\n    ;\n\n    public static CorpResourceTreeNodeVo convertToVo(App o) {\n        CorpResourceTreeNodeVo vo = new CorpResourceTreeNodeVo();\n        vo.setAppId(o.getId());\n        vo.setType(1);\n        vo.setName(o.getName());\n        return vo;\n    }\n\n    public static CorpResourceTreeNodeVo convertToVo(AppResource o) {\n        CorpResourceTreeNodeVo vo = new CorpResourceTreeNodeVo();\n        vo.setAppId(o.getAppId());\n        vo.setRid(o.getId());\n        vo.setType(2);\n        vo.setName(o.getName());\n        return vo;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/CorpVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport cn.hiauth.server.entity.Corp;\nimport cn.webestar.scms.commons.api.PageVO;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Data\npublic class CorpVo {\n\n    private Long id;\n    private String name;\n    private String icon;\n    private Integer depCount;\n    private Integer empCount;\n    private Integer appCount;\n    private Integer status;\n\n    public static CorpVo convert(Corp corp) {\n        CorpVo vo = new CorpVo();\n        vo.setId(corp.getId());\n        vo.setName(corp.getName());\n        vo.setIcon(corp.getIcon());\n        vo.setAppCount(corp.getAppCount());\n        vo.setDepCount(corp.getDepCount());\n        vo.setEmpCount(corp.getEmpCount());\n        vo.setStatus(corp.getStatus());\n        return vo;\n    }\n\n    public static List<CorpVo> convert(List<Corp> corps) {\n        List<CorpVo> corpVos = new ArrayList<>();\n        corps.forEach(i -> corpVos.add(convert(i)));\n        return corpVos;\n    }\n\n    public static PageVO<CorpVo> toPageVo(IPage<Corp> page) {\n        List<CorpVo> vos = convert(page.getRecords());\n        PageVO<CorpVo> pageVo = new PageVO<>(page.getCurrent(), page.getSize(), page.getTotal(), vos);\n        return pageVo;\n    }\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/CurrentLoginUserVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n@Data\npublic class CurrentLoginUserVo {\n\n    @Schema(description = \"用户ID\")\n    private Long userId;\n\n    @Schema(description = \"CID\")\n    private Long cid;\n\n    @Schema(description = \"员工id\")\n    private Long empId;\n\n    @Schema(description = \"名称\")\n    private String name;\n    private String realName;\n\n    @Schema(description = \"头像\")\n    private String avatar;\n\n    @Schema(description = \"用户名\")\n    private String username;\n\n//    @Schema(description = \"是否为企业管理员\")\n//    private Boolean isCorpAdmin;\n//\n//    @Schema(description = \"是否为系统管理员\")\n//    private Boolean isSysAdmin;\n\n    @Schema(description = \"角色\")\n    private Set<String> roles = new HashSet<>();\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/EmpVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport cn.hiauth.server.entity.Employee;\nimport cn.hiauth.server.utils.DateTimeUtils;\nimport cn.webestar.scms.commons.api.PageVO;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n@Data\npublic class EmpVo {\n\n    @Schema(description = \"id\")\n    private Long id;\n\n    @Schema(description = \"租户ID\")\n    private Long cid;\n\n    @Schema(description = \"用户id\")\n    private Long userId;\n\n    @Schema(description = \"员工号\")\n    private String no;\n\n    @Schema(description = \"姓名\")\n    private String name;\n\n    @Schema(description = \"邮箱\")\n    private String email;\n\n    @Schema(description = \"创建时间\")\n    private String createTime;\n\n    @Schema(description = \"是否为租户管理员\")\n    private Boolean isCorpAdmin;\n\n    @Schema(description = \"所属部门\")\n    private Set<Long> depIds;\n\n    @Schema(description = \"角色\")\n    private Set<Long> roleIds;\n\n    public static EmpVo convert(Employee o, Set<Long> depIds, Set<Long> roleIds) {\n        EmpVo vo = new EmpVo();\n        vo.setId(o.getId());\n        vo.setCid(o.getCid());\n        vo.setUserId(o.getUserId());\n        vo.setNo(o.getNo());\n        vo.setName(o.getName());\n        vo.setEmail(o.getEmail());\n        vo.setCreateTime(DateTimeUtils.format(o.getCreateTime()));\n        vo.setIsCorpAdmin(o.getIsCorpAdmin());\n        vo.setDepIds(depIds);\n        vo.setRoleIds(roleIds);\n        return vo;\n    }\n\n    public static List<EmpVo> convert(List<Employee> os) {\n        List<EmpVo> vos = new ArrayList<>();\n        os.forEach(i -> vos.add(convert(i, null, null)));\n        return vos;\n    }\n\n    public static PageVO<EmpVo> toPageVo(IPage<Employee> page) {\n        List<EmpVo> vos = convert(page.getRecords());\n        PageVO<EmpVo> pageVo = new PageVO<>(page.getCurrent(), page.getSize(), page.getTotal(), vos);\n        return pageVo;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/IndexCorpAppVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport cn.hiauth.server.entity.CorpAppInfo;\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@Data\npublic class IndexCorpAppVo {\n\n    private Long cid;\n    private String corpName;\n    private List<CorpAppInfo> apps = new ArrayList<>();\n\n    public static List<IndexCorpAppVo> convert(List<CorpAppInfo> cais) {\n        List<IndexCorpAppVo> vos = new ArrayList<>();\n        Map<Long, IndexCorpAppVo> map = new HashMap<>();\n        if (cais != null && !cais.isEmpty()) {\n            cais.forEach(o -> {\n                IndexCorpAppVo cai = map.get(o.getCorpId());\n                if (cai == null) {\n                    cai = new IndexCorpAppVo();\n                    cai.setCid(o.getCorpId());\n                    cai.setCorpName(o.getCorpName());\n                    cai.setApps(new ArrayList<>());\n                    map.put(o.getCorpId(), cai);\n                }\n                cai.getApps().add(o);\n            });\n        }\n        vos = map.values().stream().collect(ArrayList::new, ArrayList::add, ArrayList::addAll);\n        return vos;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/SysMenuVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@Data\npublic class SysMenuVo {\n\n    private String path;\n    private String name;\n    private String redirect;\n    private String component;\n    private Map<String, ?> meta = new HashMap<>();\n    private List<SysMenuVo> children = new ArrayList<>();\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/api/vo/UserVo.java",
    "content": "package cn.hiauth.server.api.vo;\n\nimport cn.hiauth.server.entity.User;\nimport cn.webestar.scms.commons.api.PageVO;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Data\npublic class UserVo {\n\n    @Schema(description = \"id\")\n    private Long id;\n\n    @Schema(description = \"名称\")\n    private String name;\n\n    @Schema(description = \"头像\")\n    private String avatar;\n\n    @Schema(description = \"用户名\")\n    private String username;\n\n    @Schema(description = \"手机号码\")\n    private String phoneNum;\n\n    @Schema(description = \"性别，0：未知，1：男，2：女\")\n    private Integer gender;\n\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    private Integer status;\n\n    @Schema(description = \"注册时间\")\n    private LocalDateTime regtime;\n\n    @Schema(description = \"最后登录时间\")\n    private LocalDateTime lastLoginTime;\n\n    @Schema(description = \"是否为系统管理员\")\n    private Integer isSysAdmin;\n\n    public static UserVo convert(User o) {\n        UserVo vo = new UserVo();\n        vo.setId(o.getId());\n        vo.setName(o.getName());\n        vo.setAvatar(o.getAvatarUrl());\n        vo.setUsername(o.getUsername());\n        vo.setPhoneNum(o.getPhoneNum());\n        vo.setGender(o.getGender());\n        vo.setStatus(o.getStatus());\n        vo.setRegtime(o.getRegtime());\n        vo.setLastLoginTime(o.getLastLoginTime());\n        if (o.getIsSysAdmin() != null && o.getIsSysAdmin()) {\n            vo.setIsSysAdmin(1);\n        } else {\n            vo.setIsSysAdmin(0);\n        }\n        return vo;\n    }\n\n    public static List<UserVo> convert(List<User> os) {\n        List<UserVo> vos = new ArrayList<>();\n        os.forEach(i -> vos.add(convert(i)));\n        return vos;\n    }\n\n    public static PageVO<UserVo> toPageVo(IPage<User> page) {\n        List<UserVo> vos = convert(page.getRecords());\n        PageVO<UserVo> pageVo = new PageVO<>(page.getCurrent(), page.getSize(), page.getTotal(), vos);\n        return pageVo;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/AuthServerConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport cn.hiauth.server.config.web.auth.AuthFailureHandler;\nimport cn.hiauth.server.config.web.auth.CustomJdbcRegisteredClientRepository;\nimport cn.hiauth.server.config.web.auth.CustomOidcUserInfoMapper;\nimport cn.hiauth.server.config.web.auth.FederatedIdentityIdTokenCustomizer;\nimport cn.hiauth.server.config.web.security.MultiAuthUserService;\nimport cn.hiauth.server.utils.jose.Jwks;\nimport cn.webestar.scms.cache.CacheUtil;\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.nimbusds.jose.jwk.JWKSet;\nimport com.nimbusds.jose.jwk.RSAKey;\nimport com.nimbusds.jose.jwk.source.JWKSource;\nimport com.nimbusds.jose.proc.SecurityContext;\nimport jakarta.annotation.Resource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.MediaType;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.support.lob.DefaultLobHandler;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.crypto.factory.PasswordEncoderFactories;\nimport org.springframework.security.jackson2.SecurityJackson2Modules;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.core.oidc.OidcScopes;\nimport org.springframework.security.oauth2.core.oidc.OidcUserInfo;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;\nimport org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;\nimport org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;\nimport org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;\nimport org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;\nimport org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;\nimport org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationContext;\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.ClientSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.TokenSettings;\nimport org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;\nimport org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;\nimport org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Function;\n\n/**\n * 认证授权配置\n */\n@Configuration\npublic class AuthServerConfig {\n\n    @Resource\n    private CacheUtil cacheUtil;\n\n    @Resource\n    private MultiAuthUserService multiAuthUserService;\n\n    @Resource\n    private LoginUrlAuthenticationEntryPoint authenticationEntryPoint;\n\n    /**\n     * Spring Authorization Server 相关配置，主要配置OAuth 2.1和OpenID Connect 1.0\n     */\n    @Bean\n    @Order(Ordered.HIGHEST_PRECEDENCE)\n    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {\n        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer();\n        http\n                .securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())\n                .with(authorizationServerConfigurer, (authorizationServer) ->\n                        authorizationServer\n                                .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint\n                                        //自定义授权页\n                                        .consentPage(\"/oauth2/consent\")\n                                        //自定义授权处理\n                                        //.authorizationResponseHandler(customAuthorizationResponseHandler())\n                                        //自定义异常处理\n                                        .errorResponseHandler(new AuthFailureHandler())\n                                )\n                                //开启OpenID Connect 1.0（其中oidc为OpenID Connect的缩写，默认配置位于OidcUserInfoAuthenticationProvider\n                                .oidc(oidcConfigurer -> oidcConfigurer.userInfoEndpoint(userInfoEndpointConfigurer ->\n                                        userInfoEndpointConfigurer.userInfoMapper(oidcUserInfoMapper())\n                                ))\n                )\n                .authorizeHttpRequests((authorize) ->\n                        authorize.anyRequest().authenticated()\n                )\n                // Redirect to the login page when not authenticated from the authorization endpoint\n                // 将需要认证的请求，重定向到login进行登录认证。\n                .exceptionHandling((exceptions) -> exceptions\n                        // 此处自定义，解决登录失败后，在url中保持client_id参数\n                        .authenticationEntryPoint(authenticationEntryPoint)\n                        .defaultAuthenticationEntryPointFor(\n                                authenticationEntryPoint,\n                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)\n                        )\n                )\n                // Accept access tokens for User Info and/or Client Registration\n                // 使用jwt处理接收到的access token\n                .oauth2ResourceServer((resourceServer) -> resourceServer.jwt(Customizer.withDefaults()));\n                //.oauth2ResourceServer((oauth2ResourceServer) -> oauth2ResourceServer\n                //   .jwt(Customizer.withDefaults()) // 使用jwt\n                //   .authenticationEntryPoint(new MyAuthenticationEntryPoint()) // 请求未携带Token处理\n                //   .accessDeniedHandler(new MyAccessDeniedHandler()) // 权限不足处理\n                //   //.authenticationFailureHandler(this::failureHandler) // Token解析失败处理\n                //);\n        return http.build();\n    }\n\n    /**\n     * jdbc注册客户端管理\n     */\n    @Bean\n    public CustomJdbcRegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {\n        CustomJdbcRegisteredClientRepository registeredClientRepository = new CustomJdbcRegisteredClientRepository(jdbcTemplate);\n        // this.createDemoRegisteredClient(registeredClientRepository);\n        return registeredClientRepository;\n    }\n\n    /**\n     * 授权信息，对应表：oauth2_authorization\n     */\n    @Bean\n    public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {\n        JdbcOAuth2AuthorizationService service = new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);\n        JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper authorizationRowMapper = new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(registeredClientRepository);\n        // 在现代 JDBC 驱动（JDBC 4.0+）中，通常不需要显式设置 LobHandler\n        //authorizationRowMapper.setLobHandler(new DefaultLobHandler());\n        ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();\n        List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);\n        ObjectMapper om = new ObjectMapper();\n        om.registerModules(securityModules);\n        om.registerModule(new OAuth2AuthorizationServerJackson2Module());\n        //om.addMixIn(AuthUser.class, AuthUserMixin.class);\n        //om.addMixIn(AuthGrantedAuthority.class, AuthGrantedAuthorityMixin.class);\n        om.addMixIn(Long.class, Object.class);\n        authorizationRowMapper.setObjectMapper(om);\n        service.setAuthorizationRowMapper(authorizationRowMapper);\n        return service;\n    }\n\n    /**\n     * 授权确认，对应表：oauth2_authorization_consent\n     */\n    @Bean\n    public JdbcOAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {\n        return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);\n    }\n\n\n    @Bean\n    public Function<OidcUserInfoAuthenticationContext, OidcUserInfo> oidcUserInfoMapper() {\n        return new CustomOidcUserInfoMapper(cacheUtil, multiAuthUserService);\n    }\n\n    @Bean\n    public OAuth2TokenCustomizer<JwtEncodingContext> idTokenCustomizer() {\n        return new FederatedIdentityIdTokenCustomizer();\n    }\n\n    /**\n     * 配置 JWK，为JWT(id_token)提供加密密钥，用于加密/解密或签名/验签\n     * JWK详细见：https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key-41\n     */\n    @Bean\n    public JWKSource<SecurityContext> jwkSource() {\n        RSAKey rsaKey = Jwks.generateRsa();\n        JWKSet jwkSet = new JWKSet(rsaKey);\n        return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);\n    }\n\n    /**\n     * 配置jwt解析器\n     */\n    @Bean\n    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {\n        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);\n    }\n\n    /**\n     * 配置认证服务器请求地址\n     */\n    @Bean\n    public AuthorizationServerSettings authorizationServerSettings() {\n        return AuthorizationServerSettings.builder().build();\n    }\n\n    /**\n     * 创建一个客户端供测试\n     */\n    private void createDemoRegisteredClient(JdbcRegisteredClientRepository registeredClientRepository) {\n\n        String clientId = \"himall\";\n        RegisteredClient demoClient = registeredClientRepository.findByClientId(clientId);\n\n        if (demoClient != null) {\n            return;\n        }\n\n        // JWT（Json Web Token）的配置项：TTL、是否复用refrechToken等等\n        TokenSettings tokenSettings = TokenSettings.builder()\n                // 令牌存活时间：10小时\n                .accessTokenTimeToLive(Duration.ofHours(10))\n                .authorizationCodeTimeToLive(Duration.ofMinutes(10))\n                // 令牌可以刷新，重新获取\n                .reuseRefreshTokens(true)\n                // 刷新时间：30天（30天内当令牌过期时，可以用刷新令牌重新申请新令牌，不需要再认证）\n                .refreshTokenTimeToLive(Duration.ofDays(30))\n                .build();\n        // 客户端相关配置\n        ClientSettings clientSettings = ClientSettings.builder()\n                // 是否需要用户授权确认\n                .requireAuthorizationConsent(true)\n                .setting(\"cid\", \"1\")\n                .build();\n\n        demoClient = RegisteredClient.withId(UUID.randomUUID().toString())\n                .clientName(\"himall\")\n                .clientId(clientId)\n                .clientSecret(PasswordEncoderFactories.createDelegatingPasswordEncoder().encode(\"123456\"))\n                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)\n                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)\n                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)\n                .redirectUri(\"http://127.0.0.1:9000/login/oauth2/code/hiauth-code\")\n                .redirectUri(\"http://localhost:9000/login/oauth2/code/hiauth-code\")\n                .scope(OidcScopes.OPENID)\n                .scope(OidcScopes.PROFILE)\n                .scope(\"openid\")\n                .scope(\"profile\")\n                .scope(\"user\")\n                // JWT（Json Web Token）配置项\n                .tokenSettings(tokenSettings)\n                // 客户端配置项\n                .clientSettings(clientSettings)\n                .build();\n\n        registeredClientRepository.save(demoClient);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/BeanConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport cn.hiauth.server.config.rest.security.ReadonlyFilter;\nimport cn.hiauth.server.utils.AliyunSmsUtils;\nimport cn.hiauth.server.utils.SmsUtils;\nimport cn.hutool.captcha.generator.RandomGenerator;\nimport com.fasterxml.jackson.databind.ser.std.ToStringSerializer;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.client.RestTemplate;\n\n@Slf4j\n@Configuration\npublic class BeanConfig {\n\n    @Value(\"${app.readonly.account:}\")\n    private String readonlyAccount;\n\n    @Value(\"${app.login.baseImageChar:}\")\n    private String baseImageChar;\n\n    @Value(\"${smsUils.accessKeyId:}\")\n    private String accessKeyId;\n\n    @Value(\"${smsUils.accessKeySecret:}\")\n    private String accessKeySecret;\n\n    @Value(\"${smsUils.endpoint:dysmsapi.aliyuncs.com}\")\n    private String endpoint;\n\n    @Value(\"${smsUils.sign:}\")\n    private String sign;\n\n    @Bean\n    public RestTemplate restTemplate() {\n        return new RestTemplate();\n    }\n\n    /**\n     * 验证码生成器，用于图形验证码生成\n     */\n    @Bean\n    public RandomGenerator randomGenerator() {\n        return new RandomGenerator(baseImageChar, 4);\n    }\n\n    /**\n     * 短信发送工具类\n     */\n    @Bean\n    public SmsUtils smsUtils() {\n        return new AliyunSmsUtils(accessKeyId, accessKeySecret, endpoint, sign);\n    }\n\n    /**\n     * 解决将Long类型转成String\n     */\n    @Bean\n    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {\n        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder\n                .serializerByType(Long.class, ToStringSerializer.instance)\n                .serializerByType(Long.TYPE, ToStringSerializer.instance);\n    }\n\n    /**\n     * 只读过滤器，配置中申明的账号只有读权限\n     */\n    @Bean\n    @ConditionalOnProperty(prefix = \"app.readonly\", name = \"account\")\n    public FilterRegistrationBean<ReadonlyFilter> readOnlyFilterRegister() {\n        FilterRegistrationBean<ReadonlyFilter> registration = new FilterRegistrationBean<>();\n        registration.setOrder(1001);\n        registration.setFilter(new ReadonlyFilter(readonlyAccount.split(\",\")));\n        registration.setName(\"readonlyFilter\");\n        registration.addUrlPatterns(\"/api/*\");\n        log.info(\"Register ReadonlyFilter,url={}\", \"/api/*\");\n        return registration;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/DocConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport io.swagger.v3.oas.models.OpenAPI;\nimport io.swagger.v3.oas.models.info.Contact;\nimport io.swagger.v3.oas.models.info.Info;\nimport io.swagger.v3.oas.models.info.License;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class DocConfig {\n\n    @Bean\n    public OpenAPI openApi() {\n        return new OpenAPI()\n                .info(new Info()\n                        .title(\"HiAuth接口文档\")\n                        .version(\"v3\")\n                        .description(\"提供HiAuth的业务接口\")\n                        .contact(new Contact()\n                                .name(\"技术支持\")\n                                .url(\"http://hiauth.cn\")\n                                .email(\"bestaone@163.com\"))\n                        .license(new License()\n                                .name(\"MIT License\")\n                                .url(\"http://hiauth.cn\")));\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/SecurityConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport cn.hiauth.server.config.web.security.*;\nimport cn.hiauth.server.config.web.security.account.AccountAuthenticationFilter;\nimport cn.hiauth.server.config.web.security.account.AccountAuthenticationProvider;\nimport cn.hiauth.server.config.web.security.phone.SmsCodeAuthenticationFilter;\nimport cn.hiauth.server.config.web.security.phone.SmsCodeAuthenticationProvider;\nimport cn.hiauth.server.config.web.security.wechat.QrCodeAuthenticationFilter;\nimport cn.hiauth.server.config.web.security.wechat.QrCodeAuthenticationProvider;\nimport cn.hiauth.server.mapper.AppMapper;\nimport cn.webestar.scms.cache.CacheUtil;\nimport jakarta.annotation.Resource;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.authentication.ProviderManager;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.password.DelegatingPasswordEncoder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;\nimport org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;\nimport org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;\nimport org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;\nimport org.springframework.security.web.context.DelegatingSecurityContextRepository;\nimport org.springframework.security.web.context.HttpSessionSecurityContextRepository;\nimport org.springframework.security.web.context.RequestAttributeSecurityContextRepository;\nimport org.springframework.security.web.context.SecurityContextRepository;\nimport org.springframework.security.web.savedrequest.HttpSessionRequestCache;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 安全管理配置\n */\n@Configuration(proxyBeanMethods = true)\n@EnableWebSecurity\n@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)\npublic class SecurityConfig {\n\n    @Value(\"${smsUils.superSmsCode:}\")\n    private String superSmsCode;\n\n    @Resource\n    private CacheUtil cacheUtil;\n\n    @Resource\n    private MultiAuthUserService multiAuthUserService;\n\n    @Resource\n    private AppMapper appMapper;\n\n    @Bean\n    public PasswordEncoder passwordEncoder() {\n        String encodingId = \"bcrypt\";\n        Map<String, PasswordEncoder> encoders = new HashMap<>(8);\n        encoders.put(encodingId, new BCryptPasswordEncoder());\n        return new DelegatingPasswordEncoder(encodingId, encoders);\n    }\n\n    @Bean\n    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n        http.authorizeHttpRequests(auth -> auth\n                        .requestMatchers(\"/login\").permitAll()\n                        .anyRequest().authenticated()\n                )\n                .cors(Customizer.withDefaults())\n                // 跨站攻击防护，默认开启，两个登录的应用先后退出，第二个退出操作会导致前一个退出后的登录页面中的csrf token失效\n                // 禁用csrf能够解决这个问题，但是会带来安全风险，所以这里不禁用\n                //.csrf(AbstractHttpConfigurer::disable)\n                //.formLogin(Customizer.withDefaults())\n                // 用户名密码登录配置\n                .formLogin(form -> form\n                        .loginPage(\"/login\")\n                        .loginProcessingUrl(\"/account/doLogin\")\n                        .permitAll()\n                )\n                .formLogin(form -> form\n                        .loginPage(\"/login\")\n                        .loginProcessingUrl(\"/phone/doLogin\")\n                        .permitAll()\n                )\n                .exceptionHandling(exceptions -> exceptions\n                        // 此处添加AuthenticationEntryPoint，会在登录失败后被执行\n                        // 此处自定义，解决登录失败后，在url中保持client_id参数\n                        .authenticationEntryPoint(authenticationEntryPoint())\n                )\n                // 用户名证码认证过滤器\n                .addFilterBefore(accountAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)\n                // 添加手机验证码认证过滤器\n                .addFilterBefore(smsCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)\n                // 微信二维码登录认证过滤器\n                .addFilterBefore(qrCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)\n                // 设置全局authenticationManager\n                .authenticationManager(authenticationManager())\n                // 设置全局securityContextRepository\n                .securityContext(c -> c.securityContextRepository(securityContextRepository()));\n        return http.build();\n    }\n\n    /**\n     * 定义securityContextRepository，加入两种securityContextRepository\n     */\n    @Bean\n    public SecurityContextRepository securityContextRepository() {\n        HttpSessionSecurityContextRepository httpSecurityRepository = new HttpSessionSecurityContextRepository();\n        return new DelegatingSecurityContextRepository(httpSecurityRepository, new RequestAttributeSecurityContextRepository());\n    }\n\n    /**\n     * 自定义登录成功处理器\n     */\n    @Bean\n    public SavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler() {\n        SavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler = new CustomAuthenticationSuccessHandler();\n        authenticationSuccessHandler.setRequestCache(httpSessionRequestCache());\n        return authenticationSuccessHandler;\n    }\n\n    /**\n     * 自定义登录失败处理器\n     */\n    @Bean\n    public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() {\n        return new CustomAuthenticationFailureHandler(\"/login?error\");\n    }\n\n    /**\n     * 自定义自定义登录页面\n     */\n    @Bean\n    public LoginUrlAuthenticationEntryPoint authenticationEntryPoint() {\n        return new CustomLoginUrlAuthenticationEntryPoint(\"/login\");\n    }\n\n    /**\n     * 请求缓存\n     */\n    @Bean\n    public HttpSessionRequestCache httpSessionRequestCache() {\n        HttpSessionRequestCache requestCache = new MultiAppHttpSessionRequestCache();\n        requestCache.setMatchingRequestParameterName(\"continue\");\n        return requestCache;\n    }\n\n    /**\n     * 账号登录过滤器\n     */\n    @Bean\n    public AccountAuthenticationFilter accountAuthenticationFilter() {\n        AccountAuthenticationFilter accountAuthenticationFilter = new AccountAuthenticationFilter(\"/account/doLogin\");\n        accountAuthenticationFilter.setAuthenticationManager(authenticationManager());\n        accountAuthenticationFilter.setSecurityContextRepository(securityContextRepository());\n        accountAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());\n        accountAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler());\n        return accountAuthenticationFilter;\n    }\n\n    /**\n     * 手机验证码登录过滤器\n     */\n    @Bean\n    public SmsCodeAuthenticationFilter smsCodeAuthenticationFilter() {\n        SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter(\"/phone/doLogin\");\n        smsCodeAuthenticationFilter.setAuthenticationManager(authenticationManager());\n        smsCodeAuthenticationFilter.setSecurityContextRepository(securityContextRepository());\n        smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());\n        smsCodeAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler());\n        return smsCodeAuthenticationFilter;\n    }\n\n    /**\n     * 微信二维码登录过滤器\n     */\n    @Bean\n    public QrCodeAuthenticationFilter qrCodeAuthenticationFilter() {\n        QrCodeAuthenticationFilter qrCodeAuthenticationFilter = new QrCodeAuthenticationFilter(\"/wechat/qrcode/doLogin\");\n        qrCodeAuthenticationFilter.setAuthenticationManager(authenticationManager());\n        qrCodeAuthenticationFilter.setSecurityContextRepository(securityContextRepository());\n        qrCodeAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());\n        qrCodeAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler());\n        return qrCodeAuthenticationFilter;\n    }\n\n    @Bean\n    public AuthenticationManager authenticationManager() {\n        // 账号登录provider\n        AccountAuthenticationProvider accountAuthenticationProvider = new AccountAuthenticationProvider();\n        accountAuthenticationProvider.setPasswordEncoder(passwordEncoder());\n        accountAuthenticationProvider.setHttpSessionRequestCache(httpSessionRequestCache());\n        accountAuthenticationProvider.setCacheUtil(cacheUtil);\n        accountAuthenticationProvider.setUserDetailsService(multiAuthUserService);\n        accountAuthenticationProvider.setAppMapper(appMapper);\n        // 手机验证码登录provider\n        SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider();\n        smsCodeAuthenticationProvider.setHttpSessionRequestCache(httpSessionRequestCache());\n        smsCodeAuthenticationProvider.setCacheUtil(cacheUtil);\n        smsCodeAuthenticationProvider.setUserDetailsService(multiAuthUserService);\n        smsCodeAuthenticationProvider.setSuperSmsCode(superSmsCode);\n        smsCodeAuthenticationProvider.setAppMapper(appMapper);\n        // 微信二维码登录provider\n        QrCodeAuthenticationProvider qrCodeAuthenticationProvider = new QrCodeAuthenticationProvider();\n        qrCodeAuthenticationProvider.setHttpSessionRequestCache(httpSessionRequestCache());\n        qrCodeAuthenticationProvider.setUserDetailsService(multiAuthUserService);\n        qrCodeAuthenticationProvider.setAppMapper(appMapper);\n        return new ProviderManager(accountAuthenticationProvider, smsCodeAuthenticationProvider, qrCodeAuthenticationProvider);\n    }\n\n    /**\n     * 不走过滤器链的放行配置\n     */\n    @Bean\n    public WebSecurityCustomizer webSecurityCustomizer() {\n        return (web) -> web.ignoring().requestMatchers(\n                AntPathRequestMatcher.antMatcher(\"/api/**\"),\n                AntPathRequestMatcher.antMatcher(\"/unpapi/**\"),\n                AntPathRequestMatcher.antMatcher(\"/auth/code/image\"),\n                AntPathRequestMatcher.antMatcher(\"/auth/code/captcha\"),\n                AntPathRequestMatcher.antMatcher(\"/auth/code/sms\"),\n                AntPathRequestMatcher.antMatcher(\"/actuator/**\"),\n                AntPathRequestMatcher.antMatcher(\"/static/**\"),\n                AntPathRequestMatcher.antMatcher(\"/favicon.ico\"),\n                AntPathRequestMatcher.antMatcher(\"/webjars/**\"),\n                AntPathRequestMatcher.antMatcher(\"/doc.html\"),\n                AntPathRequestMatcher.antMatcher(\"/swagger-resources/**\"),\n                AntPathRequestMatcher.antMatcher(\"/v3/api-docs/**\"),\n                AntPathRequestMatcher.antMatcher(\"/swagger-ui/**\"),\n                AntPathRequestMatcher.antMatcher(\"/docs/**\")\n        );\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/WebMvcConfig.java",
    "content": "package cn.hiauth.server.config;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.CacheControl;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport java.util.concurrent.TimeUnit;\n\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n\n    @Value(\"${app.cacheControl.maxAge:0}\")\n    private Integer maxAge;\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/static/**\", \"/webjars/**\")\n                .addResourceLocations(\"classpath:/static/\", \"classpath:/META-INF/resources/webjars/\")\n                .setCacheControl(CacheControl.maxAge(maxAge, TimeUnit.HOURS).cachePrivate());\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/props/AppProperties.java",
    "content": "package cn.hiauth.server.config.props;\n\nimport lombok.Data;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.io.Serializable;\nimport java.util.Set;\n\n@Data\n@Configuration\npublic class AppProperties implements Serializable {\n\n    @Value(value = \"${loginPage.title:统一认证中心}\")\n    private String loginPageTitle;\n\n    @Value(value = \"${loginPage.path:login}\")\n    private String loginPagePath;\n\n    @Value(value = \"${loginPage.username:}\")\n    private String loginPageUsername;\n\n    @Value(value = \"${loginPage.password:}\")\n    private String loginPagePassword;\n\n    @Value(value = \"${loginPage.usernamePlaceholder:用户名}\")\n    private String loginPageUsernamePlaceholder;\n\n    @Value(value = \"${loginPage.passwordPlaceholder:密码}\")\n    private String loginPagePasswordPlaceholder;\n\n    @Value(value = \"${loginPage.loginTypes:phone,account}\")\n    private Set<String> loginTypes;\n\n    /**\n     * 公钥\n     */\n    @Value(\"${scms.security.publicKey:}\")\n    private String publicKey;\n\n    /**\n     * 加密类型 NONE、RSA\n     */\n    @Value(\"${scms.security.encryptType:NONE}\")\n    private String encryptType;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/props/WechatProperties.java",
    "content": "package cn.hiauth.server.config.props;\n\nimport lombok.Data;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.io.Serializable;\n\n@Data\n@Configuration\npublic class WechatProperties implements Serializable {\n\n    @Value(value = \"${wechat.open.appid:}\")\n    private String appid;\n\n    @Value(value = \"${wechat.open.appSecret:}\")\n    private String appSecret;\n\n    @Value(value = \"${wechat.open.redirectUri:}\")\n    private String redirectUri;\n\n    @Value(value = \"${wechat.open.style:}\")\n    private String style;\n\n    @Value(value = \"${wechat.open.href:}\")\n    private String href;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/rest/ApiExceptionAdvice.java",
    "content": "package cn.hiauth.server.config.rest;\n\nimport cn.webestar.scms.commons.CommonException;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport jakarta.annotation.PostConstruct;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.validation.ConstraintViolation;\nimport jakarta.validation.ConstraintViolationException;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.validation.BindException;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.ObjectError;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\nimport java.nio.file.AccessDeniedException;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * @author zgs\n */\n@Slf4j\n@RestControllerAdvice(annotations = ResourceApi.class, basePackages = \"cn.webestar.scms.security.controller\")\npublic class ApiExceptionAdvice {\n\n    private static final String ERROR_MSG = \"系统异常\";\n\n    @Value(\"${spring.profiles.active:pro}\")\n    private String profile;\n\n    private Boolean showErrorMsg = false;\n\n    @PostConstruct\n    public void init() {\n        showErrorMsg = \"dev\".equals(profile);\n    }\n\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(BindException.class)\n    public R<?> handle(HttpServletRequest request, BindException e) {\n        logger(request, e);\n        List<ObjectError> allErrors = e.getAllErrors();\n        ObjectError objectError = allErrors.get(0);\n        return R.fail(showErrorMsg ? objectError.getDefaultMessage() : ERROR_MSG);\n    }\n\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public R<CommonException> handle(HttpServletRequest request, MethodArgumentNotValidException e) {\n        logger(request, e);\n        StringBuilder msg = new StringBuilder(\"参数不合法：\");\n        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();\n        for (ObjectError oe : allErrors) {\n            if (oe instanceof FieldError) {\n                msg.append(((FieldError) oe).getField()).append(oe.getDefaultMessage()).append(\", \");\n            } else {\n                msg.append(oe.toString()).append(\", \");\n            }\n        }\n        return R.fail(new CommonException(10450, showErrorMsg ? msg.toString() : ERROR_MSG));\n    }\n\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(ConstraintViolationException.class)\n    public R<CommonException> handle(HttpServletRequest request, ConstraintViolationException e) {\n        logger(request, e);\n        StringBuilder msg = new StringBuilder(\"参数不合法：\");\n        Set<ConstraintViolation<?>> cvs = e.getConstraintViolations();\n        for (ConstraintViolation<?> cv : cvs) {\n            msg.append(cv.getMessage()).append(\", \");\n        }\n        return R.fail(new CommonException(10450, showErrorMsg ? msg.toString() : ERROR_MSG));\n    }\n\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(Exception.class)\n    public R<CommonException> handle(HttpServletRequest request, Exception e) {\n        logger(request, e);\n        CommonException ce = null;\n        if (e instanceof CommonException) {\n            ce = (CommonException) e;\n        } else {\n            ce = new CommonException(SysCode.ERROR.getCode(), showErrorMsg ? e.getMessage() : ERROR_MSG);\n        }\n        return R.fail(ce);\n    }\n\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(CommonException.class)\n    public R<CommonException> handle(HttpServletRequest request, CommonException e) {\n        logger(request, e);\n        return R.fail(e);\n    }\n\n    @ResponseStatus(HttpStatus.OK)\n    @ExceptionHandler(AccessDeniedException.class)\n    public R<CommonException> handle(HttpServletRequest request, AccessDeniedException e) {\n        logger(request, e);\n        return R.fail(new CommonException(40006, \"权限不足.\"));\n    }\n\n    private void logger(HttpServletRequest request, Exception e) {\n        log.warn(\"ERROR URI: {}, exception: {}\", request.getRequestURI(), e.getMessage());\n        log.debug(e.getMessage(), e);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/rest/ResourceAccessDeniedHandler.java",
    "content": "package cn.hiauth.server.config.rest;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;\nimport org.springframework.security.web.access.AccessDeniedHandler;\n\nimport java.io.IOException;\n\npublic class ResourceAccessDeniedHandler implements AccessDeniedHandler {\n    @Override\n    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {\n        if (request.getUserPrincipal() instanceof AbstractOAuth2TokenAuthenticationToken<?>) {\n            ResourceAuthenticationEntryPoint.printError(response, \"权限不足\");\n        } else {\n            ResourceAuthenticationEntryPoint.printError(response, accessDeniedException.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/rest/ResourceApi.java",
    "content": "package cn.hiauth.server.config.rest;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ResourceApi {\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/rest/ResourceAuthenticationEntryPoint.java",
    "content": "package cn.hiauth.server.config.rest;\n\nimport cn.webestar.scms.commons.SysCode;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.web.AuthenticationEntryPoint;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\npublic class ResourceAuthenticationEntryPoint implements AuthenticationEntryPoint {\n\n    private final static String ERROR_RESULT = \"{ \\\"code\\\": %d, \\\"message\\\": \\\"%s\\\" }\";\n\n    public static void printError(HttpServletResponse response, String msg) {\n\n        response.setContentType(\"application/json;charset=utf-8\");\n        response.setStatus(HttpServletResponse.SC_OK);\n\n        Integer code = SysCode.ERROR.getCode();\n\n        PrintWriter out = null;\n        try {\n            out = response.getWriter();\n            out.write(String.format(ERROR_RESULT, code, msg));\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        } finally {\n            if (out != null) {\n                out.flush();\n                out.close();\n            }\n        }\n\n    }\n\n    @Override\n    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {\n\n        printError(response, \"令牌无效或已过期\");\n\n//        if (authException instanceof InsufficientAuthenticationException) {\n//            String accept = request.getHeader(\"accept\");\n//            if (accept.contains(MediaType.TEXT_HTML_VALUE)) {\n//                //如果是html请求类型，则返回登录页\n//                LoginUrlAuthenticationEntryPoint loginUrlAuthenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(\"/login\");\n//                loginUrlAuthenticationEntryPoint.commence(request, response, authException);\n//            } else {\n//                printError(response, \"需要带上令牌进行访问\");\n//            }\n//        } else if (authException instanceof InvalidBearerTokenException) {\n//            printError(response, \"令牌无效或已过期\");\n//        } else {\n//            printError(response, authException.getMessage());\n//        }\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/rest/security/ApiFilter.java",
    "content": "package cn.hiauth.server.config.rest.security;//package cn.hiauth.server.config.apilogin;\n//\n//import jakarta.servlet.Filter;\n//import jakarta.servlet.FilterChain;\n//import jakarta.servlet.ServletRequest;\n//import jakarta.servlet.ServletResponse;\n//import jakarta.servlet.http.HttpServletRequest;\n//import jakarta.servlet.http.HttpServletResponse;\n//import lombok.extern.slf4j.Slf4j;\n//\n///**\n// * @author zgs\n// */\n//@Slf4j\n//public class ApiFilter implements Filter {\n//\n//    @Override\n//    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) {\n//        final HttpServletRequest request = (HttpServletRequest) servletRequest;\n//        final HttpServletResponse response = (HttpServletResponse) servletResponse;\n//        try {\n//            chain.doFilter(request, response);\n//        } catch (Exception e) {\n//            e.printStackTrace();\n//        }\n//    }\n//\n//\n//}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/rest/security/MySecurityUser.java",
    "content": "package cn.hiauth.server.config.rest.security;\n\nimport cn.webestar.scms.security.SecurityUser;\nimport lombok.Data;\n\n@Data\npublic class MySecurityUser extends SecurityUser {\n\n    private Boolean isCorpAdmin;\n    private Boolean isSysAdmin;\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/rest/security/ReadonlyFilter.java",
    "content": "package cn.hiauth.server.config.rest.security;\n\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.CommonException;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.security.Constant;\nimport cn.webestar.scms.security.SecurityUser;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport jakarta.servlet.*;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.util.AntPathMatcher;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.List;\n\n/**\n * @author zgs\n */\n@Slf4j\npublic class ReadonlyFilter implements Filter {\n\n    public final static List<String> EDIT_KEY = List.of(\"/**/*create*\", \"/**/*update*\", \"/**/*delete*\", \"/**/*upload*\");\n    private final static String ERROR_RESULT = \"{ \\\"code\\\": %d, \\\"message\\\": \\\"%s\\\" }\";\n    private final AntPathMatcher matcher = new AntPathMatcher();\n    public String[] readonlyAccount;\n\n    public ReadonlyFilter(String[] readonlyAccount) {\n        this.readonlyAccount = readonlyAccount;\n    }\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n        Filter.super.init(filterConfig);\n    }\n\n    @Override\n    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) {\n        final HttpServletRequest request = (HttpServletRequest) servletRequest;\n        final HttpServletResponse response = (HttpServletResponse) servletResponse;\n        try {\n            doIt(request, response, chain);\n        } catch (Exception e) {\n            printError(request, response, e);\n        }\n    }\n\n    private void doIt(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws Exception {\n\n        if (Constant.IGNORE_METHOD.equalsIgnoreCase(request.getMethod())) {\n            chain.doFilter(request, response);\n            return;\n        }\n\n        SecurityUser securityUser = SessionContextHolder.getPrincipal();\n        if (securityUser == null) {\n            chain.doFilter(request, response);\n            return;\n        }\n\n        String username = securityUser.getUsername();\n        if (username == null) {\n            chain.doFilter(request, response);\n            return;\n        }\n\n        boolean matcherAccount = matcherAccount(username);\n        if (matcherAccount) {\n            boolean readOnly = readOnlyUrl(request.getRequestURI());\n            Assert.isTrue(readOnly, SysCode.ERROR.getCode(), \"此账号为只读账号，不能修改数据\");\n        }\n        chain.doFilter(request, response);\n    }\n\n    public boolean matcherAccount(String username) {\n        for (String account : readonlyAccount) {\n            if (matcher.match(account, username)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public boolean readOnlyUrl(String uri) {\n        for (String key : EDIT_KEY) {\n            if (matcher.match(key, uri)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private void printError(HttpServletRequest request, HttpServletResponse response, Exception e) {\n        log.error(e.getMessage(), e);\n        Integer code = SysCode.ERROR.getCode();\n        String msg;\n        if (e instanceof CommonException ce) {\n            code = ce.getCode();\n            msg = e.getMessage();\n        } else {\n            msg = \"系统异常\";\n        }\n        response.setContentType(\"application/json;charset=utf-8\");\n        response.setStatus(HttpServletResponse.SC_OK);\n        PrintWriter out = null;\n        try {\n            out = response.getWriter();\n            out.write(String.format(ERROR_RESULT, code, msg));\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        } finally {\n            if (out != null) {\n                out.flush();\n                out.close();\n            }\n        }\n    }\n\n    @Override\n    public void destroy() {\n        Filter.super.destroy();\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/AuthFailureHandler.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.webestar.scms.commons.R;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationException;\nimport org.springframework.security.web.authentication.AuthenticationFailureHandler;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\npublic class AuthFailureHandler implements AuthenticationFailureHandler {\n\n    @Override\n    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {\n        String errorMsg = \"UNKNOW\";\n        if (exception instanceof OAuth2AuthorizationCodeRequestAuthenticationException ex) {\n            String description = ex.getError().getDescription();\n            if (description != null && description.contains(\"redirect_uri\")) {\n                errorMsg = \"未授权的回调地址，请检查redirect_uri参数\";\n            } else {\n                errorMsg = ex.getMessage();\n            }\n        }\n        response.setContentType(MediaType.APPLICATION_JSON_VALUE);\n        response.setCharacterEncoding(StandardCharsets.UTF_8.name());\n        String json = JSONUtil.toJsonStr(R.fail(50000, errorMsg));\n        response.getWriter().write(json);\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/AuthGrantedAuthority.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\nimport com.fasterxml.jackson.databind.annotation.JsonDeserialize;\nimport lombok.Data;\nimport org.springframework.security.core.GrantedAuthority;\n\n@Data\n@JsonDeserialize(using = AuthGrantedAuthorityDeserializer.class)\npublic class AuthGrantedAuthority implements GrantedAuthority {\n\n    private String code;\n    private String page;\n    private String api;\n\n    public AuthGrantedAuthority() {\n    }\n\n    public AuthGrantedAuthority(String authority) {\n        this.code = authority;\n    }\n\n    public AuthGrantedAuthority(String code, String page, String api) {\n        this.code = code;\n        this.page = page;\n        this.api = api;\n    }\n\n    @Override\n    public String getAuthority() {\n        return code;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/AuthGrantedAuthorityDeserializer.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonDeserializer;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.node.MissingNode;\n\nimport java.io.IOException;\n\npublic class AuthGrantedAuthorityDeserializer extends JsonDeserializer<AuthGrantedAuthority> {\n\n    @Override\n    public AuthGrantedAuthority deserialize(JsonParser jp, DeserializationContext ctx) throws IOException {\n        ObjectMapper mapper = (ObjectMapper) jp.getCodec();\n        JsonNode jsonNode = mapper.readTree(jp);\n        String code = readJsonNode(jsonNode, \"code\").asText();\n        String page = readJsonNode(jsonNode, \"page\").asText();\n        String api = readJsonNode(jsonNode, \"api\").asText();\n        return new AuthGrantedAuthority(code, page, api);\n    }\n\n    private JsonNode readJsonNode(JsonNode jsonNode, String field) {\n        return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/AuthGrantedAuthorityMixin.java",
    "content": "//package cn.hiauth.server.config.web.auth;\n//\n//import com.fasterxml.jackson.annotation.JsonAutoDetect;\n//import com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n//import com.fasterxml.jackson.annotation.JsonTypeInfo;\n//import com.fasterxml.jackson.databind.annotation.JsonDeserialize;\n//\n//@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)\n//@JsonDeserialize(using = AuthGrantedAuthorityDeserializer.class)\n//@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)\n//@JsonIgnoreProperties(ignoreUnknown = true)\n//public abstract class AuthGrantedAuthorityMixin {\n//\n//}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/AuthUser.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\nimport cn.hiauth.server.entity.Employee;\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport cn.hiauth.server.entity.User;\nimport com.fasterxml.jackson.databind.annotation.JsonDeserialize;\nimport lombok.Data;\nimport org.springframework.security.core.CredentialsContainer;\nimport org.springframework.security.core.userdetails.UserDetails;\n\nimport java.util.Collection;\n\n@Data\n@JsonDeserialize(using = AuthUserDeserializer.class)\npublic class AuthUser implements UserDetails, CredentialsContainer {\n\n    private Long appId;\n    private Long cid;\n    private Long userId;\n    private Long empId;\n    private String name;\n    private String username;\n    private String password;\n    private String phoneNum;\n    private String avatarUrl;\n    private Collection<AuthGrantedAuthority> authorities;\n    private Boolean isCorpAdmin;\n    private Boolean isSysAdmin;\n\n    public AuthUser() {\n    }\n\n    public AuthUser(final Oauth2RegisteredClient client, final User user, final Employee employee, final Collection<AuthGrantedAuthority> authorities) {\n        if (client != null) {\n            this.appId = client.getAppId();\n        }\n        if (employee != null) {\n            this.empId = employee.getId();\n            this.cid = employee.getCid();\n            this.isCorpAdmin = employee.getIsCorpAdmin();\n        }\n        this.userId = user.getId();\n        this.name = user.getName();\n        this.username = user.getUsername();\n        this.password = user.getPwd();\n        this.phoneNum = user.getPhoneNum();\n        this.avatarUrl = user.getAvatarUrl();\n        this.isSysAdmin = user.getIsSysAdmin();\n        this.authorities = authorities;\n    }\n\n    public AuthUser(Long appId, Long cid, Long userId, Long empId, String name, String username, String password, String phoneNum, String avatarUrl, Boolean isSysAdmin, Collection<AuthGrantedAuthority> authorities, Boolean isCorpAdmin) {\n        this.appId = appId;\n        this.cid = cid;\n        this.userId = userId;\n        this.empId = empId;\n        this.name = name;\n        this.username = username;\n        this.password = password;\n        this.phoneNum = phoneNum;\n        this.avatarUrl = avatarUrl;\n        this.isSysAdmin = isSysAdmin;\n        this.authorities = authorities;\n        this.isCorpAdmin = isCorpAdmin;\n    }\n\n    @Override\n    public void eraseCredentials() {\n        this.password = null;\n    }\n\n    @Override\n    public Collection<AuthGrantedAuthority> getAuthorities() {\n        return authorities;\n    }\n\n    @Override\n    public String getPassword() {\n        return password;\n    }\n\n    @Override\n    public String getUsername() {\n        return username;\n    }\n\n    @Override\n    public boolean isAccountNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isAccountNonLocked() {\n        return true;\n    }\n\n    @Override\n    public boolean isCredentialsNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return true;\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/AuthUserDeserializer.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonDeserializer;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.node.MissingNode;\n\nimport java.io.IOException;\nimport java.util.Set;\n\npublic class AuthUserDeserializer extends JsonDeserializer<AuthUser> {\n\n    private static final TypeReference<Set<AuthGrantedAuthority>> AUTHORITY_SET = new TypeReference<>() {\n    };\n\n    @Override\n    public AuthUser deserialize(JsonParser jp, DeserializationContext ctx) throws IOException {\n        ObjectMapper mapper = (ObjectMapper) jp.getCodec();\n        JsonNode jsonNode = mapper.readTree(jp);\n        Long appId = readJsonNode(jsonNode, CustomAuthUserAttrs.APP_ID).asLong();\n        Long cid = readJsonNode(jsonNode, CustomAuthUserAttrs.CID).asLong();\n        Long userId = readJsonNode(jsonNode, CustomAuthUserAttrs.USER_ID).asLong();\n        Long empId = readJsonNode(jsonNode, CustomAuthUserAttrs.EMP_ID).asLong();\n        String name = readJsonNode(jsonNode, CustomAuthUserAttrs.NAME).asText();\n        String username = readJsonNode(jsonNode, CustomAuthUserAttrs.USERNAME).asText();\n        String phoneNum = readJsonNode(jsonNode, CustomAuthUserAttrs.PHONE_NUM).asText();\n        String avatarUrl = readJsonNode(jsonNode, CustomAuthUserAttrs.AVATAR_URL).asText();\n        Boolean isSysAdmin = readJsonNode(jsonNode, CustomAuthUserAttrs.IS_SYS_ADMIN).asBoolean();\n        Boolean isCorpAdmin = readJsonNode(jsonNode, CustomAuthUserAttrs.IS_CORP_ADMIN).asBoolean();\n\n        Set<AuthGrantedAuthority> authorities = mapper.convertValue(jsonNode.get(CustomAuthUserAttrs.AUTHORITIES), AUTHORITY_SET);\n\n        JsonNode passwordNode = readJsonNode(jsonNode, \"password\");\n        String password = passwordNode.asText(\"\");\n\n        return new AuthUser(appId, cid, userId, empId, name, username, password, phoneNum, avatarUrl, isSysAdmin, authorities, isCorpAdmin);\n    }\n\n    private JsonNode readJsonNode(JsonNode jsonNode, String field) {\n        return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/AuthUserMixin.java",
    "content": "//package cn.hiauth.server.config.web.auth;\n//\n//import com.fasterxml.jackson.annotation.JsonAutoDetect;\n//import com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n//import com.fasterxml.jackson.annotation.JsonTypeInfo;\n//import com.fasterxml.jackson.databind.annotation.JsonDeserialize;\n//\n//@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)\n//@JsonDeserialize(using = AuthUserDeserializer.class)\n//@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)\n//@JsonIgnoreProperties(ignoreUnknown = true)\n//public abstract class AuthUserMixin {\n//}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/CustomAuthUserAttrs.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\npublic class CustomAuthUserAttrs {\n\n    public static final String APP_ID = \"appId\";\n    public static final String CID = \"cid\";\n    public static final String USER_ID = \"userId\";\n    public static final String EMP_ID = \"empId\";\n    public static final String NAME = \"name\";\n    public static final String USERNAME = \"username\";\n    public static final String PHONE_NUM = \"phoneNum\";\n    public static final String AVATAR_URL = \"avatarUrl\";\n    public static final String IS_CORP_ADMIN = \"isCorpAdmin\";\n    public static final String IS_SYS_ADMIN = \"isSysAdmin\";\n    public static final String AUTHORITIES = \"authorities\";\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/CustomAuthorizationResponseHandler.java",
    "content": "//package cn.hiauth.server.config.web.auth;\n//\n//import cn.hiauth.server.entity.CorpAppInfo;\n//import cn.hiauth.server.entity.Oauth2RegisteredClient;\n//import cn.hiauth.server.mapper.CorpAppMapper;\n//import cn.hiauth.server.service.Oauth2RegisteredClientService;\n//import jakarta.servlet.http.HttpServletRequest;\n//import jakarta.servlet.http.HttpServletResponse;\n//import lombok.extern.slf4j.Slf4j;\n//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\n//import org.springframework.security.core.Authentication;\n//import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\n//import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken;\n//import org.springframework.security.web.DefaultRedirectStrategy;\n//import org.springframework.security.web.RedirectStrategy;\n//import org.springframework.security.web.authentication.AuthenticationSuccessHandler;\n//import org.springframework.util.StringUtils;\n//import org.springframework.web.util.UriComponentsBuilder;\n//import org.springframework.web.util.UriUtils;\n//\n//import java.io.IOException;\n//import java.nio.charset.StandardCharsets;\n//import java.util.List;\n//import java.util.Objects;\n//\n///**\n// * 自定义授权响应处理，后期看看能不能删除这个自定义功能，把对应的功能写到CustomAuthenticationSuccessHandler中\n// */\n//@Slf4j\n//public class CustomAuthorizationResponseHandler implements AuthenticationSuccessHandler {\n//\n//    private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();\n//\n//    private Oauth2RegisteredClientService oauth2RegisteredClientService;\n//\n//    private CorpAppMapper corpAppMapper;\n//\n//    public CustomAuthorizationResponseHandler(Oauth2RegisteredClientService oauth2RegisteredClientService, CorpAppMapper corpAppMapper) {\n//        this.oauth2RegisteredClientService = oauth2RegisteredClientService;\n//        this.corpAppMapper = corpAppMapper;\n//    }\n//\n//    @Override\n//    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {\n//        OAuth2AuthorizationCodeRequestAuthenticationToken token = (OAuth2AuthorizationCodeRequestAuthenticationToken) authentication;\n//        String redirectUri = token.getRedirectUri();\n//\n//        // 自定义逻辑\n//        log.info(\"自定义逻辑开始: {}、{}\", token.getClientId(), redirectUri);\n//        String loginClientId = (String) request.getSession().getAttribute(\"clientId\");\n//        String loginRedirectUri = (String) request.getSession().getAttribute(\"redirectUri\");\n//        if (StringUtils.hasText(loginClientId)\n//                && token.getClientId() != null\n//                && !loginClientId.equals(token.getClientId())\n//                && StringUtils.hasText(loginRedirectUri)) {\n//            redirectUri = modifyRedirectUrl(token, loginClientId, loginRedirectUri, redirectUri);\n//        }\n//        log.info(\"自定义逻辑结束\");\n//        // 自定义逻辑\n//\n//        UriComponentsBuilder uriBuilder = UriComponentsBuilder\n//                .fromUriString(Objects.requireNonNull(redirectUri))\n//                .queryParam(OAuth2ParameterNames.CODE, Objects.requireNonNull(token.getAuthorizationCode()).getTokenValue());\n//        if (StringUtils.hasText(token.getState())) {\n//            uriBuilder.queryParam(OAuth2ParameterNames.STATE, UriUtils.encode(token.getState(), StandardCharsets.UTF_8));\n//        }\n//        redirectUri = uriBuilder.build(true).toUriString();\n//\n//        this.redirectStrategy.sendRedirect(request, response, redirectUri);\n//    }\n//\n//    private String modifyRedirectUrl(OAuth2AuthorizationCodeRequestAuthenticationToken token, String loginClientId, String loginRedirectUri, String redirectUri) {\n//        log.info(\"1: {}、{}、{}\", loginClientId, loginRedirectUri, redirectUri);\n//        // 无登录信息或者登录信息类型错误，直接返回\n//        if (token.getPrincipal() == null || !(token.getPrincipal() instanceof UsernamePasswordAuthenticationToken)) {\n//            return redirectUri;\n//        }\n//        UsernamePasswordAuthenticationToken authToken = (UsernamePasswordAuthenticationToken) token.getPrincipal();\n//\n//        log.info(\"2: {}、{}、{}\", token.getPrincipal(), loginRedirectUri, redirectUri);\n//        // 无登录用户信息或者登录用户信息类型错误，直接返回\n//        if (authToken.getPrincipal() == null || !(authToken.getPrincipal() instanceof AuthUser)) {\n//            return redirectUri;\n//        }\n//        AuthUser authUser = (AuthUser) authToken.getPrincipal();\n//\n//        log.info(\"3: {}、{}、{}\", authToken.getPrincipal(), loginRedirectUri, redirectUri);\n//        // 获取登录应用信息\n//        Oauth2RegisteredClient client = oauth2RegisteredClientService.findByClientId(loginClientId);\n//        if (client == null || client.getAppId() == null) {\n//            return redirectUri;\n//        }\n//\n//        log.info(\"4: {}、{}、{}\", client.getAppId(), loginRedirectUri, redirectUri);\n//        // 检查是否有权限\n//        List<CorpAppInfo> cpis = corpAppMapper.limitCorpAppInfoByUserId(authUser.getUserId(), client.getAppId());\n//        if (cpis == null || cpis.isEmpty()) {\n//            return redirectUri;\n//        }\n//\n//        log.info(\"5: {}、{}、{}\", cpis, loginRedirectUri, redirectUri);\n//        return loginRedirectUri;\n//    }\n//\n//}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/CustomJdbcRegisteredClientRepository.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jdbc.core.namedparam.MapSqlParameterSource;\nimport org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\n\nimport java.util.List;\nimport java.util.Set;\n\npublic class CustomJdbcRegisteredClientRepository extends JdbcRegisteredClientRepository {\n\n    private static final String TABLE_NAME = \"oauth2_registered_client\";\n\n    private static final String COLUMN_NAMES = \"id, \"\n            + \"client_id, \"\n            + \"client_id_issued_at, \"\n            + \"client_secret, \"\n            + \"client_secret_expires_at, \"\n            + \"client_name, \"\n            + \"client_authentication_methods, \"\n            + \"authorization_grant_types, \"\n            + \"redirect_uris, \"\n            + \"post_logout_redirect_uris, \"\n            + \"scopes, \"\n            + \"client_settings,\"\n            + \"token_settings\";\n\n    private static final String LOAD_REGISTERED_CLIENT_SQL = \"SELECT \" + COLUMN_NAMES + \" FROM \" + TABLE_NAME + \" WHERE \";\n\n    public CustomJdbcRegisteredClientRepository(JdbcOperations jdbcOperations) {\n        super(jdbcOperations);\n    }\n\n    public List<RegisteredClient> findByClientIds(Set<String> clientIds) {\n        MapSqlParameterSource parameters = new MapSqlParameterSource();\n        parameters.addValue(\"clientIds\", clientIds);\n        StringBuilder sb = new StringBuilder();\n        sb.append(LOAD_REGISTERED_CLIENT_SQL).append(\"client_id IN (\");\n        clientIds.forEach(i -> sb.append(\"'\").append(i).append(\"',\"));\n        sb.deleteCharAt(sb.length() - 1);\n        sb.append(\")\");\n        List<RegisteredClient> result = this.getJdbcOperations().query(sb.toString(), this.getRegisteredClientRowMapper());\n        return !result.isEmpty() ? result : null;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/CustomOidcUserInfoMapper.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\nimport cn.hiauth.server.config.web.security.MultiAuthUserService;\nimport cn.webestar.scms.cache.CacheUtil;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.oauth2.core.OAuth2AccessToken;\nimport org.springframework.security.oauth2.core.oidc.OidcScopes;\nimport org.springframework.security.oauth2.core.oidc.OidcUserInfo;\nimport org.springframework.security.oauth2.core.oidc.StandardClaimNames;\nimport org.springframework.security.oauth2.server.authorization.OAuth2Authorization;\nimport org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationContext;\n\nimport java.security.Principal;\nimport java.util.*;\nimport java.util.function.Function;\n\n/**\n * 自定义用户信息查询\n */\npublic class CustomOidcUserInfoMapper implements Function<OidcUserInfoAuthenticationContext, OidcUserInfo> {\n\n    private final static Long EXPIRE = 10 * 60 * 60L;\n\n    /**\n     * 邮箱对应的属性\n     */\n    private static final List<String> EMAIL_CLAIMS = Arrays.asList(\n            StandardClaimNames.EMAIL,\n            StandardClaimNames.EMAIL_VERIFIED\n    );\n\n    /**\n     * 手机号码对应的属性\n     */\n    private static final List<String> PHONE_CLAIMS = Arrays.asList(\n            StandardClaimNames.PHONE_NUMBER,\n            StandardClaimNames.PHONE_NUMBER_VERIFIED\n    );\n\n    /**\n     * 用户信息对应的属性\n     */\n    private static final List<String> PROFILE_CLAIMS = Arrays.asList(\n            StandardClaimNames.NAME,\n            CustomAuthUserAttrs.APP_ID,\n            CustomAuthUserAttrs.CID,\n            CustomAuthUserAttrs.USER_ID,\n            CustomAuthUserAttrs.EMP_ID,\n            CustomAuthUserAttrs.NAME,\n            CustomAuthUserAttrs.USERNAME,\n            CustomAuthUserAttrs.PHONE_NUM,\n            CustomAuthUserAttrs.AVATAR_URL,\n            CustomAuthUserAttrs.IS_CORP_ADMIN,\n            CustomAuthUserAttrs.AUTHORITIES\n    );\n\n    private CacheUtil cacheUtil;\n\n    private MultiAuthUserService multiAuthUserService;\n\n    public CustomOidcUserInfoMapper(CacheUtil cacheUtil, MultiAuthUserService multiAuthUserService) {\n        this.cacheUtil = cacheUtil;\n        this.multiAuthUserService = multiAuthUserService;\n    }\n\n    private static Map<String, Object> getClaimsRequestedByScope(Map<String, Object> claims, Set<String> requestedScopes) {\n        Set<String> scopeRequestedClaimNames = new HashSet<>(32);\n        scopeRequestedClaimNames.add(StandardClaimNames.SUB);\n        //是否拥有地址scope\n        if (requestedScopes.contains(OidcScopes.ADDRESS)) {\n            scopeRequestedClaimNames.add(StandardClaimNames.ADDRESS);\n        }\n        //是否拥有邮箱scope\n        if (requestedScopes.contains(OidcScopes.EMAIL)) {\n            scopeRequestedClaimNames.addAll(EMAIL_CLAIMS);\n        }\n        //是否拥有手机号码scope\n        if (requestedScopes.contains(OidcScopes.PHONE)) {\n            scopeRequestedClaimNames.addAll(PHONE_CLAIMS);\n        }\n        //是否拥有用户信息scope\n        if (requestedScopes.contains(OidcScopes.PROFILE)) {\n            scopeRequestedClaimNames.addAll(PROFILE_CLAIMS);\n        }\n        Map<String, Object> requestedClaims = new HashMap<>(claims);\n        requestedClaims.keySet().removeIf((claimName) -> !scopeRequestedClaimNames.contains(claimName));\n        return requestedClaims;\n    }\n\n    @Override\n    public OidcUserInfo apply(OidcUserInfoAuthenticationContext authenticationContext) {\n        OAuth2Authorization authorization = authenticationContext.getAuthorization();\n        // 获取登录用户\n        Authentication authentication = authorization.getAttribute(Principal.class.getName());\n        assert authentication != null;\n        AuthUser authUser = (AuthUser) authentication.getPrincipal();\n        Long userId = authUser.getUserId();\n        // 获取最新状态的用户\n        OAuth2AccessToken oat = authenticationContext.getAccessToken();\n        String clientId = authorization.getRegisteredClientId();\n        AuthUser freshAuthUser = multiAuthUserService.loadUserByUserId(clientId, userId);\n        cacheUtil.set(\"userinfo:\" + oat.getTokenValue(), freshAuthUser, EXPIRE);\n        // 构建用户信息\n        Map<String, Object> claims = new HashMap<>(10);\n        claims.put(StandardClaimNames.SUB, freshAuthUser.getUsername());\n        claims.put(CustomAuthUserAttrs.APP_ID, freshAuthUser.getAppId());\n        claims.put(CustomAuthUserAttrs.CID, freshAuthUser.getCid());\n        claims.put(CustomAuthUserAttrs.USER_ID, freshAuthUser.getUserId());\n        claims.put(CustomAuthUserAttrs.EMP_ID, freshAuthUser.getEmpId());\n        claims.put(CustomAuthUserAttrs.NAME, freshAuthUser.getName());\n        claims.put(CustomAuthUserAttrs.USERNAME, freshAuthUser.getUsername());\n        claims.put(CustomAuthUserAttrs.PHONE_NUM, freshAuthUser.getPhoneNum());\n        claims.put(CustomAuthUserAttrs.AVATAR_URL, freshAuthUser.getAvatarUrl());\n        claims.put(CustomAuthUserAttrs.IS_CORP_ADMIN, freshAuthUser.getIsCorpAdmin());\n        if (freshAuthUser.getAuthorities() != null) {\n            Set<Map<String, String>> authorities = new HashSet<>();\n            freshAuthUser.getAuthorities().forEach(i -> {\n                Map<String, String> map = new HashMap<>(3);\n                map.put(\"code\", i.getCode());\n                map.put(\"page\", i.getPage());\n                map.put(\"api\", i.getApi());\n                authorities.add(map);\n            });\n            claims.put(CustomAuthUserAttrs.AUTHORITIES, authorities);\n        }\n        Map<String, Object> scopeRequestedClaims = getClaimsRequestedByScope(claims, oat.getScopes());\n        return new OidcUserInfo(scopeRequestedClaims);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/auth/FederatedIdentityIdTokenCustomizer.java",
    "content": "package cn.hiauth.server.config.web.auth;\n\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;\nimport org.springframework.security.oauth2.core.oidc.OidcIdToken;\nimport org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;\nimport org.springframework.security.oauth2.core.oidc.user.OidcUser;\nimport org.springframework.security.oauth2.core.user.OAuth2User;\nimport org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;\nimport org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;\n\nimport java.util.*;\n\npublic final class FederatedIdentityIdTokenCustomizer implements OAuth2TokenCustomizer<JwtEncodingContext> {\n\n    private static final Set<String> ID_TOKEN_CLAIMS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(\n            IdTokenClaimNames.ISS,\n            IdTokenClaimNames.SUB,\n            IdTokenClaimNames.AUD,\n            IdTokenClaimNames.EXP,\n            IdTokenClaimNames.IAT,\n            IdTokenClaimNames.AUTH_TIME,\n            IdTokenClaimNames.NONCE,\n            IdTokenClaimNames.ACR,\n            IdTokenClaimNames.AMR,\n            IdTokenClaimNames.AZP,\n            IdTokenClaimNames.AT_HASH,\n            IdTokenClaimNames.C_HASH\n    )));\n\n    @Override\n    public void customize(JwtEncodingContext context) {\n        if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) {\n            Map<String, Object> thirdPartyClaims = extractClaims(context.getPrincipal());\n            context.getClaims().claims(existingClaims -> {\n                // 移除本认证服务器设置的冲突声明\n                existingClaims.keySet().forEach(thirdPartyClaims::remove);\n                // 移除可能导致客户端问题的标准id_token声明\n                ID_TOKEN_CLAIMS.forEach(thirdPartyClaims::remove);\n                // 将所有其他声明直接添加到id_token中\n                existingClaims.putAll(thirdPartyClaims);\n            });\n        }\n    }\n\n    private Map<String, Object> extractClaims(Authentication principal) {\n        Map<String, Object> claims = new HashMap<>(5);\n        if (principal.getPrincipal() instanceof AuthUser authUser) {\n            claims.put(\"cid\", authUser.getCid());\n            claims.put(\"userId\", authUser.getUserId());\n            claims.put(\"empId\", authUser.getEmpId());\n        } else if (principal.getPrincipal() instanceof OidcUser oidcUser) {\n            OidcIdToken idToken = oidcUser.getIdToken();\n            claims = idToken.getClaims();\n        } else if (principal.getPrincipal() instanceof OAuth2User oauth2User) {\n            claims = oauth2User.getAttributes();\n        }\n        return claims;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/CaptchaFilter.java",
    "content": "//package cn.hiauth.server.config.web.security;\n//\n//import cn.hiauth.server.utils.Constant;\n//import cn.webestar.scms.cache.CacheUtil;\n//import jakarta.servlet.FilterChain;\n//import jakarta.servlet.ServletException;\n//import jakarta.servlet.ServletRequest;\n//import jakarta.servlet.ServletResponse;\n//import jakarta.servlet.http.HttpServletRequest;\n//import jakarta.servlet.http.HttpServletResponse;\n//import org.springframework.http.HttpMethod;\n//import org.springframework.security.authentication.InsufficientAuthenticationException;\n//import org.springframework.security.core.Authentication;\n//import org.springframework.security.core.AuthenticationException;\n//import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;\n//import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;\n//import org.springframework.util.AntPathMatcher;\n//\n//import java.io.IOException;\n//\n///**\n// * 改进,使用只验证一次的过滤器 extends OncePerRequestFilter implements InitializingBean\n// */\n//public class CaptchaFilter extends AbstractAuthenticationProcessingFilter {\n//\n//    private static final String FORM_CAPTCHA_KEY = \"captcha\";\n//\n//    private final AntPathMatcher pathMatcher = new AntPathMatcher();\n//\n//    private final String processUrl;\n//\n//    private CacheUtil cacheUtil;\n//\n//    public CaptchaFilter(String processUrl, String failureUrl) {\n//        super(processUrl);\n//        this.processUrl = processUrl;\n//        setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(failureUrl));\n//    }\n//\n//    @Override\n//    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n//        HttpServletRequest req = (HttpServletRequest) request;\n//        HttpServletResponse res = (HttpServletResponse) response;\n//        if (pathMatcher.match(processUrl, req.getServletPath()) && HttpMethod.POST.name().equalsIgnoreCase(req.getMethod())) {\n//            String formToken = request.getParameter(Constant.REQUEST_KEY_FORM_TOKEN);\n//            String imgCodeKey = Constant.CACHE_KEY_CAPTCHA + \":\" + formToken;\n//            String captchaCache = (String) cacheUtil.get(imgCodeKey);\n//            if (captchaCache == null) {\n//                unsuccessfulAuthentication(req, res, new InsufficientAuthenticationException(\"验证失败:图形验证码错误\"));\n//                return;\n//            }\n//            String captchaParam = req.getParameter(FORM_CAPTCHA_KEY);\n//            if (!captchaCache.equalsIgnoreCase(captchaParam)) {\n//                unsuccessfulAuthentication(req, res, new InsufficientAuthenticationException(\"验证失败:图形验证码错误\"));\n//                return;\n//            }\n//            //销毁图形验证码，以免别人使用次图像验证码刷接口\n//            cacheUtil.expire(imgCodeKey, 0);\n//        }\n//        chain.doFilter(request, response);\n//    }\n//\n//    @Override\n//    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException {\n//        return null;\n//    }\n//\n//    public CacheUtil getCacheUtil() {\n//        return cacheUtil;\n//    }\n//\n//    public void setCacheUtil(CacheUtil cacheUtil) {\n//        this.cacheUtil = cacheUtil;\n//    }\n//\n//}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/CustomAuthenticationFailureHandler.java",
    "content": "package cn.hiauth.server.config.web.security;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport java.io.IOException;\nimport java.net.URI;\n\n/**\n * 认证失败处理器，主要作用是在失败的页面url后缀中添加参数client_id\n */\npublic class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {\n\n    private String defaultFailureUrl;\n\n    public CustomAuthenticationFailureHandler(String failureUrl) {\n        super(failureUrl);\n        this.defaultFailureUrl = failureUrl;\n    }\n\n    /**\n     * 认证失败后，如果存在client_id参数，则添加到失败的页面url中，以助于再次尝试登录后能跳转到指定的应用\n     */\n    @Override\n    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {\n        String clientId = request.getParameter(MultiAppHttpSessionRequestCache.CLIENT_ID_KEY);\n        String failureUrl = defaultFailureUrl;\n        if (StringUtils.hasText(clientId)) {\n            URI uri = URI.create(defaultFailureUrl);\n            failureUrl = UriComponentsBuilder.fromUri(uri).queryParam(OAuth2ParameterNames.CLIENT_ID, clientId).toUriString();\n        }\n        saveException(request, exception);\n        getRedirectStrategy().sendRedirect(request, response, failureUrl);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/CustomAuthenticationSuccessHandler.java",
    "content": "package cn.hiauth.server.config.web.security;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;\nimport org.springframework.security.web.savedrequest.RequestCache;\nimport org.springframework.security.web.savedrequest.SavedRequest;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * 自定义认证成功处理\n */\npublic class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {\n\n    private static final List<String> IGNORE_URLS = Arrays.asList(\"/logout?\", \"/error\");\n\n    private RequestCache requestCache;\n\n    @Override\n    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {\n        // 上个页面是 logout 则到默认页面\n        SavedRequest savedRequest = requestCache.getRequest(request, response);\n        if (savedRequest != null && savedRequest.getRedirectUrl() != null) {\n            String targetUrl = savedRequest.getRedirectUrl();\n            for (String url : IGNORE_URLS) {\n                if (targetUrl.contains(url)) {\n                    requestCache.removeRequest(request, response);\n                    break;\n                }\n            }\n        }\n        super.onAuthenticationSuccess(request, response, authentication);\n    }\n\n    @Override\n    public void setRequestCache(RequestCache requestCache) {\n        super.setRequestCache(requestCache);\n        this.requestCache = requestCache;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/CustomLoginUrlAuthenticationEntryPoint.java",
    "content": "package cn.hiauth.server.config.web.security;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;\nimport org.springframework.security.web.savedrequest.DefaultSavedRequest;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport java.net.URI;\n\n/**\n * 自定义登录页面，主要是在登录页的URL中添加client_id参数，以便收藏下次登录时自动跳回对应的应用\n */\npublic class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {\n\n    public CustomLoginUrlAuthenticationEntryPoint(String loginFormUrl) {\n        super(loginFormUrl);\n    }\n\n    /**\n     * 在对地方法应用授权时，将client_id从Request提取出来，追加到url中，以便于用户收藏此登录页。\n     * 而且用户使用此收藏的地址登录时，会自动带上client_id参数，从而跳转到对应应用。\n     */\n    @Override\n    protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) {\n        String url = super.determineUrlToUseForThisRequest(request, response, exception);\n        String clientId = request.getParameter(OAuth2ParameterNames.CLIENT_ID);\n        if (!StringUtils.hasText(clientId)) {\n            clientId = request.getParameter(MultiAppHttpSessionRequestCache.CLIENT_ID_KEY);\n        }\n        DefaultSavedRequest savedRequest = (DefaultSavedRequest) request.getSession().getAttribute(\"SPRING_SECURITY_SAVED_REQUEST\");\n        if (savedRequest != null) {\n            String[] clientIds = savedRequest.getParameterValues(OAuth2ParameterNames.CLIENT_ID);\n            if (clientIds != null && clientIds.length > 0) {\n                clientId = clientIds[0];\n            }\n        }\n        if (!StringUtils.hasText(clientId)) {\n            return url;\n        }\n        URI uri = URI.create(url);\n        return UriComponentsBuilder.fromUri(uri).queryParam(OAuth2ParameterNames.CLIENT_ID, clientId).toUriString();\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/MultiAppHttpSessionRequestCache.java",
    "content": "package cn.hiauth.server.config.web.security;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpSession;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.web.PortResolver;\nimport org.springframework.security.web.PortResolverImpl;\nimport org.springframework.security.web.savedrequest.DefaultSavedRequest;\nimport org.springframework.security.web.savedrequest.HttpSessionRequestCache;\nimport org.springframework.security.web.savedrequest.SavedRequest;\nimport org.springframework.security.web.util.matcher.AnyRequestMatcher;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.StringUtils;\n\n/**\n * 记录请求，重写缓存工具，实现需求：登录页如果携带了client_id，指定了具体的应用，则登录成功后跳转到指定应用\n * 在原有的缓存逻辑中添加自定义逻辑：将savedRequest用对应的key单独存储了一份，\n * 应用于在同一个浏览器、同一个session下，同时对多个应用授权，不至于后一个应用覆盖前一个，导致错乱。\n * 如果去除此逻辑，不至于影响核心功能，但是同一个浏览器、同一个session下对多应用授权可能会错乱。\n */\npublic class MultiAppHttpSessionRequestCache extends HttpSessionRequestCache {\n\n    public static final String CLIENT_ID_KEY = \"clientId\";\n\n    static final String SAVED_REQUEST = \"SPRING_SECURITY_SAVED_REQUEST\";\n\n    private PortResolver portResolver = new PortResolverImpl();\n\n    private boolean createSessionAllowed = true;\n\n    private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;\n\n    private String sessionAttrName = SAVED_REQUEST;\n\n    private String matchingRequestParameterName = \"continue\";\n\n    @Override\n    public void saveRequest(HttpServletRequest request, HttpServletResponse response) {\n        if (!this.requestMatcher.matches(request)) {\n            if (this.logger.isTraceEnabled()) {\n                this.logger.trace(LogMessage.format(\"Did not save request since it did not match [%s]\", this.requestMatcher));\n            }\n            return;\n        }\n        if (this.createSessionAllowed || request.getSession(false) != null) {\n            DefaultSavedRequest savedRequest = new DefaultSavedRequest(request, this.portResolver, this.matchingRequestParameterName);\n            request.getSession().setAttribute(this.sessionAttrName, savedRequest);\n            // 自定义逻辑\n            String clientId = request.getParameter(OAuth2ParameterNames.CLIENT_ID);\n            if (StringUtils.hasText(clientId)) {\n                request.getSession().setAttribute(this.sessionAttrName + \"_\" + clientId, savedRequest);\n            }\n            // 自定义逻辑\n            if (this.logger.isDebugEnabled()) {\n                this.logger.debug(LogMessage.format(\"Saved request %s to session\", savedRequest.getRedirectUrl()));\n            }\n        } else {\n            this.logger.trace(\"Did not save request since there's no session and createSessionAllowed is false\");\n        }\n    }\n\n    @Override\n    public SavedRequest getRequest(HttpServletRequest currentRequest, HttpServletResponse response) {\n        HttpSession session = currentRequest.getSession(false);\n        if (session == null) {\n            return null;\n        }\n        // 自定义逻辑\n        String clientId = currentRequest.getParameter(CLIENT_ID_KEY);\n        if (StringUtils.hasText(clientId)) {\n            return (SavedRequest) session.getAttribute(this.sessionAttrName + \"_\" + clientId);\n        }\n        // 自定义逻辑\n        return (SavedRequest) session.getAttribute(this.sessionAttrName);\n    }\n\n    @Override\n    public void removeRequest(HttpServletRequest currentRequest, HttpServletResponse response) {\n        HttpSession session = currentRequest.getSession(false);\n        if (session != null) {\n            this.logger.trace(\"Removing DefaultSavedRequest from session if present\");\n            session.removeAttribute(this.sessionAttrName);\n            // 自定义逻辑\n            String clientId = currentRequest.getParameter(CLIENT_ID_KEY);\n            if (StringUtils.hasText(clientId)) {\n                session.removeAttribute(this.sessionAttrName + \"_\" + clientId);\n            }\n            // 自定义逻辑\n        }\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/MultiAuthUserService.java",
    "content": "package cn.hiauth.server.config.web.security;\n\nimport cn.hiauth.server.config.props.WechatProperties;\nimport cn.hiauth.server.config.web.auth.AuthGrantedAuthority;\nimport cn.hiauth.server.config.web.auth.AuthUser;\nimport cn.hiauth.server.entity.*;\nimport cn.hiauth.server.mapper.AppMapper;\nimport cn.hiauth.server.mapper.EmployeeMapper;\nimport cn.hiauth.server.mapper.UserMapper;\nimport cn.hiauth.server.service.AppResourceService;\nimport cn.hiauth.server.service.Oauth2RegisteredClientService;\nimport cn.hiauth.server.service.RoleService;\nimport cn.hutool.json.JSONUtil;\nimport cn.webestar.scms.commons.Assert;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport jakarta.annotation.Resource;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestTemplate;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Service\npublic class MultiAuthUserService {\n\n    @Resource\n    private UserMapper userMapper;\n\n    @Resource\n    private EmployeeMapper employeeMapper;\n\n    @Resource\n    private AppMapper appMapper;\n\n    @Resource\n    private RoleService roleService;\n\n    @Resource\n    private AppResourceService appResourceService;\n\n    @Resource\n    private Oauth2RegisteredClientService oauth2RegisteredClientService;\n\n    @Resource\n    private RestTemplate restTemplate;\n\n    @Resource\n    private WechatProperties wechatProperties;\n\n    public AuthUser loadUserByUsername(String clientId, String username) throws UsernameNotFoundException {\n        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(User::getUsername, username);\n        User user = userMapper.selectOne(queryWrapper);\n        Assert.notNull(user, \"账号不存在请先注册\");\n        Oauth2RegisteredClient client = oauth2RegisteredClientService.findByClientId(clientId);\n        return loadAuthUser(client, user);\n    }\n\n    public AuthUser loadUserByPhoneNum(String clientId, String phoneNum) {\n        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(User::getPhoneNum, phoneNum);\n        User user = userMapper.selectOne(queryWrapper);\n        Assert.notNull(user, \"账号不存在请先注册\");\n        Oauth2RegisteredClient client = oauth2RegisteredClientService.findByClientId(clientId);\n        return loadAuthUser(client, user);\n    }\n\n    public AuthUser loadUserByUserId(String registeredClientId, Long userId) {\n        User user = userMapper.selectById(userId);\n        Assert.notNull(user, \"账号不存在请先注册\");\n        Oauth2RegisteredClient client = oauth2RegisteredClientService.getById(registeredClientId);\n        Assert.notNull(client, \"用户名或者密码错误\");\n        return loadAuthUser(client, user);\n    }\n\n    public AuthUser loadAuthUser(Oauth2RegisteredClient client, User user) {\n        Employee employee = null;\n        Set<AuthGrantedAuthority> authorities = new HashSet<>();\n        if (client != null && client.getAppId() != null) {\n            App app = appMapper.selectById(client.getAppId());\n            Boolean corpAdminOnly = null;\n            if (app != null && app.getExtend() != null && app.getExtend().containsKey(\"corpAdminOnly\")) {\n                corpAdminOnly = (Boolean) app.getExtend().get(\"corpAdminOnly\");\n            }\n            employee = employeeMapper.findOneByAppIdAndUserId(client.getAppId(), user.getId(), corpAdminOnly);\n            Assert.notNull(employee, String.format(\"不是应用“%s”的用户\", client.getClientName()));\n            List<Role> roles = roleService.findByEmpId(employee.getId());\n            Set<Long> roleIds = new HashSet<>();\n            roles.forEach(i -> roleIds.add(i.getId()));\n            if (client.getAppId() != null && !roleIds.isEmpty()) {\n                List<AppResource> resources = appResourceService.findByAppIdAndRoleIds(client.getAppId(), roleIds);\n                resources.forEach(i -> {\n                    AuthGrantedAuthority aga = new AuthGrantedAuthority(i.getCode());\n                    aga.setPage(i.getUrl());\n                    aga.setApi(i.getApi());\n                    authorities.add(aga);\n                });\n            }\n        }\n        return new AuthUser(client, user, employee, authorities);\n    }\n\n    public AuthUser loadUserWeChatCode(String clientId, String code) {\n        Map<String, Object> tokenMap = getWechatAccessToken(code);\n        String unionId = (String) tokenMap.get(\"unionid\");\n        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(User::getWxUnionid, unionId);\n        User user = userMapper.selectOne(queryWrapper);\n        Assert.notNull(user, \"账号未注册\");\n        Oauth2RegisteredClient client = oauth2RegisteredClientService.findByClientId(clientId);\n        return loadAuthUser(client, user);\n    }\n\n    private Map<String, Object> getWechatAccessToken(String code) {\n        String appid = wechatProperties.getAppid();\n        String appSecret = wechatProperties.getAppSecret();\n        String url = String.format(\"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code\", appid, appSecret, code);\n        String str = restTemplate.getForObject(url, String.class);\n        return JSONUtil.toBean(str, Map.class);\n    }\n\n    private Map<String, Object> getWechatUserInfo(String accessToken, String openId) {\n        String url = String.format(\"https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s\", accessToken, openId);\n        String str = restTemplate.getForObject(url, String.class);\n        return JSONUtil.toBean(str, Map.class);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/MultiAuthenticationProvider.java",
    "content": "//package cn.hiauth.server.config.web.security;\n//\n//import cn.hiauth.server.config.web.auth.AuthUser;\n//import cn.hiauth.server.utils.Constant;\n//import cn.webestar.scms.cache.CacheUtil;\n//import cn.webestar.scms.commons.CommonException;\n//import jakarta.servlet.http.HttpServletRequest;\n//import lombok.extern.slf4j.Slf4j;\n//import org.springframework.security.authentication.AuthenticationProvider;\n//import org.springframework.security.authentication.BadCredentialsException;\n//import org.springframework.security.authentication.InternalAuthenticationServiceException;\n//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\n//import org.springframework.security.core.Authentication;\n//import org.springframework.security.core.AuthenticationException;\n//import org.springframework.security.crypto.password.PasswordEncoder;\n//import org.springframework.security.web.savedrequest.DefaultSavedRequest;\n//import org.springframework.web.context.request.RequestContextHolder;\n//import org.springframework.web.context.request.ServletRequestAttributes;\n//\n//@Slf4j\n//public class MultiAuthenticationProvider implements AuthenticationProvider {\n//\n//    private CacheUtil cacheUtil;\n//\n//    private PasswordEncoder passwordEncoder;\n//\n//    private MultiAuthUserService multiAuthUserService;\n//\n//    private String superSmsCode;\n//\n//    public MultiAuthenticationProvider(CacheUtil cacheUtil, MultiAuthUserService multiAuthUserService, PasswordEncoder passwordEncoder, String superSmsCode) {\n//        this.cacheUtil = cacheUtil;\n//        this.multiAuthUserService = multiAuthUserService;\n//        this.passwordEncoder = passwordEncoder;\n//        this.superSmsCode = superSmsCode;\n//    }\n//\n//    @Override\n//    public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n//        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n//        String url = request.getRequestURI();\n//        if (!Constant.LOGIN_ACTION.equals(url)) {\n//            return null;\n//        }\n//        String loginType = request.getParameter(\"loginType\");\n//        // TODO 这个要改用 MultiAppHttpSessionRequestCache\n//        DefaultSavedRequest savedRequest = (DefaultSavedRequest) request.getSession().getAttribute(\"SPRING_SECURITY_SAVED_REQUEST\");\n//        String clientId = null;\n//        if (savedRequest != null) {\n//            String[] clientIds = savedRequest.getParameterValues(\"client_id\");\n//            if (clientIds != null && clientIds.length > 0) {\n//                clientId = clientIds[0];\n//            }\n//        }\n//        AuthUser authUser = null;\n//        try {\n//            if (\"pwd\".equals(loginType)) {\n//                String username = (String) authentication.getPrincipal();\n//                authUser = multiAuthUserService.loadUserByUsername(clientId, username);\n//                checkPwdLogin(authUser, authentication);\n//            } else if (\"sms\".equals(loginType)) {\n//                String phoneNum = (String) authentication.getPrincipal();\n//                authUser = multiAuthUserService.loadUserByPhoneNum(clientId, phoneNum);\n//                checkSmsLogin(request, authentication);\n//            } else {\n//                log.debug(\"不支持的登录方式: \" + loginType);\n//                throw new BadCredentialsException(\"不支持的登录方式: \" + loginType);\n//            }\n//        } catch (CommonException | BadCredentialsException ex) {\n//            throw new InternalAuthenticationServiceException(\"登录失败:\" + ex.getMessage(), ex);\n//        } catch (Exception ex) {\n//            throw new InternalAuthenticationServiceException(\"登录失败:账号异常\", ex);\n//        }\n//\n//        if (authUser == null) {\n//            throw new InternalAuthenticationServiceException(\"UserDetailsService returned null, which is an interface contract violation\");\n//        }\n//\n//        return new UsernamePasswordAuthenticationToken(authUser, authUser.getPassword(), authUser.getAuthorities());\n//    }\n//\n//    /**\n//     * 用户名+密码登录\n//     */\n//    private void checkPwdLogin(AuthUser authUser, Authentication authentication) {\n//        if (authentication.getCredentials() == null) {\n//            log.debug(\"Failed to authenticate since no credentials provided\");\n//            throw new BadCredentialsException(\"用户名或者密码错误\");\n//        }\n//        String presentedPassword = authentication.getCredentials().toString();\n//        if (!this.passwordEncoder.matches(presentedPassword, authUser.getPassword())) {\n//            log.debug(\"Failed to authenticate since password does not match stored value\");\n//            throw new BadCredentialsException(\"用户名或者密码错误\");\n//        }\n//    }\n//\n//    /**\n//     * 短信验证码登录\n//     */\n//    private void checkSmsLogin(HttpServletRequest request, Authentication authentication) {\n//        //此处写验证短信码\n//        String smsCodeParam = request.getParameter(\"smsCode\");\n//        String key = Constant.CACHE_KEY_SMS_CODE + \":\" + authentication.getPrincipal();\n//        String smsCode = (String) cacheUtil.get(key);\n//        if (smsCodeParam.equals(superSmsCode)) {\n//            return;\n//        }\n//        if (smsCode == null || !smsCode.equals(smsCodeParam)) {\n//            throw new BadCredentialsException(\"短信验证码错误\");\n//        }\n//    }\n//\n//    @Override\n//    public boolean supports(Class<?> authentication) {\n//        return true;\n//    }\n//\n//}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/account/AccountAuthenticationFilter.java",
    "content": "package cn.hiauth.server.config.web.security.account;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.authentication.AuthenticationServiceException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\n\nimport java.io.IOException;\n\npublic class AccountAuthenticationFilter extends AbstractAuthenticationProcessingFilter {\n\n    public AccountAuthenticationFilter(String processUrl) {\n        super(new AntPathRequestMatcher(processUrl, HttpMethod.POST.name()));\n    }\n\n    /**\n     * 获取登录表单中提交的参数（formToken、clientId...），并创建authenticationToken，进行认证\n     */\n    @Override\n    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, ServletException, IOException {\n        String method = request.getMethod();\n        if (!HttpMethod.POST.name().equalsIgnoreCase(method)) {\n            throw new AuthenticationServiceException(\"Authentication method not supported: \" + request.getMethod());\n        } else {\n            String formToken = request.getParameter(\"formToken\");\n            String clientId = request.getParameter(\"clientId\");\n            String username = request.getParameter(\"username\");\n            String password = request.getParameter(\"password\");\n            String captcha = request.getParameter(\"captcha\");\n            AccountAuthenticationToken authenticationToken = new AccountAuthenticationToken(formToken, clientId, username, password, captcha);\n            return this.getAuthenticationManager().authenticate(authenticationToken);\n        }\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/account/AccountAuthenticationProvider.java",
    "content": "package cn.hiauth.server.config.web.security.account;\n\nimport cn.hiauth.server.config.web.auth.AuthUser;\nimport cn.hiauth.server.config.web.security.MultiAuthUserService;\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.mapper.AppMapper;\nimport cn.hiauth.server.utils.Constant;\nimport cn.webestar.scms.cache.CacheUtil;\nimport cn.webestar.scms.commons.CommonException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport lombok.Data;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.authentication.BadCredentialsException;\nimport org.springframework.security.authentication.InternalAuthenticationServiceException;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.web.savedrequest.HttpSessionRequestCache;\nimport org.springframework.security.web.savedrequest.SavedRequest;\nimport org.springframework.security.web.savedrequest.SimpleSavedRequest;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\n@Data\n@Slf4j\npublic class AccountAuthenticationProvider implements AuthenticationProvider {\n\n    private CacheUtil cacheUtil;\n\n    private PasswordEncoder passwordEncoder;\n\n    private MultiAuthUserService userDetailsService;\n\n    private HttpSessionRequestCache httpSessionRequestCache;\n\n    private AppMapper appMapper;\n\n    /**\n     * 直接从登录页登录时：获取url中的client_id，并且在登录成功后跳转到对应的应；\n     * 第三方集成、调整过来进行登录授权：判断savedRequest与url中的client_id是否相等，通常都是相等的，所以登录成功后会按照savedRequest设定跳转到对应的应用；\n     */\n    @Override\n    public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n        AccountAuthenticationToken authenticationToken = (AccountAuthenticationToken) authentication;\n        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n        SavedRequest savedRequest = httpSessionRequestCache.getRequest(request, null);\n        String loginClientId = authenticationToken.getClientId();\n        String clientId = null;\n        if (savedRequest != null) {\n            String[] clientIds = savedRequest.getParameterValues(OAuth2ParameterNames.CLIENT_ID);\n            if (clientIds != null && clientIds.length > 0) {\n                clientId = clientIds[0];\n            }\n        }\n        // 如果登录时指定了具体的应用，并且应用和跳转授权指定的应用不一致时，使用登录时指定的应用\n        if (StringUtils.hasText(loginClientId) && !loginClientId.equals(clientId)) {\n            clientId = loginClientId;\n            App app = appMapper.findByClientId(loginClientId);\n            if (app != null && StringUtils.hasText(app.getHome())) {\n                savedRequest = new SimpleSavedRequest(app.getHome());\n                // TODO 这里是否可以优化封装到 MultiAppHttpSessionRequestCache 中\n                request.getSession().setAttribute(\"SPRING_SECURITY_SAVED_REQUEST\", savedRequest);\n                request.getSession().setAttribute(\"SPRING_SECURITY_SAVED_REQUEST\" + \"_\" + clientId, savedRequest);\n            }\n        }\n        AuthUser authUser = null;\n        try {\n            String formToken = authenticationToken.getFormToken();\n            String username = (String) authenticationToken.getPrincipal();\n            String password = (String) authenticationToken.getCredentials();\n            String captcha = authenticationToken.getCaptcha();\n            checkCaptcha(formToken, captcha);\n            authUser = userDetailsService.loadUserByUsername(clientId, username);\n            checkPwdLogin(authUser, password);\n        } catch (CommonException | BadCredentialsException ex) {\n            throw new InternalAuthenticationServiceException(ex.getMessage(), ex);\n        } catch (Exception ex) {\n            throw new InternalAuthenticationServiceException(\"登录失败，请重新登陆\", ex);\n        }\n        if (authUser == null) {\n            throw new InternalAuthenticationServiceException(\"UserDetailsService returned null, which is an interface contract violation\");\n        }\n        return new UsernamePasswordAuthenticationToken(authUser, authUser.getPassword(), authUser.getAuthorities());\n    }\n\n    private void checkPwdLogin(AuthUser authUser, String password) {\n        if (password == null) {\n            log.debug(\"Failed to authenticate since no credentials provided\");\n            throw new BadCredentialsException(\"用户名或者密码错误\");\n        }\n        if (!this.passwordEncoder.matches(password, authUser.getPassword())) {\n            log.debug(\"Failed to authenticate since password does not match stored value\");\n            throw new BadCredentialsException(\"用户名或者密码错误\");\n        }\n    }\n\n    private void checkCaptcha(String formToken, String captcha) {\n        String imgCodeKey = Constant.CACHE_KEY_CAPTCHA + \":\" + formToken;\n        String captchaCache = (String) cacheUtil.get(imgCodeKey);\n        if (captchaCache == null) {\n            throw new BadCredentialsException(\"验证失败请重新验证\");\n        }\n        if (!captchaCache.equalsIgnoreCase(captcha)) {\n            throw new BadCredentialsException(\"验证失败请重新验证\");\n        }\n        //销毁图形验证码，以免别人使用次图像验证码刷接口\n        cacheUtil.expire(imgCodeKey, 0);\n    }\n\n    @Override\n    public boolean supports(Class<?> authentication) {\n        return AccountAuthenticationToken.class.isAssignableFrom(authentication);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/account/AccountAuthenticationToken.java",
    "content": "package cn.hiauth.server.config.web.security.account;\n\nimport org.springframework.security.authentication.AbstractAuthenticationToken;\nimport org.springframework.security.core.GrantedAuthority;\n\nimport java.util.Collection;\n\npublic class AccountAuthenticationToken extends AbstractAuthenticationToken {\n\n    private static final long serialVersionUID = 1L;\n    private final Object principal;\n    private String formToken;\n    private String clientId;\n    private String password;\n    private String captcha;\n\n    public AccountAuthenticationToken(String formToken, String clientId, String username, String password, String captcha) {\n        super(null);\n        this.formToken = formToken;\n        this.clientId = clientId;\n        this.principal = username;\n        this.password = password;\n        this.captcha = captcha;\n        setAuthenticated(false);\n    }\n\n    public AccountAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {\n        super(authorities);\n        this.principal = principal;\n        super.setAuthenticated(true);\n    }\n\n    @Override\n    public Object getCredentials() {\n        return password;\n    }\n\n    @Override\n    public Object getPrincipal() {\n        return principal;\n    }\n\n    public String getFormToken() {\n        return formToken;\n    }\n\n    public String getCaptcha() {\n        return captcha;\n    }\n\n    public String getClientId() {\n        return clientId;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/phone/SmsCodeAuthenticationFilter.java",
    "content": "package cn.hiauth.server.config.web.security.phone;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.authentication.AuthenticationServiceException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\n\npublic class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {\n\n    public SmsCodeAuthenticationFilter(String processUrl) {\n        super(new AntPathRequestMatcher(processUrl, HttpMethod.POST.name()));\n    }\n\n    /**\n     * 获取登录表单中提交的参数（formToken、clientId...），并创建authenticationToken，进行认证\n     */\n    @Override\n    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {\n        String method = request.getMethod();\n        if (!HttpMethod.POST.name().equalsIgnoreCase(method)) {\n            throw new AuthenticationServiceException(\"Authentication method not supported: \" + request.getMethod());\n        } else {\n            String formToken = request.getParameter(\"formToken\");\n            String clientId = request.getParameter(\"clientId\");\n            String phone = request.getParameter(\"phone\");\n            String smsCode = request.getParameter(\"smsCode\");\n            String captcha = request.getParameter(\"captcha\");\n            SmsCodeAuthenticationToken authenticationToken = new SmsCodeAuthenticationToken(formToken, clientId, phone, smsCode, captcha);\n            return this.getAuthenticationManager().authenticate(authenticationToken);\n        }\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/phone/SmsCodeAuthenticationProvider.java",
    "content": "package cn.hiauth.server.config.web.security.phone;\n\nimport cn.hiauth.server.config.web.auth.AuthUser;\nimport cn.hiauth.server.config.web.security.MultiAuthUserService;\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.mapper.AppMapper;\nimport cn.hiauth.server.utils.Constant;\nimport cn.webestar.scms.cache.CacheUtil;\nimport cn.webestar.scms.commons.CommonException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport lombok.Data;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.authentication.BadCredentialsException;\nimport org.springframework.security.authentication.InternalAuthenticationServiceException;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.web.savedrequest.HttpSessionRequestCache;\nimport org.springframework.security.web.savedrequest.SavedRequest;\nimport org.springframework.security.web.savedrequest.SimpleSavedRequest;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\n@Data\npublic class SmsCodeAuthenticationProvider implements AuthenticationProvider {\n\n    private CacheUtil cacheUtil;\n\n    private MultiAuthUserService userDetailsService;\n\n    private String superSmsCode;\n\n    private HttpSessionRequestCache httpSessionRequestCache;\n\n    private AppMapper appMapper;\n\n    /**\n     * 直接从登录页登录时：获取url中的client_id，并且在登录成功后跳转到对应的应；\n     * 第三方集成、调整过来进行登录授权：判断savedRequest与url中的client_id是否相等，通常都是相等的，所以登录成功后会按照savedRequest设定跳转到对应的应用；\n     */\n    @Override\n    public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;\n        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n        SavedRequest savedRequest = httpSessionRequestCache.getRequest(request, null);\n\n        String loginClientId = authenticationToken.getClientId();\n        String clientId = null;\n        if (savedRequest != null) {\n            String[] clientIds = savedRequest.getParameterValues(OAuth2ParameterNames.CLIENT_ID);\n            if (clientIds != null && clientIds.length > 0) {\n                clientId = clientIds[0];\n            }\n        }\n        // 如果登录时指定了具体的应用，并且应用和跳转授权指定的应用不一致时，使用登录时指定的应用\n        if (StringUtils.hasText(loginClientId) && !loginClientId.equals(clientId)) {\n            clientId = loginClientId;\n            App app = appMapper.findByClientId(loginClientId);\n            if (app != null && StringUtils.hasText(app.getHome())) {\n                savedRequest = new SimpleSavedRequest(app.getHome());\n                // TODO 这里是否可以优化封装到 MultiAppHttpSessionRequestCache 中\n                request.getSession().setAttribute(\"SPRING_SECURITY_SAVED_REQUEST\", savedRequest);\n                request.getSession().setAttribute(\"SPRING_SECURITY_SAVED_REQUEST\" + \"_\" + clientId, savedRequest);\n            }\n        }\n        AuthUser authUser = null;\n        try {\n            String formToken = authenticationToken.getFormToken();\n            String phone = (String) authenticationToken.getPrincipal();\n            String smsCode = (String) authenticationToken.getCredentials();\n            String captcha = authenticationToken.getCaptcha();\n            checkCaptcha(formToken, captcha);\n            authUser = userDetailsService.loadUserByPhoneNum(clientId, phone);\n            checkSmsLogin(phone, smsCode);\n        } catch (CommonException | BadCredentialsException ex) {\n            throw new InternalAuthenticationServiceException(ex.getMessage(), ex);\n        } catch (Exception ex) {\n            throw new InternalAuthenticationServiceException(\"登录失败，请重新登陆\", ex);\n        }\n        if (authUser == null) {\n            throw new InternalAuthenticationServiceException(\"UserDetailsService returned null, which is an interface contract violation\");\n        }\n        return new UsernamePasswordAuthenticationToken(authUser, authUser.getPassword(), authUser.getAuthorities());\n    }\n\n    private void checkSmsLogin(String phone, String smsCode) {\n        //此处写验证短信码\n        String key = Constant.CACHE_KEY_SMS_CODE + \":\" + phone;\n        String smsCodeCache = (String) cacheUtil.get(key);\n        if (smsCode.equals(superSmsCode)) {\n            return;\n        }\n        if (smsCodeCache == null || !smsCodeCache.equals(smsCode)) {\n            throw new BadCredentialsException(\"短信验证码错误或者过期，请重新验证\");\n        }\n    }\n\n    private void checkCaptcha(String formToken, String captcha) {\n        String imgCodeKey = Constant.CACHE_KEY_CAPTCHA + \":\" + formToken;\n        String captchaCache = (String) cacheUtil.get(imgCodeKey);\n        if (captchaCache == null) {\n            throw new BadCredentialsException(\"验证失败请重新验证\");\n        }\n        if (!captchaCache.equalsIgnoreCase(captcha)) {\n            throw new BadCredentialsException(\"验证失败请重新验证\");\n        }\n        //销毁图形验证码，以免别人使用次图像验证码刷接口\n        cacheUtil.expire(imgCodeKey, 0);\n    }\n\n    @Override\n    public boolean supports(Class<?> authentication) {\n        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/phone/SmsCodeAuthenticationToken.java",
    "content": "package cn.hiauth.server.config.web.security.phone;\n\nimport org.springframework.security.authentication.AbstractAuthenticationToken;\nimport org.springframework.security.core.GrantedAuthority;\n\nimport java.util.Collection;\n\npublic class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {\n\n    private static final long serialVersionUID = 1L;\n    private final Object principal;\n    private String formToken;\n    private String clientId;\n    private String smsCode;\n    private String captcha;\n\n    public SmsCodeAuthenticationToken(String formToken, String clientId, String phone, String smsCode, String captcha) {\n        super(null);\n        this.formToken = formToken;\n        this.clientId = clientId;\n        this.principal = phone;\n        this.smsCode = smsCode;\n        this.captcha = captcha;\n        setAuthenticated(false);\n    }\n\n    public SmsCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {\n        super(authorities);\n        this.principal = principal;\n        super.setAuthenticated(true);\n    }\n\n    @Override\n    public Object getCredentials() {\n        return smsCode;\n    }\n\n    @Override\n    public Object getPrincipal() {\n        return principal;\n    }\n\n    public String getFormToken() {\n        return formToken;\n    }\n\n    public String getCaptcha() {\n        return captcha;\n    }\n\n    public String getClientId() {\n        return clientId;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/wechat/QrCodeAuthenticationFilter.java",
    "content": "package cn.hiauth.server.config.web.security.wechat;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\n\npublic class QrCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {\n\n    public QrCodeAuthenticationFilter(String processUrl) {\n        super(new AntPathRequestMatcher(processUrl));\n    }\n\n    /**\n     * 获取登录表单中提交的两个参数（clientId、code），并创建authenticationToken，进行认证\n     */\n    @Override\n    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {\n        String clientId = request.getParameter(\"clientId\");\n        String code = request.getParameter(\"code\");\n        QrCodeAuthenticationToken authenticationToken = new QrCodeAuthenticationToken(clientId, code);\n        return this.getAuthenticationManager().authenticate(authenticationToken);\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/wechat/QrCodeAuthenticationProvider.java",
    "content": "package cn.hiauth.server.config.web.security.wechat;\n\nimport cn.hiauth.server.config.web.auth.AuthUser;\nimport cn.hiauth.server.config.web.security.MultiAuthUserService;\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.mapper.AppMapper;\nimport jakarta.servlet.http.HttpServletRequest;\nimport lombok.Data;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.authentication.InternalAuthenticationServiceException;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.web.savedrequest.HttpSessionRequestCache;\nimport org.springframework.security.web.savedrequest.SavedRequest;\nimport org.springframework.security.web.savedrequest.SimpleSavedRequest;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\n@Data\npublic class QrCodeAuthenticationProvider implements AuthenticationProvider {\n\n    private MultiAuthUserService userDetailsService;\n\n    private HttpSessionRequestCache httpSessionRequestCache;\n\n    private AppMapper appMapper;\n\n    /**\n     * 直接从登录页登录时：获取url中的client_id，并且在登录成功后跳转到对应的应；\n     * 第三方集成、调整过来进行登录授权：判断savedRequest与url中的client_id是否相等，通常都是相等的，所以登录成功后会按照savedRequest设定跳转到对应的应用；\n     */\n    @Override\n    public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n        QrCodeAuthenticationToken authenticationToken = (QrCodeAuthenticationToken) authentication;\n\n        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n        SavedRequest savedRequest = httpSessionRequestCache.getRequest(request, null);\n\n        String loginClientId = authenticationToken.getClientId();\n        String clientId = null;\n        if (savedRequest != null) {\n            String[] clientIds = savedRequest.getParameterValues(OAuth2ParameterNames.CLIENT_ID);\n            if (clientIds != null && clientIds.length > 0) {\n                clientId = clientIds[0];\n            }\n        }\n        // 如果登录时指定了具体的应用，并且应用和跳转授权指定的应用不一致时，使用登录时指定的应用\n        if (StringUtils.hasText(loginClientId) && !loginClientId.equals(clientId)) {\n            clientId = loginClientId;\n            App app = appMapper.findByClientId(loginClientId);\n            if (app != null && StringUtils.hasText(app.getHome())) {\n                savedRequest = new SimpleSavedRequest(app.getHome());\n                // TODO 这里是否可以优化封装到 MultiAppHttpSessionRequestCache 中\n                request.getSession().setAttribute(\"SPRING_SECURITY_SAVED_REQUEST\", savedRequest);\n                request.getSession().setAttribute(\"SPRING_SECURITY_SAVED_REQUEST\" + \"_\" + clientId, savedRequest);\n            }\n        }\n\n        String code = (String) authenticationToken.getPrincipal();\n        AuthUser authUser = null;\n        try {\n            authUser = userDetailsService.loadUserWeChatCode(clientId, code);\n        } catch (Exception ex) {\n            throw new InternalAuthenticationServiceException(\"登录失败，请重新登陆\", ex);\n        }\n        if (authUser == null) {\n            throw new InternalAuthenticationServiceException(\"账号未注册，请先注册账号\");\n        }\n        return new UsernamePasswordAuthenticationToken(authUser, authUser.getPassword(), authUser.getAuthorities());\n    }\n\n    @Override\n    public boolean supports(Class<?> authentication) {\n        return QrCodeAuthenticationToken.class.isAssignableFrom(authentication);\n    }\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/config/web/security/wechat/QrCodeAuthenticationToken.java",
    "content": "package cn.hiauth.server.config.web.security.wechat;\n\nimport org.springframework.security.authentication.AbstractAuthenticationToken;\nimport org.springframework.security.core.GrantedAuthority;\n\nimport java.util.Collection;\n\npublic class QrCodeAuthenticationToken extends AbstractAuthenticationToken {\n\n    private static final long serialVersionUID = 1L;\n    private final Object principal;\n    private String clientId;\n    private String code;\n\n    public QrCodeAuthenticationToken(String clientId, String code) {\n        super(null);\n        this.principal = code;\n        this.clientId = clientId;\n        this.code = code;\n        setAuthenticated(false);\n    }\n\n    public QrCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {\n        super(authorities);\n        this.principal = principal;\n        super.setAuthenticated(true);\n    }\n\n    @Override\n    public Object getCredentials() {\n        return code;\n    }\n\n    @Override\n    public Object getPrincipal() {\n        return principal;\n    }\n\n    public String getClientId() {\n        return clientId;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/AuthConsentController.java",
    "content": "package cn.hiauth.server.controller;\n\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.oauth2.core.oidc.OidcScopes;\nimport org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;\nimport org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\n\nimport java.security.Principal;\nimport java.util.*;\n\n@Controller\npublic class AuthConsentController {\n\n    private final RegisteredClientRepository registeredClientRepository;\n    private final OAuth2AuthorizationConsentService authorizationConsentService;\n\n    public AuthConsentController(RegisteredClientRepository registeredClientRepository, OAuth2AuthorizationConsentService authorizationConsentService) {\n        this.registeredClientRepository = registeredClientRepository;\n        this.authorizationConsentService = authorizationConsentService;\n    }\n\n    private static Set<ScopeWithDescription> withDescription(Set<String> scopes) {\n        Set<ScopeWithDescription> scopeWithDescriptions = new HashSet<>();\n        for (String scope : scopes) {\n            scopeWithDescriptions.add(new ScopeWithDescription(scope));\n        }\n        return scopeWithDescriptions;\n    }\n\n    @GetMapping(value = \"/oauth2/consent\")\n    public String consent(Principal principal, Model model,\n                          @RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId,\n                          @RequestParam(OAuth2ParameterNames.SCOPE) String scope,\n                          @RequestParam(OAuth2ParameterNames.STATE) String state) {\n\n        // Remove scopes that were already approved\n        Set<String> scopesToApprove = new HashSet<>();\n        Set<String> previouslyApprovedScopes = new HashSet<>();\n        RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);\n        OAuth2AuthorizationConsent currentAuthorizationConsent = this.authorizationConsentService.findById(registeredClient.getId(), principal.getName());\n        Set<String> authorizedScopes;\n        if (currentAuthorizationConsent != null) {\n            authorizedScopes = currentAuthorizationConsent.getScopes();\n        } else {\n            authorizedScopes = Collections.emptySet();\n        }\n        for (String requestedScope : StringUtils.delimitedListToStringArray(scope, \" \")) {\n            if (OidcScopes.OPENID.equals(requestedScope)) {\n                continue;\n            }\n            if (authorizedScopes.contains(requestedScope)) {\n                previouslyApprovedScopes.add(requestedScope);\n            } else {\n                scopesToApprove.add(requestedScope);\n            }\n        }\n\n        model.addAttribute(\"clientId\", clientId);\n        model.addAttribute(\"state\", state);\n        model.addAttribute(\"scopes\", withDescription(scopesToApprove));\n        model.addAttribute(\"previouslyApprovedScopes\", withDescription(previouslyApprovedScopes));\n        model.addAttribute(\"principalName\", principal.getName());\n\n        return \"consent\";\n    }\n\n    public static class ScopeWithDescription {\n\n        private static final String DEFAULT_DESCRIPTION = \"UNKNOWN SCOPE - We cannot provide information about this permission, use caution when granting this.\";\n        private static final Map<String, String> scopeDescriptions = new HashMap<>();\n\n        static {\n            scopeDescriptions.put(OidcScopes.PROFILE, \"此应用程序将能够读取您的个人资料信息。\");\n            scopeDescriptions.put(\"user\", \"This application will be able to read your user information.\");\n            scopeDescriptions.put(\"message.read\", \"This application will be able to read your message.\");\n            scopeDescriptions.put(\"message.write\", \"This application will be able to add new messages. It will also be able to edit and delete existing messages.\");\n            scopeDescriptions.put(\"other.scope\", \"This is another scope example of a scope description.\");\n        }\n\n        public final String scope;\n        public final String description;\n\n        ScopeWithDescription(String scope) {\n            this.scope = scope;\n            this.description = scopeDescriptions.getOrDefault(scope, DEFAULT_DESCRIPTION);\n        }\n\n    }\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/IndexController.java",
    "content": "package cn.hiauth.server.controller;\n\nimport cn.hiauth.server.api.vo.IndexCorpAppVo;\nimport cn.hiauth.server.config.props.AppProperties;\nimport cn.hiauth.server.config.props.WechatProperties;\nimport cn.hiauth.server.config.web.auth.AuthUser;\nimport cn.hiauth.server.entity.*;\nimport cn.hiauth.server.mapper.CorpAppMapper;\nimport cn.hiauth.server.service.AppService;\nimport cn.hiauth.server.service.CorpService;\nimport cn.hiauth.server.service.EmployeeService;\nimport cn.hiauth.server.service.Oauth2RegisteredClientService;\nimport cn.hiauth.server.utils.Constant;\nimport cn.hutool.core.lang.Snowflake;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.BeanPropertyRowMapper;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\n@Controller\n@PreAuthorize(\"isAuthenticated()\")\npublic class IndexController {\n\n    @Autowired\n    private AppProperties appProperties;\n\n    @Autowired\n    private Snowflake idGenerator;\n\n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n\n    @Autowired\n    private CorpService corpService;\n\n    @Autowired\n    private AppService appService;\n\n    @Autowired\n    private EmployeeService employeeService;\n\n    @Autowired\n    private WechatProperties wechatProperties;\n\n    @Autowired\n    private Oauth2RegisteredClientService oauth2RegisteredClientService;\n\n    @Autowired\n    private CorpAppMapper corpAppMapper;\n\n    @GetMapping(value = {\"/\", \"/index\"})\n    public String index(HttpServletRequest request, Model model, Authentication auth) {\n        AuthUser authUser = (AuthUser) auth.getPrincipal();\n        //如果主动添加了client_id,则跳转到对应的系统\n        String clientId = (String) request.getSession().getAttribute(\"clientId\");\n        if (StringUtils.hasText(clientId)) {\n            Oauth2RegisteredClient client = oauth2RegisteredClientService.findByClientId(clientId);\n            if (client != null && client.getAppId() != null) {\n                List<CorpAppInfo> cpis = corpAppMapper.limitCorpAppInfoByUserId(authUser.getUserId(), client.getAppId());\n                if (cpis != null && !cpis.isEmpty() && StringUtils.hasText(cpis.get(0).getAppHome())) {\n                    return \"redirect:\" + cpis.get(0).getAppHome();\n                }\n            }\n        }\n        //如果主动添加了client_id,则跳转到对应的系统\n        List<IndexCorpAppVo> indexCorpApps = corpService.findIndexCorpAppByUserId(authUser.getUserId(), null);\n        model.addAttribute(\"corpApps\", indexCorpApps);\n        return \"index\";\n    }\n\n    @GetMapping(value = {\"/openApp\"})\n    public String openApp(@RequestParam(\"cid\") Long cid, @RequestParam(\"appId\") Long appId, Authentication auth) {\n        AuthUser authUser = (AuthUser) auth.getPrincipal();\n        App app = appService.getById(appId);\n        employeeService.swichCorp(authUser.getUserId(), cid);\n        return \"redirect:\" + app.getHome();\n    }\n\n    @GetMapping(value = {\"/profile\"})\n    public String profile(Authentication auth) {\n        return \"profile\";\n    }\n\n    @GetMapping(value = {\"/setting\"})\n    public String setting(Authentication auth) {\n        return \"setting\";\n    }\n\n    @ResponseBody\n    @GetMapping(value = {\"/me\"})\n    public String me() {\n        return \"zhangsan\";\n    }\n\n    @GetMapping(value = \"/logout\")\n    public String logout(HttpServletRequest request, HttpServletResponse response, Model model) {\n        Authentication auth = SecurityContextHolder.getContext().getAuthentication();\n        if (auth != null) {\n            new SecurityContextLogoutHandler().logout(request, response, auth);\n        }\n        // 登录方式\n        model.addAttribute(\"loginTypes\", appProperties.getLoginTypes());\n        // 登录页面配置\n        model.addAttribute(Constant.REQUEST_KEY_FORM_TOKEN, idGenerator.nextId());\n        model.addAttribute(\"title\", appProperties.getLoginPageTitle());\n        model.addAttribute(\"username\", appProperties.getLoginPageUsername());\n        model.addAttribute(\"password\", appProperties.getLoginPagePassword());\n        model.addAttribute(\"usernamePlaceholder\", appProperties.getLoginPageUsernamePlaceholder());\n        model.addAttribute(\"passwordPlaceholder\", appProperties.getLoginPagePasswordPlaceholder());\n        // 微信登录配置\n        model.addAttribute(\"wechatAppid\", wechatProperties.getAppid());\n        model.addAttribute(\"wechatRedirectUri\", wechatProperties.getRedirectUri());\n        model.addAttribute(\"wechatStyle\", wechatProperties.getStyle());\n        model.addAttribute(\"wechatHref\", wechatProperties.getHref());\n        model.addAttribute(\"wechaState\", idGenerator.nextId());\n        return appProperties.getLoginPagePath();\n    }\n\n    @GetMapping({\"/user/me\"})\n    public String me(Model model, Authentication auth) {\n        if (auth.getPrincipal() != null) {\n            User user = (User) auth.getPrincipal();\n            model.addAttribute(\"user\", user);\n            List<AuthorizationConsent> authorizationConsentList = myAuthorizationConsentList(user.getUsername());\n            model.addAttribute(\"authorizationConsentList\", authorizationConsentList);\n        }\n        return \"user/me\";\n    }\n\n    private List<AuthorizationConsent> myAuthorizationConsentList(String username) {\n        String sql = \"\"\"\n                SELECT\n                \tT.registered_client_id  registered_client_id,\n                \tT.principal_name        principal_name,\n                \tT.authorities           authorities,\n                \tRC.client_name \t        client_name\n                FROM oauth2_authorization_consent T\n                LEFT JOIN oauth2_registered_client RC ON RC.id=T.registered_client_id\n                WHERE T.principal_name='%s'\n                \"\"\";\n        List<AuthorizationConsent> authorizationConsentList = jdbcTemplate.query(String.format(sql, username), new BeanPropertyRowMapper(AuthorizationConsent.class));\n        return authorizationConsentList;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/LoginController.java",
    "content": "package cn.hiauth.server.controller;\n\nimport cn.hiauth.server.api.dto.login.CaptchaVerifyDto;\nimport cn.hiauth.server.config.props.AppProperties;\nimport cn.hiauth.server.config.props.WechatProperties;\nimport cn.hiauth.server.config.web.security.MultiAppHttpSessionRequestCache;\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.entity.User;\nimport cn.hiauth.server.mapper.AppMapper;\nimport cn.hiauth.server.service.UserService;\nimport cn.hiauth.server.utils.Constant;\nimport cn.hiauth.server.utils.SmsUtils;\nimport cn.hutool.captcha.CaptchaUtil;\nimport cn.hutool.captcha.ICaptcha;\nimport cn.hutool.captcha.generator.RandomGenerator;\nimport cn.hutool.core.lang.Snowflake;\nimport cn.hutool.core.util.RandomUtil;\nimport cn.webestar.scms.cache.CacheUtil;\nimport cn.webestar.scms.commons.R;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\n@Slf4j\n@Controller\npublic class LoginController {\n\n    private final static long timeout = 600;\n\n    @Resource\n    private AppProperties appProperties;\n\n    @Resource\n    private WechatProperties wechatProperties;\n\n    @Resource\n    private CacheUtil cacheUtil;\n\n    @Resource\n    private Snowflake idGenerator;\n\n    @Resource\n    private SmsUtils smsUtils;\n\n    @Resource\n    private AppMapper appMapper;\n\n    @Value(\"${smsUils.smsTemplateCode:}\")\n    private String smsTemplateCode;\n\n    @Resource\n    private RandomGenerator randomGenerator;\n\n    @Resource\n    private UserService userService;\n\n    @GetMapping(value = {\"/login\"}, produces = \"text/html\")\n    public String login(@RequestParam(value = OAuth2ParameterNames.CLIENT_ID, required = false) String clientId, HttpServletRequest request, Model model) {\n        Set<String> loginTypes = appProperties.getLoginTypes();\n        String loginPage = appProperties.getLoginPagePath();\n        // 获取当前授权应用，查询自定义配\n        if (clientId != null) {\n            App app = appMapper.findByClientId(clientId);\n            if (app != null) {\n                model.addAttribute(\"appName\", app.getName());\n                if (app.getExtend() != null) {\n                    if (app.getExtend().containsKey(\"loginTypes\")) {\n                        String str = (String) app.getExtend().get(\"loginTypes\");\n                        loginTypes = Stream.of(str.split(\",\")).collect(Collectors.toSet());\n                    }\n                    if (app.getExtend().containsKey(\"loginPage\")) {\n                        loginPage = (String) app.getExtend().get(\"loginPage\");\n                    }\n                }\n            }\n        }\n        // URL中指定要登录的应用\n        model.addAttribute(MultiAppHttpSessionRequestCache.CLIENT_ID_KEY, clientId);\n        // 登录方式\n        model.addAttribute(\"loginTypes\", loginTypes);\n        // 登录页面配置\n        model.addAttribute(Constant.REQUEST_KEY_FORM_TOKEN, idGenerator.nextId());\n        model.addAttribute(\"title\", appProperties.getLoginPageTitle());\n        model.addAttribute(\"username\", appProperties.getLoginPageUsername());\n        model.addAttribute(\"password\", appProperties.getLoginPagePassword());\n        model.addAttribute(\"usernamePlaceholder\", appProperties.getLoginPageUsernamePlaceholder());\n        model.addAttribute(\"passwordPlaceholder\", appProperties.getLoginPagePasswordPlaceholder());\n        // 微信登录配置\n        String wechatRedirectUri = wechatProperties.getRedirectUri();\n        if (StringUtils.hasText(clientId)) {\n            wechatRedirectUri += \"?\" + MultiAppHttpSessionRequestCache.CLIENT_ID_KEY + \"=\" + clientId;\n        }\n        model.addAttribute(\"wechatAppid\", wechatProperties.getAppid());\n        model.addAttribute(\"wechatRedirectUri\", wechatRedirectUri);\n        model.addAttribute(\"wechatStyle\", wechatProperties.getStyle());\n        model.addAttribute(\"wechatHref\", wechatProperties.getHref());\n        model.addAttribute(\"wechaState\", idGenerator.nextId());\n        return loginPage;\n    }\n\n    /**\n     * 生成一个有效期为180秒的图形验证码，\n     * 并将此验证码和需要保护的数据进行绑定（如:账号、手机号）\n     */\n    @GetMapping(\"/auth/code/image\")\n    public void image(HttpServletRequest request, HttpServletResponse response) throws IOException {\n        String formToken = request.getParameter(Constant.REQUEST_KEY_FORM_TOKEN);\n        ICaptcha captcha = CaptchaUtil.createCircleCaptcha(90, 30, randomGenerator, 10);\n        cacheUtil.set(Constant.CACHE_KEY_CAPTCHA + \":\" + formToken, captcha.getCode(), timeout);\n        log.debug(\"生成图形验证码：{}, 有效期:{}妙\", captcha.getCode(), timeout);\n        captcha.write(response.getOutputStream());\n    }\n\n    /**\n     * 生成一个有效期为180秒的验证码，适用于滑动验证码，需要验证用户行为，验证成功后返回验证码\n     * 并将此验证码和需要保护的数据进行绑定（如:账号、手机号）\n     */\n    @ResponseBody\n    @PostMapping(\"/auth/code/captcha\")\n    public R<String> captcha(@RequestBody CaptchaVerifyDto dto) {\n        String formToken = dto.getToken();\n        ICaptcha captcha = CaptchaUtil.createCircleCaptcha(90, 30, randomGenerator, 10);\n        cacheUtil.set(Constant.CACHE_KEY_CAPTCHA + \":\" + formToken, captcha.getCode(), 60);\n        log.debug(\"生成图形验证码：{}, 有效期:{}妙\", captcha.getCode(), timeout);\n        return R.success(captcha.getCode());\n    }\n\n    /**\n     * 发送一个短信验证码，验证码有效时间为180秒，\n     * 每申请发送一次短信验证码，就需要提供一次不同的imgCode，从而防止接口被刷\n     */\n    @ResponseBody\n    @GetMapping(\"/auth/code/sms\")\n    public R<?> sms(HttpServletRequest request) {\n\n        String formToken = request.getParameter(Constant.REQUEST_KEY_FORM_TOKEN);\n        String imgCode = request.getParameter(\"imgCode\");\n        String telNo = request.getParameter(\"telNo\");\n\n        if (formToken == null || imgCode == null || telNo == null) {\n            return R.fail(20001, \"参数不能为null\");\n        }\n\n        //校验图形验证码是否有效\n        {\n            String imgCodeCache = (String) cacheUtil.get(Constant.CACHE_KEY_CAPTCHA + \":\" + formToken);\n            if (imgCodeCache == null || !imgCodeCache.equalsIgnoreCase(imgCode)) {\n                return R.fail(20101, \"验证码错误\");\n            }\n        }\n\n        //检查imgCode是否已经用于发送短信，一个imgCode只运行发送一次短信\n        {\n            // TODO 暂时未实现\n            String telNoCache = (String) cacheUtil.get(Constant.CACHE_KEY_SMS_CODE + \":\" + formToken + \":\" + imgCode);\n            if (telNoCache != null) {\n                return R.fail(20102, \"验证码已失效\");\n            }\n        }\n\n        LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();\n        qw.eq(User::getIsDeleted, false);\n        qw.eq(User::getPhoneNum, telNo);\n        boolean exists = userService.exists(qw);\n        if (!exists) {\n            return R.fail(20103, \"手机号未注册\");\n        }\n\n        String smsCode = RandomUtil.randomNumbers(6);\n\n        //记录数据到缓存\n        {\n            //记录发往telNo的短信验证码为smsCode\n            cacheUtil.set(Constant.CACHE_KEY_SMS_CODE + \":\" + telNo, smsCode, timeout);\n            //记录imgCode已经用于telNo的短信验证码发送\n            cacheUtil.set(Constant.CACHE_KEY_SMS_CODE + \":\" + formToken + \":\" + imgCode, telNo, timeout);\n        }\n\n        Map<String, String> paramMap = new HashMap<>(2);\n        paramMap.put(\"code\", smsCode);\n        smsUtils.sendSms(telNo, smsTemplateCode, paramMap);\n\n        log.debug(\"生成短信验证码：{}, 有效期:{}妙\", smsCode, timeout);\n        return R.success();\n    }\n\n    @GetMapping(\"/unpapi/logoutWithRedirect\")\n    public String logoutWithRedirect(@RequestParam(\"redirect_uri\") String redirectUri, HttpServletRequest request, HttpServletResponse response) {\n        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();\n        new SecurityContextLogoutHandler().logout(request, response, authentication);\n        return \"redirect:\" + redirectUri;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/OauthController.java",
    "content": "package cn.hiauth.server.controller;\n\nimport cn.hiauth.server.api.dto.user.UserPwdUpdateDto;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.User;\nimport cn.hiauth.server.service.UserService;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.Map;\n\n@Slf4j\n@ResourceApi\n@RestController\n@PreAuthorize(\"isAuthenticated()\")\npublic class OauthController {\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Autowired\n    private UserService userService;\n\n//    @GetMapping(\"/oauth2/user\")\n//    public R<?> oauth2UserInfo(){\n//        Authentication auth = SecurityContextHolder.getContext().getAuthentication();\n//        Jwt jwt = (Jwt) auth.getPrincipal();\n//        Map<String, Object> claims =jwt.getClaims();\n//        Long userId = (Long) claims.get(\"userId\");\n//        return R.success(userId);\n//    }\n\n    @PostMapping(\"/oauth2/user/updatePwd\")\n    public R<Boolean> updatePwd(@RequestBody @Validated UserPwdUpdateDto body) {\n        // 获取当前用户\n        Authentication auth = SecurityContextHolder.getContext().getAuthentication();\n        Jwt jwt = (Jwt) auth.getPrincipal();\n        Map<String, Object> claims = jwt.getClaims();\n        Long userId = (Long) claims.get(\"userId\");\n\n        // 查询用户，比对密码\n        User user = userService.getById(userId);\n        Assert.notNull(user, SysCode.biz(1), \"用户不存在\");\n        Assert.isTrue(passwordEncoder.matches(body.getRawPwd(), user.getPwd()), SysCode.biz(2), \"原密码错误\");\n\n        // 修改密码\n        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();\n        updateWrapper.set(User::getPwd, passwordEncoder.encode(body.getPwd()));\n        updateWrapper.eq(User::getId, user.getId());\n\n        // 更新密码\n        boolean ret = userService.update(updateWrapper);\n        return R.success(ret);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/TestController.java",
    "content": "package cn.hiauth.server.controller;\n\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping\npublic class TestController {\n\n    @GetMapping(\"/unpapi/test/exception\")\n    public R<String> testException() throws Exception {\n        throw new Exception(\"exception\");\n    }\n\n    @GetMapping(\"/unpapi/test/byZero\")\n    public R<String> testByZero() {\n        int i = 1 / 0;\n        return R.success(\"byZero\");\n    }\n\n    @GetMapping(\"/unpapi/test/assert\")\n    public R<String> testAssert() {\n        Assert.isTrue(false, SysCode.biz(1), \"assert false\");\n        return R.success(\"testAssert\");\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/UnpController.java",
    "content": "package cn.hiauth.server.controller;\n\nimport cn.hiauth.server.api.dto.RegisterDto;\nimport cn.hiauth.server.config.props.AppProperties;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.File;\nimport cn.hiauth.server.service.CorpService;\nimport cn.hiauth.server.service.FileService;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport jakarta.servlet.http.HttpServletRequest;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/unpapi\")\npublic class UnpController {\n\n    @Autowired\n    private AppProperties appProperties;\n\n    @Autowired\n    private FileService fileService;\n\n    @Autowired\n    private CorpService corpService;\n\n    @GetMapping(\"/info\")\n    public R<Map<String, String>> info() {\n        Map<String, String> map = new HashMap<>();\n        map.put(\"version\", \"version\");\n        map.put(\"buildTimestamp\", \"buildTimestamp\");\n        return R.success(map);\n    }\n\n    @PostMapping(\"/metadata\")\n    public R<Map<String, Object>> metadata(HttpServletRequest request) {\n        Map<String, Object> data = new HashMap<>(5);\n        data.put(\"usernamePlaceholder\", appProperties.getLoginPageUsernamePlaceholder());\n        data.put(\"passwordPlaceholder\", appProperties.getLoginPagePasswordPlaceholder());\n        data.put(\"encryptType\", appProperties.getEncryptType());\n        data.put(\"publicKey\", appProperties.getPublicKey());\n        return R.success(data);\n    }\n\n    @GetMapping(\"/image/{code}\")\n    public ResponseEntity<byte[]> getImageAsByteArray(@PathVariable(\"code\") String code) {\n        Assert.notNull(code, SysCode.biz(1), \"文件编码错误\");\n        LambdaQueryWrapper<File> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(File::getCode, code);\n        File file = fileService.getOne(queryWrapper);\n        byte[] imageBytes = file.getData();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.IMAGE_JPEG);\n        headers.setContentLength(imageBytes.length);\n        return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);\n    }\n\n    @PostMapping(\"/register\")\n    public R<Boolean> register(@RequestBody @Validated RegisterDto dto) {\n        corpService.register(dto);\n        return R.success(Boolean.TRUE);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/adminspace/CorpMgrController.java",
    "content": "package cn.hiauth.server.controller.adminspace;\n\nimport cn.hiauth.server.api.dto.corp.CorpCreateDto;\nimport cn.hiauth.server.api.dto.corp.CorpPageDto;\nimport cn.hiauth.server.api.dto.corp.CorpUpdateDto;\nimport cn.hiauth.server.api.vo.CorpVo;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.config.rest.security.MySecurityUser;\nimport cn.hiauth.server.entity.Corp;\nimport cn.hiauth.server.entity.Department;\nimport cn.hiauth.server.entity.User;\nimport cn.hiauth.server.service.CorpService;\nimport cn.hiauth.server.service.DepartmentService;\nimport cn.hiauth.server.service.UserService;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.commons.api.PageVO;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/adminSpace/corpMgr\")\npublic class CorpMgrController {\n\n    @Autowired\n    private CorpService corpService;\n\n    @Autowired\n    private UserService userService;\n\n    @Autowired\n    private DepartmentService departmentService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<CorpVo>> page(@RequestBody @Valid CorpPageDto dto) {\n        Page<Corp> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        IPage<Corp> page = corpService.page(p, dto.toQueryWapper());\n        PageVO<CorpVo> pageVo = CorpVo.toPageVo(page);\n        return R.success(pageVo);\n    }\n\n    @PostMapping(\"/findById\")\n    public R<CorpVo> findById(@RequestParam(\"id\") Long id) {\n        Corp o = corpService.getById(id);\n        return R.success(CorpVo.convert(o));\n    }\n\n    @PostMapping(\"/create\")\n    public R<CorpVo> create(@RequestBody @Valid CorpCreateDto body) {\n        Corp o = body.toDO();\n        corpService.save(o);\n        Department dep = new Department();\n        dep.setCid(o.getId());\n        dep.setName(o.getName());\n        departmentService.save(dep);\n        return R.success(CorpVo.convert(o));\n    }\n\n    @PostMapping(\"/update\")\n    public R<CorpVo> update(@RequestBody @Valid CorpUpdateDto body) {\n        Corp o = body.toDO();\n        corpService.updateById(o);\n        return R.success(CorpVo.convert(o));\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<Long>> map) {\n        Set<Long> ids = map.get(\"ids\");\n        boolean b = corpService.removeByIds(ids);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/listCorp\")\n    public R<List<CorpVo>> listCorp() {\n        LambdaQueryWrapper<Corp> wrapper = new LambdaQueryWrapper<>();\n        wrapper.eq(Corp::getIsDeleted, false);\n        List<Corp> corps = corpService.list(wrapper);\n        List<CorpVo> corpVos = CorpVo.convert(corps);\n        return R.success(corpVos);\n    }\n\n    @PostMapping(\"/intoAdminSpace\")\n    public R<Boolean> intoAdminSpace() {\n        MySecurityUser securityUser = (MySecurityUser) SessionContextHolder.getPrincipal();\n        User u = userService.getById(securityUser.getUserId());\n        Assert.isTrue(u.getIsSysAdmin() != null && u.getIsSysAdmin(), SysCode.biz(1), \"您不是管理员，无权切换到管理员工作台\");\n        securityUser.setCid(null);\n        securityUser.setIsCorpAdmin(false);\n        securityUser.setIsSysAdmin(true);\n        SessionContextHolder.refresh();\n        return R.success(Boolean.TRUE);\n    }\n\n    @PostMapping(\"/intoCorpSpace\")\n    public R<Boolean> intoCorpSpace(@RequestParam(\"cid\") Long cid) {\n        MySecurityUser securityUser = (MySecurityUser) SessionContextHolder.getPrincipal();\n        securityUser.setCid(cid);\n        securityUser.setIsCorpAdmin(true);\n        securityUser.setIsSysAdmin(false);\n        SessionContextHolder.refresh();\n        return R.success(Boolean.TRUE);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/adminspace/UserMgrController.java",
    "content": "package cn.hiauth.server.controller.adminspace;\n\nimport cn.hiauth.server.api.dto.user.UserCreateDto;\nimport cn.hiauth.server.api.dto.user.UserPageDto;\nimport cn.hiauth.server.api.dto.user.UserUpdateDto;\nimport cn.hiauth.server.api.vo.UserVo;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.User;\nimport cn.hiauth.server.service.UserService;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.api.PageVO;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/adminSpace/userMgr\")\npublic class UserMgrController {\n\n    private static String DEFAULT_PWD = \"123456\";\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Autowired\n    private UserService userService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<UserVo>> page(@RequestBody @Valid UserPageDto dto) {\n        Page<User> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        LambdaQueryWrapper<User> qw = dto.toQueryWapper();\n        qw.orderByDesc(User::getCreateTime);\n        IPage<User> page = userService.page(p, qw);\n        PageVO<UserVo> pageVo = UserVo.toPageVo(page);\n        return R.success(pageVo);\n    }\n\n    @PostMapping(\"/findById\")\n    public R<UserVo> findById(@RequestParam(\"id\") Long id) {\n        User o = userService.getById(id);\n        return R.success(UserVo.convert(o));\n    }\n\n    @PostMapping(\"/create\")\n    public R<UserVo> create(@RequestBody @Valid UserCreateDto body) {\n        User o = body.toDO();\n        o.setPwd(passwordEncoder.encode(DEFAULT_PWD));\n        userService.save(o);\n        return R.success(UserVo.convert(o));\n    }\n\n    @PostMapping(\"/update\")\n    public R<UserVo> update(@RequestBody @Valid UserUpdateDto body) {\n        User o = body.toDO();\n        userService.updateById(o);\n        return R.success(UserVo.convert(o));\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<Long>> map) {\n        Set<Long> ids = map.get(\"ids\");\n        boolean b = userService.removeByIds(ids);\n        return R.success(b);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/common/AppMgrController.java",
    "content": "package cn.hiauth.server.controller.common;\n\nimport cn.hiauth.server.api.dto.app.AppCreateDto;\nimport cn.hiauth.server.api.dto.app.AppLimitDto;\nimport cn.hiauth.server.api.dto.app.AppPageDto;\nimport cn.hiauth.server.api.dto.app.AppUpdateDto;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.config.rest.security.MySecurityUser;\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.service.AppService;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.commons.api.PageVO;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/common/appMgr\")\npublic class AppMgrController {\n\n    @Autowired\n    private AppService appService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<App>> page(@RequestBody @Valid AppPageDto dto) {\n        MySecurityUser user = (MySecurityUser) SessionContextHolder.getPrincipal();\n        Assert.notNull(user, SysCode.biz(1), \"请先登录\");\n        if (!user.getIsSysAdmin()) {\n            dto.setCid(user.getCid());\n        }\n        Page<App> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        LambdaQueryWrapper<App> qw = dto.toQueryWapper();\n        qw.orderByDesc(App::getCreateTime);\n        IPage<App> page = appService.page(p, qw);\n        return R.success(new PageVO<>(page.getCurrent(), page.getSize(), page.getTotal(), page.getRecords()));\n    }\n\n    @PostMapping(\"/findById\")\n    public R<App> findById(@RequestParam(\"id\") Long id) {\n        App o = appService.getById(id);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/create\")\n    public R<App> create(@RequestBody @Valid AppCreateDto dto) {\n        MySecurityUser user = (MySecurityUser) SessionContextHolder.getPrincipal();\n        Assert.notNull(user, SysCode.biz(1), \"请先登录\");\n        dto.setCid(user.getCid());\n        App o = dto.toDO();\n        appService.save(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/update\")\n    public R<App> update(@RequestBody @Valid AppUpdateDto body) {\n        App o = body.toDO();\n        appService.updateById(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<Long>> map) {\n        Set<Long> ids = map.get(\"ids\");\n        boolean b = appService.removeByIds(ids);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/limitList\")\n    public R<List<App>> limitList(@RequestBody @Valid AppLimitDto dto) {\n        List<App> list = appService.list(dto.toQueryWapper());\n        return R.success(list);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/common/AppResourceMgrController.java",
    "content": "package cn.hiauth.server.controller.common;\n\nimport cn.hiauth.server.api.dto.appResource.AppResourceCreateDto;\nimport cn.hiauth.server.api.dto.appResource.AppResourcePageDto;\nimport cn.hiauth.server.api.dto.appResource.AppResourceUpdateDto;\nimport cn.hiauth.server.api.dto.appResource.FindAppResourceIdsByRoleAndAppDto;\nimport cn.hiauth.server.api.vo.CommonTreeNodeVo;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.AppResource;\nimport cn.hiauth.server.service.AppResourceService;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.api.PageVO;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/common/appResourceMgr\")\npublic class AppResourceMgrController {\n\n    @Autowired\n    private AppResourceService appResourceService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<AppResource>> page(@RequestBody @Valid AppResourcePageDto dto) {\n        Page<AppResource> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        IPage<AppResource> page = appResourceService.page(p, dto.toQueryWapper());\n        page.getRecords().sort(Comparator.comparing(AppResource::getSort));\n        return R.success(new PageVO<>(page.getCurrent(), page.getSize(), page.getTotal(), page.getRecords()));\n    }\n\n    @PostMapping(\"/findById\")\n    public R<AppResource> findById(@RequestParam(\"id\") Long id) {\n        AppResource o = appResourceService.getById(id);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/create\")\n    public R<AppResource> create(@RequestBody @Valid AppResourceCreateDto body) {\n        AppResource o = body.toDO();\n        appResourceService.save(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/update\")\n    public R<AppResource> update(@RequestBody @Valid AppResourceUpdateDto body) {\n        AppResource o = body.toDO();\n        appResourceService.updateById(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<Long>> map) {\n        Set<Long> ids = map.get(\"ids\");\n        boolean b = appResourceService.removeByIds(ids);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/tree\")\n    public R<List<CommonTreeNodeVo>> tree(@RequestParam(\"appId\") Long appId) {\n        List<CommonTreeNodeVo> tree = appResourceService.findAppResourceTree(appId);\n        return R.success(tree);\n    }\n\n    @PostMapping(\"/findAppResourceIdsByRoleAndApp\")\n    public R<Set<Long>> findAppResourceIdsByRoleAndApp(@RequestBody @Valid FindAppResourceIdsByRoleAndAppDto dto) {\n        Set<Long> ids = appResourceService.findAppResourceIdsByRoleAndApp(dto);\n        return R.success(ids);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/common/CommonController.java",
    "content": "package cn.hiauth.server.controller.common;\n\nimport cn.hiauth.server.api.vo.CurrentLoginUserVo;\nimport cn.hiauth.server.api.vo.SysMenuVo;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.config.rest.security.MySecurityUser;\nimport cn.hiauth.server.entity.File;\nimport cn.hiauth.server.service.FileService;\nimport cn.hiauth.server.utils.Constant;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.micrometer.core.instrument.util.IOUtils;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/common\")\npublic class CommonController {\n\n    private static String menu;\n    private static String corpMenu;\n    @Autowired\n    private ObjectMapper objectMapper;\n    @Autowired\n    private FileService fileService;\n\n    @PostMapping(\"/userInfo\")\n    public R<CurrentLoginUserVo> userInfo() {\n        MySecurityUser securityUser = (MySecurityUser) SessionContextHolder.getPrincipal();\n        Assert.notNull(securityUser, SysCode.biz(1), \"未登录，无法获取用户信息\");\n        CurrentLoginUserVo vo = new CurrentLoginUserVo();\n        vo.setUserId(securityUser.getUserId());\n        vo.setName(securityUser.getName());\n        vo.setRealName(securityUser.getName());\n        vo.setAvatar(securityUser.getAvatar());\n        vo.setUsername(securityUser.getUsername());\n        vo.setCid(securityUser.getCid());\n        vo.setEmpId(securityUser.getEmpId());\n        if (securityUser.getIsSysAdmin() != null && securityUser.getIsSysAdmin()) {\n            vo.getRoles().add(\"sysAdmin\");\n        } else if (securityUser.getIsCorpAdmin() != null && securityUser.getIsCorpAdmin()) {\n            vo.getRoles().add(\"corpAdmin\");\n        }\n        return R.success(vo);\n    }\n\n//    @PostMapping(\"/userInfo1\")\n//    public R userInfo1() {\n//        Map<String, Object> map = new HashMap<>();\n//        String[] roles = new String[]{\"corpAdmin\"};\n//        map.put(\"realName\", \"admin\");\n//        map.put(\"username\", \"admin\");\n//        map.put(\"roles\", roles);\n//        return R.success(map);\n//    }\n\n    @PostMapping(\"/codes\")\n    public R codes() {\n        String[] codes = new String[]{\"AC_100100\", \"AC_100110\", \"AC_100120\", \"AC_100010\"};\n        return R.success(codes);\n    }\n\n    @GetMapping(\"/sysMenus\")\n    public R<List<SysMenuVo>> sysMenus(@RequestParam(\"type\") Integer type) throws IOException {\n        String file = \"/mock/sysMenu.json\";\n        String json = null;\n        if (type == 1) {\n            if (menu == null) {\n                ClassPathResource resource = new ClassPathResource(file);\n                menu = IOUtils.toString(resource.getInputStream());\n                menu = menu.replace(\"\\\"{commonIsHide}\\\"\", \"false\")\n                        .replace(\"\\\"{systemIsHide}\\\"\", \"false\")\n                        .replace(\"\\\"{corpIsHide}\\\"\", \"true\");\n            }\n            json = menu;\n        } else if (type == 2) {\n            if (corpMenu == null) {\n                ClassPathResource resource = new ClassPathResource(file);\n                corpMenu = IOUtils.toString(resource.getInputStream());\n                corpMenu = corpMenu.replace(\"\\\"{commonIsHide}\\\"\", \"false\")\n                        .replace(\"\\\"{systemIsHide}\\\"\", \"true\")\n                        .replace(\"\\\"{corpIsHide}\\\"\", \"false\");\n            }\n            json = corpMenu;\n        }\n        List<SysMenuVo> list = objectMapper.readValue(json, List.class);\n        return R.success(list);\n    }\n\n    @GetMapping(\"/sysAction\")\n    public R<Map<String, ?>> sysAction() throws IOException {\n        ClassPathResource resource = new ClassPathResource(\"/mock/sysAction.json\");\n        String content = IOUtils.toString(resource.getInputStream());\n        Map<String, ?> map = objectMapper.readValue(content, Map.class);\n        return R.success(map);\n    }\n\n    @PostMapping(\"/file/uploadImg\")\n    public R<String> handleFileUpload(@RequestParam(\"file\") MultipartFile file) throws IOException {\n        Assert.isTrue(!file.isEmpty(), SysCode.biz(1), \"文件错误\");\n        Assert.isTrue(file.getSize() < 500 * 1024, SysCode.biz(2), \"文件大小不得超过0.5M\");\n        String filename = file.getOriginalFilename();\n        Assert.notNull(filename, SysCode.biz(3), \"文件名错误\");\n        String extName = filename.substring(filename.lastIndexOf(\".\"));\n        String newFileName = UUID.randomUUID().toString().replace(\"-\", \"\") + extName;\n        File f = new File();\n        f.setCode(newFileName);\n        f.setOriginName(filename);\n        f.setName(newFileName);\n        f.setExt(extName);\n        f.setData(file.getBytes());\n        fileService.save(f);\n        Map<String, String> map = new HashMap<>();\n        map.put(\"fileUrl\", Constant.IMG_API + newFileName);\n        return R.success(Constant.IMG_API + newFileName);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/corpspace/AppClientMgrController.java",
    "content": "package cn.hiauth.server.controller.corpspace;\n\nimport cn.hiauth.server.api.dto.appClient.AppClientCreateDto;\nimport cn.hiauth.server.api.dto.appClient.AppClientLimitDto;\nimport cn.hiauth.server.api.dto.appClient.AppClientPageDto;\nimport cn.hiauth.server.api.dto.appClient.AppClientUpdateDto;\nimport cn.hiauth.server.api.vo.CorpAppVo;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.entity.CorpApp;\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport cn.hiauth.server.service.AppService;\nimport cn.hiauth.server.service.CorpAppService;\nimport cn.hiauth.server.service.Oauth2RegisteredClientService;\nimport cn.hiauth.server.utils.Oauth2RegisteredClientUtils;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.commons.api.PageVO;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.*;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/corpSpace/appClientMgr\")\npublic class AppClientMgrController {\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Autowired\n    private Oauth2RegisteredClientService oauth2RegisteredClientService;\n\n    @Autowired\n    private AppService appService;\n\n    @Autowired\n    private CorpAppService corpAppService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<CorpAppVo>> page(@RequestBody @Valid AppClientPageDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Page<Oauth2RegisteredClient> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        IPage<Oauth2RegisteredClient> page = oauth2RegisteredClientService.pageByCorpId(p, dto.toQueryWapper(), cid);\n        Set<Long> appIds = new HashSet<>();\n        page.getRecords().forEach(i -> appIds.add(i.getAppId()));\n        Map<Long, App> apps = new HashMap<>();\n        if (!appIds.isEmpty()) {\n            apps = appService.findByIds(appIds);\n        }\n\n        return R.success(CorpAppVo.toPageVo(page, apps));\n    }\n\n    @PostMapping(\"/findById\")\n    public R<CorpAppVo> findById(@RequestParam(\"id\") String id) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Oauth2RegisteredClient o = oauth2RegisteredClientService.getById(id);\n        App app = appService.getById(o.getAppId());\n        return R.success(CorpAppVo.convert(o, app));\n    }\n\n    @PostMapping(\"/add\")\n    public R<Boolean> add(@RequestBody @Valid AppClientCreateDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCorpId(cid);\n        List<Oauth2RegisteredClient> list = new ArrayList<>();\n        List<CorpApp> corpApps = new ArrayList<>();\n        for (Long appId : dto.getAppIds()) {\n            App app = appService.getById(appId);\n            String clientSecret = passwordEncoder.encode(\"123456\");\n            Oauth2RegisteredClient o = Oauth2RegisteredClientUtils.getDefaultClient(dto.getCorpId(), appId, app.getName(), clientSecret);\n            list.add(o);\n            CorpApp corpApp = new CorpApp();\n            corpApp.setCorpId(dto.getCorpId());\n            corpApp.setAppId(appId);\n            corpApps.add(corpApp);\n        }\n        Boolean b = oauth2RegisteredClientService.saveBatch(list);\n        corpAppService.saveBatch(corpApps);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/update\")\n    public R<Oauth2RegisteredClient> update(@RequestBody @Valid AppClientUpdateDto body) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Oauth2RegisteredClient o = body.toDO();\n        if (StringUtils.isNotBlank(o.getClientSecret())) {\n            o.setClientSecret(passwordEncoder.encode(o.getClientSecret()));\n        }\n        oauth2RegisteredClientService.updateById(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<String>> map) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Set<Long> appIds = new HashSet<>();\n        Set<String> ids = map.get(\"ids\");\n        List<Oauth2RegisteredClient> list = oauth2RegisteredClientService.listByIds(ids);\n        list.forEach(i -> appIds.add(i.getAppId()));\n        boolean b = oauth2RegisteredClientService.removeByIds(ids);\n        LambdaQueryWrapper<CorpApp> qw = new LambdaQueryWrapper<>();\n        qw.eq(CorpApp::getCorpId, cid);\n        qw.in(CorpApp::getAppId, appIds);\n        corpAppService.remove(qw);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/limitNotHaveApp\")\n    public R<List<App>> limitNotHaveApp(@RequestBody @Valid AppClientLimitDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        List<App> list = appService.limitNotHaveApp(dto);\n        return R.success(list);\n    }\n\n    @PostMapping(\"/limitHaveApp\")\n    public R<List<App>> limitHaveApp(@RequestBody @Valid AppClientLimitDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        List<App> list = appService.limitHaveApp(dto);\n        return R.success(list);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/corpspace/DepMgrController.java",
    "content": "package cn.hiauth.server.controller.corpspace;\n\nimport cn.hiauth.server.api.dto.dep.DepCreateDto;\nimport cn.hiauth.server.api.dto.dep.DepLimitDto;\nimport cn.hiauth.server.api.dto.dep.DepPageDto;\nimport cn.hiauth.server.api.dto.dep.DepUpdateDto;\nimport cn.hiauth.server.api.vo.CommonTreeNodeVo;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.Department;\nimport cn.hiauth.server.service.DepartmentService;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.commons.api.PageVO;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/corpSpace/depMgr\")\npublic class DepMgrController {\n\n    @Autowired\n    private DepartmentService departmentService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<Department>> page(@RequestBody @Valid DepPageDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        Page<Department> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        IPage<Department> page = departmentService.page(p, dto.toQueryWapper());\n        page.getRecords().sort(Comparator.comparing(Department::getSort));\n        return R.success(new PageVO<>(page.getCurrent(), page.getSize(), page.getTotal(), page.getRecords()));\n    }\n\n    @PostMapping(\"/limit\")\n    public R<List<Department>> limit(@RequestBody @Valid DepLimitDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        List<Department> list = departmentService.list(dto.toQueryWapper());\n        return R.success(list);\n    }\n\n    @PostMapping(\"/findById\")\n    public R<Department> findById(@RequestParam(\"id\") Long id) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Department o = departmentService.getById(id);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/create\")\n    public R<Department> create(@RequestBody @Valid DepCreateDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        Department o = dto.toDO();\n        departmentService.save(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/update\")\n    public R<Department> update(@RequestBody @Valid DepUpdateDto body) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Department o = body.toDO();\n        departmentService.updateById(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<Long>> map) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Set<Long> ids = map.get(\"ids\");\n        boolean b = departmentService.removeByIds(ids);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/depTree\")\n    public R<List<CommonTreeNodeVo>> depTree() {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        List<CommonTreeNodeVo> tree = departmentService.findDepTree(cid);\n        return R.success(tree);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/corpspace/DictMgrController.java",
    "content": "package cn.hiauth.server.controller.corpspace;\n\nimport cn.hiauth.server.api.dto.dict.DictCreateDto;\nimport cn.hiauth.server.api.dto.dict.DictLimitDto;\nimport cn.hiauth.server.api.dto.dict.DictPageDto;\nimport cn.hiauth.server.api.dto.dict.DictUpdateDto;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.Dict;\nimport cn.hiauth.server.service.DictService;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.commons.api.PageVO;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/corpSpace/dictMgr\")\npublic class DictMgrController {\n\n    @Autowired\n    private DictService dictService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<Dict>> page(@RequestBody @Valid DictPageDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        Page<Dict> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        LambdaQueryWrapper<Dict> qw = dto.toQueryWapper();\n        qw.orderByAsc(Dict::getSort);\n        qw.orderByDesc(Dict::getCreateTime);\n        IPage<Dict> page = dictService.pageByPcode(p, qw, dto.getPCode(), dto.getIsRoot());\n        return R.success(new PageVO<>(page));\n    }\n\n    @PostMapping(\"/findById\")\n    public R<Dict> findById(@RequestParam(\"id\") Long id) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Dict o = dictService.getById(id);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/create\")\n    public R<Dict> create(@RequestBody @Valid DictCreateDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Dict dict = dto.toDO();\n        dict.setCid(cid);\n        dictService.save(dict);\n        return R.success(dict);\n    }\n\n    @PostMapping(\"/update\")\n    public R<Dict> update(@RequestBody @Valid DictUpdateDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Dict o = dto.toDO();\n        dictService.updateById(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<Long>> map) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Set<Long> ids = map.get(\"ids\");\n        int childCount = dictService.childCount(ids);\n        Assert.isTrue(childCount == 0, SysCode.biz(2), \"有子级数据，不能删除\");\n        boolean b = dictService.removeByIds(ids);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/findSubDict\")\n    public R<List<Dict>> findSubDict(@RequestBody @Valid DictLimitDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        Page<Dict> p = new Page<>(dto.getOffset(), dto.getLimit(), true);\n        LambdaQueryWrapper<Dict> qw = dto.toQueryWapper();\n        qw.orderByAsc(Dict::getSort);\n        qw.orderByDesc(Dict::getCreateTime);\n        IPage<Dict> page = dictService.pageByPcode(p, qw, dto.getPcode(), false);\n        return R.success(page.getRecords());\n    }\n\n    @PostMapping(\"/findDict\")\n    public R<List<Dict>> findDict(@RequestBody @Valid DictLimitDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        List<Dict> list = dictService.list(dto.toQueryWapper());\n        return R.success(list);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/corpspace/EmpMgrController.java",
    "content": "package cn.hiauth.server.controller.corpspace;\n\nimport cn.hiauth.server.api.dto.emp.EmpCreateDto;\nimport cn.hiauth.server.api.dto.emp.EmpPageDto;\nimport cn.hiauth.server.api.dto.emp.EmpUpdateDto;\nimport cn.hiauth.server.api.dto.user.UserLimitDto;\nimport cn.hiauth.server.api.vo.EmpVo;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.Employee;\nimport cn.hiauth.server.entity.Role;\nimport cn.hiauth.server.entity.User;\nimport cn.hiauth.server.service.DepartmentService;\nimport cn.hiauth.server.service.EmployeeService;\nimport cn.hiauth.server.service.RoleService;\nimport cn.hiauth.server.service.UserService;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.commons.api.PageVO;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/corpSpace/empMgr\")\npublic class EmpMgrController {\n\n    @Autowired\n    private EmployeeService employeeService;\n\n    @Autowired\n    private DepartmentService departmentService;\n\n    @Autowired\n    private RoleService roleService;\n\n    @Autowired\n    private UserService userService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<EmpVo>> page(@RequestBody @Valid EmpPageDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        Page<Employee> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        LambdaQueryWrapper<Employee> qw = dto.toQueryWapper();\n        qw.orderByDesc(Employee::getCreateTime);\n        IPage<Employee> page = employeeService.pageByDepId(p, qw, dto.getDepIds());\n        return R.success(EmpVo.toPageVo(page));\n    }\n\n    @PostMapping(\"/findById\")\n    public R<EmpVo> findById(@RequestParam(\"id\") Long id) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Employee o = employeeService.getById(id);\n        Set<Long> depIds = departmentService.findDepIdsByEmpId(cid, o.getId());\n        List<Role> roles = roleService.findByEmpId(o.getId());\n        Set<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toSet());\n        return R.success(EmpVo.convert(o, depIds, roleIds));\n    }\n\n    @PostMapping(\"/create\")\n    public R<EmpVo> create(@RequestBody @Valid EmpCreateDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        EmpVo vo = employeeService.create(dto);\n        roleService.setEmpRole(cid, vo.getId(), dto.getRoleIds());\n        return R.success(vo);\n    }\n\n    @PostMapping(\"/update\")\n    public R<EmpVo> update(@RequestBody @Valid EmpUpdateDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        EmpVo vo = employeeService.modify(cid, dto);\n        roleService.setEmpRole(cid, vo.getId(), dto.getRoleIds());\n        return R.success(vo);\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<Long>> map) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Set<Long> ids = map.get(\"ids\");\n        boolean b = employeeService.del(cid, ids);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/findUser\")\n    public R<List<User>> findUser(@RequestBody @Valid UserLimitDto dto) {\n        List<User> list = userService.list(dto.toQueryWapper());\n        return R.success(list);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/controller/corpspace/RoleMgrController.java",
    "content": "package cn.hiauth.server.controller.corpspace;\n\nimport cn.hiauth.server.api.dto.role.*;\nimport cn.hiauth.server.config.rest.ResourceApi;\nimport cn.hiauth.server.entity.Role;\nimport cn.hiauth.server.service.RoleService;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.R;\nimport cn.webestar.scms.commons.SysCode;\nimport cn.webestar.scms.commons.api.PageVO;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.validation.Valid;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Validated\n@ResourceApi\n@RestController\n@RequestMapping(\"/api/corpSpace/roleMgr\")\npublic class RoleMgrController {\n\n    @Autowired\n    private RoleService roleService;\n\n    @PostMapping(\"/page\")\n    public R<PageVO<Role>> page(@RequestBody @Valid RolePageDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        Page<Role> p = new Page<>(dto.getPageNum(), dto.getPageSize(), true);\n        LambdaQueryWrapper<Role> qw = dto.toQueryWapper();\n        qw.orderByDesc(Role::getCreateTime);\n        IPage<Role> page = roleService.page(p, qw);\n        return R.success(new PageVO<>(page.getCurrent(), page.getSize(), page.getTotal(), page.getRecords()));\n    }\n\n    @PostMapping(\"/limit\")\n    public R<List<Role>> page(@RequestBody @Valid RoleLimitDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        dto.setCid(cid);\n        List<Role> list = roleService.list(dto.toQueryWapper());\n        return R.success(list);\n    }\n\n    @PostMapping(\"/findById\")\n    public R<Role> findById(@RequestParam(\"id\") Long id) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Role o = roleService.getById(id);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/create\")\n    public R<Role> create(@RequestBody @Valid RoleCreateDto body) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Role o = body.toDO();\n        o.setCid(cid);\n        roleService.save(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/update\")\n    public R<Role> update(@RequestBody @Valid RoleUpdateDto body) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Role o = body.toDO();\n        roleService.updateById(o);\n        return R.success(o);\n    }\n\n    @PostMapping(\"/delete\")\n    public R<Boolean> delete(@RequestBody Map<String, Set<Long>> map) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        Set<Long> ids = map.get(\"ids\");\n        boolean b = roleService.removeByIds(ids);\n        return R.success(b);\n    }\n\n    @PostMapping(\"/auth\")\n    public R<Boolean> auth(@RequestBody @Valid RoleAuthDto dto) {\n        Long cid = SessionContextHolder.getPrincipal().getCid();\n        Assert.notNull(cid, SysCode.biz(1), \"未登录租户空间\");\n        roleService.auth(dto);\n        return R.success(true);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/App.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\nimport java.util.Map;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_app\", autoResultMap = true)\n@Schema(name = \"App\", description = \"应用\")\npublic class App extends BasicDO<Long> {\n\n    @TableField(\"cid\")\n    @Schema(description = \"创建应用的企业CID\")\n    private Long cid;\n\n    @TableField(\"name\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @TableField(\"icon\")\n    @Schema(description = \"图标\")\n    private String icon;\n\n    @TableField(\"home\")\n    @Schema(description = \"图标\")\n    private String home;\n\n    @TableField(\"create_time\")\n    @Schema(description = \"创建时间\")\n    private LocalDateTime createTime;\n\n    @TableField(\"creator\")\n    @Schema(description = \"创建人\")\n    private Long creator;\n\n    @TableField(\"remark\")\n    @Schema(description = \"说明\")\n    private String remark;\n\n    @Schema(description = \"扩展字段\")\n    @TableField(value = \"extend\", typeHandler = JacksonTypeHandler.class)\n    private Map<String, Object> extend;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/AppResource.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.util.Map;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_app_resource\", autoResultMap = true)\n@Schema(name = \"AppResource\", description = \"系统资源\")\npublic class AppResource extends BasicDO<Long> {\n\n    @TableField(\"pid\")\n    @Schema(description = \"父节点\")\n    private Long pid;\n\n    @TableField(\"app_id\")\n    @Schema(description = \"应用id\")\n    private Long appId;\n\n    @TableField(\"code\")\n    @Schema(description = \"编码\")\n    private String code;\n\n    @TableField(\"url\")\n    @Schema(description = \"URL\")\n    private String url;\n\n    @TableField(\"api\")\n    @Schema(description = \"api\")\n    private String api;\n\n    @TableField(\"sort\")\n    @Schema(description = \"排序\")\n    private Integer sort;\n\n    @TableField(\"name\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @TableField(\"type\")\n    @Schema(description = \"资源类型，1：目录、菜单，2：页面，3：功能、接口\")\n    private Integer type;\n\n    @TableField(\"remark\")\n    @Schema(description = \"备注\")\n    private String remark;\n\n    @Schema(description = \"扩展字段\")\n    @TableField(value = \"extend\", typeHandler = JacksonTypeHandler.class)\n    private Map<String, ?> extend;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/AuthorizationConsent.java",
    "content": "package cn.hiauth.server.entity;\n\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"oauth2_authorization_consent\", autoResultMap = true)\n@Schema(name = \"AuthorizationConsent\", description = \"认证授权\")\npublic class AuthorizationConsent {\n\n    private String registeredClientId;\n    private String clientName;\n    private String principalName;\n    private String authorities;\n\n}\n\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/Corp.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableLogic;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_corp\", autoResultMap = true)\n@Schema(name = \"Corp\", description = \"租户\")\npublic class Corp extends BasicDO<Long> {\n\n    @TableField(\"name\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @TableField(\"icon\")\n    @Schema(description = \"图标\")\n    private String icon;\n\n    @TableField(\"app_count\")\n    @Schema(description = \"应用数\")\n    private Integer appCount;\n\n    @TableField(\"dep_count\")\n    @Schema(description = \"部门数\")\n    private Integer depCount;\n\n    @TableField(\"emp_count\")\n    @Schema(description = \"员工数\")\n    private Integer empCount;\n\n    @TableField(\"status\")\n    @Schema(description = \"状态，1：正常\")\n    private Integer status;\n\n    @TableField(\"creator\")\n    @Schema(description = \"创建人\")\n    private Long creator;\n\n    @TableField(\"updater\")\n    @Schema(description = \"更新人\")\n    private Long updater;\n\n    @TableField(\"deleter\")\n    @Schema(description = \"删除人\")\n    private Long deleter;\n\n    @TableField(\"create_time\")\n    @Schema(description = \"创建时间\")\n    private LocalDateTime createTime;\n\n    @TableField(\"update_time\")\n    @Schema(description = \"更新时间\")\n    private LocalDateTime updateTime;\n\n    @TableField(\"delete_time\")\n    @Schema(description = \"删除时间\")\n    private LocalDateTime deleteTime;\n\n    @TableLogic(value = \"false\", delval = \"true\")\n    @TableField(\"is_deleted\")\n    @Schema(description = \"是否已删除\")\n    private Boolean isDeleted;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/CorpApp.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_corp_app\", autoResultMap = true)\n@Schema(name = \"CorpApp\", description = \"租户应用关联\")\npublic class CorpApp extends BasicDO<Long> {\n\n    @TableField(\"app_id\")\n    @Schema(description = \"应用id\")\n    private Long appId;\n\n    @TableField(\"corp_id\")\n    @Schema(description = \"租户id\")\n    private Long corpId;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/CorpAppInfo.java",
    "content": "package cn.hiauth.server.entity;\n\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\n\n@Data\npublic class CorpAppInfo {\n\n    @Schema(description = \"租户id\")\n    private Long corpId;\n\n    @Schema(description = \"租户名称\")\n    private String corpName;\n\n    @Schema(description = \"应用id\")\n    private Long appId;\n\n    @Schema(description = \"应用名称\")\n    private String appName;\n\n    @Schema(description = \"应用首页\")\n    private String appHome;\n\n    @Schema(description = \"应用说明\")\n    private String appRemark;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/Department.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_department\", autoResultMap = true)\n@Schema(name = \"Department\", description = \"部门\")\npublic class Department extends BasicDO<Long> {\n\n    @TableField(\"cid\")\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @TableField(\"pid\")\n    @Schema(description = \"父部门\")\n    private Long pid;\n\n    @TableField(\"sort\")\n    @Schema(description = \"排序号\")\n    private Integer sort;\n\n    @TableField(\"no\")\n    @Schema(description = \"部门编码\")\n    private String no;\n\n    @TableField(\"name\")\n    @Schema(description = \"部门名称\")\n    private String name;\n\n    @TableField(\"creator\")\n    @Schema(description = \"创建人\")\n    private Long creator;\n\n    @TableField(\"updater\")\n    @Schema(description = \"更新人\")\n    private Long updater;\n\n    @TableField(\"create_time\")\n    @Schema(description = \"创建时间\")\n    private LocalDateTime createTime;\n\n    @TableField(\"update_time\")\n    @Schema(description = \"更新时间\")\n    private LocalDateTime updateTime;\n\n    @TableField(\"status\")\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    private Integer status;\n\n    @TableField(\"remark\")\n    @Schema(description = \"备注\")\n    private String remark;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/Dict.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_dict\", autoResultMap = true)\n@Schema(name = \"Dict\", description = \"字典\")\npublic class Dict extends BasicDO<Long> {\n\n    @TableField(\"cid\")\n    @Schema(description = \"cid\")\n    private Long cid;\n\n    @TableField(\"sort\")\n    @Schema(description = \"排序\")\n    private Integer sort;\n\n    @TableField(\"code\")\n    @Schema(description = \"编码\")\n    private String code;\n\n    @TableField(\"p_code\")\n    @Schema(description = \"父编码\")\n    private String pCode;\n\n    @TableField(\"name\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @TableField(\"value\")\n    @Schema(description = \"值\")\n    private String value;\n\n    @TableField(\"is_enable\")\n    @Schema(description = \"是否启用\")\n    private Boolean isEnable;\n\n    @TableField(\"create_time\")\n    @Schema(description = \"创建时间\")\n    private LocalDateTime createTime;\n\n    @TableField(\"has_child\")\n    @Schema(description = \"是否有子节点\")\n    private Boolean hasChild;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/Employee.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_employee\", autoResultMap = true)\n@Schema(name = \"Employee\", description = \"员工\")\npublic class Employee extends BasicDO<Long> {\n\n    @TableField(\"cid\")\n    @Schema(description = \"租户ID\")\n    private Long cid;\n\n    @TableField(\"user_id\")\n    @Schema(description = \"用户id\")\n    private Long userId;\n\n    @TableField(\"no\")\n    @Schema(description = \"员工号\")\n    private String no;\n\n    @TableField(\"name\")\n    @Schema(description = \"姓名\")\n    private String name;\n\n    @TableField(\"email\")\n    @Schema(description = \"邮箱\")\n    private String email;\n\n    @TableField(\"is_corp_admin\")\n    @Schema(description = \"是否为租户管理员\")\n    private Boolean isCorpAdmin;\n\n    @TableField(\"last_login_time\")\n    @Schema(description = \"最后登录时间\")\n    private LocalDateTime lastLoginTime;\n\n    @TableField(\"creator\")\n    @Schema(description = \"创建人\")\n    private Long creator;\n\n    @TableField(\"updater\")\n    @Schema(description = \"更新人\")\n    private Long updater;\n\n    @TableField(\"deleter\")\n    @Schema(description = \"删除人\")\n    private Long deleter;\n\n    @TableField(\"create_time\")\n    @Schema(description = \"创建时间\")\n    private LocalDateTime createTime;\n\n    @TableField(\"update_time\")\n    @Schema(description = \"更新时间\")\n    private LocalDateTime updateTime;\n\n    @TableField(\"delete_time\")\n    @Schema(description = \"删除时间\")\n    private LocalDateTime deleteTime;\n\n    // 使用起来太麻烦，去掉\n    // @TableLogic(value = \"false\", delval = \"true\")\n    @TableField(\"is_deleted\")\n    @Schema(description = \"是否已删除\")\n    private Boolean isDeleted;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/File.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_file\", autoResultMap = true)\n@Schema(name = \"File\", description = \"文件\")\npublic class File extends BasicDO<Long> {\n\n    @TableField(\"origin_name\")\n    @Schema(description = \"原始名称\")\n    private String originName;\n\n    @TableField(\"code\")\n    @Schema(description = \"编码\")\n    private String code;\n\n    @TableField(\"name\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @TableField(\"ext\")\n    @Schema(description = \"扩展名\")\n    private String ext;\n\n    @TableField(\"data\")\n    @Schema(description = \"数据\")\n    private byte[] data;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/Oauth2Authorization.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"oauth2_authorization\", autoResultMap = true)\n@Schema(name = \"Oauth2Authorization\", description = \"oauth2认证\")\npublic class Oauth2Authorization extends BasicDO<String> {\n\n    @TableField(\"registered_client_id\")\n    @Schema(description = \"\")\n    private String registeredClientId;\n\n    @TableField(\"principal_name\")\n    @Schema(description = \"\")\n    private String principalName;\n\n    @TableField(\"authorization_grant_type\")\n    @Schema(description = \"\")\n    private String authorizationGrantType;\n\n    @TableField(\"authorized_scopes\")\n    @Schema(description = \"\")\n    private String authorizedScopes;\n\n    @TableField(\"attributes\")\n    @Schema(description = \"\")\n    private String attributes;\n\n    @TableField(\"state\")\n    @Schema(description = \"\")\n    private String state;\n\n    @TableField(\"authorization_code_value\")\n    @Schema(description = \"\")\n    private String authorizationCodeValue;\n\n    @TableField(\"authorization_code_issued_at\")\n    @Schema(description = \"\")\n    private LocalDateTime authorizationCodeIssuedAt;\n\n    @TableField(\"authorization_code_expires_at\")\n    @Schema(description = \"\")\n    private LocalDateTime authorizationCodeExpiresAt;\n\n    @TableField(\"authorization_code_metadata\")\n    @Schema(description = \"\")\n    private String authorizationCodeMetadata;\n\n    @TableField(\"access_token_value\")\n    @Schema(description = \"\")\n    private String accessTokenValue;\n\n    @TableField(\"access_token_issued_at\")\n    @Schema(description = \"\")\n    private LocalDateTime accessTokenIssuedAt;\n\n    @TableField(\"access_token_expires_at\")\n    @Schema(description = \"\")\n    private LocalDateTime accessTokenExpiresAt;\n\n    @TableField(\"access_token_metadata\")\n    @Schema(description = \"\")\n    private String accessTokenMetadata;\n\n    @TableField(\"access_token_type\")\n    @Schema(description = \"\")\n    private String accessTokenType;\n\n    @TableField(\"access_token_scopes\")\n    @Schema(description = \"\")\n    private String accessTokenScopes;\n\n    @TableField(\"oidc_id_token_value\")\n    @Schema(description = \"\")\n    private String oidcIdTokenValue;\n\n    @TableField(\"oidc_id_token_issued_at\")\n    @Schema(description = \"\")\n    private LocalDateTime oidcIdTokenIssuedAt;\n\n    @TableField(\"oidc_id_token_expires_at\")\n    @Schema(description = \"\")\n    private LocalDateTime oidcIdTokenExpiresAt;\n\n    @TableField(\"oidc_id_token_metadata\")\n    @Schema(description = \"\")\n    private String oidcIdTokenMetadata;\n\n    @TableField(\"refresh_token_value\")\n    @Schema(description = \"\")\n    private String refreshTokenValue;\n\n    @TableField(\"refresh_token_issued_at\")\n    @Schema(description = \"\")\n    private LocalDateTime refreshTokenIssuedAt;\n\n    @TableField(\"refresh_token_expires_at\")\n    @Schema(description = \"\")\n    private LocalDateTime refreshTokenExpiresAt;\n\n    @TableField(\"refresh_token_metadata\")\n    @Schema(description = \"\")\n    private String refreshTokenMetadata;\n\n    @TableField(\"user_code_value\")\n    @Schema(description = \"\")\n    private String userCodeValue;\n\n    @TableField(\"user_code_issued_at\")\n    @Schema(description = \"\")\n    private LocalDateTime userCodeIssuedAt;\n\n    @TableField(\"user_code_expires_at\")\n    @Schema(description = \"\")\n    private LocalDateTime userCodeExpiresAt;\n\n    @TableField(\"user_code_metadata\")\n    @Schema(description = \"\")\n    private String userCodeMetadata;\n\n    @TableField(\"device_code_value\")\n    @Schema(description = \"\")\n    private String deviceCodeValue;\n\n    @TableField(\"device_code_issued_at\")\n    @Schema(description = \"\")\n    private LocalDateTime deviceCodeIssuedAt;\n\n    @TableField(\"device_code_expires_at\")\n    @Schema(description = \"\")\n    private LocalDateTime deviceCodeExpiresAt;\n\n    @TableField(\"device_code_metadata\")\n    @Schema(description = \"\")\n    private String deviceCodeMetadata;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/Oauth2AuthorizationConsent.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.Entity;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"oauth2_authorization_consent\", autoResultMap = true)\n@Schema(name = \"Oauth2AuthorizationConsent\", description = \"oauth2认证授权\")\npublic class Oauth2AuthorizationConsent implements Entity {\n\n    @TableField(\"registered_client_id\")\n    @Schema(description = \"\")\n    private String registeredClientId;\n\n    @TableField(\"principal_name\")\n    @Schema(description = \"\")\n    private String principalName;\n\n    @TableField(\"authorities\")\n    @Schema(description = \"\")\n    private String authorities;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/Oauth2RegisteredClient.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"oauth2_registered_client\", autoResultMap = true)\n@Schema(name = \"Oauth2RegisteredClient\", description = \"oauth2客户端\")\npublic class Oauth2RegisteredClient extends BasicDO<String> {\n\n    @TableField(\"cid\")\n    @Schema(description = \"租户ID(扩展添加字段)\")\n    private Long cid;\n\n    @TableField(\"app_id\")\n    @Schema(description = \"应用id(扩展添加字段)\")\n    private Long appId;\n\n    @TableField(\"client_id\")\n    @Schema(description = \"\")\n    private String clientId;\n\n    @TableField(\"client_id_issued_at\")\n    @Schema(description = \"\")\n    private LocalDateTime clientIdIssuedAt;\n\n    @TableField(\"client_secret\")\n    @Schema(description = \"\")\n    private String clientSecret;\n\n    @TableField(\"client_secret_expires_at\")\n    @Schema(description = \"\")\n    private LocalDateTime clientSecretExpiresAt;\n\n    @TableField(\"client_name\")\n    @Schema(description = \"\")\n    private String clientName;\n\n    @TableField(\"client_authentication_methods\")\n    @Schema(description = \"\")\n    private String clientAuthenticationMethods;\n\n    @TableField(\"authorization_grant_types\")\n    @Schema(description = \"\")\n    private String authorizationGrantTypes;\n\n    @TableField(\"redirect_uris\")\n    @Schema(description = \"\")\n    private String redirectUris;\n\n    @TableField(\"post_logout_redirect_uris\")\n    @Schema(description = \"\")\n    private String postLogoutRedirectUris;\n\n    @TableField(\"scopes\")\n    @Schema(description = \"\")\n    private String scopes;\n\n    @TableField(\"client_settings\")\n    @Schema(description = \"\")\n    private String clientSettings;\n\n    @TableField(\"token_settings\")\n    @Schema(description = \"\")\n    private String tokenSettings;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/Role.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport com.fasterxml.jackson.databind.annotation.JsonDeserialize;\nimport com.fasterxml.jackson.databind.annotation.JsonSerialize;\nimport com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;\nimport com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_role\", autoResultMap = true)\n@Schema(name = \"Role\", description = \"角色\")\npublic class Role extends BasicDO<Long> {\n\n    @TableField(\"cid\")\n    @Schema(description = \"cid\")\n    private Long cid;\n\n    @TableField(\"name\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @TableField(\"remark\")\n    @Schema(description = \"备注\")\n    private String remark;\n\n    @TableField(\"creator\")\n    @Schema(description = \"创建人\")\n    private Long creator;\n\n    @TableField(\"updater\")\n    @Schema(description = \"更新人\")\n    private Long updater;\n\n    @TableField(\"create_time\")\n    @Schema(description = \"创建时间\")\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\", timezone = \"GMT+8\")\n    @JsonDeserialize(using = LocalDateTimeDeserializer.class)\n    @JsonSerialize(using = LocalDateTimeSerializer.class)\n    private LocalDateTime createTime;\n\n    @TableField(\"update_time\")\n    @Schema(description = \"更新时间\")\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\", timezone = \"GMT+8\")\n    @JsonDeserialize(using = LocalDateTimeDeserializer.class)\n    @JsonSerialize(using = LocalDateTimeSerializer.class)\n    private LocalDateTime updateTime;\n\n    @TableField(\"is_enable\")\n    @Schema(description = \"是否可用\")\n    private Boolean isEnable;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/RoleAppResource.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_role_app_resource\", autoResultMap = true)\n@Schema(name = \"RoleAppResource\", description = \"角色应用资源关联\")\npublic class RoleAppResource extends BasicDO<Long> {\n\n    @TableField(\"app_id\")\n    @Schema(description = \"应用id\")\n    private Long appId;\n\n    @TableField(\"cid\")\n    @Schema(description = \"租户id\")\n    private Long cid;\n\n    @TableField(\"role_id\")\n    @Schema(description = \"角色id\")\n    private Long roleId;\n\n    @TableField(\"app_resource_id\")\n    @Schema(description = \"应用资源id\")\n    private Long appResourceId;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/SysLog.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_sys_log\", autoResultMap = true)\n@Schema(name = \"SysLog\", description = \"系统日志\")\npublic class SysLog extends BasicDO<Long> {\n\n    @TableField(\"cid\")\n    @Schema(description = \"cid\")\n    private Long cid;\n\n    @TableField(\"actor\")\n    @Schema(description = \"事件触发者\")\n    private String actor;\n\n    @TableField(\"actor_ip\")\n    @Schema(description = \"触发者ip\")\n    private String actorIp;\n\n    @TableField(\"actor_type\")\n    @Schema(description = \"触发者类型，1：系统，2：员工\")\n    private Integer actorType;\n\n    @TableField(\"actor_emp_id\")\n    @Schema(description = \"触发者员工id\")\n    private Long actorEmpId;\n\n    @TableField(\"actor_user_id\")\n    @Schema(description = \"事件触发者用户id\")\n    private Long actorUserId;\n\n    @TableField(\"event_time\")\n    @Schema(description = \"事件产生时间\")\n    private LocalDateTime eventTime;\n\n    @TableField(\"event_type\")\n    @Schema(description = \"事件分类\")\n    private String eventType;\n\n    @TableField(\"event_level\")\n    @Schema(description = \"事件等级\")\n    private Integer eventLevel;\n\n    @TableField(\"event_result\")\n    @Schema(description = \"事件结果\")\n    private String eventResult;\n\n    @TableField(\"event_desc\")\n    @Schema(description = \"事件描述\")\n    private String eventDesc;\n\n    @TableField(\"username\")\n    @Schema(description = \"触发者的用户名\")\n    private String username;\n\n    @TableField(\"source_sys\")\n    @Schema(description = \"事件产生的系统\")\n    private String sourceSys;\n\n    @TableField(\"source_module\")\n    @Schema(description = \"事件产生的模块\")\n    private String sourceModule;\n\n    @TableField(\"create_time\")\n    @Schema(description = \"创建时间\")\n    private LocalDateTime createTime;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/entity/User.java",
    "content": "package cn.hiauth.server.entity;\n\nimport cn.webestar.scms.commons.entity.BasicDO;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;\nimport io.swagger.v3.oas.annotations.media.Schema;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport java.time.LocalDateTime;\nimport java.util.Map;\n\n@Data\n@Accessors(chain = true)\n@EqualsAndHashCode(callSuper = false)\n@TableName(value = \"t_user\", autoResultMap = true)\n@Schema(name = \"User\", description = \"用户\")\npublic class User extends BasicDO<Long> {\n\n    @TableField(\"name\")\n    @Schema(description = \"名称\")\n    private String name;\n\n    @TableField(\"gender\")\n    @Schema(description = \"性别，0：未知，1：男，2：女\")\n    private Integer gender;\n\n    @TableField(\"avatar_url\")\n    @Schema(description = \"头像\")\n    private String avatarUrl;\n\n    @TableField(\"phone_num\")\n    @Schema(description = \"手机号码\")\n    private String phoneNum;\n\n    @TableField(\"username\")\n    @Schema(description = \"用户名\")\n    private String username;\n\n    @TableField(\"pwd\")\n    @Schema(description = \"密码\")\n    private String pwd;\n\n    @TableField(\"wxmp_openid\")\n    @Schema(description = \"微信小程序openid\")\n    private String wxmpOpenid;\n\n    @TableField(\"wx_openid\")\n    @Schema(description = \"微信openid\")\n    private String wxOpenid;\n\n    @TableField(\"wx_unionid\")\n    @Schema(description = \"微信unionid\")\n    private String wxUnionid;\n\n    @TableField(\"status\")\n    @Schema(description = \"状态，0：禁用，1：启用\")\n    private Integer status;\n\n    @TableField(\"regtime\")\n    @Schema(description = \"注册时间\")\n    private LocalDateTime regtime;\n\n    @TableField(\"last_login_time\")\n    @Schema(description = \"最后登录时间\")\n    private LocalDateTime lastLoginTime;\n\n    @TableField(\"creator\")\n    @Schema(description = \"创建人\")\n    private Long creator;\n\n    @TableField(\"updater\")\n    @Schema(description = \"更新人\")\n    private Long updater;\n\n    @TableField(\"deleter\")\n    @Schema(description = \"删除人\")\n    private Long deleter;\n\n    @TableField(\"create_time\")\n    @Schema(description = \"创建时间\")\n    private LocalDateTime createTime;\n\n    @TableField(\"update_time\")\n    @Schema(description = \"更新时间\")\n    private LocalDateTime updateTime;\n\n    @TableField(\"delete_time\")\n    @Schema(description = \"删除时间\")\n    private LocalDateTime deleteTime;\n\n    // 使用起来太麻烦，去掉\n    //@TableLogic(value = \"false\", delval = \"true\")\n    @TableField(\"is_deleted\")\n    @Schema(description = \"是否已删除\")\n    private Boolean isDeleted;\n\n    @TableField(\"is_sys_admin\")\n    @Schema(description = \"是否为系统管理员\")\n    private Boolean isSysAdmin;\n\n    @Schema(description = \"扩展字段\")\n    @TableField(value = \"extend\", typeHandler = JacksonTypeHandler.class)\n    private Map<String, Object> extend;\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/AppMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.api.dto.appClient.AppClientLimitDto;\nimport cn.hiauth.server.entity.App;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.ResultMap;\nimport org.apache.ibatis.annotations.Select;\n\nimport java.util.List;\n\n/**\n * 应用\n */\n@Mapper\npublic interface AppMapper extends BaseMapper<App> {\n\n    @Select(\"\"\"\n                SELECT DISTINCT O.* FROM t_app O\n                LEFT JOIN t_corp_app AS O1 ON O1.app_id = O.id\n                WHERE O1.corp_id = #{cid}\n            \"\"\")\n    List<App> findByCid(@Param(\"cid\") Long cid);\n\n    @Select(\"\"\"\n                SELECT * FROM t_app\n                WHERE id NOT IN(\n                    SELECT O.id FROM t_app O\n                    LEFT JOIN oauth2_registered_client AS O1 ON O1.app_id = O.id\n                    WHERE O1.cid = #{dto.cid}\n                )\n                OFFSET #{dto.offset} LIMIT #{dto.limit}\n            \"\"\")\n    List<App> limitNotHaveApp(@Param(\"dto\") AppClientLimitDto dto);\n\n    @Select(\"\"\"\n                SELECT O.* FROM t_app O\n                LEFT JOIN oauth2_registered_client AS O1 ON O1.app_id = O.id\n                WHERE O1.cid = #{dto.cid}\n                OFFSET #{dto.offset} LIMIT #{dto.limit}\n            \"\"\")\n    List<App> limitHaveApp(@Param(\"dto\") AppClientLimitDto dto);\n\n    @ResultMap(\"BaseResultMap\")\n    @Select(\"\"\"\n                SELECT O.* FROM t_app O\n                LEFT JOIN oauth2_registered_client AS O1 ON O1.app_id = O.id\n                WHERE O1.client_id = #{clientId}\n            \"\"\")\n    App findByClientId(@Param(\"clientId\") String clientId);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/AppResourceMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.AppResource;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Select;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 系统资源\n */\n@Mapper\npublic interface AppResourceMapper extends BaseMapper<AppResource> {\n\n    @Select(\"\"\"\n                <script>\n                SELECT O.* FROM t_app_resource O\n                LEFT JOIN t_role_app_resource AS O1 ON O1.app_resource_id = O.id\n                WHERE O.app_id=#{appId} AND O1.role_id IN <foreach collection='roleIds' item='id' open='(' separator=',' close=')'>#{id}</foreach>\n                </script>\n            \"\"\")\n    List<AppResource> findByAppIdAndRoleIds(@Param(\"appId\") Long appId, @Param(\"roleIds\") Set<Long> roleIds);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/CorpAppMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.CorpApp;\nimport cn.hiauth.server.entity.CorpAppInfo;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Select;\n\nimport java.util.List;\n\n/**\n * 租户\n */\n@Mapper\npublic interface CorpAppMapper extends BaseMapper<CorpApp> {\n\n    @Select(\"\"\"\n            <script>\n            SELECT\n               O1.id\t\tappId,\n               O1.name\t\tappName,\n               O1.home\t\tappHome,\n               O1.remark\tappRemark,\n               O2.id\t\tcorpId,\n               O2.name\t\tcorpName\n            FROM t_corp_app O\n            LEFT JOIN t_app AS O1 ON O1.id = O.app_id\n            LEFT JOIN t_corp AS O2 ON O2.id = O.corp_id\n            LEFT JOIN t_employee AS O3 ON O3.cid = O.corp_id\n            WHERE O3.user_id = #{userId} <if test=\"appId!=null\">AND O.app_id=#{appId}</if>\n            ORDER BY O3.last_login_time DESC NULLS LAST\n            </script>\n            \"\"\")\n    List<CorpAppInfo> limitCorpAppInfoByUserId(@Param(\"userId\") Long userId, @Param(\"appId\") Long appId);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/CorpMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.Corp;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.ResultMap;\nimport org.apache.ibatis.annotations.Select;\n\nimport java.util.List;\n\n/**\n * 租户\n */\n@Mapper\npublic interface CorpMapper extends BaseMapper<Corp> {\n\n    @ResultMap(\"BaseResultMap\")\n    @Select(\"\"\"\n                <script>\n                SELECT O.* FROM t_corp O\n                LEFT JOIN t_employee O1 ON O1.cid = O.id\n                WHERE O1.user_id=#{userId}\n                ORDER BY O1.last_login_time DESC\n                </script>\n            \"\"\")\n    List<Corp> findByUserId(@Param(\"userId\") Long userId);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/DepartmentMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.Department;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * 部门\n */\n@Mapper\npublic interface DepartmentMapper extends BaseMapper<Department> {\n\n    @Select(\"\"\"\n                SELECT O.dep_id FROM t_dep_emp O\n                WHERE O.cid=#{cid} AND O.emp_id=#{empId}\n            \"\"\")\n    Set<Long> findDepIdsByEmpId(@Param(\"cid\") Long cid, @Param(\"empId\") Long empId);\n\n    @Insert(\"\"\"\n                <script>\n                INSERT INTO t_dep_emp (id, cid, emp_id, dep_id) VALUES\n                <foreach collection=\"depEmps\" item=\"o\" index=\"index\" separator=\",\">\n                    (#{o.id}, #{o.cid},#{o.empId},#{o.depId})\n                </foreach>\n                </script>\n            \"\"\")\n    void addDepEmp(@Param(\"depEmps\") List<Map<String, Object>> depEmps);\n\n    @Insert(\"\"\"\n                <script>\n                INSERT INTO t_dep_emp (id, cid, emp_id, dep_id) VALUES\n                <foreach collection=\"depEmps\" item=\"o\" index=\"index\" separator=\",\">\n                    (#{o.id}, #{o.cid},#{o.empId},#{o.depId})\n                </foreach>\n                ON CONFLICT DO NOTHING\n                </script>\n            \"\"\")\n    void modifyDepEmp(@Param(\"depEmps\") List<Map<String, Object>> depEmps);\n\n    @Delete(\"\"\"\n                <script>\n                DELETE FROM t_dep_emp WHERE cid=#{cid} AND emp_id=#{empId} \n                    AND dep_id NOT IN <foreach collection=\"depIds\" item=\"depId\" index=\"index\" open=\"(\" separator=\",\" close=\")\">#{depId}</foreach>\n                </script>\n            \"\"\")\n    void resetEmpDep(@Param(\"cid\") Long cid, @Param(\"empId\") Long empId, @Param(\"depIds\") Set<Long> depIds);\n\n    @Delete(\"\"\"\n                <script>\n                DELETE FROM t_dep_emp WHERE cid=#{cid} AND emp_id IN <foreach collection=\"empIds\" item=\"empId\" index=\"index\" open=\"(\" separator=\",\" close=\")\">#{empId}</foreach>\n                </script>\n            \"\"\")\n    void del(@Param(\"cid\") Long cid, @Param(\"empIds\") Set<Long> empIds);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/DictMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.Dict;\nimport cn.webestar.scms.mybatisplus.cache.CacheHelper;\nimport com.baomidou.mybatisplus.core.conditions.Wrapper;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport org.apache.ibatis.annotations.*;\n\nimport java.util.Set;\n\n/**\n * 字典\n */\n@Mapper\n@CacheNamespace(implementation = CacheHelper.class, eviction = CacheHelper.class)\npublic interface DictMapper extends BaseMapper<Dict> {\n\n    @ResultMap(\"BaseResultMap\")\n    @Select(\"\"\"\n            <script>\n            SELECT DISTINCT * FROM (\n                SELECT (O1.id IS NOT NULL) AS has_child, O.*  FROM t_dict O\n                LEFT JOIN t_dict O1 ON O1.p_code = O.code\n            ) AS Q ${ew.customSqlSegment}\n            </script>\n            \"\"\")\n    IPage<Dict> pageByPcode(@Param(\"page\") IPage page, @Param(\"ew\") Wrapper<Dict> queryWrapper, @Param(\"pCode\") String pCode, @Param(\"isRoot\") boolean isRoot);\n\n    @Select(\"\"\"\n            <script>\n            SELECT count(O1.id) FROM t_dict O\n            LEFT JOIN t_dict O1 ON O1.p_code = O.code\n            WHERE O.id IN <foreach collection='ids' item='id' open='(' separator=',' close=')'>#{id}</foreach>\n            </script>\n            \"\"\")\n    int childCount(@Param(\"ids\") Set<Long> ids);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/EmployeeMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.Employee;\nimport com.baomidou.mybatisplus.core.conditions.Wrapper;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.ResultMap;\nimport org.apache.ibatis.annotations.Select;\n\nimport java.util.Set;\n\n/**\n * 员工\n */\n@Mapper\npublic interface EmployeeMapper extends BaseMapper<Employee> {\n\n    @Select(\"\"\"\n            <script>\n            SELECT DISTINCT * FROM (\n                SELECT O.* FROM t_employee AS O\n                LEFT JOIN t_dep_emp AS O1 ON O1.emp_id = O.id\n                <if test=\"depIds!=null and depIds.size()>0\">\n                WHERE O1.dep_id IN <foreach collection='depIds' item='id' open='(' separator=',' close=')'>#{id}</foreach>\n                </if>\n                ORDER BY O.create_time DESC\n            ) AS Q ${ew.customSqlSegment}\n            </script>\n            \"\"\")\n    IPage<Employee> pageByDepId(@Param(\"page\") IPage page, @Param(\"ew\") Wrapper<Employee> queryWrapper, @Param(\"depIds\") Set<Long> depIds);\n\n    @ResultMap(\"BaseResultMap\")\n    @Select(\"\"\"\n                <script>\n                SELECT O.* FROM t_employee O\n                LEFT JOIN t_corp_app O1 ON O1.corp_id = O.cid\n                WHERE O.user_id=#{userId} AND O1.app_id=#{appId}\n                    <if test=\"corpAdminOnly!=null\">\n                        AND O.is_corp_admin=#{corpAdminOnly}\n                    </if>\n                ORDER BY O.last_login_time DESC\n                LIMIT 1 OFFSET 0\n                </script>\n            \"\"\")\n    Employee findOneByAppIdAndUserId(@Param(\"appId\") Long appId, @Param(\"userId\") Long userId, @Param(\"corpAdminOnly\") Boolean corpAdminOnly);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/FileMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.File;\nimport cn.webestar.scms.mybatisplus.cache.CacheHelper;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.CacheNamespace;\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * 文件\n */\n@Mapper\n@CacheNamespace(implementation = CacheHelper.class, eviction = CacheHelper.class)\npublic interface FileMapper extends BaseMapper<File> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/Oauth2AuthorizationConsentMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.Oauth2AuthorizationConsent;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * oauth2认证授权\n */\n@Mapper\npublic interface Oauth2AuthorizationConsentMapper extends BaseMapper<Oauth2AuthorizationConsent> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/Oauth2AuthorizationMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.Oauth2Authorization;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * oauth2认证\n */\n@Mapper\npublic interface Oauth2AuthorizationMapper extends BaseMapper<Oauth2Authorization> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/Oauth2RegisteredClientMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport com.baomidou.mybatisplus.core.conditions.Wrapper;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.ResultMap;\nimport org.apache.ibatis.annotations.Select;\n\n/**\n * oauth2客户端\n */\n@Mapper\npublic interface Oauth2RegisteredClientMapper extends BaseMapper<Oauth2RegisteredClient> {\n\n    @Select(\"SELECT DISTINCT O.* FROM oauth2_registered_client O WHERE O.client_id = #{clientId}\")\n    Oauth2RegisteredClient findByClientId(@Param(\"clientId\") String clientId);\n\n    @ResultMap(\"BaseResultMap\")\n    @Select(\"\"\"\n            <script>\n            SELECT DISTINCT * FROM (\n                SELECT * FROM oauth2_registered_client O\n                LEFT JOIN t_corp_app AS O1 ON O1.app_id = O.app_id\n                WHERE O1.corp_id = #{corpId}\n                ORDER BY O.id DESC\n            ) AS Q ${ew.customSqlSegment}\n            </script>\n            \"\"\")\n    IPage<Oauth2RegisteredClient> pageByCorpId(@Param(\"page\") IPage<Oauth2RegisteredClient> page, @Param(\"ew\") Wrapper<Oauth2RegisteredClient> queryWrapper, @Param(\"corpId\") Long corpId);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/RoleAppResourceMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.RoleAppResource;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Select;\n\nimport java.util.List;\n\n/**\n * 角色应用资源关联关系\n */\n@Mapper\npublic interface RoleAppResourceMapper extends BaseMapper<RoleAppResource> {\n\n    @Select(\"\"\"\n            <script>\n                INSERT INTO t_role_app_resource ( id, app_id, cid, role_id, app_resource_id ) VALUES\n                <foreach collection=\"list\" item=\"o\" separator=\",\">\n                    (#{o.id},#{o.appId},#{o.cid},#{o.roleId},#{o.appResourceId})\n                </foreach>\n                ON CONFLICT (role_id, app_resource_id) DO NOTHING\n            </script>\n            \"\"\")\n    void auth(@Param(\"list\") List<RoleAppResource> list);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/RoleMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.Role;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * 角色\n */\n@Mapper\npublic interface RoleMapper extends BaseMapper<Role> {\n\n    @ResultMap(\"BaseResultMap\")\n    @Select(\"\"\"\n                SELECT O.*\n                FROM t_role AS O\n                LEFT JOIN t_emp_role AS O1 ON O1.role_id = O.id\n                WHERE O1.emp_id = #{empId}\n            \"\"\")\n    List<Role> findByEmpId(@Param(\"empId\") Long empId);\n\n    @Delete(\"\"\"\n                <script>\n                DELETE FROM t_emp_role WHERE emp_id=#{empId}\n                    <if test=\"roleIds!=null and roleIds.size() > 0\">\n                        AND role_id NOT IN \n                        <foreach collection=\"roleIds\" item=\"roleId\" index=\"index\" open=\"(\" separator=\",\" close=\")\">\n                            #{roleId}\n                        </foreach>\n                    </if>\n                </script>\n            \"\"\")\n    void removeEmpRole(@Param(\"empId\") Long empId, @Param(\"roleIds\") Set<Long> roleIds);\n\n    @Insert(\"\"\"\n                <script>\n                INSERT INTO t_emp_role (id, cid, role_id, emp_id) VALUES\n                <foreach collection=\"empRoles\" item=\"o\" index=\"index\" separator=\",\">\n                    (#{o.id}, #{o.cid},#{o.roleId},#{o.empId})\n                </foreach>\n                ON CONFLICT (role_id, emp_id) DO NOTHING\n                </script>\n            \"\"\")\n    void createEmpRole(@Param(\"empRoles\") List<Map<String, Object>> empRoles);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/SysLogMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.SysLog;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * 系统日志\n */\n@Mapper\npublic interface SysLogMapper extends BaseMapper<SysLog> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/mapper/UserMapper.java",
    "content": "package cn.hiauth.server.mapper;\n\nimport cn.hiauth.server.entity.User;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * 用户\n */\n@Mapper\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/AppResourceService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.api.dto.appResource.FindAppResourceIdsByRoleAndAppDto;\nimport cn.hiauth.server.api.vo.CommonTreeNodeVo;\nimport cn.hiauth.server.entity.AppResource;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 系统资源\n */\npublic interface AppResourceService extends IService<AppResource> {\n\n    List<AppResource> findByAppIdAndRoleIds(Long appId, Set<Long> roleIds);\n\n    List<CommonTreeNodeVo> findAppResourceTree(Long appId);\n\n    Set<Long> findAppResourceIdsByRoleAndApp(FindAppResourceIdsByRoleAndAppDto dto);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/AppService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.api.dto.appClient.AppClientLimitDto;\nimport cn.hiauth.server.entity.App;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * 应用\n */\npublic interface AppService extends IService<App> {\n\n    List<App> limitNotHaveApp(AppClientLimitDto dto);\n\n    List<App> limitHaveApp(AppClientLimitDto dto);\n\n    Map<Long, App> findByIds(Set<Long> appIds);\n\n//    List<App> limitAppByUserId(Long userId);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/CorpAppService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.entity.CorpApp;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\npublic interface CorpAppService extends IService<CorpApp> {\n\n//    List<CorpAppInfo> limitCorpAppInfoByUserId(Long userId);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/CorpService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.api.dto.RegisterDto;\nimport cn.hiauth.server.api.vo.CorpResourceTreeNodeVo;\nimport cn.hiauth.server.api.vo.IndexCorpAppVo;\nimport cn.hiauth.server.entity.Corp;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 租户\n */\npublic interface CorpService extends IService<Corp> {\n\n    List<CorpResourceTreeNodeVo> findCorpAppResourceTree(Long cid);\n\n    void register(RegisterDto dto);\n\n    List<IndexCorpAppVo> findIndexCorpAppByUserId(Long userId, Long appId);\n\n    void saveCorpAppBatch(Long cid, Set<Long> appIds);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/DepartmentService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.api.vo.CommonTreeNodeVo;\nimport cn.hiauth.server.entity.Department;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 部门\n */\npublic interface DepartmentService extends IService<Department> {\n\n    List<CommonTreeNodeVo> findDepTree(Long cid);\n\n    Set<Long> findDepIdsByEmpId(Long cid, Long empId);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/DictService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.entity.Dict;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport java.util.Set;\n\n/**\n * 字典\n */\npublic interface DictService extends IService<Dict> {\n\n    IPage<Dict> pageByPcode(Page<Dict> p, LambdaQueryWrapper<Dict> queryWapper, String pCode, boolean isRoot);\n\n    int childCount(Set<Long> ids);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/EmployeeService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.api.dto.emp.EmpCreateDto;\nimport cn.hiauth.server.api.dto.emp.EmpUpdateDto;\nimport cn.hiauth.server.api.vo.EmpVo;\nimport cn.hiauth.server.entity.Employee;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport java.util.Set;\n\n/**\n * 员工\n */\npublic interface EmployeeService extends IService<Employee> {\n\n    IPage<Employee> pageByDepId(Page<Employee> p, LambdaQueryWrapper<Employee> queryWapper, Set<Long> depIds);\n\n    Employee lastLoginCorpAdminByUserId(Long userId);\n\n    EmpVo create(EmpCreateDto dto);\n\n    EmpVo modify(Long cid, EmpUpdateDto dto);\n\n    boolean del(Long cid, Set<Long> ids);\n\n    void swichCorp(Long userId, Long cid);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/FileService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.entity.File;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * 文件\n */\npublic interface FileService extends IService<File> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/Oauth2AuthorizationConsentService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.entity.Oauth2AuthorizationConsent;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * oauth2认证授权\n */\npublic interface Oauth2AuthorizationConsentService extends IService<Oauth2AuthorizationConsent> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/Oauth2AuthorizationService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.entity.Oauth2Authorization;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * oauth2认证\n */\npublic interface Oauth2AuthorizationService extends IService<Oauth2Authorization> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/Oauth2RegisteredClientService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * oauth2客户端\n */\npublic interface Oauth2RegisteredClientService extends IService<Oauth2RegisteredClient> {\n\n    Oauth2RegisteredClient findByClientId(String clientId);\n\n    IPage<Oauth2RegisteredClient> pageByCorpId(Page<Oauth2RegisteredClient> page, LambdaQueryWrapper<Oauth2RegisteredClient> queryWapper, Long corpId);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/RoleService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.api.dto.role.RoleAuthDto;\nimport cn.hiauth.server.entity.Role;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 角色\n */\npublic interface RoleService extends IService<Role> {\n\n    List<Role> findByEmpId(Long empId);\n\n    void setEmpRole(Long cid, Long empId, Set<Long> roleIds);\n\n    Boolean auth(RoleAuthDto dto);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/SimpleSecurityService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.config.rest.security.MySecurityUser;\nimport cn.hiauth.server.entity.Corp;\nimport cn.hiauth.server.entity.Employee;\nimport cn.hiauth.server.entity.User;\nimport cn.hiauth.server.mapper.CorpMapper;\nimport cn.hiauth.server.mapper.EmployeeMapper;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.security.SecurityCorp;\nimport cn.webestar.scms.security.SecurityService;\nimport cn.webestar.scms.security.SecurityUser;\nimport cn.webestar.scms.security.SessionContextHolder;\nimport cn.webestar.scms.security.api.AccountLoginDto;\nimport cn.webestar.scms.security.api.PhoneNumLoginDto;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.time.LocalDateTime;\nimport java.util.List;\n\n@Slf4j\n@Component\npublic class SimpleSecurityService implements SecurityService {\n\n    @Autowired\n    private UserService userService;\n\n    @Autowired\n    private EmployeeService employeeService;\n\n    @Autowired\n    private CorpMapper corpMapper;\n\n    @Autowired\n    private EmployeeMapper employeeMapper;\n\n    @Override\n    public MySecurityUser loadSecurityUser(AccountLoginDto dto) {\n        //查找用户\n        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, dto.getUsername()));\n        return convert(user);\n    }\n\n    @Override\n    public SecurityUser loadSecurityUser(PhoneNumLoginDto dto) {\n        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getPhoneNum, dto.getPhoneNum()));\n        return convert(user);\n    }\n\n    @Override\n    public String sendSmsCode(Integer type, String phoneNum, String smsCode) {\n        log.debug(\"生成短信验证码:{}, 手机号:{}, 有效期:{}秒\", smsCode, phoneNum, 300);\n        return smsCode;\n    }\n\n    @Override\n    public List<SecurityCorp> loadUserCorps(Long userId) {\n        List<Corp> corps = corpMapper.findByUserId(userId);\n        Assert.notNull(corps, \"未加入任何组织\");\n        return corps.stream().map(corp -> new SecurityCorp(corp.getId(), corp.getName())).toList();\n    }\n\n    @Override\n    public Boolean switchCorp(Long id) {\n        SecurityUser securityUser = SessionContextHolder.getContext().getAuth().getPrincipal();\n        // 查询员工\n        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(Employee::getCid, id);\n        queryWrapper.eq(Employee::getUserId, securityUser.getUserId());\n        Employee emp = employeeService.getOne(queryWrapper);\n        Assert.notNull(emp, \"切换失败\");\n        // 更新session\n        securityUser.setCid(id);\n        securityUser.setEmpId(emp.getId());\n        SessionContextHolder.refresh();\n        // 更新登录时间\n        emp.setLastLoginTime(LocalDateTime.now());\n        employeeService.updateById(emp);\n        return true;\n    }\n\n    private MySecurityUser convert(User user) {\n        Assert.notNull(user, 30010, \"用户名或者密码错误\");\n        MySecurityUser securityUser = new MySecurityUser();\n        securityUser.setId(user.getId() + \"\");\n        securityUser.setUserId(user.getId());\n        securityUser.setName(user.getName());\n        securityUser.setUsername(user.getUsername());\n        securityUser.setPassword(user.getPwd());\n        securityUser.setPhoneNum(user.getPhoneNum());\n        securityUser.setAvatar(user.getAvatarUrl());\n        securityUser.setIsSysAdmin(user.getIsSysAdmin());\n        if (user.getIsSysAdmin() == null || !user.getIsSysAdmin()) {\n            Employee emp = employeeService.lastLoginCorpAdminByUserId(user.getId());\n            Assert.notNull(emp, 30010, \"用户名或者密码错误\");\n            securityUser.setCid(emp.getCid());\n            securityUser.setEmpId(emp.getId());\n            securityUser.setIsCorpAdmin(emp.getIsCorpAdmin());\n        }\n        return securityUser;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/SysLogService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.entity.SysLog;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * 系统日志\n */\npublic interface SysLogService extends IService<SysLog> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/UserService.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.entity.User;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * 用户\n */\npublic interface UserService extends IService<User> {\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/AppResourceServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.api.dto.appResource.FindAppResourceIdsByRoleAndAppDto;\nimport cn.hiauth.server.api.vo.CommonTreeNodeVo;\nimport cn.hiauth.server.entity.AppResource;\nimport cn.hiauth.server.entity.RoleAppResource;\nimport cn.hiauth.server.mapper.AppMapper;\nimport cn.hiauth.server.mapper.AppResourceMapper;\nimport cn.hiauth.server.mapper.CorpAppMapper;\nimport cn.hiauth.server.mapper.RoleAppResourceMapper;\nimport cn.hiauth.server.service.AppResourceService;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.*;\n\n/**\n * 系统资源\n */\n@Service\npublic class AppResourceServiceImpl extends ServiceImpl<AppResourceMapper, AppResource> implements AppResourceService {\n\n    @Autowired\n    private CorpAppMapper corpAppMapper;\n\n    @Autowired\n    private AppMapper appMapper;\n\n    @Autowired\n    private RoleAppResourceMapper roleAppResourceMapper;\n\n    private static List<CommonTreeNodeVo> buildDepTree(List<AppResource> list) {\n        list.sort(Comparator.comparing(AppResource::getSort));\n        List<CommonTreeNodeVo> vos = new ArrayList<>();\n        for (AppResource o : list) {\n            if (o.getPid() == null) {\n                CommonTreeNodeVo vo = CommonTreeNodeVo.convertToVo(o);\n                buildChild(vo, list, 1);\n                vos.add(vo);\n            }\n        }\n        return vos;\n    }\n\n    private static void buildChild(CommonTreeNodeVo parent, List<AppResource> list, int depth) {\n        if (depth > 10) return;\n        if (parent != null && list != null && !list.isEmpty()) {\n            list.forEach(o -> {\n                if (o.getPid() != null && o.getPid().equals(parent.getId())) {\n                    CommonTreeNodeVo child = CommonTreeNodeVo.convertToVo(o);\n                    buildChild(child, list, depth + 1);\n                    parent.getChildren().add(child);\n                }\n            });\n        }\n    }\n\n    @Override\n    public List<AppResource> findByAppIdAndRoleIds(Long appId, Set<Long> roleIds) {\n        return this.getBaseMapper().findByAppIdAndRoleIds(appId, roleIds);\n    }\n\n    @Override\n    public List<CommonTreeNodeVo> findAppResourceTree(Long appId) {\n        LambdaQueryWrapper<AppResource> queryWrapper = new LambdaQueryWrapper<>();\n        if (appId != null) {\n            queryWrapper.eq(AppResource::getAppId, appId);\n        }\n        List<AppResource> deps = baseMapper.selectList(queryWrapper);\n        return buildDepTree(deps);\n    }\n\n    @Override\n    public Set<Long> findAppResourceIdsByRoleAndApp(FindAppResourceIdsByRoleAndAppDto dto) {\n        LambdaQueryWrapper<RoleAppResource> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(RoleAppResource::getAppId, dto.getAppId());\n        queryWrapper.eq(RoleAppResource::getRoleId, dto.getRoleId());\n        List<RoleAppResource> list = roleAppResourceMapper.selectList(queryWrapper);\n        if (list == null || list.isEmpty()) {\n            return Set.of();\n        }\n        return list.stream().map(RoleAppResource::getAppResourceId).collect(HashSet::new, Set::add, Set::addAll);\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/AppServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.api.dto.appClient.AppClientLimitDto;\nimport cn.hiauth.server.entity.App;\nimport cn.hiauth.server.mapper.AppMapper;\nimport cn.hiauth.server.service.AppService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\n/**\n * 应用\n */\n@Service\npublic class AppServiceImpl extends ServiceImpl<AppMapper, App> implements AppService {\n\n    @Override\n    public List<App> limitNotHaveApp(AppClientLimitDto dto) {\n        return baseMapper.limitNotHaveApp(dto);\n    }\n\n    @Override\n    public List<App> limitHaveApp(AppClientLimitDto dto) {\n        return baseMapper.limitHaveApp(dto);\n    }\n\n    @Override\n    public Map<Long, App> findByIds(Set<Long> appIds) {\n        List<App> list = baseMapper.selectBatchIds(appIds);\n        return list.stream().collect(Collectors.toMap(App::getId, Function.identity()));\n    }\n\n//    @Override\n//    public List<App> limitAppByUserId(Long userId) {\n//        return baseMapper.limitAppByUserId(userId);\n//    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/CorpAppServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.entity.CorpApp;\nimport cn.hiauth.server.mapper.CorpAppMapper;\nimport cn.hiauth.server.service.CorpAppService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class CorpAppServiceImpl extends ServiceImpl<CorpAppMapper, CorpApp> implements CorpAppService {\n\n//    @Autowired\n//    private CorpAppMapper corpAppMapper;\n\n//    @Override\n//    public List<CorpAppInfo> limitCorpAppInfoByUserId(Long userId) {\n//        return corpAppMapper.limitCorpAppInfoByUserId(userId);\n//    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/CorpServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.api.dto.RegisterDto;\nimport cn.hiauth.server.api.vo.CorpResourceTreeNodeVo;\nimport cn.hiauth.server.api.vo.IndexCorpAppVo;\nimport cn.hiauth.server.entity.*;\nimport cn.hiauth.server.mapper.*;\nimport cn.hiauth.server.service.CorpService;\nimport cn.hutool.core.lang.Snowflake;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.SysCode;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * 租户\n */\n@Service\npublic class CorpServiceImpl extends ServiceImpl<CorpMapper, Corp> implements CorpService {\n\n    @Autowired\n    private Snowflake idGenerator;\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Autowired\n    private AppResourceMapper appResourceMapper;\n\n    @Autowired\n    private AppMapper appMapper;\n\n    @Autowired\n    private CorpMapper corpMapper;\n\n    @Autowired\n    private CorpAppMapper corpAppMapper;\n\n    @Autowired\n    private UserMapper userMapper;\n\n    @Autowired\n    private EmployeeMapper employeeMapper;\n\n    private static void buildTree(CorpResourceTreeNodeVo parent, List<AppResource> list, int depth) {\n        for (AppResource o : list) {\n            if (o.getPid() == null && o.getAppId() != null && o.getAppId().equals(parent.getAppId())) {\n                CorpResourceTreeNodeVo vo = CorpResourceTreeNodeVo.convertToVo(o);\n                buildChild(vo, list, 1);\n                parent.getChildren().add(vo);\n            }\n        }\n    }\n\n    private static void buildChild(CorpResourceTreeNodeVo parent, List<AppResource> list, int depth) {\n        if (depth > 10) {\n            return;\n        }\n        if (parent != null && list != null && !list.isEmpty()) {\n            list.forEach(o -> {\n                if (o.getPid() != null && o.getPid().equals(parent.getRid())) {\n                    CorpResourceTreeNodeVo child = CorpResourceTreeNodeVo.convertToVo(o);\n                    buildChild(child, list, depth + 1);\n                    parent.getChildren().add(child);\n                }\n            });\n        }\n    }\n\n    @Override\n    public List<CorpResourceTreeNodeVo> findCorpAppResourceTree(Long cid) {\n\n        // 查询应用\n        List<App> apps = appMapper.findByCid(cid);\n        Set<Long> appIds = apps.stream().map(App::getId).collect(Collectors.toSet());\n\n        // 查询应用资源\n        LambdaQueryWrapper<AppResource> qw2 = new LambdaQueryWrapper<>();\n        qw2.in(AppResource::getAppId, appIds);\n        List<AppResource> appResources = appResourceMapper.selectList(qw2);\n        appResources.sort(Comparator.comparing(AppResource::getSort));\n\n        // 构建树\n        List<CorpResourceTreeNodeVo> vos = new ArrayList<>();\n        apps.forEach(o -> {\n            CorpResourceTreeNodeVo vo = CorpResourceTreeNodeVo.convertToVo(o);\n            buildTree(vo, appResources, 1);\n            vos.add(vo);\n        });\n\n        return vos;\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void register(RegisterDto dto) {\n        LambdaQueryWrapper<Corp> corpQw = new LambdaQueryWrapper<>();\n        corpQw.eq(Corp::getName, dto.getCorpName());\n        boolean corpExists = corpMapper.exists(corpQw);\n        Assert.isTrue(!corpExists, SysCode.ERROR.getCode(), \"租户已存在\");\n\n        LambdaQueryWrapper<User> userQw = new LambdaQueryWrapper<>();\n        userQw.eq(User::getUsername, dto.getUsername()).or().eq(User::getPhoneNum, dto.getPhoneNum());\n        boolean userExists = userMapper.exists(userQw);\n        Assert.isTrue(!userExists, SysCode.ERROR.getCode(), \"用户已存在\");\n\n        dto.setPassword(passwordEncoder.encode(dto.getPassword()));\n\n        Corp corp = dto.toCorp();\n        corp.setId(idGenerator.nextId());\n        corpMapper.insert(corp);\n\n        User user = dto.toUser();\n        user.setId(idGenerator.nextId());\n        userMapper.insert(user);\n\n        Employee employee = new Employee();\n        employee.setId(idGenerator.nextId());\n        employee.setCid(corp.getId());\n        employee.setName(user.getName());\n        employee.setUserId(user.getId());\n        employee.setIsCorpAdmin(true);\n        employeeMapper.insert(employee);\n    }\n\n    @Override\n    public List<IndexCorpAppVo> findIndexCorpAppByUserId(Long userId, Long appId) {\n        List<CorpAppInfo> cpis = corpAppMapper.limitCorpAppInfoByUserId(userId, appId);\n        return IndexCorpAppVo.convert(cpis);\n    }\n\n    @Override\n    public void saveCorpAppBatch(Long cid, Set<Long> appIds) {\n\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/DepartmentServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.api.vo.CommonTreeNodeVo;\nimport cn.hiauth.server.entity.Department;\nimport cn.hiauth.server.mapper.DepartmentMapper;\nimport cn.hiauth.server.service.DepartmentService;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 部门\n *\n * @author zgs\n */\n@Service\npublic class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements DepartmentService {\n\n    private static List<CommonTreeNodeVo> buildDepTree(List<Department> list) {\n        list.sort(Comparator.comparing(Department::getSort));\n        List<CommonTreeNodeVo> vos = new ArrayList<>();\n        for (Department o : list) {\n            if (o.getPid() == null) {\n                CommonTreeNodeVo vo = CommonTreeNodeVo.convertToVo(o);\n                buildChild(vo, list, 1);\n                vos.add(vo);\n            }\n        }\n        return vos;\n    }\n\n    private static void buildChild(CommonTreeNodeVo parent, List<Department> list, int depth) {\n        if (depth > 10) return;\n        if (parent != null && list != null && !list.isEmpty()) {\n            list.forEach(o -> {\n                if (o.getPid() != null && o.getPid().equals(parent.getId())) {\n                    CommonTreeNodeVo child = CommonTreeNodeVo.convertToVo(o);\n                    buildChild(child, list, depth + 1);\n                    parent.getChildren().add(child);\n                }\n            });\n        }\n    }\n\n    @Override\n    public Set<Long> findDepIdsByEmpId(Long cid, Long empId) {\n        return baseMapper.findDepIdsByEmpId(cid, empId);\n    }\n\n    @Override\n    public List<CommonTreeNodeVo> findDepTree(Long cid) {\n        LambdaQueryWrapper<Department> queryWrapper = new LambdaQueryWrapper<>();\n        if (cid != null) {\n            queryWrapper.eq(Department::getCid, cid);\n        }\n        List<Department> deps = baseMapper.selectList(queryWrapper);\n        return buildDepTree(deps);\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/DictServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.entity.Dict;\nimport cn.hiauth.server.mapper.DictMapper;\nimport cn.hiauth.server.service.DictService;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\nimport java.util.Set;\n\n/**\n * 字典\n */\n@Service\npublic class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {\n\n    @Override\n    public IPage<Dict> pageByPcode(Page<Dict> p, LambdaQueryWrapper<Dict> queryWapper, String pCode, boolean isRoot) {\n        return baseMapper.pageByPcode(p, queryWapper, pCode, isRoot);\n    }\n\n    @Override\n    public int childCount(Set<Long> ids) {\n        return baseMapper.childCount(ids);\n    }\n\n//    @Override\n//    public Map<String, List<Dict>> findByPCodes(Set<String> codes) {\n//        Map<String, List<Dict>> resMap = new HashMap<>();\n//        if (CollUtil.isEmpty(codes)) {\n//            return resMap;\n//        }\n//        LambdaQueryWrapper<Dict> wrapper = new LambdaQueryWrapper<>();\n//        wrapper.in(Dict::getPCode, codes);\n//        wrapper.eq(Dict::getIsEnable, Boolean.TRUE);\n//        List<Dict> list = list(wrapper);\n//        if (CollUtil.isEmpty(list)) {\n//            return resMap;\n//        }\n//        //按照父类编码分类\n//        return list.stream().collect(Collectors.groupingBy(Dict::getPCode));\n//    }\n//\n//    @Override\n//    public List<Dict> getByPCodes(Set<String> codes) {\n//        Map<Dict, List<Dict>> resMap = new HashMap<>();\n//        LambdaQueryWrapper<Dict> wrapper = new LambdaQueryWrapper<>();\n//        wrapper.in(Dict::getPCode, codes);\n//        wrapper.or();\n//        wrapper.in(Dict::getCode, codes);\n//        wrapper.eq(Dict::getIsEnable, Boolean.TRUE);\n//        return list(wrapper);\n//    }\n//\n//    @Override\n//    public Map<String, Dict> findByCodes(List<String> codes) {\n//        LambdaQueryWrapper<Dict> wrapper = new LambdaQueryWrapper<>();\n//        wrapper.in(Dict::getCode, codes);\n//        wrapper.eq(Dict::getIsEnable, Boolean.TRUE);\n//        List<Dict> list = list(wrapper);\n//        Map<String, Dict> map = list.stream().collect(Collectors.toMap(Dict::getCode, dict -> dict));\n//        return map;\n//    }\n//\n//    @Override\n//    public Map<String, String> findNameByCodes(Set<String> codes) {\n//        LambdaQueryWrapper<Dict> wrapper = new LambdaQueryWrapper<>();\n//        wrapper.in(Dict::getCode, codes);\n//        wrapper.eq(Dict::getIsEnable, Boolean.TRUE);\n//        List<Dict> list = list(wrapper);\n//        Map<String, String> map = list.stream().collect(Collectors.toMap(Dict::getCode, Dict::getName));\n//        return map;\n//    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/EmployeeServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.api.dto.emp.EmpCreateDto;\nimport cn.hiauth.server.api.dto.emp.EmpUpdateDto;\nimport cn.hiauth.server.api.vo.EmpVo;\nimport cn.hiauth.server.entity.Employee;\nimport cn.hiauth.server.mapper.DepartmentMapper;\nimport cn.hiauth.server.mapper.EmployeeMapper;\nimport cn.hiauth.server.service.EmployeeService;\nimport cn.hutool.core.lang.Snowflake;\nimport cn.webestar.scms.commons.Assert;\nimport cn.webestar.scms.commons.SysCode;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.time.LocalDateTime;\nimport java.util.*;\n\n/**\n * 员工\n */\n@Service\npublic class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {\n\n    @Autowired\n    private DepartmentMapper departmentMapper;\n\n    @Autowired\n    private EmployeeMapper employeeMapper;\n\n    @Autowired\n    private Snowflake idGenerator;\n\n    @Override\n    public IPage<Employee> pageByDepId(Page<Employee> p, LambdaQueryWrapper<Employee> queryWapper, Set<Long> depIds) {\n        return baseMapper.pageByDepId(p, queryWapper, depIds);\n    }\n\n    @Override\n    public Employee lastLoginCorpAdminByUserId(Long userId) {\n        Assert.notNull(userId, SysCode.biz(1), \"userId不能为空\");\n        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(Employee::getUserId, userId);\n        queryWrapper.eq(Employee::getIsCorpAdmin, true);\n        queryWrapper.last(\"OFFSET 0 LIMIT 1\");\n        queryWrapper.orderByDesc(Employee::getLastLoginTime);\n        List<Employee> emps = this.list(queryWrapper);\n        return emps != null && !emps.isEmpty() ? emps.get(0) : null;\n    }\n\n    @Override\n    @Transactional\n    public EmpVo create(EmpCreateDto dto) {\n        // 保存员工信息\n        Employee o = dto.toDO();\n        this.save(o);\n        // 保存部门信息\n        if (dto.getDepIds() != null && !dto.getDepIds().isEmpty()) {\n            List<Map<String, Object>> depEmps = new ArrayList<>();\n            dto.getDepIds().forEach(item -> {\n                Map<String, Object> map = new HashMap<>();\n                map.put(\"id\", idGenerator.nextId());\n                map.put(\"cid\", dto.getCid());\n                map.put(\"empId\", o.getId());\n                map.put(\"depId\", item);\n                depEmps.add(map);\n            });\n            departmentMapper.addDepEmp(depEmps);\n        }\n        return EmpVo.convert(o, dto.getDepIds(), null);\n    }\n\n    @Override\n    public EmpVo modify(Long cid, EmpUpdateDto dto) {\n        Employee o = dto.toDO();\n        this.updateById(o);\n        // 更新部门\n        if (dto.getDepIds() != null && !dto.getDepIds().isEmpty()) {\n            List<Map<String, Object>> depEmps = new ArrayList<>();\n            dto.getDepIds().forEach(item -> {\n                Map<String, Object> map = new HashMap<>();\n                map.put(\"id\", idGenerator.nextId());\n                map.put(\"cid\", cid);\n                map.put(\"empId\", o.getId());\n                map.put(\"depId\", item);\n                depEmps.add(map);\n            });\n            departmentMapper.resetEmpDep(cid, o.getId(), dto.getDepIds());\n            departmentMapper.modifyDepEmp(depEmps);\n        }\n        return EmpVo.convert(o, dto.getDepIds(), null);\n    }\n\n    @Override\n    public boolean del(Long cid, Set<Long> ids) {\n        boolean b = this.removeByIds(ids);\n        departmentMapper.del(cid, ids);\n        return b;\n    }\n\n    @Override\n    public void swichCorp(Long userId, Long cid) {\n        // 查询指定租户下的员工\n        LambdaQueryWrapper<Employee> empQw = new LambdaQueryWrapper<>();\n        empQw.eq(Employee::getCid, cid);\n        empQw.eq(Employee::getUserId, userId);\n        Employee emp = employeeMapper.selectOne(empQw);\n        // 更新登录时间\n        LambdaUpdateWrapper<Employee> empUw = new LambdaUpdateWrapper<>();\n        empUw.set(Employee::getLastLoginTime, LocalDateTime.now());\n        empUw.eq(Employee::getId, emp.getId());\n        employeeMapper.update(empUw);\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/FileServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.entity.File;\nimport cn.hiauth.server.mapper.FileMapper;\nimport cn.hiauth.server.service.FileService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * 文件\n */\n@Service\npublic class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/Oauth2AuthorizationConsentServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.entity.Oauth2AuthorizationConsent;\nimport cn.hiauth.server.mapper.Oauth2AuthorizationConsentMapper;\nimport cn.hiauth.server.service.Oauth2AuthorizationConsentService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * oauth2认证授权\n */\n@Service\npublic class Oauth2AuthorizationConsentServiceImpl extends ServiceImpl<Oauth2AuthorizationConsentMapper, Oauth2AuthorizationConsent> implements Oauth2AuthorizationConsentService {\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/Oauth2AuthorizationServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.entity.Oauth2Authorization;\nimport cn.hiauth.server.mapper.Oauth2AuthorizationMapper;\nimport cn.hiauth.server.service.Oauth2AuthorizationService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * oauth2认证\n */\n@Service\npublic class Oauth2AuthorizationServiceImpl extends ServiceImpl<Oauth2AuthorizationMapper, Oauth2Authorization> implements Oauth2AuthorizationService {\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/Oauth2RegisteredClientServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport cn.hiauth.server.mapper.Oauth2RegisteredClientMapper;\nimport cn.hiauth.server.service.Oauth2RegisteredClientService;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * oauth2客户端\n */\n@Service\npublic class Oauth2RegisteredClientServiceImpl extends ServiceImpl<Oauth2RegisteredClientMapper, Oauth2RegisteredClient> implements Oauth2RegisteredClientService {\n\n    @Override\n    public Oauth2RegisteredClient findByClientId(String clientId) {\n        return this.baseMapper.findByClientId(clientId);\n    }\n\n    @Override\n    public IPage<Oauth2RegisteredClient> pageByCorpId(Page<Oauth2RegisteredClient> page, LambdaQueryWrapper<Oauth2RegisteredClient> queryWapper, Long corpId) {\n        return this.baseMapper.pageByCorpId(page, queryWapper, corpId);\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/RoleServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.api.dto.role.RoleAuthDto;\nimport cn.hiauth.server.entity.Role;\nimport cn.hiauth.server.entity.RoleAppResource;\nimport cn.hiauth.server.mapper.RoleAppResourceMapper;\nimport cn.hiauth.server.mapper.RoleMapper;\nimport cn.hiauth.server.service.RoleService;\nimport cn.hutool.core.lang.Snowflake;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * 角色\n */\n@Service\npublic class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {\n\n    @Autowired\n    private RoleAppResourceMapper roleAppResourceMapper;\n\n    @Autowired\n    private Snowflake snowflake;\n    @Autowired\n    private Snowflake idGenerator;\n\n    @Override\n    public List<Role> findByEmpId(Long empId) {\n        return this.baseMapper.findByEmpId(empId);\n    }\n\n    @Override\n    public void setEmpRole(Long cid, Long empId, Set<Long> roleIds) {\n        this.baseMapper.removeEmpRole(empId, roleIds);\n        if (roleIds != null && !roleIds.isEmpty()) {\n            List<Map<String, Object>> empRoles = new ArrayList<>();\n            roleIds.forEach(roleId -> {\n                Map<String, Object> empRole = new java.util.HashMap<>();\n                empRole.put(\"id\", idGenerator.nextId());\n                empRole.put(\"cid\", cid);\n                empRole.put(\"empId\", empId);\n                empRole.put(\"roleId\", roleId);\n                empRoles.add(empRole);\n            });\n            this.baseMapper.createEmpRole(empRoles);\n        }\n    }\n\n    @Override\n    public Boolean auth(RoleAuthDto dto) {\n\n        Role role = this.baseMapper.selectById(dto.getRoleId());\n        List<RoleAppResource> list = new ArrayList<>();\n        // 写入新权限\n        if (dto.getAppResourceIds() != null && !dto.getAppResourceIds().isEmpty()) {\n            for (Long appResourceId : dto.getAppResourceIds()) {\n                RoleAppResource o = new RoleAppResource();\n                o.setId(snowflake.nextId());\n                o.setCid(role.getCid());\n                o.setAppId(dto.getAppId());\n                o.setRoleId(dto.getRoleId());\n                o.setAppResourceId(appResourceId);\n                list.add(o);\n            }\n            roleAppResourceMapper.auth(list);\n        }\n\n        // 删除旧权限\n        LambdaQueryWrapper<RoleAppResource> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(RoleAppResource::getRoleId, dto.getRoleId());\n        queryWrapper.eq(RoleAppResource::getAppId, dto.getAppId());\n        if (dto.getAppResourceIds() != null && !dto.getAppResourceIds().isEmpty()) {\n            queryWrapper.notIn(RoleAppResource::getAppResourceId, dto.getAppResourceIds());\n        }\n        roleAppResourceMapper.delete(queryWrapper);\n\n        return Boolean.TRUE;\n    }\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/SysLogServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.entity.SysLog;\nimport cn.hiauth.server.mapper.SysLogMapper;\nimport cn.hiauth.server.service.SysLogService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * 系统日志\n */\n@Service\npublic class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements SysLogService {\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/service/impl/UserServiceImpl.java",
    "content": "package cn.hiauth.server.service.impl;\n\nimport cn.hiauth.server.entity.User;\nimport cn.hiauth.server.mapper.UserMapper;\nimport cn.hiauth.server.service.UserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * 用户\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {\n\n}"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/AliyunSmsUtils.java",
    "content": "package cn.hiauth.server.utils;\n\nimport cn.hutool.json.JSONUtil;\nimport com.aliyun.dysmsapi20170525.Client;\nimport com.aliyun.dysmsapi20170525.models.CreateSmsTemplateRequest;\nimport com.aliyun.dysmsapi20170525.models.CreateSmsTemplateResponse;\nimport com.aliyun.dysmsapi20170525.models.SendSmsRequest;\nimport com.aliyun.dysmsapi20170525.models.SendSmsResponse;\nimport com.aliyun.teaopenapi.models.Config;\nimport com.aliyun.teautil.models.RuntimeOptions;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\n@Slf4j\npublic class AliyunSmsUtils implements SmsUtils {\n\n    private String sign;\n\n    private Client client;\n\n    private AliyunSmsUtils() {\n    }\n\n    public AliyunSmsUtils(String accessKeyId, String accessKeySecret, String endpoint, String sign) {\n        this.sign = sign;\n        Config config = new Config().setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret);\n        config.endpoint = endpoint;\n        try {\n            client = new Client(config);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        String accessKeyId = \"\", accessKeySecret = \"\", endpoint = \"dysmsapi.aliyuncs.com\";\n        AliyunSmsUtils aliyunSmsUtil = new AliyunSmsUtils(accessKeyId, accessKeySecret, endpoint, \"蚂蚁智飞\");\n        aliyunSmsUtil.testSendSmsVerify();\n\n        //aliyunSmsUtil.sendVerificationCode(phone, code);\n        // 0-验证码 1-通知 2-推广\n        /*int type = 1;\n        String applySceneContent = \"http://mayizhifei.com\";\n        List<SmsTemplate> templates = getTemplates();\n        for(SmsTemplate e : templates){\n            String rule = \"{\\\"order_sn\\\":\\\"other_number2\\\"}\";\n            if(e.getTitle().contains(\"任务签到通知\")){\n                rule = \"{\\\"order_sn\\\":\\\"other_number2\\\",\\\"time\\\":\\\"time\\\"}\";\n            }\n            if(e.getTitle().contains(\"钱包账户\")){\n                rule = \"{\\\"order_sn\\\":\\\"other_number2\\\",\\\"amount\\\":\\\"money\\\"}\";\n            }\n            if(e.getTitle().contains(\"验证码\")){\n                type = 0;\n                rule = \"{\\\"code\\\":\\\"numberCaptcha\\\"}\";\n            }\n            CreateSmsTemplateResponse response = aliyunSmsUtil.createSmsTemplate(signName, type, e.getTitle(), e.getContent(), rule, applySceneContent);\n            if(null != response){\n                String templateCode = response.getBody().getTemplateCode();\n                System.out.println(\"templateName: \" + e.getTitle() + \"   templateCode: \" + templateCode);\n            }\n            Thread.sleep(1500);\n        }*/\n    }\n\n    public void sendSms(String phoneNumbers, String templateCode, Map<String, String> templateParam) {\n        sendSms(phoneNumbers, sign, templateCode, templateParam);\n    }\n\n    /**\n     * 发送短信\n     *\n     * @param phoneNumbers  手机号（多个用逗号分隔）\n     * @param templateParam 模板参数（JSON字符串）\n     * @return 发送结果\n     */\n    public void sendSms(String phoneNumbers, String signName, String templateCode, Map<String, String> templateParam) {\n        String param = JSONUtil.toJsonStr(templateParam);\n        SendSmsRequest sendSmsRequest = new SendSmsRequest().setPhoneNumbers(phoneNumbers)\n                .setSignName(signName)\n                .setTemplateCode(templateCode)\n                .setTemplateParam(param);\n        log.info(\"phoneNumbers:{}, signName:{}, templateCode:{}, templateParam:{}\", phoneNumbers, signName, templateCode, param);\n        try {\n            RuntimeOptions runtime = new RuntimeOptions();\n            SendSmsResponse response = client.sendSmsWithOptions(sendSmsRequest, runtime);\n            if (!Objects.equals(response.getBody().getCode(), \"OK\")) {\n                throw new RuntimeException(\"短信发送失败: \" + response.getBody().getMessage());\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 创建短信模板\n     *\n     * @return 结果\n     */\n    private CreateSmsTemplateResponse createSmsTemplate(String signName, Integer templateType, String templateName, String templateContent, String templateRule, String applySceneContent) throws Exception {\n        CreateSmsTemplateRequest request = new CreateSmsTemplateRequest();\n        request.setTemplateName(templateName);\n        request.setTemplateContent(templateContent);\n        request.setTemplateType(templateType);\n        request.setApplySceneContent(applySceneContent);\n        request.setRelatedSignName(signName);\n        request.setTemplateRule(templateRule);\n        RuntimeOptions runtime = new RuntimeOptions();\n        try {\n            CreateSmsTemplateResponse response = client.createSmsTemplateWithOptions(request, runtime);\n            if (!Objects.equals(response.getBody().getCode(), \"OK\")) {\n                throw new RuntimeException(\"创建模板失败: \" + response.getBody().getMessage());\n            }\n            return response;\n        } catch (Exception e) {\n            throw new Exception(\"创建模板异常: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * [默认验证码]发送验证码短信\n     *\n     * @param phone 手机号\n     * @param code  验证码\n     */\n    private void sendVerificationCode(String phone, String code) throws Exception {\n        //String templateParam = \"{\\\"code\\\":\\\"\"+code+\"\\\"}\";\n        Map<String, String> paramMap = new HashMap<>();\n        paramMap.put(\"code\", code);\n        //String templateParam = JSONUtil.toJsonStr(paramMap);\n        //System.out.println(templateParam);\n        String signName = \"蚂蚁智飞\";\n        String templateCode = \"SMS_479050505\";\n        sendSms(phone, templateCode, paramMap);\n    }\n\n    private void testSendSmsVerify() throws Exception {\n        //String phone = \"13916383295\";\n        String phone = \"13761379816\";\n        String code = \"112233\";\n        sendVerificationCode(phone, code);\n    }\n\n    /*public static List<SmsTemplate> getTemplates(){\n        List<SmsTemplate> list = new ArrayList<>();\n        list.add(new SmsTemplate(\"服务订单/驻点订单审核通过通知\", \"您的订单${order_sn}审核完成，请尽快前往“蚂蚁智飞平台-我的订单-我的用工”支付!\"));\n        list.add(new SmsTemplate(\"服务订单/驻点订单报价调整通知\", \"您的订单${order_sn}报价有调整，请尽快前往“蚂蚁智飞平台-我的订单-我的用工”查看和支付!\"));\n        list.add(new SmsTemplate(\"团长结束任务通知\", \"您的订单${order_sn}已完成服务，请前往“蚂蚁智飞平台-我的订单-我的用工”进行验收!\"));\n        list.add(new SmsTemplate(\"任务订单状态变更通知\", \"您的任务${order_sn}需确认设备，请尽快前往“蚂蚁智飞小程序-订单-服务中”进行确认！\"));\n        list.add(new SmsTemplate(\"任务设备状态变更通知\", \"您的任务${order_sn}需确认任务信息，请尽快前往“蚂蚁智飞小程序-订单-服务中”进行确认！\"));\n        list.add(new SmsTemplate(\"任务签到通知\", \"您的任务${order_sn}需现场签到，请在${time}前抵达现场，并前往“蚂蚁智飞小程序-订单-服务中”进行签到！\"));\n        list.add(new SmsTemplate(\"用户钱包账户通知\", \"恭喜您，您的“${order_sn}”任务报酬${amount}已到账！请前往“蚂蚁智飞小程序-我的-钱包”中进行查看和提现。\"));\n        list.add(new SmsTemplate(\"用户注册/登录验证码\", \"您的短信验证码是${code}，验证码有效时间10分钟。您正在登录蚂蚁智飞账号，如非本人操作，请忽略该短信。\"));\n        return list;\n    }*/\n\n\n    /*static class SmsTemplate {\n        public String getTitle() {\n            return title;\n        }\n\n        public void setTitle(String title) {\n            this.title = title;\n        }\n\n        private String title;\n\n        public String getContent() {\n            return content;\n        }\n\n        public void setContent(String content) {\n            this.content = content;\n        }\n\n        private String content;\n\n        public SmsTemplate(String title, String content){\n            this.title = title;\n            this.content = content;\n        }\n    }*/\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/AppResourceUtils.java",
    "content": "package cn.hiauth.server.utils;\n\nimport cn.hiauth.server.entity.AppResource;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class AppResourceUtils {\n\n    public static List<AppResource> sort(List<AppResource> datas) {\n        // 找到所有根节点\n        List<AppResource> root = new ArrayList<>();\n        datas.forEach(i -> {\n            if (i.getPid() == null) {\n                root.add(i);\n            }\n        });\n        // 从根节点开始构建\n        List<AppResource> list = new ArrayList<>();\n        root.forEach(i -> {\n            list.add(i);\n            list.addAll(getChild(i, datas));\n        });\n        return list;\n    }\n\n    private static List<AppResource> getChild(AppResource node, List<AppResource> datas) {\n        List<AppResource> list = new ArrayList<>();\n        if (node != null) {\n            datas.forEach(i -> {\n                if (Objects.equals(node.getId(), i.getPid())) {\n                    list.add(i);\n                    list.addAll(getChild(i, datas));\n                }\n            });\n        }\n        return list;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/Constant.java",
    "content": "package cn.hiauth.server.utils;\n\npublic class Constant {\n\n    /**\n     * 登录时存储图形验证码到缓存中的key\n     */\n    public static final String LOGIN_ACTION = \"/auth/doLogin\";\n\n    /**\n     * 登录时存储图形验证码到缓存中的key\n     */\n    public static final String CACHE_KEY_CAPTCHA = \"captcha\";\n    /**\n     * 登录时存储短信验证码到缓存中的key\n     */\n    public static final String CACHE_KEY_SMS_CODE = \"smsCode\";\n\n    /**\n     * 提交表单时request key\n     */\n    public static final String REQUEST_KEY_FORM_TOKEN = \"formToken\";\n\n    public final static String IMG_API = \"/unpapi/image/\";\n\n    /**\n     * 默认的用户头像\n     */\n    public final static String USER_DEFAULT_AVATAR = \"/user/default/avatar.jpeg\";\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/DateTimeUtils.java",
    "content": "package cn.hiauth.server.utils;\n\nimport java.time.LocalDateTime;\nimport java.time.format.DateTimeFormatter;\n\npublic class DateTimeUtils {\n\n    private final static DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\");\n\n    public static String format(LocalDateTime time) {\n        if (time == null) {\n            return \"\";\n        }\n        return time.format(FORMATTER);\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/DepartmentUtils.java",
    "content": "package cn.hiauth.server.utils;\n\nimport cn.hiauth.server.entity.Department;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class DepartmentUtils {\n\n    public static List<Department> sort(List<Department> deps) {\n        // 找到所有根节点\n        List<Department> root = new ArrayList<>();\n        deps.forEach(i -> {\n            if (i.getPid() == null) {\n                root.add(i);\n            }\n        });\n        // 从根节点开始构建\n        List<Department> list = new ArrayList<>();\n        root.forEach(i -> {\n            list.add(i);\n            list.addAll(getChild(i, deps));\n        });\n        return list;\n    }\n\n    private static List<Department> getChild(Department dep, List<Department> deps) {\n        List<Department> list = new ArrayList<>();\n        if (dep != null) {\n            deps.forEach(i -> {\n                if (Objects.equals(dep.getId(), i.getPid())) {\n                    list.add(i);\n                    list.addAll(getChild(i, deps));\n                }\n            });\n        }\n        return list;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/Oauth2RegisteredClientUtils.java",
    "content": "package cn.hiauth.server.utils;\n\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\n\nimport java.time.LocalDateTime;\nimport java.util.UUID;\n\npublic class Oauth2RegisteredClientUtils {\n\n    public final static String CLIENT_SETTINGS = \"\"\"\n            {\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-authorization-consent\":true,\"settings.client.require-proof-key\":false,\"cid\":\"${CID}\",\"appId\":\"${APPID}\"}\n            \"\"\";\n    public final static String TOKEN_SETTINGS = \"\"\"\n            {\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",${ACCESS_TOKEN_TIME_TO_LIVE}],\"settings.token.access-token-format\":{\"@class\":\"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat\",\"value\":\"self-contained\"},\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",2592000],\"settings.token.authorization-code-time-to-live\":[\"java.time.Duration\",600],\"settings.token.device-code-time-to-live\":[\"java.time.Duration\",300]}\n            \"\"\";\n\n    public static final String ACCESS_TOKEN_TIME_TO_LIVE = \"36000\";\n\n    public static Oauth2RegisteredClient getDefaultClient(Long cid, Long appId, String clientName, String clientSecret) {\n\n        String clientId = UUID.randomUUID().toString().replace(\"-\", \"\");\n        String clientSettings = CLIENT_SETTINGS.replace(\"${CID}\", cid + \"\").replace(\"${APPID}\", appId + \"\");\n        String tokenSettings = TOKEN_SETTINGS.replace(\"${ACCESS_TOKEN_TIME_TO_LIVE}\", ACCESS_TOKEN_TIME_TO_LIVE);\n\n        Oauth2RegisteredClient o = new Oauth2RegisteredClient();\n        o.setCid(cid);\n        o.setAppId(appId);\n        o.setClientId(clientId);\n        o.setClientIdIssuedAt(LocalDateTime.now());\n        o.setClientSecret(clientSecret);\n        o.setClientName(clientName);\n        o.setClientAuthenticationMethods(\"client_secret_basic,client_secret_post\");\n        o.setAuthorizationGrantTypes(\"refresh_token,authorization_code,client_credentials,password\");\n        o.setScopes(\"openid,profile,user\");\n        o.setClientSettings(clientSettings);\n        o.setTokenSettings(tokenSettings);\n\n        return o;\n    }\n\n    public static String getClientSettings(Long cid, Long appId) {\n        return CLIENT_SETTINGS.replace(\"${CID}\", cid + \"\").replace(\"${APPID}\", appId + \"\");\n    }\n\n    public static String getTokenSettings(Integer accessTokenTimeToLive) {\n        return TOKEN_SETTINGS.replace(\"${ACCESS_TOKEN_TIME_TO_LIVE}\", accessTokenTimeToLive + \"\");\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/RsaUtils.java",
    "content": "package cn.hiauth.server.utils;\n\nimport cn.hutool.core.codec.Base64;\nimport cn.hutool.crypto.SecureUtil;\nimport cn.hutool.crypto.asymmetric.KeyType;\nimport cn.hutool.crypto.asymmetric.RSA;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.security.KeyPair;\nimport java.security.PrivateKey;\nimport java.security.PublicKey;\nimport java.util.HashMap;\nimport java.util.Map;\n\n@Slf4j\npublic class RsaUtils {\n\n    /**\n     * 类型\n     */\n    public static final String ENCRYPT_TYPE = \"RSA\";\n\n    /**\n     * 获取公钥的key\n     */\n    private static final String PUBLIC_KEY = \"RSAPublicKey\";\n\n    /**\n     * 获取私钥的key\n     */\n    private static final String PRIVATE_KEY = \"RSAPrivateKey\";\n\n    /**\n     * 公钥加密\n     *\n     * @param content:\n     * @param publicKey:\n     */\n    public static String encrypt(String content, PublicKey publicKey) {\n        try {\n            RSA rsa = new RSA(null, publicKey);\n            return rsa.encryptBase64(content, KeyType.PublicKey);\n        } catch (Exception e) {\n            log.error(\"公钥加密异常 msg:{}\", e.getMessage());\n        }\n        return null;\n    }\n\n    /**\n     * 公钥加密\n     *\n     * @param content:\n     * @param publicKey:\n     */\n    public static String encrypt(String content, String publicKey) {\n        try {\n            RSA rsa = new RSA(null, publicKey);\n            return rsa.encryptBase64(content, KeyType.PublicKey);\n        } catch (Exception e) {\n            log.error(\"公钥加密异常 msg:{}\", e.getMessage());\n        }\n        return null;\n    }\n\n\n    /**\n     * 私钥解密\n     *\n     * @param content:\n     * @param privateKey:\n     */\n    public static String decrypt(String content, PrivateKey privateKey) {\n        try {\n            RSA rsa = new RSA(privateKey, null);\n            return rsa.decryptStr(content, KeyType.PrivateKey);\n        } catch (Exception e) {\n            log.error(\"私钥解密异常 msg:{}\", e.getMessage());\n        }\n        return null;\n    }\n\n    /**\n     * 私钥解密\n     *\n     * @param content:\n     * @param privateKey:\n     */\n    public static String decrypt(String content, String privateKey) {\n        try {\n            RSA rsa = new RSA(privateKey, null);\n            return rsa.decryptStr(content, KeyType.PrivateKey);\n        } catch (Exception e) {\n            log.error(\"私钥解密异常 msg:{}\", e.getMessage());\n        }\n        return null;\n    }\n\n    /**\n     * 获取公私钥-请获取一次后保存公私钥使用\n     */\n    public static Map<String, String> generateKeyPair() {\n        try {\n            KeyPair pair = SecureUtil.generateKeyPair(ENCRYPT_TYPE);\n            PrivateKey privateKey = pair.getPrivate();\n            PublicKey publicKey = pair.getPublic();\n            // 获取 公钥和私钥 的 编码格式（通过该 编码格式 可以反过来 生成公钥和私钥对象）\n            byte[] pubEncBytes = publicKey.getEncoded();\n            byte[] priEncBytes = privateKey.getEncoded();\n\n            // 把 公钥和私钥 的 编码格式 转换为 Base64文本 方便保存\n            String pubEncBase64 = Base64.encode(pubEncBytes);\n            String priEncBase64 = Base64.encode(priEncBytes);\n\n            Map<String, String> map = new HashMap<String, String>(2);\n            map.put(PUBLIC_KEY, pubEncBase64);\n            map.put(PRIVATE_KEY, priEncBase64);\n\n            return map;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n\n    public static void main(String[] args) {\n        Map<String, String> key = generateKeyPair();\n        System.out.println(key);\n        String privateKey = key.get(PRIVATE_KEY);\n        String publicKey = key.get(PUBLIC_KEY);\n        String text = \"wasu:234@125.2321321he12321321\";\n        String content = encrypt(text, publicKey);\n        content = decrypt(content, privateKey);\n        System.out.println(content);\n    }\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/SmsUtils.java",
    "content": "package cn.hiauth.server.utils;\n\nimport java.util.Map;\n\npublic interface SmsUtils {\n\n    void sendSms(String phoneNumbers, String templateCode, Map<String, String> templateParam);\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/jose/Jwks.java",
    "content": "/*\n * Copyright 2020-2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.hiauth.server.utils.jose;\n\nimport com.nimbusds.jose.jwk.Curve;\nimport com.nimbusds.jose.jwk.ECKey;\nimport com.nimbusds.jose.jwk.OctetSequenceKey;\nimport com.nimbusds.jose.jwk.RSAKey;\n\nimport javax.crypto.SecretKey;\nimport java.security.KeyPair;\nimport java.security.interfaces.ECPrivateKey;\nimport java.security.interfaces.ECPublicKey;\nimport java.security.interfaces.RSAPrivateKey;\nimport java.security.interfaces.RSAPublicKey;\nimport java.util.UUID;\n\n/**\n * @author Joe Grandja\n * @since 1.1\n */\npublic final class Jwks {\n\n    private Jwks() {\n    }\n\n    public static RSAKey generateRsa() {\n        KeyPair keyPair = KeyGeneratorUtils.generateRsaKey();\n        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();\n        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();\n        return new RSAKey.Builder(publicKey)\n                .privateKey(privateKey)\n                .keyID(UUID.randomUUID().toString())\n                .build();\n    }\n\n    public static ECKey generateEc() {\n        KeyPair keyPair = KeyGeneratorUtils.generateEcKey();\n        ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();\n        ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();\n        Curve curve = Curve.forECParameterSpec(publicKey.getParams());\n        return new ECKey.Builder(curve, publicKey)\n                .privateKey(privateKey)\n                .keyID(UUID.randomUUID().toString())\n                .build();\n    }\n\n    public static OctetSequenceKey generateSecret() {\n        SecretKey secretKey = KeyGeneratorUtils.generateSecretKey();\n        return new OctetSequenceKey.Builder(secretKey)\n                .keyID(UUID.randomUUID().toString())\n                .build();\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/java/cn/hiauth/server/utils/jose/KeyGeneratorUtils.java",
    "content": "/*\n * Copyright 2020-2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.hiauth.server.utils.jose;\n\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport java.math.BigInteger;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.spec.ECFieldFp;\nimport java.security.spec.ECParameterSpec;\nimport java.security.spec.ECPoint;\nimport java.security.spec.EllipticCurve;\n\n/**\n * @author Joe Grandja\n * @since 1.1\n */\nfinal class KeyGeneratorUtils {\n\n    private KeyGeneratorUtils() {\n    }\n\n    static SecretKey generateSecretKey() {\n        SecretKey hmacKey;\n        try {\n            hmacKey = KeyGenerator.getInstance(\"HmacSha256\").generateKey();\n        } catch (Exception ex) {\n            throw new IllegalStateException(ex);\n        }\n        return hmacKey;\n    }\n\n    static KeyPair generateRsaKey() {\n        KeyPair keyPair;\n        try {\n            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"RSA\");\n            keyPairGenerator.initialize(2048);\n            keyPair = keyPairGenerator.generateKeyPair();\n        } catch (Exception ex) {\n            throw new IllegalStateException(ex);\n        }\n        return keyPair;\n    }\n\n    static KeyPair generateEcKey() {\n        EllipticCurve ellipticCurve = new EllipticCurve(\n                new ECFieldFp(new BigInteger(\"115792089210356248762697446949407573530086143415290314195533631308867097853951\")),\n                new BigInteger(\"115792089210356248762697446949407573530086143415290314195533631308867097853948\"),\n                new BigInteger(\"41058363725152142129326129780047268409114441015993725554835256314039467401291\"));\n        ECPoint ecPoint = new ECPoint(\n                new BigInteger(\"48439561293906451759052585252797914202762949526041747995844080717082404635286\"),\n                new BigInteger(\"36134250956749795798585127919587881956611106672985015071877198253568414405109\"));\n        ECParameterSpec ecParameterSpec = new ECParameterSpec(\n                ellipticCurve,\n                ecPoint,\n                new BigInteger(\"115792089210356248762697446949407573529996955224135760342422259061068512044369\"),\n                1);\n\n        KeyPair keyPair;\n        try {\n            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"EC\");\n            keyPairGenerator.initialize(ecParameterSpec);\n            keyPair = keyPairGenerator.generateKeyPair();\n        } catch (Exception ex) {\n            throw new IllegalStateException(ex);\n        }\n        return keyPair;\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/main/resources/application-common.yml",
    "content": "spring.mvc.pathmatch.matching-strategy: ant-path-matcher\n\nspring.jackson:\n  default-property-inclusion: NON_NULL\n  serialization:\n    indent-output: true"
  },
  {
    "path": "hiauth-server/src/main/resources/application-doc.yml",
    "content": "# 配置springdoc-openapi，用于文档化和访问API\nspringdoc:\n  # 配置Swagger UI的访问路径和排序方式\n  swagger-ui:\n    # Swagger UI的访问路径\n    path: /swagger-ui.html\n    # 按字母顺序排序标签\n    tags-sorter: alpha\n    # 按字母顺序排序操作\n    operations-sorter: alpha\n  # 配置API文档的访问路径\n  api-docs:\n    # API文档的访问路径\n    path: /v3/api-docs\n  # 配置API分组，用于组织和管理API\n  group-configs:\n    # API分组名称\n    - group: 'default'\n      # 匹配所有路径\n      paths-to-match: '/**'\n      # 扫描的包，用于自动发现API\n      packages-to-scan: cn.hiauth.server.controller\n"
  },
  {
    "path": "hiauth-server/src/main/resources/application-hiauth.yml",
    "content": "server.port: 8080\n\napp.cache.prefix: hiauth\napp.readonly.account: admin,corpadmin\napp.login.baseImageChar: 23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ\n\nlogging.level:\n  root: INFO\n  cn.hiauth: DEBUG\n  com.alibaba.nacos: INFO\n  org.springframework.data.redis: INFO\n  io.lettuce.core: INFO\n\nspring.datasource:\n  type: ${datasource.type}\n  driver-class-name: ${datasource.driverClassName}\n  url: ${datasource.url}\n  username: ${datasource.username}\n  password: ${datasource.password}\n\nscms.security:\n  enable: true\n  cachePrefix: ${app.cache.prefix}\n  publicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsHC0eWi8AKjlh8IHjK2BIEPSclSs/P6RiJJN09X9A04n6K87SGEBCsplJdVntFUkQqmwICzuq537VpS+1tBpgHykbBT1tev9kra9HIc0LpkGVFIjOPS2PPnhUiZO/ruHuJ0Sn9Drq6qWpSJtcM3QkLAXvuqwQAWufHT/Gf2wpPwIDAQAB\n  privateKey: MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKwcLR5aLwAqOWHwgeMrYEgQ9JyVKz8/pGIkk3T1f0DTiforztIYQEKymUl1We0VSRCqbAgLO6rnftWlL7W0GmAfKRsFPW16/2Str0chzQumQZUUiM49LY8+eFSJk7+u4e4nRKf0OurqpalIm1wzdCQsBe+6rBABa58dP8Z/bCk/AgMBAAECgYAOXf1eNUULJhTLZwC3IZEHmXK+x3nOujwf456NLhkrV8ocbVL2GTqNo5isMY5wl7N7uRFyzA1B3QVERf/PktmvEHAnbjBYWe1O2734gDyrtBuzsKA+qpN1rV6+ZCRiz9TdvVJM8oRq0Vr5t/ih3ZoofZWW5T8h8jNmR1WKcKEBEQJBAOiSwLQttUHLrW3lgsbK6m3bgyQbtItBt55hQmYrq0qbDidBY7kJJJ58uqk/IkukIRwajOK2PaJ32YTxTHr8rcUCQQC9ckpMDjwAQqv8+9zPQ65x+6bI13L+2DIayF/sqKXkTSDF0Wi6yMgRTYfkyTUaVIJahh7SgxoqSv3wGa9auw8zAkEAzn11YMPwWYGH8rnCedOxfmZWMhnzG2z2pUT/Gg2NoMi4MTxKWP/4Jkrhw+DNB1GrH/OmwKdDY9t7IiDHYa60bQJBAIJ3C/2Wq/GN+L2vgeBm/uLWaITWAwbIQrE5Hv5vIle4WgKBdXt0vHtWBmkju+NXIbJPvThCOym3HWxVc/Kq8gsCQQDCV0ofj8avZQBJTlfLcedsur+SXbjM6tre3o6w05aDqXIy5Q9FhTjwoJF4sTZ1zUK4p2mm8mRaNOtTkmYvaIct\n  encryptType: RSA\n  enableImageCaptcha: false\n  urlPatterns:\n    - /api/*\n\nspring.session.timeout: 600m\nspring.session.redis:\n  # 支持发布session事件，默认值不支持发布session事件\n  repository-type: indexed\n  namespace: \"hiauth:session\"\n  # 每次保存或更新 session 时立即将数据同步到 Redis\n  flush-mode: on_save\n  # 每次请求结束时都保存 session\n  save-mode: always\n  # 关闭Spring Session的自动配置检查,否则在使用aliyun redis（Tair）时会报错\n  # 报错内容为：NOPERM this user has no permissions to run the 'config|get' command\n  configure-action: none\n\nspring.security.oauth2:\n  authorization.consent.template-location: classpath:/META-INF/resources/consent.html\n  access-token.time-to-live: 60m\n  resource-server.jwt.issuer-uri: http://127.0.0.1:9000\n\nspring.thymeleaf:\n  # 开启视图解析\n  enabled: true\n  encoding: UTF-8\n  prefix: classpath:/templates/\n  # 后缀配置\n  suffix: .html\n  #是否使用缓存 开发环境时不设置缓存\n  cache: false\n  mode: HTML\n  # 配置类型\n  servlet:\n    content-type: text/html\n\nsmsUils:\n  accessKeyId: ${aliyun.sms.accessKeyId}\n  accessKeySecret: ${aliyun.sms.accessKeySecret}\n  sign: ${aliyun.sms.sign}\n  smsTemplateCode: ${aliyun.sms.smsTemplateCode}\n  superSmsCode: ${aliyun.sms.superSmsCode}"
  },
  {
    "path": "hiauth-server/src/main/resources/application-mybatis.yml",
    "content": "mybatis-plus:\n  mapper-locations: classpath:mapper/*.xml\n  type-aliases-package: cn.hiauth.**.entity, cn.hiauth.**.enums\n  global-config:\n    db-config:\n      id-type: input\n      table-prefix:\n      table-underline: false\n      logic-delete-value: true\n      logic-not-delete-value: false\n  configuration:\n    cache-enabled: true\n    cache-expire: 300\n    map-underscore-to-camel-case: true\n    call-setters-on-nulls: true\n    #log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl\n    #log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl"
  },
  {
    "path": "hiauth-server/src/main/resources/application-redis.yml",
    "content": "# 单节点写法\nspring.data.redis:\n  host: ${redis.host}\n  port: ${redis.port}\n  database: ${redis.database}\n  username: ${redis.username}\n  password: ${redis.password}\n  timeout: 10000\n  connect-timeout: 10000\n\n# 集群写法\n#spring.redis:\n#  username: ${redis.username}\n#  password: ${redis.password}\n#  timeout: 5000\n#  cluster:\n#   nodes: 192.168.0.1:6379,192.168.0.2:6379\n#   max-redirects: 3\n#  lettuce:\n#   pool:\n#     max-active: 8\n#     max-idle: 8\n#     min-idle: 0\n#     max-wait: 1000\n#   shutdown-timeout: 100"
  },
  {
    "path": "hiauth-server/src/main/resources/application.yml",
    "content": "app.version: '@project.version@'\napp.build.timestamp: '@app.build.timestamp@'\nspring.application.name: hiauth-server\n\n# 加载模块化配置\nspring.profiles.active: hiauth,doc,common,mybatis,redis\n\n# 加载外部配置文件，覆盖内置配置文件\nspring.config.import: ${CONFIG_FILE:optional:/hiauth/conf/hiauth.properties}\n\ndatasource:\n  type: com.alibaba.druid.pool.DruidDataSource\n  driverClassName: org.postgresql.Driver\n  url: jdbc:mysql://${DB_HOST:127.0.0.1}:3306/hiauth\n  username: ${DB_USER:test}\n  password: ${DB_pwd:123456}\n\nredis:\n  host: ${REDIS_HOST:127.0.0.1}\n  username: ${REDIS_USERNAME:}\n  password: ${REDIS_PWD:}\n  port: 6379\n  database: 0\n"
  },
  {
    "path": "hiauth-server/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n\n    <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符-->\n    <property name=\"LOG_PATTERN\" value=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <!-- 彩色日志格式 -->\n    <property name=\"LOG_PATTERN_COLORED\" value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}) %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"LOG_FILE\" value=\"./hiauth/logs/server.log\"/>\n\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>false</withJansi>\n        <encoder>\n            <pattern>${LOG_PATTERN_COLORED}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <encoder>\n            <pattern>${LOG_PATTERN}</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>\n        </encoder>\n        <file>${LOG_FILE}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.FixedWindowRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}.%i.zip</fileNamePattern>\n            <minIndex>1</minIndex>\n            <maxIndex>10</maxIndex>\n        </rollingPolicy>\n        <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n            <MaxFileSize>100MB</MaxFileSize>\n        </triggeringPolicy>\n    </appender>\n\n    <!-- 日志输出级别 -->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/AppMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.AppMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"App\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"cid\" property=\"cid\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"icon\" property=\"icon\"/>\n        <result column=\"home\" property=\"home\"/>\n        <result column=\"create_time\" property=\"createTime\"/>\n        <result column=\"creator\" property=\"creator\"/>\n        <result column=\"remark\" property=\"remark\"/>\n        <result column=\"extend\" property=\"extend\"\n                typeHandler=\"com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, cid, name, icon, home, create_time, creator, remark, extend\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/AppResourceMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.AppResourceMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"AppResource\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"pid\" property=\"pid\"/>\n        <result column=\"app_id\" property=\"appId\"/>\n        <result column=\"code\" property=\"code\"/>\n        <result column=\"url\" property=\"url\"/>\n        <result column=\"api\" property=\"api\"/>\n        <result column=\"sort\" property=\"sort\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"type\" property=\"type\"/>\n        <result column=\"remark\" property=\"remark\"/>\n        <result column=\"extend\" property=\"extend\"\n                typeHandler=\"com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, pid, app_id, code, url, api, sort, name, type, remark, extend\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/CorpAppMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.CorpAppMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"CorpApp\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"app_id\" property=\"appId\"/>\n        <result column=\"corp_id\" property=\"corpId\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, app_id, corp_id\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/CorpMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.CorpMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"Corp\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"status\" property=\"status\"/>\n        <result column=\"creator\" property=\"creator\"/>\n        <result column=\"updater\" property=\"updater\"/>\n        <result column=\"deleter\" property=\"deleter\"/>\n        <result column=\"create_time\" property=\"createTime\"/>\n        <result column=\"update_time\" property=\"updateTime\"/>\n        <result column=\"delete_time\" property=\"deleteTime\"/>\n        <result column=\"is_deleted\" property=\"isDeleted\"/>\n        <result column=\"app_count\" property=\"appCount\"/>\n        <result column=\"dep_count\" property=\"depCount\"/>\n        <result column=\"emp_count\" property=\"empCount\"/>\n        <result column=\"icon\" property=\"icon\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id,name, status, creator, updater, deleter, create_time, update_time, delete_time, is_deleted, app_count,\n        dep_count, emp_count, icon\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/DepartmentMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.DepartmentMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"Department\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"cid\" property=\"cid\"/>\n        <result column=\"pid\" property=\"pid\"/>\n        <result column=\"sort\" property=\"sort\"/>\n        <result column=\"no\" property=\"no\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"creator\" property=\"creator\"/>\n        <result column=\"updater\" property=\"updater\"/>\n        <result column=\"create_time\" property=\"createTime\"/>\n        <result column=\"update_time\" property=\"updateTime\"/>\n        <result column=\"status\" property=\"status\"/>\n        <result column=\"remark\" property=\"remark\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id,\n        cid, pid, sort, no, name, creator, updater, create_time, update_time, status, remark\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/DictMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.DictMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"Dict\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"cid\" property=\"cid\"/>\n        <result column=\"sort\" property=\"sort\"/>\n        <result column=\"code\" property=\"code\"/>\n        <result column=\"p_code\" property=\"pCode\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"value\" property=\"value\"/>\n        <result column=\"is_enable\" property=\"isEnable\"/>\n        <result column=\"create_time\" property=\"createTime\"/>\n        <result column=\"has_child\" property=\"hasChild\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, cid, sort, code, p_code, name, value, is_enable, create_time\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/EmployeeMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.EmployeeMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"Employee\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"cid\" property=\"cid\"/>\n        <result column=\"user_id\" property=\"userId\"/>\n        <result column=\"no\" property=\"no\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"email\" property=\"email\"/>\n        <result column=\"is_corp_admin\" property=\"isCorpAdmin\"/>\n        <result column=\"last_login_time\" property=\"lastLoginTime\"/>\n        <result column=\"creator\" property=\"creator\"/>\n        <result column=\"updater\" property=\"updater\"/>\n        <result column=\"deleter\" property=\"deleter\"/>\n        <result column=\"create_time\" property=\"createTime\"/>\n        <result column=\"update_time\" property=\"updateTime\"/>\n        <result column=\"delete_time\" property=\"deleteTime\"/>\n        <result column=\"is_deleted\" property=\"isDeleted\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, cid, user_id, no, name, email, creator, updater, deleter, create_time, update_time, delete_time, is_deleted,\n        is_corp_admin last_login_time\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/FileMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.FileMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"File\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"origin_name\" property=\"originName\"/>\n        <result column=\"code\" property=\"code\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"ext\" property=\"ext\"/>\n        <result column=\"data\" property=\"data\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, origin_name, code, name, ext, data\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/Oauth2AuthorizationConsentMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.Oauth2AuthorizationConsentMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"Oauth2AuthorizationConsent\">\n        <id column=\"registered_client_id\" property=\"registeredClientId\"/>\n        <id column=\"principal_name\" property=\"principalName\"/>\n        <result column=\"authorities\" property=\"authorities\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        registered_client_id, principal_name, authorities\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/Oauth2AuthorizationMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.Oauth2AuthorizationMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"Oauth2Authorization\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"registered_client_id\" property=\"registeredClientId\"/>\n        <result column=\"principal_name\" property=\"principalName\"/>\n        <result column=\"authorization_grant_type\" property=\"authorizationGrantType\"/>\n        <result column=\"authorized_scopes\" property=\"authorizedScopes\"/>\n        <result column=\"attributes\" property=\"attributes\"/>\n        <result column=\"state\" property=\"state\"/>\n        <result column=\"authorization_code_value\" property=\"authorizationCodeValue\"/>\n        <result column=\"authorization_code_issued_at\" property=\"authorizationCodeIssuedAt\"/>\n        <result column=\"authorization_code_expires_at\" property=\"authorizationCodeExpiresAt\"/>\n        <result column=\"authorization_code_metadata\" property=\"authorizationCodeMetadata\"/>\n        <result column=\"access_token_value\" property=\"accessTokenValue\"/>\n        <result column=\"access_token_issued_at\" property=\"accessTokenIssuedAt\"/>\n        <result column=\"access_token_expires_at\" property=\"accessTokenExpiresAt\"/>\n        <result column=\"access_token_metadata\" property=\"accessTokenMetadata\"/>\n        <result column=\"access_token_type\" property=\"accessTokenType\"/>\n        <result column=\"access_token_scopes\" property=\"accessTokenScopes\"/>\n        <result column=\"oidc_id_token_value\" property=\"oidcIdTokenValue\"/>\n        <result column=\"oidc_id_token_issued_at\" property=\"oidcIdTokenIssuedAt\"/>\n        <result column=\"oidc_id_token_expires_at\" property=\"oidcIdTokenExpiresAt\"/>\n        <result column=\"oidc_id_token_metadata\" property=\"oidcIdTokenMetadata\"/>\n        <result column=\"refresh_token_value\" property=\"refreshTokenValue\"/>\n        <result column=\"refresh_token_issued_at\" property=\"refreshTokenIssuedAt\"/>\n        <result column=\"refresh_token_expires_at\" property=\"refreshTokenExpiresAt\"/>\n        <result column=\"refresh_token_metadata\" property=\"refreshTokenMetadata\"/>\n        <result column=\"user_code_value\" property=\"userCodeValue\"/>\n        <result column=\"user_code_issued_at\" property=\"userCodeIssuedAt\"/>\n        <result column=\"user_code_expires_at\" property=\"userCodeExpiresAt\"/>\n        <result column=\"user_code_metadata\" property=\"userCodeMetadata\"/>\n        <result column=\"device_code_value\" property=\"deviceCodeValue\"/>\n        <result column=\"device_code_issued_at\" property=\"deviceCodeIssuedAt\"/>\n        <result column=\"device_code_expires_at\" property=\"deviceCodeExpiresAt\"/>\n        <result column=\"device_code_metadata\" property=\"deviceCodeMetadata\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id,\n        registered_client_id, principal_name, authorization_grant_type, authorized_scopes, attributes, state,\n        authorization_code_value, authorization_code_issued_at, authorization_code_expires_at,\n        authorization_code_metadata, access_token_value, access_token_issued_at, access_token_expires_at,\n        access_token_metadata, access_token_type, access_token_scopes, oidc_id_token_value, oidc_id_token_issued_at,\n        oidc_id_token_expires_at, oidc_id_token_metadata, refresh_token_value, refresh_token_issued_at,\n        refresh_token_expires_at, refresh_token_metadata, user_code_value, user_code_issued_at, user_code_expires_at,\n        user_code_metadata, device_code_value, device_code_issued_at, device_code_expires_at, device_code_metadata\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/Oauth2RegisteredClientMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.Oauth2RegisteredClientMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"Oauth2RegisteredClient\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"cid\" property=\"cid\"/>\n        <result column=\"app_id\" property=\"appId\"/>\n        <result column=\"client_id\" property=\"clientId\"/>\n        <result column=\"client_id_issued_at\" property=\"clientIdIssuedAt\"/>\n        <result column=\"client_secret\" property=\"clientSecret\"/>\n        <result column=\"client_secret_expires_at\" property=\"clientSecretExpiresAt\"/>\n        <result column=\"client_name\" property=\"clientName\"/>\n        <result column=\"client_authentication_methods\" property=\"clientAuthenticationMethods\"/>\n        <result column=\"authorization_grant_types\" property=\"authorizationGrantTypes\"/>\n        <result column=\"redirect_uris\" property=\"redirectUris\"/>\n        <result column=\"post_logout_redirect_uris\" property=\"postLogoutRedirectUris\"/>\n        <result column=\"scopes\" property=\"scopes\"/>\n        <result column=\"client_settings\" property=\"clientSettings\"/>\n        <result column=\"token_settings\" property=\"tokenSettings\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, cid, app_id, client_id, client_id_issued_at, client_secret, client_secret_expires_at, client_name,\n        client_authentication_methods, authorization_grant_types, redirect_uris, post_logout_redirect_uris, scopes,\n        client_settings, token_settings\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/RoleMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.RoleMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"Role\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"cid\" property=\"cid\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"remark\" property=\"remark\"/>\n        <result column=\"creator\" property=\"creator\"/>\n        <result column=\"updater\" property=\"updater\"/>\n        <result column=\"create_time\" property=\"createTime\"/>\n        <result column=\"update_time\" property=\"updateTime\"/>\n        <result column=\"is_enable\" property=\"isEnable\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id,\n        cid, name, remark, creator, updater, create_time, update_time, is_enable\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/SysLogMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.SysLogMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"SysLog\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"cid\" property=\"cid\"/>\n        <result column=\"actor\" property=\"actor\"/>\n        <result column=\"actor_ip\" property=\"actorIp\"/>\n        <result column=\"actor_type\" property=\"actorType\"/>\n        <result column=\"actor_emp_id\" property=\"actorEmpId\"/>\n        <result column=\"actor_user_id\" property=\"actorUserId\"/>\n        <result column=\"event_time\" property=\"eventTime\"/>\n        <result column=\"event_type\" property=\"eventType\"/>\n        <result column=\"event_level\" property=\"eventLevel\"/>\n        <result column=\"event_result\" property=\"eventResult\"/>\n        <result column=\"event_desc\" property=\"eventDesc\"/>\n        <result column=\"username\" property=\"username\"/>\n        <result column=\"source_sys\" property=\"sourceSys\"/>\n        <result column=\"source_module\" property=\"sourceModule\"/>\n        <result column=\"create_time\" property=\"createTime\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, cid, actor, actor_ip, actor_type, actor_emp_id, actor_user_id, event_time, event_type, event_level,\n        event_result, event_desc, username, source_sys, source_module, create_time\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/mapper/UserMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"cn.hiauth.server.mapper.UserMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"User\">\n        <result column=\"id\" property=\"id\"/>\n        <result column=\"name\" property=\"name\"/>\n        <result column=\"gender\" property=\"gender\"/>\n        <result column=\"avatar_url\" property=\"avatarUrl\"/>\n        <result column=\"phone_num\" property=\"phoneNum\"/>\n        <result column=\"username\" property=\"username\"/>\n        <result column=\"pwd\" property=\"pwd\"/>\n        <result column=\"wxmp_openid\" property=\"wxmpOpenid\"/>\n        <result column=\"wx_openid\" property=\"wxOpenid\"/>\n        <result column=\"wx_unionid\" property=\"wxUnionid\"/>\n        <result column=\"status\" property=\"status\"/>\n        <result column=\"regtime\" property=\"regtime\"/>\n        <result column=\"last_login_time\" property=\"lastLoginTime\"/>\n        <result column=\"creator\" property=\"creator\"/>\n        <result column=\"updater\" property=\"updater\"/>\n        <result column=\"deleter\" property=\"deleter\"/>\n        <result column=\"create_time\" property=\"createTime\"/>\n        <result column=\"update_time\" property=\"updateTime\"/>\n        <result column=\"delete_time\" property=\"deleteTime\"/>\n        <result column=\"is_deleted\" property=\"isDeleted\"/>\n        <result column=\"is_sys_admin\" property=\"isSysAdmin\"/>\n        <result column=\"extend\" property=\"extend\"\n                typeHandler=\"com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler\"/>\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, name, gender, avatar_url, phone_num, username, pwd, wxmp_openid, wx_openid, wx_unionid, status, regtime,\n        last_login_time, creator, updater, deleter, create_time, update_time, delete_time, is_deleted, is_sys_admin,\n        extend\n    </sql>\n\n</mapper>"
  },
  {
    "path": "hiauth-server/src/main/resources/static/bootstrap-5.3.0/css/bootstrap.min.css",
    "content": "@charset \"UTF-8\";/*!\n * Bootstrap  v5.3.0-alpha1 (https://getbootstrap.com/)\n * Copyright 2011-2022 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */: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:#0a58ca;--bs-secondary-text:#6c757d;--bs-success-text:#146c43;--bs-info-text:#087990;--bs-warning-text:#997404;--bs-danger-text:#b02a37;--bs-light-text:#6c757d;--bs-dark-text:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#f8f9fa;--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:#e9ecef;--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-body-color-rgb:33,37,41;--bs-body-bg-rgb:255,255,255;--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-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-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--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-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-2xl:2rem;--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(var(--bs-body-color-rgb), 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(var(--bs-body-color-rgb), 0.075);--bs-emphasis-color:#000;--bs-form-control-bg:var(--bs-body-bg);--bs-form-control-disabled-bg:var(--bs-secondary-bg);--bs-highlight-bg:#fff3cd;--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}[data-bs-theme=dark]{--bs-body-color:#adb5bd;--bs-body-color-rgb:173,181,189;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#f8f9fa;--bs-emphasis-color-rgb:248,249,250;--bs-secondary-color:rgba(173, 181, 189, 0.75);--bs-secondary-color-rgb:173,181,189;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(173, 181, 189, 0.5);--bs-tertiary-color-rgb:173,181,189;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-emphasis-color:#fff;--bs-primary-text:#6ea8fe;--bs-secondary-text:#dee2e6;--bs-success-text:#75b798;--bs-info-text:#6edff6;--bs-warning-text:#ffda6a;--bs-danger-text:#ea868f;--bs-light-text:#f8f9fa;--bs-dark-text:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#212529;--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:#495057;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#055160;--bs-warning-border-subtle:#664d03;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:#fff;--bs-link-color:#6ea8fe;--bs-link-hover-color:#9ec5fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:158,197,254;--bs-code-color:#e685b5;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15)}*,::after,::before{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:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color,inherit)}.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 + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .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}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.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}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{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]{outline-offset:-2px;-webkit-appearance:textfield}::-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}}.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.3333333333%}.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.6666666667%}.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.3333333333%}.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.6666666667%}.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.3333333333%}.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.6666666667%}.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.3333333333%}.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.6666666667%}.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.3333333333%}.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.6666666667%}.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.3333333333%}.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.6666666667%}.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:var(--bs-body-color);--bs-table-bg:transparent;--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-body-color);--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:var(--bs-body-color);--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:var(--bs-body-color);--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:var(--bs-table-color);vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px 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-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#bacbe6;--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:#cbccce;--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:#bcd0c7;--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:#badce3;--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:#e6dbb9;--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:#dfc2c4;--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:#dfe0e1;--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:#373b3e;--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);background-color:var(--bs-form-control-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.375rem;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-form-control-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.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-form-control-disabled-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:.25rem}.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:.5rem}.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:.375rem}.form-control-color::-webkit-color-swatch{border-radius:.375rem}.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;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);background-color:var(--bs-form-control-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:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@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-form-control-disabled-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:.25rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.5rem}[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='%23adb5bd' 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-form-control-bg);width:1em;height:1em;margin-top:.25em;vertical-align:top;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-appearance:none;-moz-appearance:none;appearance:none;-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;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.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;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;-webkit-appearance:none;appearance:none}@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-tertiary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;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;-moz-appearance:none;appearance:none}@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-tertiary-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::before:not(.form-control:disabled){position:absolute;top:var(--bs-border-width);left:var(--bs-border-width);width:calc(100% - (calc(calc(.375em + .1875rem) + calc(.75em + .375rem))));height:1.875em;content:\"\";background-color:var(--bs-form-control-bg);border-radius:.375rem}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;width:100%;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{opacity:.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{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.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{color:#6c757d}.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:.375rem}.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:.5rem}.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:.25rem}.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-success-text)}.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-success);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-success);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-success)}.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-success);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-success)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-success-text)}.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-success-text)}.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-danger-text)}.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-danger);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-danger);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-danger)}.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-danger);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-danger)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-danger-text)}.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-danger-text)}.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:#212529;--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:0.375rem;--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.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:none;--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:0.5rem}.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:0.25rem}.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:0.375rem;--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(0.375rem - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);--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:#adb5bd;--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:.375rem}.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;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.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));background:0 0;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-link.disabled,.nav-tabs .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.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:0.375rem;--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{background:0 0;border:0;border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.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-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:0.375rem;--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 .show>.nav-link{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{--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{--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);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='%23212529'%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-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='%230a58ca'%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-focus-border-color:#86b7fe;--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);--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;border-color:var(--bs-accordion-btn-focus-border-color);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-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-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-collapse{border-width:0}.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-button,.accordion-flush .accordion-item .accordion-button.collapsed{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:0.5rem}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:0.25rem}.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:0.375rem;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:0.375rem;--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);--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)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text);--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)}.alert-success{--bs-alert-color:var(--bs-success-text);--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)}.alert-info{--bs-alert-color:var(--bs-info-text);--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)}.alert-warning{--bs-alert-color:var(--bs-warning-text);--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)}.alert-danger{--bs-alert-color:var(--bs-danger-text);--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)}.alert-light{--bs-alert-color:var(--bs-light-text);--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)}.alert-dark{--bs-alert-color:var(--bs-dark-text);--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)}@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);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle)}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle)}.list-group-item-primary.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-primary-text);--bs-list-group-active-border-color:var(--bs-primary-text)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle)}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle)}.list-group-item-secondary.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-secondary-text);--bs-list-group-active-border-color:var(--bs-secondary-text)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle)}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle)}.list-group-item-success.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-success-text);--bs-list-group-active-border-color:var(--bs-success-text)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle)}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle)}.list-group-item-info.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-info-text);--bs-list-group-active-border-color:var(--bs-info-text)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle)}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle)}.list-group-item-warning.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-warning-text);--bs-list-group-active-border-color:var(--bs-warning-text)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle)}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle)}.list-group-item-danger.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-danger-text);--bs-list-group-active-border-color:var(--bs-danger-text)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle)}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle)}.list-group-item-light.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-light-text);--bs-list-group-active-border-color:var(--bs-light-text)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle)}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle)}.list-group-item-dark.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-dark-text);--bs-list-group-active-border-color:var(--bs-dark-text)}.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:0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);--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;justify-content:space-between;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:0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15)}.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;padding:var(--bs-tooltip-arrow-height);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:0}.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:0;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:0}.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:0;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:0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: ;--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%;list-style:none}.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{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target]{background-color:#000}[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:0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);--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%)}}@media (max-width:575.98px){.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%)}}@media (max-width:575.98px){.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%)}}@media (max-width:575.98px){.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%)}}@media (max-width:575.98px){.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}}@media (max-width:575.98px){.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%)}}@media (max-width:767.98px){.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%)}}@media (max-width:767.98px){.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%)}}@media (max-width:767.98px){.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%)}}@media (max-width:767.98px){.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}}@media (max-width:767.98px){.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%)}}@media (max-width:991.98px){.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%)}}@media (max-width:991.98px){.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%)}}@media (max-width:991.98px){.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%)}}@media (max-width:991.98px){.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}}@media (max-width:991.98px){.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%)}}@media (max-width:1199.98px){.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%)}}@media (max-width:1199.98px){.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%)}}@media (max-width:1199.98px){.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%)}}@media (max-width:1199.98px){.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}}@media (max-width:1199.98px){.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%)}}@media (max-width:1399.98px){.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%)}}@media (max-width:1399.98px){.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%)}}@media (max-width:1399.98px){.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%)}}@media (max-width:1399.98px){.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}}@media (max-width:1399.98px){.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;justify-content:space-between;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-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y))}.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(13,110,253,var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(108,117,125,var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(25,135,84,var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(13,202,240,var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(255,193,7,var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(220,53,69,var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(248,249,250,var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(33,37,41,var(--bs-bg-opacity,1))!important}.link-primary{color:#0d6efd!important}.link-primary:focus,.link-primary:hover{color:#0a58ca!important}.link-secondary{color:#6c757d!important}.link-secondary:focus,.link-secondary:hover{color:#565e64!important}.link-success{color:#198754!important}.link-success:focus,.link-success:hover{color:#146c43!important}.link-info{color:#0dcaf0!important}.link-info:focus,.link-info:hover{color:#3dd5f3!important}.link-warning{color:#ffc107!important}.link-warning:focus,.link-warning:hover{color:#ffcd39!important}.link-danger{color:#dc3545!important}.link-danger:focus,.link-danger:hover{color:#b02a37!important}.link-light{color:#f8f9fa!important}.link-light:focus,.link-light:hover{color:#f9fafb!important}.link-dark{color:#212529!important}.link-dark:focus,.link-dark:hover{color:#1a1e21!important}.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){position:absolute!important;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}.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:1px;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-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:0 .5rem 1rem rgba(var(--bs-body-color-rgb),.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(var(--bs-body-color-rgb),.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(var(--bs-body-color-rgb),.175)!important}.shadow-none{box-shadow:none!important}.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-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{--bs-border-width:1px}.border-2{--bs-border-width:2px}.border-3{--bs-border-width:3px}.border-4{--bs-border-width:4px}.border-5{--bs-border-width:5px}.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)!important}.text-secondary-emphasis{color:var(--bs-secondary-text)!important}.text-success-emphasis{color:var(--bs-success-text)!important}.text-info-emphasis{color:var(--bs-info-text)!important}.text-warning-emphasis{color:var(--bs-warning-text)!important}.text-danger-emphasis{color:var(--bs-danger-text)!important}.text-light-emphasis{color:var(--bs-light-text)!important}.text-dark-emphasis{color:var(--bs-dark-text)!important}.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-body-emphasis{--bs-bg-opacity:1;background-color:rgba(var(--bs-emphasis-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-2xl)!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-2xl)!important;border-top-right-radius:var(--bs-border-radius-2xl)!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-2xl)!important;border-bottom-right-radius:var(--bs-border-radius-2xl)!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-2xl)!important;border-bottom-left-radius:var(--bs-border-radius-2xl)!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-2xl)!important;border-top-left-radius:var(--bs-border-radius-2xl)!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-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-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-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-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-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-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}}\n/*# sourceMappingURL=bootstrap.min.css.map */"
  },
  {
    "path": "hiauth-server/src/main/resources/static/bootstrap-5.3.0/css/bootstrap.min.css.map",
    "content": "{\"version\":3,\"sources\":[\"../../scss/mixins/_banner.scss\",\"../../scss/_root.scss\",\"dist/css/bootstrap.css\",\"../../scss/vendor/_rfs.scss\",\"../../scss/mixins/_color-mode.scss\",\"../../scss/_reboot.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/_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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\",\"sourcesContent\":[\"@mixin bsBanner($file) {\\n  /*!\\n   * Bootstrap #{$file} v5.3.0-alpha1 (https://getbootstrap.com/)\\n   * Copyright 2011-2022 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: #{$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  --#{$prefix}body-color-rgb: #{to-rgb($body-color)};\\n  --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};\\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  --#{$prefix}body-color: #{$body-color};\\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\\n  @if $body-text-align != null {\\n    --#{$prefix}body-text-align: #{$body-text-align};\\n  }\\n  --#{$prefix}body-bg: #{$body-bg};\\n  --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};\\n  // scss-docs-end root-body-variables\\n\\n  @if $headings-color != null {\\n    --#{$prefix}heading-color: #{$headings-color};\\n  }\\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-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-2xl: #{$border-radius-2xl};\\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  --#{$prefix}emphasis-color: #{$emphasis-color};\\n\\n  // scss-docs-start form-control-vars\\n  --#{$prefix}form-control-bg: var(--#{$prefix}body-bg);\\n  --#{$prefix}form-control-disabled-bg: var(--#{$prefix}secondary-bg);\\n  // scss-docs-end form-control-vars\\n\\n  --#{$prefix}highlight-bg: #{$mark-bg};\\n\\n  @each $name, $value in $grid-breakpoints {\\n    --#{$prefix}breakpoint-#{$name}: #{$value};\\n  }\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark, true) {\\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    --#{$prefix}emphasis-color: #{$emphasis-color-dark};\\n\\n    --#{$prefix}primary-text: #{$primary-text-dark};\\n    --#{$prefix}secondary-text: #{$secondary-text-dark};\\n    --#{$prefix}success-text: #{$success-text-dark};\\n    --#{$prefix}info-text: #{$info-text-dark};\\n    --#{$prefix}warning-text: #{$warning-text-dark};\\n    --#{$prefix}danger-text: #{$danger-text-dark};\\n    --#{$prefix}light-text: #{$light-text-dark};\\n    --#{$prefix}dark-text: #{$dark-text-dark};\\n\\n    --#{$prefix}primary-bg-subtle: #{$primary-bg-subtle-dark};\\n    --#{$prefix}secondary-bg-subtle: #{$secondary-bg-subtle-dark};\\n    --#{$prefix}success-bg-subtle: #{$success-bg-subtle-dark};\\n    --#{$prefix}info-bg-subtle: #{$info-bg-subtle-dark};\\n    --#{$prefix}warning-bg-subtle: #{$warning-bg-subtle-dark};\\n    --#{$prefix}danger-bg-subtle: #{$danger-bg-subtle-dark};\\n    --#{$prefix}light-bg-subtle: #{$light-bg-subtle-dark};\\n    --#{$prefix}dark-bg-subtle: #{$dark-bg-subtle-dark};\\n\\n    --#{$prefix}primary-border-subtle: #{$primary-border-subtle-dark};\\n    --#{$prefix}secondary-border-subtle: #{$secondary-border-subtle-dark};\\n    --#{$prefix}success-border-subtle: #{$success-border-subtle-dark};\\n    --#{$prefix}info-border-subtle: #{$info-border-subtle-dark};\\n    --#{$prefix}warning-border-subtle: #{$warning-border-subtle-dark};\\n    --#{$prefix}danger-border-subtle: #{$danger-border-subtle-dark};\\n    --#{$prefix}light-border-subtle: #{$light-border-subtle-dark};\\n    --#{$prefix}dark-border-subtle: #{$dark-border-subtle-dark};\\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\\n    --#{$prefix}border-color: #{$border-color-dark};\\n    --#{$prefix}border-color-translucent: #{$border-color-translucent-dark};\\n    // scss-docs-end root-dark-mode-vars\\n  }\\n}\\n\",\"@charset \\\"UTF-8\\\";\\n/*!\\n * Bootstrap  v5.3.0-alpha1 (https://getbootstrap.com/)\\n * Copyright 2011-2022 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: #0a58ca;\\n  --bs-secondary-text: #6c757d;\\n  --bs-success-text: #146c43;\\n  --bs-info-text: #087990;\\n  --bs-warning-text: #997404;\\n  --bs-danger-text: #b02a37;\\n  --bs-light-text: #6c757d;\\n  --bs-dark-text: #495057;\\n  --bs-primary-bg-subtle: #cfe2ff;\\n  --bs-secondary-bg-subtle: #f8f9fa;\\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: #e9ecef;\\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-body-color-rgb: 33, 37, 41;\\n  --bs-body-bg-rgb: 255, 255, 255;\\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-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-body-bg: #fff;\\n  --bs-body-bg-rgb: 255, 255, 255;\\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-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-2xl: 2rem;\\n  --bs-border-radius-pill: 50rem;\\n  --bs-box-shadow: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);\\n  --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);\\n  --bs-box-shadow-lg: 0 1rem 3rem rgba(var(--bs-body-color-rgb), 0.175);\\n  --bs-box-shadow-inset: inset 0 1px 2px rgba(var(--bs-body-color-rgb), 0.075);\\n  --bs-emphasis-color: #000;\\n  --bs-form-control-bg: var(--bs-body-bg);\\n  --bs-form-control-disabled-bg: var(--bs-secondary-bg);\\n  --bs-highlight-bg: #fff3cd;\\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[data-bs-theme=dark] {\\n  --bs-body-color: #adb5bd;\\n  --bs-body-color-rgb: 173, 181, 189;\\n  --bs-body-bg: #212529;\\n  --bs-body-bg-rgb: 33, 37, 41;\\n  --bs-emphasis-color: #f8f9fa;\\n  --bs-emphasis-color-rgb: 248, 249, 250;\\n  --bs-secondary-color: rgba(173, 181, 189, 0.75);\\n  --bs-secondary-color-rgb: 173, 181, 189;\\n  --bs-secondary-bg: #343a40;\\n  --bs-secondary-bg-rgb: 52, 58, 64;\\n  --bs-tertiary-color: rgba(173, 181, 189, 0.5);\\n  --bs-tertiary-color-rgb: 173, 181, 189;\\n  --bs-tertiary-bg: #2b3035;\\n  --bs-tertiary-bg-rgb: 43, 48, 53;\\n  --bs-emphasis-color: #fff;\\n  --bs-primary-text: #6ea8fe;\\n  --bs-secondary-text: #dee2e6;\\n  --bs-success-text: #75b798;\\n  --bs-info-text: #6edff6;\\n  --bs-warning-text: #ffda6a;\\n  --bs-danger-text: #ea868f;\\n  --bs-light-text: #f8f9fa;\\n  --bs-dark-text: #dee2e6;\\n  --bs-primary-bg-subtle: #031633;\\n  --bs-secondary-bg-subtle: #212529;\\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: #495057;\\n  --bs-success-border-subtle: #0f5132;\\n  --bs-info-border-subtle: #055160;\\n  --bs-warning-border-subtle: #664d03;\\n  --bs-danger-border-subtle: #842029;\\n  --bs-light-border-subtle: #495057;\\n  --bs-dark-border-subtle: #343a40;\\n  --bs-heading-color: #fff;\\n  --bs-link-color: #6ea8fe;\\n  --bs-link-hover-color: #9ec5fe;\\n  --bs-link-color-rgb: 110, 168, 254;\\n  --bs-link-hover-color-rgb: 158, 197, 254;\\n  --bs-code-color: #e685b5;\\n  --bs-border-color: #495057;\\n  --bs-border-color-translucent: rgba(255, 255, 255, 0.15);\\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, inherit);\\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  -webkit-text-decoration: underline dotted;\\n  text-decoration: underline dotted;\\n  cursor: help;\\n  -webkit-text-decoration-skip-ink: none;\\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  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  outline-offset: -2px;\\n  -webkit-appearance: textfield;\\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::-webkit-file-upload-button {\\n  font: inherit;\\n  -webkit-appearance: button;\\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.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.3333333333%;\\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.6666666667%;\\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.3333333333%;\\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.6666666667%;\\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.3333333333%;\\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.6666666667%;\\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.3333333333%;\\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.6666666667%;\\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.3333333333%;\\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.6666666667%;\\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.3333333333%;\\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.6666666667%;\\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: var(--bs-body-color);\\n  --bs-table-bg: transparent;\\n  --bs-table-border-color: var(--bs-border-color);\\n  --bs-table-accent-bg: transparent;\\n  --bs-table-striped-color: var(--bs-body-color);\\n  --bs-table-striped-bg: rgba(0, 0, 0, 0.05);\\n  --bs-table-active-color: var(--bs-body-color);\\n  --bs-table-active-bg: rgba(0, 0, 0, 0.1);\\n  --bs-table-hover-color: var(--bs-body-color);\\n  --bs-table-hover-bg: rgba(0, 0, 0, 0.075);\\n  width: 100%;\\n  margin-bottom: 1rem;\\n  color: var(--bs-table-color);\\n  vertical-align: top;\\n  border-color: var(--bs-table-border-color);\\n}\\n.table > :not(caption) > * > * {\\n  padding: 0.5rem 0.5rem;\\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-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-accent-bg: var(--bs-table-striped-bg);\\n  color: var(--bs-table-striped-color);\\n}\\n\\n.table-striped-columns > :not(caption) > tr > :nth-child(even) {\\n  --bs-table-accent-bg: var(--bs-table-striped-bg);\\n  color: var(--bs-table-striped-color);\\n}\\n\\n.table-active {\\n  --bs-table-accent-bg: var(--bs-table-active-bg);\\n  color: var(--bs-table-active-color);\\n}\\n\\n.table-hover > tbody > tr:hover > * {\\n  --bs-table-accent-bg: var(--bs-table-hover-bg);\\n  color: var(--bs-table-hover-color);\\n}\\n\\n.table-primary {\\n  --bs-table-color: #000;\\n  --bs-table-bg: #cfe2ff;\\n  --bs-table-border-color: #bacbe6;\\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: #cbccce;\\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: #bcd0c7;\\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: #badce3;\\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: #e6dbb9;\\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: #dfc2c4;\\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: #dfe0e1;\\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: #373b3e;\\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  background-color: var(--bs-form-control-bg);\\n  background-clip: padding-box;\\n  border: var(--bs-border-width) solid var(--bs-border-color);\\n  -webkit-appearance: none;\\n  -moz-appearance: none;\\n  appearance: none;\\n  border-radius: 0.375rem;\\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-form-control-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  height: 1.5em;\\n}\\n.form-control::-webkit-datetime-edit {\\n  display: block;\\n  padding: 0;\\n}\\n.form-control::-moz-placeholder {\\n  color: var(--bs-secondary-color);\\n  opacity: 1;\\n}\\n.form-control::placeholder {\\n  color: var(--bs-secondary-color);\\n  opacity: 1;\\n}\\n.form-control:disabled {\\n  background-color: var(--bs-form-control-disabled-bg);\\n  opacity: 1;\\n}\\n.form-control::-webkit-file-upload-button {\\n  padding: 0.375rem 0.75rem;\\n  margin: -0.375rem -0.75rem;\\n  -webkit-margin-end: 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  -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;\\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.form-control::file-selector-button {\\n  padding: 0.375rem 0.75rem;\\n  margin: -0.375rem -0.75rem;\\n  -webkit-margin-end: 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::-webkit-file-upload-button {\\n    -webkit-transition: none;\\n    transition: none;\\n  }\\n  .form-control::file-selector-button {\\n    transition: none;\\n  }\\n}\\n.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {\\n  background-color: var(--bs-secondary-bg);\\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: 0.25rem;\\n}\\n.form-control-sm::-webkit-file-upload-button {\\n  padding: 0.25rem 0.5rem;\\n  margin: -0.25rem -0.5rem;\\n  -webkit-margin-end: 0.5rem;\\n  margin-inline-end: 0.5rem;\\n}\\n.form-control-sm::file-selector-button {\\n  padding: 0.25rem 0.5rem;\\n  margin: -0.25rem -0.5rem;\\n  -webkit-margin-end: 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: 0.5rem;\\n}\\n.form-control-lg::-webkit-file-upload-button {\\n  padding: 0.5rem 1rem;\\n  margin: -0.5rem -1rem;\\n  -webkit-margin-end: 1rem;\\n  margin-inline-end: 1rem;\\n}\\n.form-control-lg::file-selector-button {\\n  padding: 0.5rem 1rem;\\n  margin: -0.5rem -1rem;\\n  -webkit-margin-end: 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: 0.375rem;\\n}\\n.form-control-color::-webkit-color-swatch {\\n  border-radius: 0.375rem;\\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  -moz-padding-start: calc(0.75rem - 3px);\\n  font-size: 1rem;\\n  font-weight: 400;\\n  line-height: 1.5;\\n  color: var(--bs-body-color);\\n  background-color: var(--bs-form-control-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: 0.375rem;\\n  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  -webkit-appearance: none;\\n  -moz-appearance: none;\\n  appearance: none;\\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-form-control-disabled-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: 0.25rem;\\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: 0.5rem;\\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='%23adb5bd' 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-form-control-bg);\\n  width: 1em;\\n  height: 1em;\\n  margin-top: 0.25em;\\n  vertical-align: top;\\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  -webkit-appearance: none;\\n  -moz-appearance: none;\\n  appearance: none;\\n  -webkit-print-color-adjust: exact;\\n  color-adjust: exact;\\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  background-color: transparent;\\n  -webkit-appearance: none;\\n  -moz-appearance: none;\\n  appearance: none;\\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  background-color: #0d6efd;\\n  border: 0;\\n  border-radius: 1rem;\\n  -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  -webkit-appearance: none;\\n  appearance: none;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n  .form-range::-webkit-slider-thumb {\\n    -webkit-transition: none;\\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-tertiary-bg);\\n  border-color: transparent;\\n  border-radius: 1rem;\\n}\\n.form-range::-moz-range-thumb {\\n  width: 1rem;\\n  height: 1rem;\\n  background-color: #0d6efd;\\n  border: 0;\\n  border-radius: 1rem;\\n  -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  -moz-appearance: none;\\n  appearance: none;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n  .form-range::-moz-range-thumb {\\n    -moz-transition: none;\\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-tertiary-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::before:not(.form-control:disabled) {\\n  position: absolute;\\n  top: var(--bs-border-width);\\n  left: var(--bs-border-width);\\n  width: calc(100% - (calc(calc(0.375em + 0.1875rem) + calc(0.75em + 0.375rem))));\\n  height: 1.875em;\\n  content: \\\"\\\";\\n  background-color: var(--bs-form-control-bg);\\n  border-radius: 0.375rem;\\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  line-height: 1.25;\\n}\\n.form-floating > label {\\n  position: absolute;\\n  top: 0;\\n  left: 0;\\n  width: 100%;\\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::-moz-placeholder, .form-floating > .form-control-plaintext::-moz-placeholder {\\n  color: transparent;\\n}\\n.form-floating > .form-control::placeholder,\\n.form-floating > .form-control-plaintext::placeholder {\\n  color: transparent;\\n}\\n.form-floating > .form-control:not(:-moz-placeholder-shown), .form-floating > .form-control-plaintext:not(:-moz-placeholder-shown) {\\n  padding-top: 1.625rem;\\n  padding-bottom: 0.625rem;\\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:not(:-moz-placeholder-shown) ~ label {\\n  opacity: 0.65;\\n  transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\\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  opacity: 0.65;\\n  transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\\n}\\n.form-floating > .form-control:-webkit-autofill ~ label {\\n  opacity: 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 > .form-control:disabled ~ label {\\n  color: #6c757d;\\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: 0.375rem;\\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: 0.5rem;\\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: 0.25rem;\\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-success-text);\\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-success);\\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-success);\\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-success);\\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-success);\\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-success);\\n}\\n.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked {\\n  background-color: var(--bs-success-text);\\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-success-text);\\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-danger-text);\\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-danger);\\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-danger);\\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-danger);\\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-danger);\\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-danger);\\n}\\n.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked {\\n  background-color: var(--bs-danger-text);\\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-danger-text);\\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: #212529;\\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: 0.375rem;\\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  -webkit-user-select: none;\\n  -moz-user-select: none;\\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: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: none;\\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: 0.5rem;\\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: 0.25rem;\\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: 0.375rem;\\n  --bs-dropdown-border-width: var(--bs-border-width);\\n  --bs-dropdown-inner-border-radius: calc(0.375rem - 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: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);\\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: #adb5bd;\\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: 0.375rem;\\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  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.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  background: none;\\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.disabled, .nav-tabs .nav-link:disabled {\\n  color: var(--bs-nav-link-disabled-color);\\n  background-color: transparent;\\n  border-color: transparent;\\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: 0.375rem;\\n  --bs-nav-pills-link-active-color: #fff;\\n  --bs-nav-pills-link-active-bg: #0d6efd;\\n}\\n.nav-pills .nav-link {\\n  background: none;\\n  border: 0;\\n  border-radius: var(--bs-nav-pills-border-radius);\\n}\\n.nav-pills .nav-link:disabled {\\n  color: var(--bs-nav-link-disabled-color);\\n  background-color: transparent;\\n  border-color: transparent;\\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-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: 0.375rem;\\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 .show > .nav-link,\\n.navbar-nav .nav-link.active {\\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  --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 {\\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  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='%23212529'%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-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='%230a58ca'%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-focus-border-color: #86b7fe;\\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);\\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  border-color: var(--bs-accordion-btn-focus-border-color);\\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-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-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-collapse {\\n  border-width: 0;\\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-button, .accordion-flush .accordion-item .accordion-button.collapsed {\\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: 0.5rem;\\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: 0.25rem;\\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: 0.375rem;\\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: 0.375rem;\\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);\\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);\\n}\\n\\n.alert-secondary {\\n  --bs-alert-color: var(--bs-secondary-text);\\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);\\n}\\n\\n.alert-success {\\n  --bs-alert-color: var(--bs-success-text);\\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);\\n}\\n\\n.alert-info {\\n  --bs-alert-color: var(--bs-info-text);\\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);\\n}\\n\\n.alert-warning {\\n  --bs-alert-color: var(--bs-warning-text);\\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);\\n}\\n\\n.alert-danger {\\n  --bs-alert-color: var(--bs-danger-text);\\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);\\n}\\n\\n.alert-light {\\n  --bs-alert-color: var(--bs-light-text);\\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);\\n}\\n\\n.alert-dark {\\n  --bs-alert-color: var(--bs-dark-text);\\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);\\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);\\n  --bs-list-group-bg: var(--bs-primary-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-primary-border-subtle);\\n}\\n.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);\\n}\\n.list-group-item-primary.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-primary-text);\\n  --bs-list-group-active-border-color: var(--bs-primary-text);\\n}\\n\\n.list-group-item-secondary {\\n  --bs-list-group-color: var(--bs-secondary-text);\\n  --bs-list-group-bg: var(--bs-secondary-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-secondary-border-subtle);\\n}\\n.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);\\n}\\n.list-group-item-secondary.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-secondary-text);\\n  --bs-list-group-active-border-color: var(--bs-secondary-text);\\n}\\n\\n.list-group-item-success {\\n  --bs-list-group-color: var(--bs-success-text);\\n  --bs-list-group-bg: var(--bs-success-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-success-border-subtle);\\n}\\n.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-success-border-subtle);\\n}\\n.list-group-item-success.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-success-text);\\n  --bs-list-group-active-border-color: var(--bs-success-text);\\n}\\n\\n.list-group-item-info {\\n  --bs-list-group-color: var(--bs-info-text);\\n  --bs-list-group-bg: var(--bs-info-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-info-border-subtle);\\n}\\n.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-info-border-subtle);\\n}\\n.list-group-item-info.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-info-text);\\n  --bs-list-group-active-border-color: var(--bs-info-text);\\n}\\n\\n.list-group-item-warning {\\n  --bs-list-group-color: var(--bs-warning-text);\\n  --bs-list-group-bg: var(--bs-warning-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-warning-border-subtle);\\n}\\n.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);\\n}\\n.list-group-item-warning.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-warning-text);\\n  --bs-list-group-active-border-color: var(--bs-warning-text);\\n}\\n\\n.list-group-item-danger {\\n  --bs-list-group-color: var(--bs-danger-text);\\n  --bs-list-group-bg: var(--bs-danger-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-danger-border-subtle);\\n}\\n.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);\\n}\\n.list-group-item-danger.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-danger-text);\\n  --bs-list-group-active-border-color: var(--bs-danger-text);\\n}\\n\\n.list-group-item-light {\\n  --bs-list-group-color: var(--bs-light-text);\\n  --bs-list-group-bg: var(--bs-light-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-light-border-subtle);\\n}\\n.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-light-border-subtle);\\n}\\n.list-group-item-light.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-light-text);\\n  --bs-list-group-active-border-color: var(--bs-light-text);\\n}\\n\\n.list-group-item-dark {\\n  --bs-list-group-color: var(--bs-dark-text);\\n  --bs-list-group-bg: var(--bs-dark-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-dark-border-subtle);\\n}\\n.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);\\n}\\n.list-group-item-dark.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-dark-text);\\n  --bs-list-group-active-border-color: var(--bs-dark-text);\\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  -webkit-user-select: none;\\n  -moz-user-select: 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: -webkit-max-content;\\n  width: -moz-max-content;\\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: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);\\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  justify-content: space-between;\\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: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);\\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  padding: var(--bs-tooltip-arrow-height);\\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: 0;\\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: 0;\\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: 0;\\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: 0;\\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: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);\\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: ;\\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  -webkit-backface-visibility: hidden;\\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/* rtl:options: {\\n  \\\"autoRename\\\": true,\\n  \\\"stringMap\\\":[ {\\n    \\\"name\\\"    : \\\"prev-next\\\",\\n    \\\"search\\\"  : \\\"prev\\\",\\n    \\\"replace\\\" : \\\"next\\\"\\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\\\");\\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\\\");\\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  list-style: none;\\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 {\\n  filter: invert(1) grayscale(100);\\n}\\n[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target] {\\n  background-color: #000;\\n}\\n[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: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);\\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}\\n@media (max-width: 575.98px) {\\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}\\n@media (max-width: 575.98px) {\\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}\\n@media (max-width: 575.98px) {\\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}\\n@media (max-width: 575.98px) {\\n  .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 575.98px) {\\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}\\n@media (max-width: 767.98px) {\\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}\\n@media (max-width: 767.98px) {\\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}\\n@media (max-width: 767.98px) {\\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}\\n@media (max-width: 767.98px) {\\n  .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 767.98px) {\\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}\\n@media (max-width: 991.98px) {\\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}\\n@media (max-width: 991.98px) {\\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}\\n@media (max-width: 991.98px) {\\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}\\n@media (max-width: 991.98px) {\\n  .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 991.98px) {\\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}\\n@media (max-width: 1199.98px) {\\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}\\n@media (max-width: 1199.98px) {\\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}\\n@media (max-width: 1199.98px) {\\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}\\n@media (max-width: 1199.98px) {\\n  .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 1199.98px) {\\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}\\n@media (max-width: 1399.98px) {\\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}\\n@media (max-width: 1399.98px) {\\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}\\n@media (max-width: 1399.98px) {\\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}\\n@media (max-width: 1399.98px) {\\n  .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 1399.98px) {\\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  justify-content: space-between;\\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-top: calc(-0.5 * var(--bs-offcanvas-padding-y));\\n  margin-right: calc(-0.5 * var(--bs-offcanvas-padding-x));\\n  margin-bottom: calc(-0.5 * var(--bs-offcanvas-padding-y));\\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  -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\\n  mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\\n  -webkit-mask-size: 200% 100%;\\n  mask-size: 200% 100%;\\n  animation: placeholder-wave 2s linear infinite;\\n}\\n\\n@keyframes placeholder-wave {\\n  100% {\\n    -webkit-mask-position: -200% 0%;\\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(13, 110, 253, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-secondary {\\n  color: #fff !important;\\n  background-color: RGBA(108, 117, 125, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-success {\\n  color: #fff !important;\\n  background-color: RGBA(25, 135, 84, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-info {\\n  color: #000 !important;\\n  background-color: RGBA(13, 202, 240, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-warning {\\n  color: #000 !important;\\n  background-color: RGBA(255, 193, 7, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-danger {\\n  color: #fff !important;\\n  background-color: RGBA(220, 53, 69, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-light {\\n  color: #000 !important;\\n  background-color: RGBA(248, 249, 250, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-dark {\\n  color: #fff !important;\\n  background-color: RGBA(33, 37, 41, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.link-primary {\\n  color: #0d6efd !important;\\n}\\n.link-primary:hover, .link-primary:focus {\\n  color: #0a58ca !important;\\n}\\n\\n.link-secondary {\\n  color: #6c757d !important;\\n}\\n.link-secondary:hover, .link-secondary:focus {\\n  color: #565e64 !important;\\n}\\n\\n.link-success {\\n  color: #198754 !important;\\n}\\n.link-success:hover, .link-success:focus {\\n  color: #146c43 !important;\\n}\\n\\n.link-info {\\n  color: #0dcaf0 !important;\\n}\\n.link-info:hover, .link-info:focus {\\n  color: #3dd5f3 !important;\\n}\\n\\n.link-warning {\\n  color: #ffc107 !important;\\n}\\n.link-warning:hover, .link-warning:focus {\\n  color: #ffcd39 !important;\\n}\\n\\n.link-danger {\\n  color: #dc3545 !important;\\n}\\n.link-danger:hover, .link-danger:focus {\\n  color: #b02a37 !important;\\n}\\n\\n.link-light {\\n  color: #f8f9fa !important;\\n}\\n.link-light:hover, .link-light:focus {\\n  color: #f9fafb !important;\\n}\\n\\n.link-dark {\\n  color: #212529 !important;\\n}\\n.link-dark:hover, .link-dark:focus {\\n  color: #1a1e21 !important;\\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: -webkit-sticky;\\n  position: sticky;\\n  top: 0;\\n  z-index: 1020;\\n}\\n\\n.sticky-bottom {\\n  position: -webkit-sticky;\\n  position: sticky;\\n  bottom: 0;\\n  z-index: 1020;\\n}\\n\\n@media (min-width: 576px) {\\n  .sticky-sm-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-sm-bottom {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    bottom: 0;\\n    z-index: 1020;\\n  }\\n}\\n@media (min-width: 768px) {\\n  .sticky-md-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-md-bottom {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    bottom: 0;\\n    z-index: 1020;\\n  }\\n}\\n@media (min-width: 992px) {\\n  .sticky-lg-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-lg-bottom {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    bottom: 0;\\n    z-index: 1020;\\n  }\\n}\\n@media (min-width: 1200px) {\\n  .sticky-xl-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-xl-bottom {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    bottom: 0;\\n    z-index: 1020;\\n  }\\n}\\n@media (min-width: 1400px) {\\n  .sticky-xxl-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-xxl-bottom {\\n    position: -webkit-sticky;\\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  position: absolute !important;\\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\\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: 1px;\\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  -o-object-fit: contain !important;\\n  object-fit: contain !important;\\n}\\n\\n.object-fit-cover {\\n  -o-object-fit: cover !important;\\n  object-fit: cover !important;\\n}\\n\\n.object-fit-fill {\\n  -o-object-fit: fill !important;\\n  object-fit: fill !important;\\n}\\n\\n.object-fit-scale {\\n  -o-object-fit: scale-down !important;\\n  object-fit: scale-down !important;\\n}\\n\\n.object-fit-none {\\n  -o-object-fit: none !important;\\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-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: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15) !important;\\n}\\n\\n.shadow-sm {\\n  box-shadow: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075) !important;\\n}\\n\\n.shadow-lg {\\n  box-shadow: 0 1rem 3rem rgba(var(--bs-body-color-rgb), 0.175) !important;\\n}\\n\\n.shadow-none {\\n  box-shadow: none !important;\\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: -webkit-sticky !important;\\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-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  --bs-border-width: 1px;\\n}\\n\\n.border-2 {\\n  --bs-border-width: 2px;\\n}\\n\\n.border-3 {\\n  --bs-border-width: 3px;\\n}\\n\\n.border-4 {\\n  --bs-border-width: 4px;\\n}\\n\\n.border-5 {\\n  --bs-border-width: 5px;\\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  -moz-column-gap: 0 !important;\\n  column-gap: 0 !important;\\n}\\n\\n.column-gap-1 {\\n  -moz-column-gap: 0.25rem !important;\\n  column-gap: 0.25rem !important;\\n}\\n\\n.column-gap-2 {\\n  -moz-column-gap: 0.5rem !important;\\n  column-gap: 0.5rem !important;\\n}\\n\\n.column-gap-3 {\\n  -moz-column-gap: 1rem !important;\\n  column-gap: 1rem !important;\\n}\\n\\n.column-gap-4 {\\n  -moz-column-gap: 1.5rem !important;\\n  column-gap: 1.5rem !important;\\n}\\n\\n.column-gap-5 {\\n  -moz-column-gap: 3rem !important;\\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) !important;\\n}\\n\\n.text-secondary-emphasis {\\n  color: var(--bs-secondary-text) !important;\\n}\\n\\n.text-success-emphasis {\\n  color: var(--bs-success-text) !important;\\n}\\n\\n.text-info-emphasis {\\n  color: var(--bs-info-text) !important;\\n}\\n\\n.text-warning-emphasis {\\n  color: var(--bs-warning-text) !important;\\n}\\n\\n.text-danger-emphasis {\\n  color: var(--bs-danger-text) !important;\\n}\\n\\n.text-light-emphasis {\\n  color: var(--bs-light-text) !important;\\n}\\n\\n.text-dark-emphasis {\\n  color: var(--bs-dark-text) !important;\\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-body-emphasis {\\n  --bs-bg-opacity: 1;\\n  background-color: rgba(var(--bs-emphasis-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  -webkit-user-select: all !important;\\n  -moz-user-select: all !important;\\n  user-select: all !important;\\n}\\n\\n.user-select-auto {\\n  -webkit-user-select: auto !important;\\n  -moz-user-select: auto !important;\\n  user-select: auto !important;\\n}\\n\\n.user-select-none {\\n  -webkit-user-select: none !important;\\n  -moz-user-select: none !important;\\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-2xl) !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-2xl) !important;\\n  border-top-right-radius: var(--bs-border-radius-2xl) !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-2xl) !important;\\n  border-bottom-right-radius: var(--bs-border-radius-2xl) !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-2xl) !important;\\n  border-bottom-left-radius: var(--bs-border-radius-2xl) !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-2xl) !important;\\n  border-top-left-radius: var(--bs-border-radius-2xl) !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    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-sm-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-sm-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-sm-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-sm-none {\\n    -o-object-fit: none !important;\\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-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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-sm-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-sm-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-sm-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-sm-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-sm-5 {\\n    -moz-column-gap: 3rem !important;\\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    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-md-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-md-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-md-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-md-none {\\n    -o-object-fit: none !important;\\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-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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-md-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-md-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-md-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-md-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-md-5 {\\n    -moz-column-gap: 3rem !important;\\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    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-lg-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-lg-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-lg-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-lg-none {\\n    -o-object-fit: none !important;\\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-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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-lg-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-lg-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-lg-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-lg-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-lg-5 {\\n    -moz-column-gap: 3rem !important;\\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    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-xl-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-xl-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-xl-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-xl-none {\\n    -o-object-fit: none !important;\\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-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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-xl-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-xl-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-xl-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-xl-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-xl-5 {\\n    -moz-column-gap: 3rem !important;\\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    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-xxl-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-xxl-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-xxl-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-xxl-none {\\n    -o-object-fit: none !important;\\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-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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-xxl-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-xxl-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-xxl-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-xxl-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-xxl-5 {\\n    -moz-column-gap: 3rem !important;\\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-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 */\",\"// stylelint-disable property-blacklist, scss/dollar-variable-default\\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  }\\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      }\\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    }\\n\\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      }\\n\\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    $fluidVal: rfs-fluid-value($values);\\n\\n    // Do not print the media query if responsive & non-responsive values are the same\\n    @if $val == $fluidVal {\\n      #{$property}: $val;\\n    }\\n    @else {\\n      @include _rfs-rule {\\n        #{$property}: if($rfs-mode == max-media-query, $val, $fluidVal);\\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, $fluidVal, $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, `<h1>`-`<h6>` 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, inherit);\\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 `<p>`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  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 `<td>` 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-`<button>` buttons\\n//\\n// Details at https://github.com/twbs/bootstrap/pull/30562\\n[role=\\\"button\\\"] {\\n  cursor: pointer;\\n}\\n\\nselect {\\n  // Remove the inheritance of word-wrap in Safari.\\n  // See https://github.com/twbs/bootstrap/issues/24990\\n  word-wrap: normal;\\n\\n  // Undo the opacity change from Chrome\\n  &:disabled {\\n    opacity: 1;\\n  }\\n}\\n\\n// Remove the dropdown arrow only from text type inputs built with datalists in Chrome.\\n// See https://stackoverflow.com/a/54997118\\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\\n// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`\\n//    controls in Android 4.\\n// 2. Correct the inability to style clickable types in iOS and Safari.\\n// 3. Opinionated: add \\\"hand\\\" cursor to non-disabled button elements.\\n\\nbutton,\\n[type=\\\"button\\\"], // 1\\n[type=\\\"reset\\\"],\\n[type=\\\"submit\\\"] {\\n  -webkit-appearance: button; // 2\\n\\n  @if $enable-button-pointers {\\n    &:not(:disabled) {\\n      cursor: pointer; // 3\\n    }\\n  }\\n}\\n\\n// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.\\n\\n::-moz-focus-inner {\\n  padding: 0;\\n  border-style: none;\\n}\\n\\n// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers.\\n\\ntextarea {\\n  resize: vertical; // 1\\n}\\n\\n// 1. Browsers set a default `min-width: min-content;` on fieldsets,\\n//    unlike e.g. `<div>`s, which have `min-width: 0;` by default.\\n//    So we reset that to ensure fieldsets behave more like a standard block element.\\n//    See https://github.com/twbs/bootstrap/issues/12359\\n//    and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements\\n// 2. Reset the default outline behavior of fieldsets so they don't affect page layout.\\n\\nfieldset {\\n  min-width: 0; // 1\\n  padding: 0; // 2\\n  margin: 0; // 2\\n  border: 0; // 2\\n}\\n\\n// 1. By using `float: left`, the legend will behave like a block element.\\n//    This way the border of a fieldset wraps around the legend if present.\\n// 2. Fix wrapping bug.\\n//    See https://github.com/twbs/bootstrap/issues/29712\\n\\nlegend {\\n  float: left; // 1\\n  width: 100%;\\n  padding: 0;\\n  margin-bottom: $legend-margin-bottom;\\n  @include font-size($legend-font-size);\\n  font-weight: $legend-font-weight;\\n  line-height: inherit;\\n\\n  + * {\\n    clear: left; // 2\\n  }\\n}\\n\\n// Fix height of inputs with a type of datetime-local, date, month, week, or time\\n// See https://github.com/twbs/bootstrap/issues/18842\\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// 1. Correct the outline style in Safari.\\n// 2. This overrides the extra rounded corners on search inputs in iOS so that our\\n//    `.form-control` class can properly style them. Note that this cannot simply\\n//    be added to `.form-control` as it's not specific enough. For details, see\\n//    https://github.com/twbs/bootstrap/issues/11586.\\n\\n[type=\\\"search\\\"] {\\n  outline-offset: -2px; // 1\\n  -webkit-appearance: textfield; // 2\\n}\\n\\n// 1. A few input types should stay LTR\\n// See https://rtlstyling.com/posts/rtl-styling#form-inputs\\n// 2. RTL only output\\n// See https://rtlcss.com/learn/usage-guide/control-directives/#raw\\n\\n/* rtl:raw:\\n[type=\\\"tel\\\"],\\n[type=\\\"url\\\"],\\n[type=\\\"email\\\"],\\n[type=\\\"number\\\"] {\\n  direction: ltr;\\n}\\n*/\\n\\n// Remove the inner padding in Chrome and Safari on macOS.\\n\\n::-webkit-search-decoration {\\n  -webkit-appearance: none;\\n}\\n\\n// Remove padding around color pickers in webkit browsers\\n\\n::-webkit-color-swatch-wrapper {\\n  padding: 0;\\n}\\n\\n\\n// 1. Inherit font family and line height for file input buttons\\n// 2. Correct the inability to style clickable types in iOS and Safari.\\n\\n::file-selector-button {\\n  font: inherit; // 1\\n  -webkit-appearance: button; // 2\\n}\\n\\n// Correct element displays\\n\\noutput {\\n  display: inline-block;\\n}\\n\\n// Remove border from iframe\\n\\niframe {\\n  border: 0;\\n}\\n\\n// Summary\\n//\\n// 1. Add the correct display in all browsers\\n\\nsummary {\\n  display: list-item; // 1\\n  cursor: pointer;\\n}\\n\\n\\n// Progress\\n//\\n// Add the correct vertical alignment in Chrome, Firefox, and Opera.\\n\\nprogress {\\n  vertical-align: baseline;\\n}\\n\\n\\n// Hidden attribute\\n//\\n// Always hide an element with the `hidden` HTML attribute.\\n\\n[hidden] {\\n  display: none !important;\\n}\\n\",\"// stylelint-disable property-disallowed-list\\n// Single side border-radius\\n\\n// Helper function to replace negative values with 0\\n@function valid-radius($radius) {\\n  $return: ();\\n  @each $value in $radius {\\n    @if type-of($value) == number {\\n      $return: append($return, max($value, 0));\\n    } @else {\\n      $return: append($return, $value);\\n    }\\n  }\\n  @return $return;\\n}\\n\\n// scss-docs-start border-radius-mixins\\n@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) {\\n  @if $enable-rounded {\\n    border-radius: valid-radius($radius);\\n  }\\n  @else if $fallback-border-radius != false {\\n    border-radius: $fallback-border-radius;\\n  }\\n}\\n\\n@mixin border-top-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-left-radius: valid-radius($radius);\\n    border-top-right-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-end-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-right-radius: valid-radius($radius);\\n    border-bottom-right-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-bottom-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-bottom-right-radius: valid-radius($radius);\\n    border-bottom-left-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-start-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-left-radius: valid-radius($radius);\\n    border-bottom-left-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-top-start-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-left-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-top-end-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-right-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-bottom-end-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-bottom-right-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-bottom-start-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-bottom-left-radius: valid-radius($radius);\\n  }\\n}\\n// scss-docs-end border-radius-mixins\\n\",\"//\\n// Headings\\n//\\n.h1 {\\n  @extend h1;\\n}\\n\\n.h2 {\\n  @extend h2;\\n}\\n\\n.h3 {\\n  @extend h3;\\n}\\n\\n.h4 {\\n  @extend h4;\\n}\\n\\n.h5 {\\n  @extend h5;\\n}\\n\\n.h6 {\\n  @extend h6;\\n}\\n\\n\\n.lead {\\n  @include font-size($lead-font-size);\\n  font-weight: $lead-font-weight;\\n}\\n\\n// Type display classes\\n@each $display, $font-size in $display-font-sizes {\\n  .display-#{$display} {\\n    @include font-size($font-size);\\n    font-family: $display-font-family;\\n    font-style: $display-font-style;\\n    font-weight: $display-font-weight;\\n    line-height: $display-line-height;\\n  }\\n}\\n\\n//\\n// Emphasis\\n//\\n.small {\\n  @extend small;\\n}\\n\\n.mark {\\n  @extend mark;\\n}\\n\\n//\\n// Lists\\n//\\n\\n.list-unstyled {\\n  @include list-unstyled();\\n}\\n\\n// Inline turns list items into inline-block\\n.list-inline {\\n  @include list-unstyled();\\n}\\n.list-inline-item {\\n  display: inline-block;\\n\\n  &:not(:last-child) {\\n    margin-right: $list-inline-padding;\\n  }\\n}\\n\\n\\n//\\n// Misc\\n//\\n\\n// Builds on `abbr`\\n.initialism {\\n  @include font-size($initialism-font-size);\\n  text-transform: uppercase;\\n}\\n\\n// Blockquotes\\n.blockquote {\\n  margin-bottom: $blockquote-margin-y;\\n  @include font-size($blockquote-font-size);\\n\\n  > :last-child {\\n    margin-bottom: 0;\\n  }\\n}\\n\\n.blockquote-footer {\\n  margin-top: -$blockquote-margin-y;\\n  margin-bottom: $blockquote-margin-y;\\n  @include font-size($blockquote-footer-font-size);\\n  color: $blockquote-footer-color;\\n\\n  &::before {\\n    content: \\\"\\\\2014\\\\00A0\\\"; // em dash, nbsp\\n  }\\n}\\n\",\"// Lists\\n\\n// Unstyled keeps list items block level, just removes default browser padding and list-style\\n@mixin list-unstyled {\\n  padding-left: 0;\\n  list-style: none;\\n}\\n\",\"// Responsive images (ensure images don't scale beyond their parents)\\n//\\n// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.\\n// We previously tried the \\\"images are responsive by default\\\" approach in Bootstrap v2,\\n// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)\\n// which weren't expecting the images within themselves to be involuntarily resized.\\n// See also https://github.com/twbs/bootstrap/issues/18178\\n.img-fluid {\\n  @include img-fluid();\\n}\\n\\n\\n// Image thumbnails\\n.img-thumbnail {\\n  padding: $thumbnail-padding;\\n  background-color: $thumbnail-bg;\\n  border: $thumbnail-border-width solid $thumbnail-border-color;\\n  @include border-radius($thumbnail-border-radius);\\n  @include box-shadow($thumbnail-box-shadow);\\n\\n  // Keep them at most 100% wide\\n  @include img-fluid();\\n}\\n\\n//\\n// Figures\\n//\\n\\n.figure {\\n  // Ensures the caption's text aligns with the image.\\n  display: inline-block;\\n}\\n\\n.figure-img {\\n  margin-bottom: $spacer * .5;\\n  line-height: 1;\\n}\\n\\n.figure-caption {\\n  @include font-size($figure-caption-font-size);\\n  color: $figure-caption-color;\\n}\\n\",\"// Image Mixins\\n// - Responsive image\\n// - Retina image\\n\\n\\n// Responsive image\\n//\\n// Keep images from scaling beyond the width of their parents.\\n\\n@mixin img-fluid {\\n  // Part 1: Set a maximum relative to the parent\\n  max-width: 100%;\\n  // Part 2: Override the height to auto, otherwise images will be stretched\\n  // when setting a width and height attribute on the img element.\\n  height: auto;\\n}\\n\",\"// Container widths\\n//\\n// Set the container width, and override it for fixed navbars in media queries.\\n\\n@if $enable-container-classes {\\n  // Single container class with breakpoint max-widths\\n  .container,\\n  // 100% wide container at all breakpoints\\n  .container-fluid {\\n    @include make-container();\\n  }\\n\\n  // Responsive containers that are 100% wide until a breakpoint\\n  @each $breakpoint, $container-max-width in $container-max-widths {\\n    .container-#{$breakpoint} {\\n      @extend .container-fluid;\\n    }\\n\\n    @include media-breakpoint-up($breakpoint, $grid-breakpoints) {\\n      %responsive-container-#{$breakpoint} {\\n        max-width: $container-max-width;\\n      }\\n\\n      // Extend each breakpoint which is smaller or equal to the current breakpoint\\n      $extend-breakpoint: true;\\n\\n      @each $name, $width in $grid-breakpoints {\\n        @if ($extend-breakpoint) {\\n          .container#{breakpoint-infix($name, $grid-breakpoints)} {\\n            @extend %responsive-container-#{$breakpoint};\\n          }\\n\\n          // Once the current breakpoint is reached, stop extending\\n          @if ($breakpoint == $name) {\\n            $extend-breakpoint: false;\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n\",\"// Container mixins\\n\\n@mixin make-container($gutter: $container-padding-x) {\\n  --#{$prefix}gutter-x: #{$gutter};\\n  --#{$prefix}gutter-y: 0;\\n  width: 100%;\\n  padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\\n  padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\\n  margin-right: auto;\\n  margin-left: auto;\\n}\\n\",\"// Breakpoint viewport sizes and media queries.\\n//\\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\\n//\\n//    (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)\\n//\\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\\n\\n// Name of the next breakpoint, or null for the last breakpoint.\\n//\\n//    >> breakpoint-next(sm)\\n//    md\\n//    >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    md\\n//    >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl))\\n//    md\\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\\n  $n: index($breakpoint-names, $name);\\n  @if not $n {\\n    @error \\\"breakpoint `#{$name}` not found in `#{$breakpoints}`\\\";\\n  }\\n  @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\\n}\\n\\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\\n//\\n//    >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    576px\\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\\n  $min: map-get($breakpoints, $name);\\n  @return if($min != 0, $min, null);\\n}\\n\\n// Maximum breakpoint width.\\n// The maximum value is reduced by 0.02px to work around the limitations of\\n// `min-` and `max-` prefixes and viewports with fractional widths.\\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\\n//\\n//    >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    767.98px\\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\\n  $max: map-get($breakpoints, $name);\\n  @return if($max and $max > 0, $max - .02, null);\\n}\\n\\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\\n// Useful for making responsive utilities.\\n//\\n//    >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    \\\"\\\"  (Returns a blank string)\\n//    >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    \\\"-sm\\\"\\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\\n  @return if(breakpoint-min($name, $breakpoints) == null, \\\"\\\", \\\"-#{$name}\\\");\\n}\\n\\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\\n// Makes the @content apply to the given breakpoint and wider.\\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\\n  $min: breakpoint-min($name, $breakpoints);\\n  @if $min {\\n    @media (min-width: $min) {\\n      @content;\\n    }\\n  } @else {\\n    @content;\\n  }\\n}\\n\\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\\n// Makes the @content apply to the given breakpoint and narrower.\\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\\n  $max: breakpoint-max($name, $breakpoints);\\n  @if $max {\\n    @media (max-width: $max) {\\n      @content;\\n    }\\n  } @else {\\n    @content;\\n  }\\n}\\n\\n// Media that spans multiple breakpoint widths.\\n// Makes the @content apply between the min and max breakpoints\\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\\n  $min: breakpoint-min($lower, $breakpoints);\\n  $max: breakpoint-max($upper, $breakpoints);\\n\\n  @if $min != null and $max != null {\\n    @media (min-width: $min) and (max-width: $max) {\\n      @content;\\n    }\\n  } @else if $max == null {\\n    @include media-breakpoint-up($lower, $breakpoints) {\\n      @content;\\n    }\\n  } @else if $min == null {\\n    @include media-breakpoint-down($upper, $breakpoints) {\\n      @content;\\n    }\\n  }\\n}\\n\\n// Media between the breakpoint's minimum and maximum widths.\\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\\n  $min:  breakpoint-min($name, $breakpoints);\\n  $next: breakpoint-next($name, $breakpoints);\\n  $max:  breakpoint-max($next, $breakpoints);\\n\\n  @if $min != null and $max != null {\\n    @media (min-width: $min) and (max-width: $max) {\\n      @content;\\n    }\\n  } @else if $max == null {\\n    @include media-breakpoint-up($name, $breakpoints) {\\n      @content;\\n    }\\n  } @else if $min == null {\\n    @include media-breakpoint-down($next, $breakpoints) {\\n      @content;\\n    }\\n  }\\n}\\n\",\"// Row\\n//\\n// Rows contain your columns.\\n\\n@if $enable-grid-classes {\\n  .row {\\n    @include make-row();\\n\\n    > * {\\n      @include make-col-ready();\\n    }\\n  }\\n}\\n\\n@if $enable-cssgrid {\\n  .grid {\\n    display: grid;\\n    grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);\\n    grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);\\n    gap: var(--#{$prefix}gap, #{$grid-gutter-width});\\n\\n    @include make-cssgrid();\\n  }\\n}\\n\\n\\n// Columns\\n//\\n// Common styles for small and large grid columns\\n\\n@if $enable-grid-classes {\\n  @include make-grid-columns();\\n}\\n\",\"// Grid system\\n//\\n// Generate semantic grid columns with these mixins.\\n\\n@mixin make-row($gutter: $grid-gutter-width) {\\n  --#{$prefix}gutter-x: #{$gutter};\\n  --#{$prefix}gutter-y: 0;\\n  display: flex;\\n  flex-wrap: wrap;\\n  // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed\\n  margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list\\n  margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\\n  margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\\n}\\n\\n@mixin make-col-ready() {\\n  // Add box sizing if only the grid is loaded\\n  box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);\\n  // Prevent columns from becoming too narrow when at smaller grid tiers by\\n  // always setting `width: 100%;`. This works because we set the width\\n  // later on to override this initial width.\\n  flex-shrink: 0;\\n  width: 100%;\\n  max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid\\n  padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\\n  padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\\n  margin-top: var(--#{$prefix}gutter-y);\\n}\\n\\n@mixin make-col($size: false, $columns: $grid-columns) {\\n  @if $size {\\n    flex: 0 0 auto;\\n    width: percentage(divide($size, $columns));\\n\\n  } @else {\\n    flex: 1 1 0;\\n    max-width: 100%;\\n  }\\n}\\n\\n@mixin make-col-auto() {\\n  flex: 0 0 auto;\\n  width: auto;\\n}\\n\\n@mixin make-col-offset($size, $columns: $grid-columns) {\\n  $num: divide($size, $columns);\\n  margin-left: if($num == 0, 0, percentage($num));\\n}\\n\\n// Row columns\\n//\\n// Specify on a parent element(e.g., .row) to force immediate children into NN\\n// number of columns. Supports wrapping to new lines, but does not do a Masonry\\n// style grid.\\n@mixin row-cols($count) {\\n  > * {\\n    flex: 0 0 auto;\\n    width: divide(100%, $count);\\n  }\\n}\\n\\n// Framework grid generation\\n//\\n// Used only by Bootstrap to generate the correct number of grid classes given\\n// any value of `$grid-columns`.\\n\\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\\n  @each $breakpoint in map-keys($breakpoints) {\\n    $infix: breakpoint-infix($breakpoint, $breakpoints);\\n\\n    @include media-breakpoint-up($breakpoint, $breakpoints) {\\n      // Provide basic `.col-{bp}` classes for equal-width flexbox columns\\n      .col#{$infix} {\\n        flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\\n      }\\n\\n      .row-cols#{$infix}-auto > * {\\n        @include make-col-auto();\\n      }\\n\\n      @if $grid-row-columns > 0 {\\n        @for $i from 1 through $grid-row-columns {\\n          .row-cols#{$infix}-#{$i} {\\n            @include row-cols($i);\\n          }\\n        }\\n      }\\n\\n      .col#{$infix}-auto {\\n        @include make-col-auto();\\n      }\\n\\n      @if $columns > 0 {\\n        @for $i from 1 through $columns {\\n          .col#{$infix}-#{$i} {\\n            @include make-col($i, $columns);\\n          }\\n        }\\n\\n        // `$columns - 1` because offsetting by the width of an entire row isn't possible\\n        @for $i from 0 through ($columns - 1) {\\n          @if not ($infix == \\\"\\\" and $i == 0) { // Avoid emitting useless .offset-0\\n            .offset#{$infix}-#{$i} {\\n              @include make-col-offset($i, $columns);\\n            }\\n          }\\n        }\\n      }\\n\\n      // Gutters\\n      //\\n      // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns.\\n      @each $key, $value in $gutters {\\n        .g#{$infix}-#{$key},\\n        .gx#{$infix}-#{$key} {\\n          --#{$prefix}gutter-x: #{$value};\\n        }\\n\\n        .g#{$infix}-#{$key},\\n        .gy#{$infix}-#{$key} {\\n          --#{$prefix}gutter-y: #{$value};\\n        }\\n      }\\n    }\\n  }\\n}\\n\\n@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) {\\n  @each $breakpoint in map-keys($breakpoints) {\\n    $infix: breakpoint-infix($breakpoint, $breakpoints);\\n\\n    @include media-breakpoint-up($breakpoint, $breakpoints) {\\n      @if $columns > 0 {\\n        @for $i from 1 through $columns {\\n          .g-col#{$infix}-#{$i} {\\n            grid-column: auto / span $i;\\n          }\\n        }\\n\\n        // Start with `1` because `0` is and invalid value.\\n        // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.\\n        @for $i from 1 through ($columns - 1) {\\n          .g-start#{$infix}-#{$i} {\\n            grid-column-start: $i;\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n\",\"//\\n// Basic Bootstrap table\\n//\\n\\n.table {\\n  --#{$prefix}table-color: #{$table-color};\\n  --#{$prefix}table-bg: #{$table-bg};\\n  --#{$prefix}table-border-color: #{$table-border-color};\\n  --#{$prefix}table-accent-bg: #{$table-accent-bg};\\n  --#{$prefix}table-striped-color: #{$table-striped-color};\\n  --#{$prefix}table-striped-bg: #{$table-striped-bg};\\n  --#{$prefix}table-active-color: #{$table-active-color};\\n  --#{$prefix}table-active-bg: #{$table-active-bg};\\n  --#{$prefix}table-hover-color: #{$table-hover-color};\\n  --#{$prefix}table-hover-bg: #{$table-hover-bg};\\n\\n  width: 100%;\\n  margin-bottom: $spacer;\\n  color: var(--#{$prefix}table-color);\\n  vertical-align: $table-cell-vertical-align;\\n  border-color: var(--#{$prefix}table-border-color);\\n\\n  // Target th & td\\n  // We need the child combinator to prevent styles leaking to nested tables which doesn't have a `.table` class.\\n  // We use the universal selectors here to simplify the selector (else we would need 6 different selectors).\\n  // Another advantage is that this generates less code and makes the selector less specific making it easier to override.\\n  // stylelint-disable-next-line selector-max-universal\\n  > :not(caption) > * > * {\\n    padding: $table-cell-padding-y $table-cell-padding-x;\\n    background-color: var(--#{$prefix}table-bg);\\n    border-bottom-width: $table-border-width;\\n    box-shadow: inset 0 0 0 9999px var(--#{$prefix}table-accent-bg);\\n  }\\n\\n  > tbody {\\n    vertical-align: inherit;\\n  }\\n\\n  > thead {\\n    vertical-align: bottom;\\n  }\\n}\\n\\n.table-group-divider {\\n  border-top: calc($table-border-width * 2) solid $table-group-separator-color; // stylelint-disable-line function-disallowed-list\\n}\\n\\n//\\n// Change placement of captions with a class\\n//\\n\\n.caption-top {\\n  caption-side: top;\\n}\\n\\n\\n//\\n// Condensed table w/ half padding\\n//\\n\\n.table-sm {\\n  // stylelint-disable-next-line selector-max-universal\\n  > :not(caption) > * > * {\\n    padding: $table-cell-padding-y-sm $table-cell-padding-x-sm;\\n  }\\n}\\n\\n\\n// Border versions\\n//\\n// Add or remove borders all around the table and between all the columns.\\n//\\n// When borders are added on all sides of the cells, the corners can render odd when\\n// these borders do not have the same color or if they are semi-transparent.\\n// Therefor we add top and border bottoms to the `tr`s and left and right borders\\n// to the `td`s or `th`s\\n\\n.table-bordered {\\n  > :not(caption) > * {\\n    border-width: $table-border-width 0;\\n\\n    // stylelint-disable-next-line selector-max-universal\\n    > * {\\n      border-width: 0 $table-border-width;\\n    }\\n  }\\n}\\n\\n.table-borderless {\\n  // stylelint-disable-next-line selector-max-universal\\n  > :not(caption) > * > * {\\n    border-bottom-width: 0;\\n  }\\n\\n  > :not(:first-child) {\\n    border-top-width: 0;\\n  }\\n}\\n\\n// Zebra-striping\\n//\\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\\n\\n// For rows\\n.table-striped {\\n  > tbody > tr:nth-of-type(#{$table-striped-order}) > * {\\n    --#{$prefix}table-accent-bg: var(--#{$prefix}table-striped-bg);\\n    color: var(--#{$prefix}table-striped-color);\\n  }\\n}\\n\\n// For columns\\n.table-striped-columns {\\n  > :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) {\\n    --#{$prefix}table-accent-bg: var(--#{$prefix}table-striped-bg);\\n    color: var(--#{$prefix}table-striped-color);\\n  }\\n}\\n\\n// Active table\\n//\\n// The `.table-active` class can be added to highlight rows or cells\\n\\n.table-active {\\n  --#{$prefix}table-accent-bg: var(--#{$prefix}table-active-bg);\\n  color: var(--#{$prefix}table-active-color);\\n}\\n\\n// Hover effect\\n//\\n// Placed here since it has to come after the potential zebra striping\\n\\n.table-hover {\\n  > tbody > tr:hover > * {\\n    --#{$prefix}table-accent-bg: var(--#{$prefix}table-hover-bg);\\n    color: var(--#{$prefix}table-hover-color);\\n  }\\n}\\n\\n\\n// Table variants\\n//\\n// Table variants set the table cell backgrounds, border colors\\n// and the colors of the striped, hovered & active tables\\n\\n@each $color, $value in $table-variants {\\n  @include table-variant($color, $value);\\n}\\n\\n// Responsive tables\\n//\\n// Generate series of `.table-responsive-*` classes for configuring the screen\\n// size of where your table will overflow.\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n  @include media-breakpoint-down($breakpoint) {\\n    .table-responsive#{$infix} {\\n      overflow-x: auto;\\n      -webkit-overflow-scrolling: touch;\\n    }\\n  }\\n}\\n\",\"// scss-docs-start table-variant\\n@mixin table-variant($state, $background) {\\n  .table-#{$state} {\\n    $color: color-contrast(opaque($body-bg, $background));\\n    $hover-bg: mix($color, $background, percentage($table-hover-bg-factor));\\n    $striped-bg: mix($color, $background, percentage($table-striped-bg-factor));\\n    $active-bg: mix($color, $background, percentage($table-active-bg-factor));\\n    $table-border-color: mix($color, $background, percentage($table-border-factor));\\n\\n    --#{$prefix}table-color: #{$color};\\n    --#{$prefix}table-bg: #{$background};\\n    --#{$prefix}table-border-color: #{$table-border-color};\\n    --#{$prefix}table-striped-bg: #{$striped-bg};\\n    --#{$prefix}table-striped-color: #{color-contrast($striped-bg)};\\n    --#{$prefix}table-active-bg: #{$active-bg};\\n    --#{$prefix}table-active-color: #{color-contrast($active-bg)};\\n    --#{$prefix}table-hover-bg: #{$hover-bg};\\n    --#{$prefix}table-hover-color: #{color-contrast($hover-bg)};\\n\\n    color: var(--#{$prefix}table-color);\\n    border-color: var(--#{$prefix}table-border-color);\\n  }\\n}\\n// scss-docs-end table-variant\\n\",\"//\\n// Labels\\n//\\n\\n.form-label {\\n  margin-bottom: $form-label-margin-bottom;\\n  @include font-size($form-label-font-size);\\n  font-style: $form-label-font-style;\\n  font-weight: $form-label-font-weight;\\n  color: $form-label-color;\\n}\\n\\n// For use with horizontal and inline forms, when you need the label (or legend)\\n// text to align with the form controls.\\n.col-form-label {\\n  padding-top: add($input-padding-y, $input-border-width);\\n  padding-bottom: add($input-padding-y, $input-border-width);\\n  margin-bottom: 0; // Override the `<legend>` default\\n  @include font-size(inherit); // Override the `<legend>` default\\n  font-style: $form-label-font-style;\\n  font-weight: $form-label-font-weight;\\n  line-height: $input-line-height;\\n  color: $form-label-color;\\n}\\n\\n.col-form-label-lg {\\n  padding-top: add($input-padding-y-lg, $input-border-width);\\n  padding-bottom: add($input-padding-y-lg, $input-border-width);\\n  @include font-size($input-font-size-lg);\\n}\\n\\n.col-form-label-sm {\\n  padding-top: add($input-padding-y-sm, $input-border-width);\\n  padding-bottom: add($input-padding-y-sm, $input-border-width);\\n  @include font-size($input-font-size-sm);\\n}\\n\",\"//\\n// Form text\\n//\\n\\n.form-text {\\n  margin-top: $form-text-margin-top;\\n  @include font-size($form-text-font-size);\\n  font-style: $form-text-font-style;\\n  font-weight: $form-text-font-weight;\\n  color: $form-text-color;\\n}\\n\",\"//\\n// General form controls (plus a few specific high-level interventions)\\n//\\n\\n.form-control {\\n  display: block;\\n  width: 100%;\\n  padding: $input-padding-y $input-padding-x;\\n  font-family: $input-font-family;\\n  @include font-size($input-font-size);\\n  font-weight: $input-font-weight;\\n  line-height: $input-line-height;\\n  color: $input-color;\\n  background-color: $input-bg;\\n  background-clip: padding-box;\\n  border: $input-border-width solid $input-border-color;\\n  appearance: none; // Fix appearance for date inputs in Safari\\n\\n  // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.\\n  @include border-radius($input-border-radius, 0);\\n\\n  @include box-shadow($input-box-shadow);\\n  @include transition($input-transition);\\n\\n  &[type=\\\"file\\\"] {\\n    overflow: hidden; // prevent pseudo element button overlap\\n\\n    &:not(:disabled):not([readonly]) {\\n      cursor: pointer;\\n    }\\n  }\\n\\n  // Customize the `:focus` state to imitate native WebKit styles.\\n  &:focus {\\n    color: $input-focus-color;\\n    background-color: $input-focus-bg;\\n    border-color: $input-focus-border-color;\\n    outline: 0;\\n    @if $enable-shadows {\\n      @include box-shadow($input-box-shadow, $input-focus-box-shadow);\\n    } @else {\\n      // Avoid using mixin so we can pass custom focus shadow properly\\n      box-shadow: $input-focus-box-shadow;\\n    }\\n  }\\n\\n  // Add some height to date inputs on iOS\\n  // https://github.com/twbs/bootstrap/issues/23307\\n  // TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved\\n  &::-webkit-date-and-time-value {\\n    // Multiply line-height by 1em if it has no unit\\n    height: if(unit($input-line-height) == \\\"\\\", $input-line-height * 1em, $input-line-height);\\n  }\\n\\n  // Prevent excessive date input height in Webkit\\n  // https://github.com/twbs/bootstrap/issues/34433\\n  &::-webkit-datetime-edit {\\n    display: block;\\n    padding: 0;\\n  }\\n\\n  // Placeholder\\n  &::placeholder {\\n    color: $input-placeholder-color;\\n    // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.\\n    opacity: 1;\\n  }\\n\\n  // Disabled inputs\\n  //\\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\\n  // don't honor that edge case; we style them as disabled anyway.\\n  &:disabled {\\n    color: $input-disabled-color;\\n    background-color: $input-disabled-bg;\\n    border-color: $input-disabled-border-color;\\n    // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.\\n    opacity: 1;\\n  }\\n\\n  // File input buttons theming\\n  &::file-selector-button {\\n    padding: $input-padding-y $input-padding-x;\\n    margin: (-$input-padding-y) (-$input-padding-x);\\n    margin-inline-end: $input-padding-x;\\n    color: $form-file-button-color;\\n    @include gradient-bg($form-file-button-bg);\\n    pointer-events: none;\\n    border-color: inherit;\\n    border-style: solid;\\n    border-width: 0;\\n    border-inline-end-width: $input-border-width;\\n    border-radius: 0; // stylelint-disable-line property-disallowed-list\\n    @include transition($btn-transition);\\n  }\\n\\n  &:hover:not(:disabled):not([readonly])::file-selector-button {\\n    background-color: $form-file-button-hover-bg;\\n  }\\n}\\n\\n// Readonly controls as plain text\\n//\\n// Apply class to a readonly input to make it appear like regular plain\\n// text (without any border, background color, focus indicator)\\n\\n.form-control-plaintext {\\n  display: block;\\n  width: 100%;\\n  padding: $input-padding-y 0;\\n  margin-bottom: 0; // match inputs if this class comes on inputs with default margins\\n  line-height: $input-line-height;\\n  color: $input-plaintext-color;\\n  background-color: transparent;\\n  border: solid transparent;\\n  border-width: $input-border-width 0;\\n\\n  &:focus {\\n    outline: 0;\\n  }\\n\\n  &.form-control-sm,\\n  &.form-control-lg {\\n    padding-right: 0;\\n    padding-left: 0;\\n  }\\n}\\n\\n// Form control sizing\\n//\\n// Build on `.form-control` with modifier classes to decrease or increase the\\n// height and font-size of form controls.\\n//\\n// Repeated in `_input_group.scss` to avoid Sass extend issues.\\n\\n.form-control-sm {\\n  min-height: $input-height-sm;\\n  padding: $input-padding-y-sm $input-padding-x-sm;\\n  @include font-size($input-font-size-sm);\\n  @include border-radius($input-border-radius-sm);\\n\\n  &::file-selector-button {\\n    padding: $input-padding-y-sm $input-padding-x-sm;\\n    margin: (-$input-padding-y-sm) (-$input-padding-x-sm);\\n    margin-inline-end: $input-padding-x-sm;\\n  }\\n}\\n\\n.form-control-lg {\\n  min-height: $input-height-lg;\\n  padding: $input-padding-y-lg $input-padding-x-lg;\\n  @include font-size($input-font-size-lg);\\n  @include border-radius($input-border-radius-lg);\\n\\n  &::file-selector-button {\\n    padding: $input-padding-y-lg $input-padding-x-lg;\\n    margin: (-$input-padding-y-lg) (-$input-padding-x-lg);\\n    margin-inline-end: $input-padding-x-lg;\\n  }\\n}\\n\\n// Make sure textareas don't shrink too much when resized\\n// https://github.com/twbs/bootstrap/pull/29124\\n// stylelint-disable selector-no-qualifying-type\\ntextarea {\\n  &.form-control {\\n    min-height: $input-height;\\n  }\\n\\n  &.form-control-sm {\\n    min-height: $input-height-sm;\\n  }\\n\\n  &.form-control-lg {\\n    min-height: $input-height-lg;\\n  }\\n}\\n// stylelint-enable selector-no-qualifying-type\\n\\n.form-control-color {\\n  width: $form-color-width;\\n  height: $input-height;\\n  padding: $input-padding-y;\\n\\n  &:not(:disabled):not([readonly]) {\\n    cursor: pointer;\\n  }\\n\\n  &::-moz-color-swatch {\\n    border: 0 !important; // stylelint-disable-line declaration-no-important\\n    @include border-radius($input-border-radius);\\n  }\\n\\n  &::-webkit-color-swatch {\\n    @include border-radius($input-border-radius);\\n  }\\n\\n  &.form-control-sm { height: $input-height-sm; }\\n  &.form-control-lg { height: $input-height-lg; }\\n}\\n\",\"// stylelint-disable property-disallowed-list\\n@mixin transition($transition...) {\\n  @if length($transition) == 0 {\\n    $transition: $transition-base;\\n  }\\n\\n  @if length($transition) > 1 {\\n    @each $value in $transition {\\n      @if $value == null or $value == none {\\n        @warn \\\"The keyword 'none' or 'null' must be used as a single argument.\\\";\\n      }\\n    }\\n  }\\n\\n  @if $enable-transitions {\\n    @if nth($transition, 1) != null {\\n      transition: $transition;\\n    }\\n\\n    @if $enable-reduced-motion and nth($transition, 1) != null and nth($transition, 1) != none {\\n      @media (prefers-reduced-motion: reduce) {\\n        transition: none;\\n      }\\n    }\\n  }\\n}\\n\",\"// Gradients\\n\\n// scss-docs-start gradient-bg-mixin\\n@mixin gradient-bg($color: null) {\\n  background-color: $color;\\n\\n  @if $enable-gradients {\\n    background-image: var(--#{$prefix}gradient);\\n  }\\n}\\n// scss-docs-end gradient-bg-mixin\\n\\n// scss-docs-start gradient-mixins\\n// Horizontal gradient, from left to right\\n//\\n// Creates two color stops, start and end, by specifying a color and position for each color stop.\\n@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) {\\n  background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent);\\n}\\n\\n// Vertical gradient, from top to bottom\\n//\\n// Creates two color stops, start and end, by specifying a color and position for each color stop.\\n@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: null, $end-percent: null) {\\n  background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent);\\n}\\n\\n@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) {\\n  background-image: linear-gradient($deg, $start-color, $end-color);\\n}\\n\\n@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) {\\n  background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color);\\n}\\n\\n@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) {\\n  background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color);\\n}\\n\\n@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) {\\n  background-image: radial-gradient(circle, $inner-color, $outer-color);\\n}\\n\\n@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) {\\n  background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);\\n}\\n// scss-docs-end gradient-mixins\\n\",\"// Select\\n//\\n// Replaces the browser default select with a custom one, mostly pulled from\\n// https://primer.github.io/.\\n\\n.form-select {\\n  --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator)};\\n\\n  display: block;\\n  width: 100%;\\n  padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x;\\n  -moz-padding-start: subtract($form-select-padding-x, 3px); // See https://github.com/twbs/bootstrap/issues/32636\\n  font-family: $form-select-font-family;\\n  @include font-size($form-select-font-size);\\n  font-weight: $form-select-font-weight;\\n  line-height: $form-select-line-height;\\n  color: $form-select-color;\\n  background-color: $form-select-bg;\\n  background-image: var(--#{$prefix}form-select-bg-img), var(--#{$prefix}form-select-bg-icon, none);\\n  background-repeat: no-repeat;\\n  background-position: $form-select-bg-position;\\n  background-size: $form-select-bg-size;\\n  border: $form-select-border-width solid $form-select-border-color;\\n  @include border-radius($form-select-border-radius, 0);\\n  @include box-shadow($form-select-box-shadow);\\n  @include transition($form-select-transition);\\n  appearance: none;\\n\\n  &:focus {\\n    border-color: $form-select-focus-border-color;\\n    outline: 0;\\n    @if $enable-shadows {\\n      @include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow);\\n    } @else {\\n      // Avoid using mixin so we can pass custom focus shadow properly\\n      box-shadow: $form-select-focus-box-shadow;\\n    }\\n  }\\n\\n  &[multiple],\\n  &[size]:not([size=\\\"1\\\"]) {\\n    padding-right: $form-select-padding-x;\\n    background-image: none;\\n  }\\n\\n  &:disabled {\\n    color: $form-select-disabled-color;\\n    background-color: $form-select-disabled-bg;\\n    border-color: $form-select-disabled-border-color;\\n  }\\n\\n  // Remove outline from select box in FF\\n  &:-moz-focusring {\\n    color: transparent;\\n    text-shadow: 0 0 0 $form-select-color;\\n  }\\n}\\n\\n.form-select-sm {\\n  padding-top: $form-select-padding-y-sm;\\n  padding-bottom: $form-select-padding-y-sm;\\n  padding-left: $form-select-padding-x-sm;\\n  @include font-size($form-select-font-size-sm);\\n  @include border-radius($form-select-border-radius-sm);\\n}\\n\\n.form-select-lg {\\n  padding-top: $form-select-padding-y-lg;\\n  padding-bottom: $form-select-padding-y-lg;\\n  padding-left: $form-select-padding-x-lg;\\n  @include font-size($form-select-font-size-lg);\\n  @include border-radius($form-select-border-radius-lg);\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .form-select {\\n      --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)};\\n    }\\n  }\\n}\\n\",\"//\\n// Check/radio\\n//\\n\\n.form-check {\\n  display: block;\\n  min-height: $form-check-min-height;\\n  padding-left: $form-check-padding-start;\\n  margin-bottom: $form-check-margin-bottom;\\n\\n  .form-check-input {\\n    float: left;\\n    margin-left: $form-check-padding-start * -1;\\n  }\\n}\\n\\n.form-check-reverse {\\n  padding-right: $form-check-padding-start;\\n  padding-left: 0;\\n  text-align: right;\\n\\n  .form-check-input {\\n    float: right;\\n    margin-right: $form-check-padding-start * -1;\\n    margin-left: 0;\\n  }\\n}\\n\\n.form-check-input {\\n  --#{$prefix}form-check-bg: #{$form-check-input-bg};\\n\\n  width: $form-check-input-width;\\n  height: $form-check-input-width;\\n  margin-top: ($line-height-base - $form-check-input-width) * .5; // line-height minus check height\\n  vertical-align: top;\\n  background-color: var(--#{$prefix}form-check-bg);\\n  background-image: var(--#{$prefix}form-check-bg-image);\\n  background-repeat: no-repeat;\\n  background-position: center;\\n  background-size: contain;\\n  border: $form-check-input-border;\\n  appearance: none;\\n  print-color-adjust: exact; // Keep themed appearance for print\\n  @include transition($form-check-transition);\\n\\n  &[type=\\\"checkbox\\\"] {\\n    @include border-radius($form-check-input-border-radius);\\n  }\\n\\n  &[type=\\\"radio\\\"] {\\n    // stylelint-disable-next-line property-disallowed-list\\n    border-radius: $form-check-radio-border-radius;\\n  }\\n\\n  &:active {\\n    filter: $form-check-input-active-filter;\\n  }\\n\\n  &:focus {\\n    border-color: $form-check-input-focus-border;\\n    outline: 0;\\n    box-shadow: $form-check-input-focus-box-shadow;\\n  }\\n\\n  &:checked {\\n    background-color: $form-check-input-checked-bg-color;\\n    border-color: $form-check-input-checked-border-color;\\n\\n    &[type=\\\"checkbox\\\"] {\\n      @if $enable-gradients {\\n        --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)}, var(--#{$prefix}gradient);\\n      } @else {\\n        --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)};\\n      }\\n    }\\n\\n    &[type=\\\"radio\\\"] {\\n      @if $enable-gradients {\\n        --#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)}, var(--#{$prefix}gradient);\\n      } @else {\\n        --#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)};\\n      }\\n    }\\n  }\\n\\n  &[type=\\\"checkbox\\\"]:indeterminate {\\n    background-color: $form-check-input-indeterminate-bg-color;\\n    border-color: $form-check-input-indeterminate-border-color;\\n\\n    @if $enable-gradients {\\n      --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)}, var(--#{$prefix}gradient);\\n    } @else {\\n      --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)};\\n    }\\n  }\\n\\n  &:disabled {\\n    pointer-events: none;\\n    filter: none;\\n    opacity: $form-check-input-disabled-opacity;\\n  }\\n\\n  // Use disabled attribute in addition of :disabled pseudo-class\\n  // See: https://github.com/twbs/bootstrap/issues/28247\\n  &[disabled],\\n  &:disabled {\\n    ~ .form-check-label {\\n      cursor: default;\\n      opacity: $form-check-label-disabled-opacity;\\n    }\\n  }\\n}\\n\\n.form-check-label {\\n  color: $form-check-label-color;\\n  cursor: $form-check-label-cursor;\\n}\\n\\n//\\n// Switch\\n//\\n\\n.form-switch {\\n  padding-left: $form-switch-padding-start;\\n\\n  .form-check-input {\\n    --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image)};\\n\\n    width: $form-switch-width;\\n    margin-left: $form-switch-padding-start * -1;\\n    background-image: var(--#{$prefix}form-switch-bg);\\n    background-position: left center;\\n    @include border-radius($form-switch-border-radius);\\n    @include transition($form-switch-transition);\\n\\n    &:focus {\\n      --#{$prefix}form-switch-bg: #{escape-svg($form-switch-focus-bg-image)};\\n    }\\n\\n    &:checked {\\n      background-position: $form-switch-checked-bg-position;\\n\\n      @if $enable-gradients {\\n        --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)}, var(--#{$prefix}gradient);\\n      } @else {\\n        --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)};\\n      }\\n    }\\n  }\\n\\n  &.form-check-reverse {\\n    padding-right: $form-switch-padding-start;\\n    padding-left: 0;\\n\\n    .form-check-input {\\n      margin-right: $form-switch-padding-start * -1;\\n      margin-left: 0;\\n    }\\n  }\\n}\\n\\n.form-check-inline {\\n  display: inline-block;\\n  margin-right: $form-check-inline-margin-end;\\n}\\n\\n.btn-check {\\n  position: absolute;\\n  clip: rect(0, 0, 0, 0);\\n  pointer-events: none;\\n\\n  &[disabled],\\n  &:disabled {\\n    + .btn {\\n      pointer-events: none;\\n      filter: none;\\n      opacity: $form-check-btn-check-disabled-opacity;\\n    }\\n  }\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .form-switch .form-check-input:not(:checked):not(:focus) {\\n      --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image-dark)};\\n    }\\n  }\\n}\\n\",\"// Range\\n//\\n// Style range inputs the same across browsers. Vendor-specific rules for pseudo\\n// elements cannot be mixed. As such, there are no shared styles for focus or\\n// active states on prefixed selectors.\\n\\n.form-range {\\n  width: 100%;\\n  height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2);\\n  padding: 0; // Need to reset padding\\n  background-color: transparent;\\n  appearance: none;\\n\\n  &:focus {\\n    outline: 0;\\n\\n    // Pseudo-elements must be split across multiple rulesets to have an effect.\\n    // No box-shadow() mixin for focus accessibility.\\n    &::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }\\n    &::-moz-range-thumb     { box-shadow: $form-range-thumb-focus-box-shadow; }\\n  }\\n\\n  &::-moz-focus-outer {\\n    border: 0;\\n  }\\n\\n  &::-webkit-slider-thumb {\\n    width: $form-range-thumb-width;\\n    height: $form-range-thumb-height;\\n    margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific\\n    @include gradient-bg($form-range-thumb-bg);\\n    border: $form-range-thumb-border;\\n    @include border-radius($form-range-thumb-border-radius);\\n    @include box-shadow($form-range-thumb-box-shadow);\\n    @include transition($form-range-thumb-transition);\\n    appearance: none;\\n\\n    &:active {\\n      @include gradient-bg($form-range-thumb-active-bg);\\n    }\\n  }\\n\\n  &::-webkit-slider-runnable-track {\\n    width: $form-range-track-width;\\n    height: $form-range-track-height;\\n    color: transparent; // Why?\\n    cursor: $form-range-track-cursor;\\n    background-color: $form-range-track-bg;\\n    border-color: transparent;\\n    @include border-radius($form-range-track-border-radius);\\n    @include box-shadow($form-range-track-box-shadow);\\n  }\\n\\n  &::-moz-range-thumb {\\n    width: $form-range-thumb-width;\\n    height: $form-range-thumb-height;\\n    @include gradient-bg($form-range-thumb-bg);\\n    border: $form-range-thumb-border;\\n    @include border-radius($form-range-thumb-border-radius);\\n    @include box-shadow($form-range-thumb-box-shadow);\\n    @include transition($form-range-thumb-transition);\\n    appearance: none;\\n\\n    &:active {\\n      @include gradient-bg($form-range-thumb-active-bg);\\n    }\\n  }\\n\\n  &::-moz-range-track {\\n    width: $form-range-track-width;\\n    height: $form-range-track-height;\\n    color: transparent;\\n    cursor: $form-range-track-cursor;\\n    background-color: $form-range-track-bg;\\n    border-color: transparent; // Firefox specific?\\n    @include border-radius($form-range-track-border-radius);\\n    @include box-shadow($form-range-track-box-shadow);\\n  }\\n\\n  &:disabled {\\n    pointer-events: none;\\n\\n    &::-webkit-slider-thumb {\\n      background-color: $form-range-thumb-disabled-bg;\\n    }\\n\\n    &::-moz-range-thumb {\\n      background-color: $form-range-thumb-disabled-bg;\\n    }\\n  }\\n}\\n\",\".form-floating {\\n  position: relative;\\n\\n  &::before:not(.form-control:disabled) {\\n    position: absolute;\\n    top: $input-border-width;\\n    left: $input-border-width;\\n    width: subtract(100%, add($input-height-inner-quarter, $input-height-inner-half));\\n    height: $form-floating-label-height;\\n    content: \\\"\\\";\\n    background-color: $input-bg;\\n    @include border-radius($input-border-radius);\\n  }\\n\\n  > .form-control,\\n  > .form-control-plaintext,\\n  > .form-select {\\n    height: $form-floating-height;\\n    line-height: $form-floating-line-height;\\n  }\\n\\n  > label {\\n    position: absolute;\\n    top: 0;\\n    left: 0;\\n    width: 100%;\\n    height: 100%; // allow textareas\\n    padding: $form-floating-padding-y $form-floating-padding-x;\\n    overflow: hidden;\\n    text-align: start;\\n    text-overflow: ellipsis;\\n    white-space: nowrap;\\n    pointer-events: none;\\n    border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model\\n    transform-origin: 0 0;\\n    @include transition($form-floating-transition);\\n  }\\n\\n  > .form-control,\\n  > .form-control-plaintext {\\n    padding: $form-floating-padding-y $form-floating-padding-x;\\n\\n    &::placeholder {\\n      color: transparent;\\n    }\\n\\n    &:focus,\\n    &:not(:placeholder-shown) {\\n      padding-top: $form-floating-input-padding-t;\\n      padding-bottom: $form-floating-input-padding-b;\\n    }\\n    // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped\\n    &:-webkit-autofill {\\n      padding-top: $form-floating-input-padding-t;\\n      padding-bottom: $form-floating-input-padding-b;\\n    }\\n  }\\n\\n  > .form-select {\\n    padding-top: $form-floating-input-padding-t;\\n    padding-bottom: $form-floating-input-padding-b;\\n  }\\n\\n  > .form-control:focus,\\n  > .form-control:not(:placeholder-shown),\\n  > .form-control-plaintext,\\n  > .form-select {\\n    ~ label {\\n      opacity: $form-floating-label-opacity;\\n      transform: $form-floating-label-transform;\\n    }\\n  }\\n  // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped\\n  > .form-control:-webkit-autofill {\\n    ~ label {\\n      opacity: $form-floating-label-opacity;\\n      transform: $form-floating-label-transform;\\n    }\\n  }\\n\\n  > .form-control-plaintext {\\n    ~ label {\\n      border-width: $input-border-width 0; // Required to properly position label text - as explained above\\n    }\\n  }\\n\\n  > .form-control:disabled ~ label {\\n    color: $form-floating-label-disabled-color;\\n  }\\n}\\n\",\"//\\n// Base styles\\n//\\n\\n.input-group {\\n  position: relative;\\n  display: flex;\\n  flex-wrap: wrap; // For form validation feedback\\n  align-items: stretch;\\n  width: 100%;\\n\\n  > .form-control,\\n  > .form-select,\\n  > .form-floating {\\n    position: relative; // For focus state's z-index\\n    flex: 1 1 auto;\\n    width: 1%;\\n    min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size\\n  }\\n\\n  // Bring the \\\"active\\\" form control to the top of surrounding elements\\n  > .form-control:focus,\\n  > .form-select:focus,\\n  > .form-floating:focus-within {\\n    z-index: 5;\\n  }\\n\\n  // Ensure buttons are always above inputs for more visually pleasing borders.\\n  // This isn't needed for `.input-group-text` since it shares the same border-color\\n  // as our inputs.\\n  .btn {\\n    position: relative;\\n    z-index: 2;\\n\\n    &:focus {\\n      z-index: 5;\\n    }\\n  }\\n}\\n\\n\\n// Textual addons\\n//\\n// Serves as a catch-all element for any text or radio/checkbox input you wish\\n// to prepend or append to an input.\\n\\n.input-group-text {\\n  display: flex;\\n  align-items: center;\\n  padding: $input-group-addon-padding-y $input-group-addon-padding-x;\\n  @include font-size($input-font-size); // Match inputs\\n  font-weight: $input-group-addon-font-weight;\\n  line-height: $input-line-height;\\n  color: $input-group-addon-color;\\n  text-align: center;\\n  white-space: nowrap;\\n  background-color: $input-group-addon-bg;\\n  border: $input-border-width solid $input-group-addon-border-color;\\n  @include border-radius($input-border-radius);\\n}\\n\\n\\n// Sizing\\n//\\n// Remix the default form control sizing classes into new ones for easier\\n// manipulation.\\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: $input-padding-y-lg $input-padding-x-lg;\\n  @include font-size($input-font-size-lg);\\n  @include border-radius($input-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: $input-padding-y-sm $input-padding-x-sm;\\n  @include font-size($input-font-size-sm);\\n  @include border-radius($input-border-radius-sm);\\n}\\n\\n.input-group-lg > .form-select,\\n.input-group-sm > .form-select {\\n  padding-right: $form-select-padding-x + $form-select-indicator-padding;\\n}\\n\\n\\n// Rounded corners\\n//\\n// These rulesets must come after the sizing ones to properly override sm and lg\\n// border-radius values when extending. They're more specific than we'd like\\n// with the `.input-group >` part, but without it, we cannot override the sizing.\\n\\n// stylelint-disable-next-line no-duplicate-selectors\\n.input-group {\\n  &:not(.has-validation) {\\n    > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),\\n    > .dropdown-toggle:nth-last-child(n + 3),\\n    > .form-floating:not(:last-child) > .form-control,\\n    > .form-floating:not(:last-child) > .form-select {\\n      @include border-end-radius(0);\\n    }\\n  }\\n\\n  &.has-validation {\\n    > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),\\n    > .dropdown-toggle:nth-last-child(n + 4),\\n    > .form-floating:nth-last-child(n + 3) > .form-control,\\n    > .form-floating:nth-last-child(n + 3) > .form-select {\\n      @include border-end-radius(0);\\n    }\\n  }\\n\\n  $validation-messages: \\\"\\\";\\n  @each $state in map-keys($form-validation-states) {\\n    $validation-messages: $validation-messages + \\\":not(.\\\" + unquote($state) + \\\"-tooltip)\\\" + \\\":not(.\\\" + unquote($state) + \\\"-feedback)\\\";\\n  }\\n\\n  > :not(:first-child):not(.dropdown-menu)#{$validation-messages} {\\n    margin-left: calc($input-border-width * -1); // stylelint-disable-line function-disallowed-list\\n    @include border-start-radius(0);\\n  }\\n\\n  > .form-floating:not(:first-child) > .form-control,\\n  > .form-floating:not(:first-child) > .form-select {\\n    @include border-start-radius(0);\\n  }\\n}\\n\",\"// This mixin uses an `if()` technique to be compatible with Dart Sass\\n// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details\\n\\n// scss-docs-start form-validation-mixins\\n@mixin form-validation-state-selector($state) {\\n  @if ($state == \\\"valid\\\" or $state == \\\"invalid\\\") {\\n    .was-validated #{if(&, \\\"&\\\", \\\"\\\")}:#{$state},\\n    #{if(&, \\\"&\\\", \\\"\\\")}.is-#{$state} {\\n      @content;\\n    }\\n  } @else {\\n    #{if(&, \\\"&\\\", \\\"\\\")}.is-#{$state} {\\n      @content;\\n    }\\n  }\\n}\\n\\n@mixin form-validation-state(\\n  $state,\\n  $color,\\n  $icon,\\n  $tooltip-color: color-contrast($color),\\n  $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),\\n  $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity),\\n  $border-color: $color\\n) {\\n  .#{$state}-feedback {\\n    display: none;\\n    width: 100%;\\n    margin-top: $form-feedback-margin-top;\\n    @include font-size($form-feedback-font-size);\\n    font-style: $form-feedback-font-style;\\n    color: $color;\\n  }\\n\\n  .#{$state}-tooltip {\\n    position: absolute;\\n    top: 100%;\\n    z-index: 5;\\n    display: none;\\n    max-width: 100%; // Contain to parent when possible\\n    padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x;\\n    margin-top: .1rem;\\n    @include font-size($form-feedback-tooltip-font-size);\\n    line-height: $form-feedback-tooltip-line-height;\\n    color: $tooltip-color;\\n    background-color: $tooltip-bg-color;\\n    @include border-radius($form-feedback-tooltip-border-radius);\\n  }\\n\\n  @include form-validation-state-selector($state) {\\n    ~ .#{$state}-feedback,\\n    ~ .#{$state}-tooltip {\\n      display: block;\\n    }\\n  }\\n\\n  .form-control {\\n    @include form-validation-state-selector($state) {\\n      border-color: $border-color;\\n\\n      @if $enable-validation-icons {\\n        padding-right: $input-height-inner;\\n        background-image: escape-svg($icon);\\n        background-repeat: no-repeat;\\n        background-position: right $input-height-inner-quarter center;\\n        background-size: $input-height-inner-half $input-height-inner-half;\\n      }\\n\\n      &:focus {\\n        border-color: $border-color;\\n        box-shadow: $focus-box-shadow;\\n      }\\n    }\\n  }\\n\\n  // stylelint-disable-next-line selector-no-qualifying-type\\n  textarea.form-control {\\n    @include form-validation-state-selector($state) {\\n      @if $enable-validation-icons {\\n        padding-right: $input-height-inner;\\n        background-position: top $input-height-inner-quarter right $input-height-inner-quarter;\\n      }\\n    }\\n  }\\n\\n  .form-select {\\n    @include form-validation-state-selector($state) {\\n      border-color: $border-color;\\n\\n      @if $enable-validation-icons {\\n        &:not([multiple]):not([size]),\\n        &:not([multiple])[size=\\\"1\\\"] {\\n          --#{$prefix}form-select-bg-icon: #{escape-svg($icon)};\\n          padding-right: $form-select-feedback-icon-padding-end;\\n          background-position: $form-select-bg-position, $form-select-feedback-icon-position;\\n          background-size: $form-select-bg-size, $form-select-feedback-icon-size;\\n        }\\n      }\\n\\n      &:focus {\\n        border-color: $border-color;\\n        box-shadow: $focus-box-shadow;\\n      }\\n    }\\n  }\\n\\n  .form-control-color {\\n    @include form-validation-state-selector($state) {\\n      @if $enable-validation-icons {\\n        width: add($form-color-width, $input-height-inner);\\n      }\\n    }\\n  }\\n\\n  .form-check-input {\\n    @include form-validation-state-selector($state) {\\n      border-color: $border-color;\\n\\n      &:checked {\\n        background-color: $color;\\n      }\\n\\n      &:focus {\\n        box-shadow: $focus-box-shadow;\\n      }\\n\\n      ~ .form-check-label {\\n        color: $color;\\n      }\\n    }\\n  }\\n  .form-check-inline .form-check-input {\\n    ~ .#{$state}-feedback {\\n      margin-left: .5em;\\n    }\\n  }\\n\\n  .input-group {\\n    > .form-control:not(:focus),\\n    > .form-select:not(:focus),\\n    > .form-floating:not(:focus-within) {\\n      @include form-validation-state-selector($state) {\\n        @if $state == \\\"valid\\\" {\\n          z-index: 3;\\n        } @else if $state == \\\"invalid\\\" {\\n          z-index: 4;\\n        }\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end form-validation-mixins\\n\",\"//\\n// Base styles\\n//\\n\\n.btn {\\n  // scss-docs-start btn-css-vars\\n  --#{$prefix}btn-padding-x: #{$btn-padding-x};\\n  --#{$prefix}btn-padding-y: #{$btn-padding-y};\\n  --#{$prefix}btn-font-family: #{$btn-font-family};\\n  @include rfs($btn-font-size, --#{$prefix}btn-font-size);\\n  --#{$prefix}btn-font-weight: #{$btn-font-weight};\\n  --#{$prefix}btn-line-height: #{$btn-line-height};\\n  --#{$prefix}btn-color: #{$body-color};\\n  --#{$prefix}btn-bg: transparent;\\n  --#{$prefix}btn-border-width: #{$btn-border-width};\\n  --#{$prefix}btn-border-color: transparent;\\n  --#{$prefix}btn-border-radius: #{$btn-border-radius};\\n  --#{$prefix}btn-hover-border-color: transparent;\\n  --#{$prefix}btn-box-shadow: #{$btn-box-shadow};\\n  --#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity};\\n  --#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5);\\n  // scss-docs-end btn-css-vars\\n\\n  display: inline-block;\\n  padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x);\\n  font-family: var(--#{$prefix}btn-font-family);\\n  @include font-size(var(--#{$prefix}btn-font-size));\\n  font-weight: var(--#{$prefix}btn-font-weight);\\n  line-height: var(--#{$prefix}btn-line-height);\\n  color: var(--#{$prefix}btn-color);\\n  text-align: center;\\n  text-decoration: if($link-decoration == none, null, none);\\n  white-space: $btn-white-space;\\n  vertical-align: middle;\\n  cursor: if($enable-button-pointers, pointer, null);\\n  user-select: none;\\n  border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color);\\n  @include border-radius(var(--#{$prefix}btn-border-radius));\\n  @include gradient-bg(var(--#{$prefix}btn-bg));\\n  @include box-shadow(var(--#{$prefix}btn-box-shadow));\\n  @include transition($btn-transition);\\n\\n  &:hover {\\n    color: var(--#{$prefix}btn-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n    background-color: var(--#{$prefix}btn-hover-bg);\\n    border-color: var(--#{$prefix}btn-hover-border-color);\\n  }\\n\\n  .btn-check + &:hover {\\n    // override for the checkbox/radio buttons\\n    color: var(--#{$prefix}btn-color);\\n    background-color: var(--#{$prefix}btn-bg);\\n    border-color: var(--#{$prefix}btn-border-color);\\n  }\\n\\n  &:focus-visible {\\n    color: var(--#{$prefix}btn-hover-color);\\n    @include gradient-bg(var(--#{$prefix}btn-hover-bg));\\n    border-color: var(--#{$prefix}btn-hover-border-color);\\n    outline: 0;\\n    // Avoid using mixin so we can pass custom focus shadow properly\\n    @if $enable-shadows {\\n      box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);\\n    } @else {\\n      box-shadow: var(--#{$prefix}btn-focus-box-shadow);\\n    }\\n  }\\n\\n  .btn-check:focus-visible + & {\\n    border-color: var(--#{$prefix}btn-hover-border-color);\\n    outline: 0;\\n    // Avoid using mixin so we can pass custom focus shadow properly\\n    @if $enable-shadows {\\n      box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);\\n    } @else {\\n      box-shadow: var(--#{$prefix}btn-focus-box-shadow);\\n    }\\n  }\\n\\n  .btn-check:checked + &,\\n  :not(.btn-check) + &:active,\\n  &:first-child:active,\\n  &.active,\\n  &.show {\\n    color: var(--#{$prefix}btn-active-color);\\n    background-color: var(--#{$prefix}btn-active-bg);\\n    // Remove CSS gradients if they're enabled\\n    background-image: if($enable-gradients, none, null);\\n    border-color: var(--#{$prefix}btn-active-border-color);\\n    @include box-shadow(var(--#{$prefix}btn-active-shadow));\\n\\n    &:focus-visible {\\n      // Avoid using mixin so we can pass custom focus shadow properly\\n      @if $enable-shadows {\\n        box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow);\\n      } @else {\\n        box-shadow: var(--#{$prefix}btn-focus-box-shadow);\\n      }\\n    }\\n  }\\n\\n  &:disabled,\\n  &.disabled,\\n  fieldset:disabled & {\\n    color: var(--#{$prefix}btn-disabled-color);\\n    pointer-events: none;\\n    background-color: var(--#{$prefix}btn-disabled-bg);\\n    background-image: if($enable-gradients, none, null);\\n    border-color: var(--#{$prefix}btn-disabled-border-color);\\n    opacity: var(--#{$prefix}btn-disabled-opacity);\\n    @include box-shadow(none);\\n  }\\n}\\n\\n\\n//\\n// Alternate buttons\\n//\\n\\n// scss-docs-start btn-variant-loops\\n@each $color, $value in $theme-colors {\\n  .btn-#{$color} {\\n    @if $color == \\\"light\\\" {\\n      @include button-variant(\\n        $value,\\n        $value,\\n        $hover-background: shade-color($value, $btn-hover-bg-shade-amount),\\n        $hover-border: shade-color($value, $btn-hover-border-shade-amount),\\n        $active-background: shade-color($value, $btn-active-bg-shade-amount),\\n        $active-border: shade-color($value, $btn-active-border-shade-amount)\\n      );\\n    } @else if $color == \\\"dark\\\" {\\n      @include button-variant(\\n        $value,\\n        $value,\\n        $hover-background: tint-color($value, $btn-hover-bg-tint-amount),\\n        $hover-border: tint-color($value, $btn-hover-border-tint-amount),\\n        $active-background: tint-color($value, $btn-active-bg-tint-amount),\\n        $active-border: tint-color($value, $btn-active-border-tint-amount)\\n      );\\n    } @else {\\n      @include button-variant($value, $value);\\n    }\\n  }\\n}\\n\\n@each $color, $value in $theme-colors {\\n  .btn-outline-#{$color} {\\n    @include button-outline-variant($value);\\n  }\\n}\\n// scss-docs-end btn-variant-loops\\n\\n\\n//\\n// Link buttons\\n//\\n\\n// Make a button look and behave like a link\\n.btn-link {\\n  --#{$prefix}btn-font-weight: #{$font-weight-normal};\\n  --#{$prefix}btn-color: #{$btn-link-color};\\n  --#{$prefix}btn-bg: transparent;\\n  --#{$prefix}btn-border-color: transparent;\\n  --#{$prefix}btn-hover-color: #{$btn-link-hover-color};\\n  --#{$prefix}btn-hover-border-color: transparent;\\n  --#{$prefix}btn-active-color: #{$btn-link-hover-color};\\n  --#{$prefix}btn-active-border-color: transparent;\\n  --#{$prefix}btn-disabled-color: #{$btn-link-disabled-color};\\n  --#{$prefix}btn-disabled-border-color: transparent;\\n  --#{$prefix}btn-box-shadow: none;\\n  --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix(color-contrast($primary), $primary, 15%))};\\n\\n  text-decoration: $link-decoration;\\n  @if $enable-gradients {\\n    background-image: none;\\n  }\\n\\n  &:hover,\\n  &:focus-visible {\\n    text-decoration: $link-hover-decoration;\\n  }\\n\\n  &:focus-visible {\\n    color: var(--#{$prefix}btn-color);\\n  }\\n\\n  &:hover {\\n    color: var(--#{$prefix}btn-hover-color);\\n  }\\n\\n  // No need for an active state here\\n}\\n\\n\\n//\\n// Button Sizes\\n//\\n\\n.btn-lg {\\n  @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg);\\n}\\n\\n.btn-sm {\\n  @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm);\\n}\\n\",\"// Button variants\\n//\\n// Easily pump out default styles, as well as :hover, :focus, :active,\\n// and disabled options for all buttons\\n\\n// scss-docs-start btn-variant-mixin\\n@mixin button-variant(\\n  $background,\\n  $border,\\n  $color: color-contrast($background),\\n  $hover-background: if($color == $color-contrast-light, shade-color($background, $btn-hover-bg-shade-amount), tint-color($background, $btn-hover-bg-tint-amount)),\\n  $hover-border: if($color == $color-contrast-light, shade-color($border, $btn-hover-border-shade-amount), tint-color($border, $btn-hover-border-tint-amount)),\\n  $hover-color: color-contrast($hover-background),\\n  $active-background: if($color == $color-contrast-light, shade-color($background, $btn-active-bg-shade-amount), tint-color($background, $btn-active-bg-tint-amount)),\\n  $active-border: if($color == $color-contrast-light, shade-color($border, $btn-active-border-shade-amount), tint-color($border, $btn-active-border-tint-amount)),\\n  $active-color: color-contrast($active-background),\\n  $disabled-background: $background,\\n  $disabled-border: $border,\\n  $disabled-color: color-contrast($disabled-background)\\n) {\\n  --#{$prefix}btn-color: #{$color};\\n  --#{$prefix}btn-bg: #{$background};\\n  --#{$prefix}btn-border-color: #{$border};\\n  --#{$prefix}btn-hover-color: #{$hover-color};\\n  --#{$prefix}btn-hover-bg: #{$hover-background};\\n  --#{$prefix}btn-hover-border-color: #{$hover-border};\\n  --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix($color, $border, 15%))};\\n  --#{$prefix}btn-active-color: #{$active-color};\\n  --#{$prefix}btn-active-bg: #{$active-background};\\n  --#{$prefix}btn-active-border-color: #{$active-border};\\n  --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow};\\n  --#{$prefix}btn-disabled-color: #{$disabled-color};\\n  --#{$prefix}btn-disabled-bg: #{$disabled-background};\\n  --#{$prefix}btn-disabled-border-color: #{$disabled-border};\\n}\\n// scss-docs-end btn-variant-mixin\\n\\n// scss-docs-start btn-outline-variant-mixin\\n@mixin button-outline-variant(\\n  $color,\\n  $color-hover: color-contrast($color),\\n  $active-background: $color,\\n  $active-border: $color,\\n  $active-color: color-contrast($active-background)\\n) {\\n  --#{$prefix}btn-color: #{$color};\\n  --#{$prefix}btn-border-color: #{$color};\\n  --#{$prefix}btn-hover-color: #{$color-hover};\\n  --#{$prefix}btn-hover-bg: #{$active-background};\\n  --#{$prefix}btn-hover-border-color: #{$active-border};\\n  --#{$prefix}btn-focus-shadow-rgb: #{to-rgb($color)};\\n  --#{$prefix}btn-active-color: #{$active-color};\\n  --#{$prefix}btn-active-bg: #{$active-background};\\n  --#{$prefix}btn-active-border-color: #{$active-border};\\n  --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow};\\n  --#{$prefix}btn-disabled-color: #{$color};\\n  --#{$prefix}btn-disabled-bg: transparent;\\n  --#{$prefix}btn-disabled-border-color: #{$color};\\n  --#{$prefix}gradient: none;\\n}\\n// scss-docs-end btn-outline-variant-mixin\\n\\n// scss-docs-start btn-size-mixin\\n@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) {\\n  --#{$prefix}btn-padding-y: #{$padding-y};\\n  --#{$prefix}btn-padding-x: #{$padding-x};\\n  @include rfs($font-size, --#{$prefix}btn-font-size);\\n  --#{$prefix}btn-border-radius: #{$border-radius};\\n}\\n// scss-docs-end btn-size-mixin\\n\",\".fade {\\n  @include transition($transition-fade);\\n\\n  &:not(.show) {\\n    opacity: 0;\\n  }\\n}\\n\\n// scss-docs-start collapse-classes\\n.collapse {\\n  &:not(.show) {\\n    display: none;\\n  }\\n}\\n\\n.collapsing {\\n  height: 0;\\n  overflow: hidden;\\n  @include transition($transition-collapse);\\n\\n  &.collapse-horizontal {\\n    width: 0;\\n    height: auto;\\n    @include transition($transition-collapse-width);\\n  }\\n}\\n// scss-docs-end collapse-classes\\n\",\"// The dropdown wrapper (`<div>`)\\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  // Generate the caret automatically\\n  @include caret();\\n}\\n\\n// The dropdown menu\\n.dropdown-menu {\\n  // scss-docs-start dropdown-css-vars\\n  --#{$prefix}dropdown-zindex: #{$zindex-dropdown};\\n  --#{$prefix}dropdown-min-width: #{$dropdown-min-width};\\n  --#{$prefix}dropdown-padding-x: #{$dropdown-padding-x};\\n  --#{$prefix}dropdown-padding-y: #{$dropdown-padding-y};\\n  --#{$prefix}dropdown-spacer: #{$dropdown-spacer};\\n  @include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size);\\n  --#{$prefix}dropdown-color: #{$dropdown-color};\\n  --#{$prefix}dropdown-bg: #{$dropdown-bg};\\n  --#{$prefix}dropdown-border-color: #{$dropdown-border-color};\\n  --#{$prefix}dropdown-border-radius: #{$dropdown-border-radius};\\n  --#{$prefix}dropdown-border-width: #{$dropdown-border-width};\\n  --#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius};\\n  --#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg};\\n  --#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y};\\n  --#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow};\\n  --#{$prefix}dropdown-link-color: #{$dropdown-link-color};\\n  --#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color};\\n  --#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg};\\n  --#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color};\\n  --#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg};\\n  --#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color};\\n  --#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x};\\n  --#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y};\\n  --#{$prefix}dropdown-header-color: #{$dropdown-header-color};\\n  --#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x};\\n  --#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y};\\n  // scss-docs-end dropdown-css-vars\\n\\n  position: absolute;\\n  z-index: var(--#{$prefix}dropdown-zindex);\\n  display: none; // none by default, but block on \\\"open\\\" of the menu\\n  min-width: var(--#{$prefix}dropdown-min-width);\\n  padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x);\\n  margin: 0; // Override default margin of ul\\n  @include font-size(var(--#{$prefix}dropdown-font-size));\\n  color: var(--#{$prefix}dropdown-color);\\n  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\\n  list-style: none;\\n  background-color: var(--#{$prefix}dropdown-bg);\\n  background-clip: padding-box;\\n  border: var(--#{$prefix}dropdown-border-width) solid var(--#{$prefix}dropdown-border-color);\\n  @include border-radius(var(--#{$prefix}dropdown-border-radius));\\n  @include box-shadow(var(--#{$prefix}dropdown-box-shadow));\\n\\n  &[data-bs-popper] {\\n    top: 100%;\\n    left: 0;\\n    margin-top: var(--#{$prefix}dropdown-spacer);\\n  }\\n\\n  @if $dropdown-padding-y == 0 {\\n    > .dropdown-item:first-child,\\n    > li:first-child .dropdown-item {\\n      @include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius));\\n    }\\n    > .dropdown-item:last-child,\\n    > li:last-child .dropdown-item {\\n      @include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius));\\n    }\\n\\n  }\\n}\\n\\n// scss-docs-start responsive-breakpoints\\n// We deliberately hardcode the `bs-` prefix because we check\\n// this custom property in JS to determine Popper's positioning\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  @include media-breakpoint-up($breakpoint) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    .dropdown-menu#{$infix}-start {\\n      --bs-position: start;\\n\\n      &[data-bs-popper] {\\n        right: auto;\\n        left: 0;\\n      }\\n    }\\n\\n    .dropdown-menu#{$infix}-end {\\n      --bs-position: end;\\n\\n      &[data-bs-popper] {\\n        right: 0;\\n        left: auto;\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end responsive-breakpoints\\n\\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\\n// Just add .dropup after the standard .dropdown class and you're set.\\n.dropup {\\n  .dropdown-menu[data-bs-popper] {\\n    top: auto;\\n    bottom: 100%;\\n    margin-top: 0;\\n    margin-bottom: var(--#{$prefix}dropdown-spacer);\\n  }\\n\\n  .dropdown-toggle {\\n    @include caret(up);\\n  }\\n}\\n\\n.dropend {\\n  .dropdown-menu[data-bs-popper] {\\n    top: 0;\\n    right: auto;\\n    left: 100%;\\n    margin-top: 0;\\n    margin-left: var(--#{$prefix}dropdown-spacer);\\n  }\\n\\n  .dropdown-toggle {\\n    @include caret(end);\\n    &::after {\\n      vertical-align: 0;\\n    }\\n  }\\n}\\n\\n.dropstart {\\n  .dropdown-menu[data-bs-popper] {\\n    top: 0;\\n    right: 100%;\\n    left: auto;\\n    margin-top: 0;\\n    margin-right: var(--#{$prefix}dropdown-spacer);\\n  }\\n\\n  .dropdown-toggle {\\n    @include caret(start);\\n    &::before {\\n      vertical-align: 0;\\n    }\\n  }\\n}\\n\\n\\n// Dividers (basically an `<hr>`) within the dropdown\\n.dropdown-divider {\\n  height: 0;\\n  margin: var(--#{$prefix}dropdown-divider-margin-y) 0;\\n  overflow: hidden;\\n  border-top: 1px solid var(--#{$prefix}dropdown-divider-bg);\\n  opacity: 1; // Revisit in v6 to de-dupe styles that conflict with <hr> element\\n}\\n\\n// Links, buttons, and more within the dropdown menu\\n//\\n// `<button>`-specific styles are denoted with `// For <button>s`\\n.dropdown-item {\\n  display: block;\\n  width: 100%; // For `<button>`s\\n  padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);\\n  clear: both;\\n  font-weight: $font-weight-normal;\\n  color: var(--#{$prefix}dropdown-link-color);\\n  text-align: inherit; // For `<button>`s\\n  text-decoration: if($link-decoration == none, null, none);\\n  white-space: nowrap; // prevent links from randomly breaking onto new lines\\n  background-color: transparent; // For `<button>`s\\n  border: 0; // For `<button>`s\\n  @include border-radius(var(--#{$prefix}dropdown-item-border-radius, 0));\\n\\n  &:hover,\\n  &:focus {\\n    color: var(--#{$prefix}dropdown-link-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n    @include gradient-bg(var(--#{$prefix}dropdown-link-hover-bg));\\n  }\\n\\n  &.active,\\n  &:active {\\n    color: var(--#{$prefix}dropdown-link-active-color);\\n    text-decoration: none;\\n    @include gradient-bg(var(--#{$prefix}dropdown-link-active-bg));\\n  }\\n\\n  &.disabled,\\n  &:disabled {\\n    color: var(--#{$prefix}dropdown-link-disabled-color);\\n    pointer-events: none;\\n    background-color: transparent;\\n    // Remove CSS gradients if they're enabled\\n    background-image: if($enable-gradients, none, null);\\n  }\\n}\\n\\n.dropdown-menu.show {\\n  display: block;\\n}\\n\\n// Dropdown section headers\\n.dropdown-header {\\n  display: block;\\n  padding: var(--#{$prefix}dropdown-header-padding-y) var(--#{$prefix}dropdown-header-padding-x);\\n  margin-bottom: 0; // for use with heading elements\\n  @include font-size($font-size-sm);\\n  color: var(--#{$prefix}dropdown-header-color);\\n  white-space: nowrap; // as with > li > a\\n}\\n\\n// Dropdown text\\n.dropdown-item-text {\\n  display: block;\\n  padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);\\n  color: var(--#{$prefix}dropdown-link-color);\\n}\\n\\n// Dark dropdowns\\n.dropdown-menu-dark {\\n  // scss-docs-start dropdown-dark-css-vars\\n  --#{$prefix}dropdown-color: #{$dropdown-dark-color};\\n  --#{$prefix}dropdown-bg: #{$dropdown-dark-bg};\\n  --#{$prefix}dropdown-border-color: #{$dropdown-dark-border-color};\\n  --#{$prefix}dropdown-box-shadow: #{$dropdown-dark-box-shadow};\\n  --#{$prefix}dropdown-link-color: #{$dropdown-dark-link-color};\\n  --#{$prefix}dropdown-link-hover-color: #{$dropdown-dark-link-hover-color};\\n  --#{$prefix}dropdown-divider-bg: #{$dropdown-dark-divider-bg};\\n  --#{$prefix}dropdown-link-hover-bg: #{$dropdown-dark-link-hover-bg};\\n  --#{$prefix}dropdown-link-active-color: #{$dropdown-dark-link-active-color};\\n  --#{$prefix}dropdown-link-active-bg: #{$dropdown-dark-link-active-bg};\\n  --#{$prefix}dropdown-link-disabled-color: #{$dropdown-dark-link-disabled-color};\\n  --#{$prefix}dropdown-header-color: #{$dropdown-dark-header-color};\\n  // scss-docs-end dropdown-dark-css-vars\\n}\\n\",\"// scss-docs-start caret-mixins\\n@mixin caret-down($width: $caret-width) {\\n  border-top: $width solid;\\n  border-right: $width solid transparent;\\n  border-bottom: 0;\\n  border-left: $width solid transparent;\\n}\\n\\n@mixin caret-up($width: $caret-width) {\\n  border-top: 0;\\n  border-right: $width solid transparent;\\n  border-bottom: $width solid;\\n  border-left: $width solid transparent;\\n}\\n\\n@mixin caret-end($width: $caret-width) {\\n  border-top: $width solid transparent;\\n  border-right: 0;\\n  border-bottom: $width solid transparent;\\n  border-left: $width solid;\\n}\\n\\n@mixin caret-start($width: $caret-width) {\\n  border-top: $width solid transparent;\\n  border-right: $width solid;\\n  border-bottom: $width solid transparent;\\n}\\n\\n@mixin caret(\\n  $direction: down,\\n  $width: $caret-width,\\n  $spacing: $caret-spacing,\\n  $vertical-align: $caret-vertical-align\\n) {\\n  @if $enable-caret {\\n    &::after {\\n      display: inline-block;\\n      margin-left: $spacing;\\n      vertical-align: $vertical-align;\\n      content: \\\"\\\";\\n      @if $direction == down {\\n        @include caret-down($width);\\n      } @else if $direction == up {\\n        @include caret-up($width);\\n      } @else if $direction == end {\\n        @include caret-end($width);\\n      }\\n    }\\n\\n    @if $direction == start {\\n      &::after {\\n        display: none;\\n      }\\n\\n      &::before {\\n        display: inline-block;\\n        margin-right: $spacing;\\n        vertical-align: $vertical-align;\\n        content: \\\"\\\";\\n        @include caret-start($width);\\n      }\\n    }\\n\\n    &:empty::after {\\n      margin-left: 0;\\n    }\\n  }\\n}\\n// scss-docs-end caret-mixins\\n\",\"// Make the div behave like a button\\n.btn-group,\\n.btn-group-vertical {\\n  position: relative;\\n  display: inline-flex;\\n  vertical-align: middle; // match .btn alignment given font-size hack above\\n\\n  > .btn {\\n    position: relative;\\n    flex: 1 1 auto;\\n  }\\n\\n  // Bring the hover, focused, and \\\"active\\\" buttons to the front to overlay\\n  // the borders properly\\n  > .btn-check:checked + .btn,\\n  > .btn-check:focus + .btn,\\n  > .btn:hover,\\n  > .btn:focus,\\n  > .btn:active,\\n  > .btn.active {\\n    z-index: 1;\\n  }\\n}\\n\\n// Optional: Group multiple button groups together for a toolbar\\n.btn-toolbar {\\n  display: flex;\\n  flex-wrap: wrap;\\n  justify-content: flex-start;\\n\\n  .input-group {\\n    width: auto;\\n  }\\n}\\n\\n.btn-group {\\n  @include border-radius($btn-border-radius);\\n\\n  // Prevent double borders when buttons are next to each other\\n  > :not(.btn-check:first-child) + .btn,\\n  > .btn-group:not(:first-child) {\\n    margin-left: calc($btn-border-width * -1); // stylelint-disable-line function-disallowed-list\\n  }\\n\\n  // Reset rounded corners\\n  > .btn:not(:last-child):not(.dropdown-toggle),\\n  > .btn.dropdown-toggle-split:first-child,\\n  > .btn-group:not(:last-child) > .btn {\\n    @include border-end-radius(0);\\n  }\\n\\n  // The left radius should be 0 if the button is:\\n  // - the \\\"third or more\\\" child\\n  // - the second child and the previous element isn't `.btn-check` (making it the first child visually)\\n  // - part of a btn-group which isn't the first child\\n  > .btn:nth-child(n + 3),\\n  > :not(.btn-check) + .btn,\\n  > .btn-group:not(:first-child) > .btn {\\n    @include border-start-radius(0);\\n  }\\n}\\n\\n// Sizing\\n//\\n// Remix the default button sizing classes into new ones for easier manipulation.\\n\\n.btn-group-sm > .btn { @extend .btn-sm; }\\n.btn-group-lg > .btn { @extend .btn-lg; }\\n\\n\\n//\\n// Split button dropdowns\\n//\\n\\n.dropdown-toggle-split {\\n  padding-right: $btn-padding-x * .75;\\n  padding-left: $btn-padding-x * .75;\\n\\n  &::after,\\n  .dropup &::after,\\n  .dropend &::after {\\n    margin-left: 0;\\n  }\\n\\n  .dropstart &::before {\\n    margin-right: 0;\\n  }\\n}\\n\\n.btn-sm + .dropdown-toggle-split {\\n  padding-right: $btn-padding-x-sm * .75;\\n  padding-left: $btn-padding-x-sm * .75;\\n}\\n\\n.btn-lg + .dropdown-toggle-split {\\n  padding-right: $btn-padding-x-lg * .75;\\n  padding-left: $btn-padding-x-lg * .75;\\n}\\n\\n\\n// The clickable button for toggling the menu\\n// Set the same inset shadow as the :active state\\n.btn-group.show .dropdown-toggle {\\n  @include box-shadow($btn-active-box-shadow);\\n\\n  // Show no shadow for `.btn-link` since it has no other button styles.\\n  &.btn-link {\\n    @include box-shadow(none);\\n  }\\n}\\n\\n\\n//\\n// Vertical button groups\\n//\\n\\n.btn-group-vertical {\\n  flex-direction: column;\\n  align-items: flex-start;\\n  justify-content: center;\\n\\n  > .btn,\\n  > .btn-group {\\n    width: 100%;\\n  }\\n\\n  > .btn:not(:first-child),\\n  > .btn-group:not(:first-child) {\\n    margin-top: calc($btn-border-width * -1); // stylelint-disable-line function-disallowed-list\\n  }\\n\\n  // Reset rounded corners\\n  > .btn:not(:last-child):not(.dropdown-toggle),\\n  > .btn-group:not(:last-child) > .btn {\\n    @include border-bottom-radius(0);\\n  }\\n\\n  > .btn ~ .btn,\\n  > .btn-group:not(:first-child) > .btn {\\n    @include border-top-radius(0);\\n  }\\n}\\n\",\"// Base class\\n//\\n// Kickstart any navigation component with a set of style resets. Works with\\n// `<nav>`s, `<ul>`s or `<ol>`s.\\n\\n.nav {\\n  // scss-docs-start nav-css-vars\\n  --#{$prefix}nav-link-padding-x: #{$nav-link-padding-x};\\n  --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};\\n  @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);\\n  --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};\\n  --#{$prefix}nav-link-color: #{$nav-link-color};\\n  --#{$prefix}nav-link-hover-color: #{$nav-link-hover-color};\\n  --#{$prefix}nav-link-disabled-color: #{$nav-link-disabled-color};\\n  // scss-docs-end nav-css-vars\\n\\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(--#{$prefix}nav-link-padding-y) var(--#{$prefix}nav-link-padding-x);\\n  @include font-size(var(--#{$prefix}nav-link-font-size));\\n  font-weight: var(--#{$prefix}nav-link-font-weight);\\n  color: var(--#{$prefix}nav-link-color);\\n  text-decoration: if($link-decoration == none, null, none);\\n  @include transition($nav-link-transition);\\n\\n  &:hover,\\n  &:focus {\\n    color: var(--#{$prefix}nav-link-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n  }\\n\\n  // Disabled state lightens text\\n  &.disabled {\\n    color: var(--#{$prefix}nav-link-disabled-color);\\n    pointer-events: none;\\n    cursor: default;\\n  }\\n}\\n\\n//\\n// Tabs\\n//\\n\\n.nav-tabs {\\n  // scss-docs-start nav-tabs-css-vars\\n  --#{$prefix}nav-tabs-border-width: #{$nav-tabs-border-width};\\n  --#{$prefix}nav-tabs-border-color: #{$nav-tabs-border-color};\\n  --#{$prefix}nav-tabs-border-radius: #{$nav-tabs-border-radius};\\n  --#{$prefix}nav-tabs-link-hover-border-color: #{$nav-tabs-link-hover-border-color};\\n  --#{$prefix}nav-tabs-link-active-color: #{$nav-tabs-link-active-color};\\n  --#{$prefix}nav-tabs-link-active-bg: #{$nav-tabs-link-active-bg};\\n  --#{$prefix}nav-tabs-link-active-border-color: #{$nav-tabs-link-active-border-color};\\n  // scss-docs-end nav-tabs-css-vars\\n\\n  border-bottom: var(--#{$prefix}nav-tabs-border-width) solid var(--#{$prefix}nav-tabs-border-color);\\n\\n  .nav-link {\\n    margin-bottom: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list\\n    background: none;\\n    border: var(--#{$prefix}nav-tabs-border-width) solid transparent;\\n    @include border-top-radius(var(--#{$prefix}nav-tabs-border-radius));\\n\\n    &:hover,\\n    &:focus {\\n      // Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link\\n      isolation: isolate;\\n      border-color: var(--#{$prefix}nav-tabs-link-hover-border-color);\\n    }\\n\\n    &.disabled,\\n    &:disabled {\\n      color: var(--#{$prefix}nav-link-disabled-color);\\n      background-color: transparent;\\n      border-color: transparent;\\n    }\\n  }\\n\\n  .nav-link.active,\\n  .nav-item.show .nav-link {\\n    color: var(--#{$prefix}nav-tabs-link-active-color);\\n    background-color: var(--#{$prefix}nav-tabs-link-active-bg);\\n    border-color: var(--#{$prefix}nav-tabs-link-active-border-color);\\n  }\\n\\n  .dropdown-menu {\\n    // Make dropdown border overlap tab border\\n    margin-top: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list\\n    // Remove the top rounded corners here since there is a hard edge above the menu\\n    @include border-top-radius(0);\\n  }\\n}\\n\\n\\n//\\n// Pills\\n//\\n\\n.nav-pills {\\n  // scss-docs-start nav-pills-css-vars\\n  --#{$prefix}nav-pills-border-radius: #{$nav-pills-border-radius};\\n  --#{$prefix}nav-pills-link-active-color: #{$nav-pills-link-active-color};\\n  --#{$prefix}nav-pills-link-active-bg: #{$nav-pills-link-active-bg};\\n  // scss-docs-end nav-pills-css-vars\\n\\n  .nav-link {\\n    background: none;\\n    border: 0;\\n    @include border-radius(var(--#{$prefix}nav-pills-border-radius));\\n\\n    &:disabled {\\n      color: var(--#{$prefix}nav-link-disabled-color);\\n      background-color: transparent;\\n      border-color: transparent;\\n    }\\n  }\\n\\n  .nav-link.active,\\n  .show > .nav-link {\\n    color: var(--#{$prefix}nav-pills-link-active-color);\\n    @include gradient-bg(var(--#{$prefix}nav-pills-link-active-bg));\\n  }\\n}\\n\\n\\n//\\n// Justified variants\\n//\\n\\n.nav-fill {\\n  > .nav-link,\\n  .nav-item {\\n    flex: 1 1 auto;\\n    text-align: center;\\n  }\\n}\\n\\n.nav-justified {\\n  > .nav-link,\\n  .nav-item {\\n    flex-basis: 0;\\n    flex-grow: 1;\\n    text-align: center;\\n  }\\n}\\n\\n.nav-fill,\\n.nav-justified {\\n  .nav-item .nav-link {\\n    width: 100%; // Make sure button will grow\\n  }\\n}\\n\\n\\n// Tabbable tabs\\n//\\n// Hide tabbable panes to start, show them when `.active`\\n\\n.tab-content {\\n  > .tab-pane {\\n    display: none;\\n  }\\n  > .active {\\n    display: block;\\n  }\\n}\\n\",\"// Navbar\\n//\\n// Provide a static navbar from which we expand to create full-width, fixed, and\\n// other navbar variations.\\n\\n.navbar {\\n  // scss-docs-start navbar-css-vars\\n  --#{$prefix}navbar-padding-x: #{if($navbar-padding-x == null, 0, $navbar-padding-x)};\\n  --#{$prefix}navbar-padding-y: #{$navbar-padding-y};\\n  --#{$prefix}navbar-color: #{$navbar-light-color};\\n  --#{$prefix}navbar-hover-color: #{$navbar-light-hover-color};\\n  --#{$prefix}navbar-disabled-color: #{$navbar-light-disabled-color};\\n  --#{$prefix}navbar-active-color: #{$navbar-light-active-color};\\n  --#{$prefix}navbar-brand-padding-y: #{$navbar-brand-padding-y};\\n  --#{$prefix}navbar-brand-margin-end: #{$navbar-brand-margin-end};\\n  --#{$prefix}navbar-brand-font-size: #{$navbar-brand-font-size};\\n  --#{$prefix}navbar-brand-color: #{$navbar-light-brand-color};\\n  --#{$prefix}navbar-brand-hover-color: #{$navbar-light-brand-hover-color};\\n  --#{$prefix}navbar-nav-link-padding-x: #{$navbar-nav-link-padding-x};\\n  --#{$prefix}navbar-toggler-padding-y: #{$navbar-toggler-padding-y};\\n  --#{$prefix}navbar-toggler-padding-x: #{$navbar-toggler-padding-x};\\n  --#{$prefix}navbar-toggler-font-size: #{$navbar-toggler-font-size};\\n  --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-light-toggler-icon-bg)};\\n  --#{$prefix}navbar-toggler-border-color: #{$navbar-light-toggler-border-color};\\n  --#{$prefix}navbar-toggler-border-radius: #{$navbar-toggler-border-radius};\\n  --#{$prefix}navbar-toggler-focus-width: #{$navbar-toggler-focus-width};\\n  --#{$prefix}navbar-toggler-transition: #{$navbar-toggler-transition};\\n  // scss-docs-end navbar-css-vars\\n\\n  position: relative;\\n  display: flex;\\n  flex-wrap: wrap; // allow us to do the line break for collapsing content\\n  align-items: center;\\n  justify-content: space-between; // space out brand from logo\\n  padding: var(--#{$prefix}navbar-padding-y) var(--#{$prefix}navbar-padding-x);\\n  @include gradient-bg();\\n\\n  // Because flex properties aren't inherited, we need to redeclare these first\\n  // few properties so that content nested within behave properly.\\n  // The `flex-wrap` property is inherited to simplify the expanded navbars\\n  %container-flex-properties {\\n    display: flex;\\n    flex-wrap: inherit;\\n    align-items: center;\\n    justify-content: space-between;\\n  }\\n\\n  > .container,\\n  > .container-fluid {\\n    @extend %container-flex-properties;\\n  }\\n\\n  @each $breakpoint, $container-max-width in $container-max-widths {\\n    > .container#{breakpoint-infix($breakpoint, $container-max-widths)} {\\n      @extend %container-flex-properties;\\n    }\\n  }\\n}\\n\\n\\n// Navbar brand\\n//\\n// Used for brand, project, or site names.\\n\\n.navbar-brand {\\n  padding-top: var(--#{$prefix}navbar-brand-padding-y);\\n  padding-bottom: var(--#{$prefix}navbar-brand-padding-y);\\n  margin-right: var(--#{$prefix}navbar-brand-margin-end);\\n  @include font-size(var(--#{$prefix}navbar-brand-font-size));\\n  color: var(--#{$prefix}navbar-brand-color);\\n  text-decoration: if($link-decoration == none, null, none);\\n  white-space: nowrap;\\n\\n  &:hover,\\n  &:focus {\\n    color: var(--#{$prefix}navbar-brand-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n  }\\n}\\n\\n\\n// Navbar nav\\n//\\n// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).\\n\\n.navbar-nav {\\n  // scss-docs-start navbar-nav-css-vars\\n  --#{$prefix}nav-link-padding-x: 0;\\n  --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};\\n  @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);\\n  --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};\\n  --#{$prefix}nav-link-color: var(--#{$prefix}navbar-color);\\n  --#{$prefix}nav-link-hover-color: var(--#{$prefix}navbar-hover-color);\\n  --#{$prefix}nav-link-disabled-color: var(--#{$prefix}navbar-disabled-color);\\n  // scss-docs-end navbar-nav-css-vars\\n\\n  display: flex;\\n  flex-direction: column; // cannot use `inherit` to get the `.navbar`s value\\n  padding-left: 0;\\n  margin-bottom: 0;\\n  list-style: none;\\n\\n  .show > .nav-link,\\n  .nav-link.active {\\n    color: var(--#{$prefix}navbar-active-color);\\n  }\\n\\n  .dropdown-menu {\\n    position: static;\\n  }\\n}\\n\\n\\n// Navbar text\\n//\\n//\\n\\n.navbar-text {\\n  padding-top: $nav-link-padding-y;\\n  padding-bottom: $nav-link-padding-y;\\n  color: var(--#{$prefix}navbar-color);\\n\\n  a,\\n  a:hover,\\n  a:focus  {\\n    color: var(--#{$prefix}navbar-active-color);\\n  }\\n}\\n\\n\\n// Responsive navbar\\n//\\n// Custom styles for responsive collapsing and toggling of navbar contents.\\n// Powered by the collapse Bootstrap JavaScript plugin.\\n\\n// When collapsed, prevent the toggleable navbar contents from appearing in\\n// the default flexbox row orientation. Requires the use of `flex-wrap: wrap`\\n// on the `.navbar` parent.\\n.navbar-collapse {\\n  flex-basis: 100%;\\n  flex-grow: 1;\\n  // For always expanded or extra full navbars, ensure content aligns itself\\n  // properly vertically. Can be easily overridden with flex utilities.\\n  align-items: center;\\n}\\n\\n// Button for toggling the navbar when in its collapsed state\\n.navbar-toggler {\\n  padding: var(--#{$prefix}navbar-toggler-padding-y) var(--#{$prefix}navbar-toggler-padding-x);\\n  @include font-size(var(--#{$prefix}navbar-toggler-font-size));\\n  line-height: 1;\\n  color: var(--#{$prefix}navbar-color);\\n  background-color: transparent; // remove default button style\\n  border: var(--#{$prefix}border-width) solid var(--#{$prefix}navbar-toggler-border-color); // remove default button style\\n  @include border-radius(var(--#{$prefix}navbar-toggler-border-radius));\\n  @include transition(var(--#{$prefix}navbar-toggler-transition));\\n\\n  &:hover {\\n    text-decoration: none;\\n  }\\n\\n  &:focus {\\n    text-decoration: none;\\n    outline: 0;\\n    box-shadow: 0 0 0 var(--#{$prefix}navbar-toggler-focus-width);\\n  }\\n}\\n\\n// Keep as a separate element so folks can easily override it with another icon\\n// or image file as needed.\\n.navbar-toggler-icon {\\n  display: inline-block;\\n  width: 1.5em;\\n  height: 1.5em;\\n  vertical-align: middle;\\n  background-image: var(--#{$prefix}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(--#{$prefix}scroll-height, 75vh);\\n  overflow-y: auto;\\n}\\n\\n// scss-docs-start navbar-expand-loop\\n// Generate series of `.navbar-expand-*` responsive classes for configuring\\n// where your navbar collapses.\\n.navbar-expand {\\n  @each $breakpoint in map-keys($grid-breakpoints) {\\n    $next: breakpoint-next($breakpoint, $grid-breakpoints);\\n    $infix: breakpoint-infix($next, $grid-breakpoints);\\n\\n    // stylelint-disable-next-line scss/selector-no-union-class-name\\n    &#{$infix} {\\n      @include media-breakpoint-up($next) {\\n        flex-wrap: nowrap;\\n        justify-content: flex-start;\\n\\n        .navbar-nav {\\n          flex-direction: row;\\n\\n          .dropdown-menu {\\n            position: absolute;\\n          }\\n\\n          .nav-link {\\n            padding-right: var(--#{$prefix}navbar-nav-link-padding-x);\\n            padding-left: var(--#{$prefix}navbar-nav-link-padding-x);\\n          }\\n        }\\n\\n        .navbar-nav-scroll {\\n          overflow: visible;\\n        }\\n\\n        .navbar-collapse {\\n          display: flex !important; // stylelint-disable-line declaration-no-important\\n          flex-basis: auto;\\n        }\\n\\n        .navbar-toggler {\\n          display: none;\\n        }\\n\\n        .offcanvas {\\n          // stylelint-disable declaration-no-important\\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          @include box-shadow(none);\\n          @include transition(none);\\n          // stylelint-enable declaration-no-important\\n\\n          .offcanvas-header {\\n            display: none;\\n          }\\n\\n          .offcanvas-body {\\n            display: flex;\\n            flex-grow: 0;\\n            padding: 0;\\n            overflow-y: visible;\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end navbar-expand-loop\\n\\n// Navbar themes\\n//\\n// Styles for switching between navbars with light or dark background.\\n\\n.navbar-light {\\n  @include deprecate(\\\"`.navbar-light`\\\", \\\"v5.2.0\\\", \\\"v6.0.0\\\", true);\\n}\\n\\n.navbar-dark {\\n  // scss-docs-start navbar-dark-css-vars\\n  --#{$prefix}navbar-color: #{$navbar-dark-color};\\n  --#{$prefix}navbar-hover-color: #{$navbar-dark-hover-color};\\n  --#{$prefix}navbar-disabled-color: #{$navbar-dark-disabled-color};\\n  --#{$prefix}navbar-active-color: #{$navbar-dark-active-color};\\n  --#{$prefix}navbar-brand-color: #{$navbar-dark-brand-color};\\n  --#{$prefix}navbar-brand-hover-color: #{$navbar-dark-brand-hover-color};\\n  --#{$prefix}navbar-toggler-border-color: #{$navbar-dark-toggler-border-color};\\n  --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};\\n  // scss-docs-end navbar-dark-css-vars\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .navbar {\\n      --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};\\n    }\\n  }\\n}\\n\",\"//\\n// Base styles\\n//\\n\\n.card {\\n  // scss-docs-start card-css-vars\\n  --#{$prefix}card-spacer-y: #{$card-spacer-y};\\n  --#{$prefix}card-spacer-x: #{$card-spacer-x};\\n  --#{$prefix}card-title-spacer-y: #{$card-title-spacer-y};\\n  --#{$prefix}card-title-color: #{$card-title-color};\\n  --#{$prefix}card-subtitle-color: #{$card-subtitle-color};\\n  --#{$prefix}card-border-width: #{$card-border-width};\\n  --#{$prefix}card-border-color: #{$card-border-color};\\n  --#{$prefix}card-border-radius: #{$card-border-radius};\\n  --#{$prefix}card-box-shadow: #{$card-box-shadow};\\n  --#{$prefix}card-inner-border-radius: #{$card-inner-border-radius};\\n  --#{$prefix}card-cap-padding-y: #{$card-cap-padding-y};\\n  --#{$prefix}card-cap-padding-x: #{$card-cap-padding-x};\\n  --#{$prefix}card-cap-bg: #{$card-cap-bg};\\n  --#{$prefix}card-cap-color: #{$card-cap-color};\\n  --#{$prefix}card-height: #{$card-height};\\n  --#{$prefix}card-color: #{$card-color};\\n  --#{$prefix}card-bg: #{$card-bg};\\n  --#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding};\\n  --#{$prefix}card-group-margin: #{$card-group-margin};\\n  // scss-docs-end card-css-vars\\n\\n  position: relative;\\n  display: flex;\\n  flex-direction: column;\\n  min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106\\n  height: var(--#{$prefix}card-height);\\n  word-wrap: break-word;\\n  background-color: var(--#{$prefix}card-bg);\\n  background-clip: border-box;\\n  border: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);\\n  @include border-radius(var(--#{$prefix}card-border-radius));\\n  @include box-shadow(var(--#{$prefix}card-box-shadow));\\n\\n  > hr {\\n    margin-right: 0;\\n    margin-left: 0;\\n  }\\n\\n  > .list-group {\\n    border-top: inherit;\\n    border-bottom: inherit;\\n\\n    &:first-child {\\n      border-top-width: 0;\\n      @include border-top-radius(var(--#{$prefix}card-inner-border-radius));\\n    }\\n\\n    &:last-child  {\\n      border-bottom-width: 0;\\n      @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));\\n    }\\n  }\\n\\n  // Due to specificity of the above selector (`.card > .list-group`), we must\\n  // use a child selector here to prevent double borders.\\n  > .card-header + .list-group,\\n  > .list-group + .card-footer {\\n    border-top: 0;\\n  }\\n}\\n\\n.card-body {\\n  // Enable `flex-grow: 1` for decks and groups so that card blocks take up\\n  // as much space as possible, ensuring footers are aligned to the bottom.\\n  flex: 1 1 auto;\\n  padding: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x);\\n  color: var(--#{$prefix}card-color);\\n}\\n\\n.card-title {\\n  margin-bottom: var(--#{$prefix}card-title-spacer-y);\\n  color: var(--#{$prefix}card-title-color);\\n}\\n\\n.card-subtitle {\\n  margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list\\n  margin-bottom: 0;\\n  color: var(--#{$prefix}card-subtitle-color);\\n}\\n\\n.card-text:last-child {\\n  margin-bottom: 0;\\n}\\n\\n.card-link {\\n  &:hover {\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n  }\\n\\n  + .card-link {\\n    margin-left: var(--#{$prefix}card-spacer-x);\\n  }\\n}\\n\\n//\\n// Optional textual caps\\n//\\n\\n.card-header {\\n  padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);\\n  margin-bottom: 0; // Removes the default margin-bottom of <hN>\\n  color: var(--#{$prefix}card-cap-color);\\n  background-color: var(--#{$prefix}card-cap-bg);\\n  border-bottom: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);\\n\\n  &:first-child {\\n    @include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0);\\n  }\\n}\\n\\n.card-footer {\\n  padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);\\n  color: var(--#{$prefix}card-cap-color);\\n  background-color: var(--#{$prefix}card-cap-bg);\\n  border-top: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);\\n\\n  &:last-child {\\n    @include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius));\\n  }\\n}\\n\\n\\n//\\n// Header navs\\n//\\n\\n.card-header-tabs {\\n  margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list\\n  margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list\\n  margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list\\n  border-bottom: 0;\\n\\n  .nav-link.active {\\n    background-color: var(--#{$prefix}card-bg);\\n    border-bottom-color: var(--#{$prefix}card-bg);\\n  }\\n}\\n\\n.card-header-pills {\\n  margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list\\n  margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list\\n}\\n\\n// Card image\\n.card-img-overlay {\\n  position: absolute;\\n  top: 0;\\n  right: 0;\\n  bottom: 0;\\n  left: 0;\\n  padding: var(--#{$prefix}card-img-overlay-padding);\\n  @include border-radius(var(--#{$prefix}card-inner-border-radius));\\n}\\n\\n.card-img,\\n.card-img-top,\\n.card-img-bottom {\\n  width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch\\n}\\n\\n.card-img,\\n.card-img-top {\\n  @include border-top-radius(var(--#{$prefix}card-inner-border-radius));\\n}\\n\\n.card-img,\\n.card-img-bottom {\\n  @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));\\n}\\n\\n\\n//\\n// Card groups\\n//\\n\\n.card-group {\\n  // The child selector allows nested `.card` within `.card-group`\\n  // to display properly.\\n  > .card {\\n    margin-bottom: var(--#{$prefix}card-group-margin);\\n  }\\n\\n  @include media-breakpoint-up(sm) {\\n    display: flex;\\n    flex-flow: row wrap;\\n    // The child selector allows nested `.card` within `.card-group`\\n    // to display properly.\\n    > .card {\\n      // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\\n      flex: 1 0 0%;\\n      margin-bottom: 0;\\n\\n      + .card {\\n        margin-left: 0;\\n        border-left: 0;\\n      }\\n\\n      // Handle rounded corners\\n      @if $enable-rounded {\\n        &:not(:last-child) {\\n          @include border-end-radius(0);\\n\\n          .card-img-top,\\n          .card-header {\\n            // stylelint-disable-next-line property-disallowed-list\\n            border-top-right-radius: 0;\\n          }\\n          .card-img-bottom,\\n          .card-footer {\\n            // stylelint-disable-next-line property-disallowed-list\\n            border-bottom-right-radius: 0;\\n          }\\n        }\\n\\n        &:not(:first-child) {\\n          @include border-start-radius(0);\\n\\n          .card-img-top,\\n          .card-header {\\n            // stylelint-disable-next-line property-disallowed-list\\n            border-top-left-radius: 0;\\n          }\\n          .card-img-bottom,\\n          .card-footer {\\n            // stylelint-disable-next-line property-disallowed-list\\n            border-bottom-left-radius: 0;\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n\",\"//\\n// Base styles\\n//\\n\\n.accordion {\\n  // scss-docs-start accordion-css-vars\\n  --#{$prefix}accordion-color: #{$accordion-color};\\n  --#{$prefix}accordion-bg: #{$accordion-bg};\\n  --#{$prefix}accordion-transition: #{$accordion-transition};\\n  --#{$prefix}accordion-border-color: #{$accordion-border-color};\\n  --#{$prefix}accordion-border-width: #{$accordion-border-width};\\n  --#{$prefix}accordion-border-radius: #{$accordion-border-radius};\\n  --#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius};\\n  --#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x};\\n  --#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y};\\n  --#{$prefix}accordion-btn-color: #{$accordion-button-color};\\n  --#{$prefix}accordion-btn-bg: #{$accordion-button-bg};\\n  --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)};\\n  --#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width};\\n  --#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform};\\n  --#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition};\\n  --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon)};\\n  --#{$prefix}accordion-btn-focus-border-color: #{$accordion-button-focus-border-color};\\n  --#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow};\\n  --#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x};\\n  --#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y};\\n  --#{$prefix}accordion-active-color: #{$accordion-button-active-color};\\n  --#{$prefix}accordion-active-bg: #{$accordion-button-active-bg};\\n  // scss-docs-end accordion-css-vars\\n}\\n\\n.accordion-button {\\n  position: relative;\\n  display: flex;\\n  align-items: center;\\n  width: 100%;\\n  padding: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x);\\n  @include font-size($font-size-base);\\n  color: var(--#{$prefix}accordion-btn-color);\\n  text-align: left; // Reset button style\\n  background-color: var(--#{$prefix}accordion-btn-bg);\\n  border: 0;\\n  @include border-radius(0);\\n  overflow-anchor: none;\\n  @include transition(var(--#{$prefix}accordion-transition));\\n\\n  &:not(.collapsed) {\\n    color: var(--#{$prefix}accordion-active-color);\\n    background-color: var(--#{$prefix}accordion-active-bg);\\n    box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list\\n\\n    &::after {\\n      background-image: var(--#{$prefix}accordion-btn-active-icon);\\n      transform: var(--#{$prefix}accordion-btn-icon-transform);\\n    }\\n  }\\n\\n  // Accordion icon\\n  &::after {\\n    flex-shrink: 0;\\n    width: var(--#{$prefix}accordion-btn-icon-width);\\n    height: var(--#{$prefix}accordion-btn-icon-width);\\n    margin-left: auto;\\n    content: \\\"\\\";\\n    background-image: var(--#{$prefix}accordion-btn-icon);\\n    background-repeat: no-repeat;\\n    background-size: var(--#{$prefix}accordion-btn-icon-width);\\n    @include transition(var(--#{$prefix}accordion-btn-icon-transition));\\n  }\\n\\n  &:hover {\\n    z-index: 2;\\n  }\\n\\n  &:focus {\\n    z-index: 3;\\n    border-color: var(--#{$prefix}accordion-btn-focus-border-color);\\n    outline: 0;\\n    box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow);\\n  }\\n}\\n\\n.accordion-header {\\n  margin-bottom: 0;\\n}\\n\\n.accordion-item {\\n  color: var(--#{$prefix}accordion-color);\\n  background-color: var(--#{$prefix}accordion-bg);\\n  border: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color);\\n\\n  &:first-of-type {\\n    @include border-top-radius(var(--#{$prefix}accordion-border-radius));\\n\\n    .accordion-button {\\n      @include border-top-radius(var(--#{$prefix}accordion-inner-border-radius));\\n    }\\n  }\\n\\n  &:not(:first-of-type) {\\n    border-top: 0;\\n  }\\n\\n  // Only set a border-radius on the last item if the accordion is collapsed\\n  &:last-of-type {\\n    @include border-bottom-radius(var(--#{$prefix}accordion-border-radius));\\n\\n    .accordion-button {\\n      &.collapsed {\\n        @include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius));\\n      }\\n    }\\n\\n    .accordion-collapse {\\n      @include border-bottom-radius(var(--#{$prefix}accordion-border-radius));\\n    }\\n  }\\n}\\n\\n.accordion-body {\\n  padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x);\\n}\\n\\n\\n// Flush accordion items\\n//\\n// Remove borders and border-radius to keep accordion items edge-to-edge.\\n\\n.accordion-flush {\\n  .accordion-collapse {\\n    border-width: 0;\\n  }\\n\\n  .accordion-item {\\n    border-right: 0;\\n    border-left: 0;\\n    @include border-radius(0);\\n\\n    &:first-child { border-top: 0; }\\n    &:last-child { border-bottom: 0; }\\n\\n    .accordion-button {\\n      &,\\n      &.collapsed {\\n        @include border-radius(0);\\n      }\\n    }\\n  }\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .accordion-button::after {\\n      --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)};\\n      --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon-dark)};\\n    }\\n  }\\n}\\n\",\".breadcrumb {\\n  // scss-docs-start breadcrumb-css-vars\\n  --#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x};\\n  --#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y};\\n  --#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom};\\n  @include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size);\\n  --#{$prefix}breadcrumb-bg: #{$breadcrumb-bg};\\n  --#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius};\\n  --#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color};\\n  --#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x};\\n  --#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color};\\n  // scss-docs-end breadcrumb-css-vars\\n\\n  display: flex;\\n  flex-wrap: wrap;\\n  padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x);\\n  margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom);\\n  @include font-size(var(--#{$prefix}breadcrumb-font-size));\\n  list-style: none;\\n  background-color: var(--#{$prefix}breadcrumb-bg);\\n  @include border-radius(var(--#{$prefix}breadcrumb-border-radius));\\n}\\n\\n.breadcrumb-item {\\n  // The separator between breadcrumbs (by default, a forward-slash: \\\"/\\\")\\n  + .breadcrumb-item {\\n    padding-left: var(--#{$prefix}breadcrumb-item-padding-x);\\n\\n    &::before {\\n      float: left; // Suppress inline spacings and underlining of the separator\\n      padding-right: var(--#{$prefix}breadcrumb-item-padding-x);\\n      color: var(--#{$prefix}breadcrumb-divider-color);\\n      content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{\\\"/* rtl:\\\"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{\\\"*/\\\"};\\n    }\\n  }\\n\\n  &.active {\\n    color: var(--#{$prefix}breadcrumb-item-active-color);\\n  }\\n}\\n\",\".pagination {\\n  // scss-docs-start pagination-css-vars\\n  --#{$prefix}pagination-padding-x: #{$pagination-padding-x};\\n  --#{$prefix}pagination-padding-y: #{$pagination-padding-y};\\n  @include rfs($pagination-font-size, --#{$prefix}pagination-font-size);\\n  --#{$prefix}pagination-color: #{$pagination-color};\\n  --#{$prefix}pagination-bg: #{$pagination-bg};\\n  --#{$prefix}pagination-border-width: #{$pagination-border-width};\\n  --#{$prefix}pagination-border-color: #{$pagination-border-color};\\n  --#{$prefix}pagination-border-radius: #{$pagination-border-radius};\\n  --#{$prefix}pagination-hover-color: #{$pagination-hover-color};\\n  --#{$prefix}pagination-hover-bg: #{$pagination-hover-bg};\\n  --#{$prefix}pagination-hover-border-color: #{$pagination-hover-border-color};\\n  --#{$prefix}pagination-focus-color: #{$pagination-focus-color};\\n  --#{$prefix}pagination-focus-bg: #{$pagination-focus-bg};\\n  --#{$prefix}pagination-focus-box-shadow: #{$pagination-focus-box-shadow};\\n  --#{$prefix}pagination-active-color: #{$pagination-active-color};\\n  --#{$prefix}pagination-active-bg: #{$pagination-active-bg};\\n  --#{$prefix}pagination-active-border-color: #{$pagination-active-border-color};\\n  --#{$prefix}pagination-disabled-color: #{$pagination-disabled-color};\\n  --#{$prefix}pagination-disabled-bg: #{$pagination-disabled-bg};\\n  --#{$prefix}pagination-disabled-border-color: #{$pagination-disabled-border-color};\\n  // scss-docs-end pagination-css-vars\\n\\n  display: flex;\\n  @include list-unstyled();\\n}\\n\\n.page-link {\\n  position: relative;\\n  display: block;\\n  padding: var(--#{$prefix}pagination-padding-y) var(--#{$prefix}pagination-padding-x);\\n  @include font-size(var(--#{$prefix}pagination-font-size));\\n  color: var(--#{$prefix}pagination-color);\\n  text-decoration: if($link-decoration == none, null, none);\\n  background-color: var(--#{$prefix}pagination-bg);\\n  border: var(--#{$prefix}pagination-border-width) solid var(--#{$prefix}pagination-border-color);\\n  @include transition($pagination-transition);\\n\\n  &:hover {\\n    z-index: 2;\\n    color: var(--#{$prefix}pagination-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n    background-color: var(--#{$prefix}pagination-hover-bg);\\n    border-color: var(--#{$prefix}pagination-hover-border-color);\\n  }\\n\\n  &:focus {\\n    z-index: 3;\\n    color: var(--#{$prefix}pagination-focus-color);\\n    background-color: var(--#{$prefix}pagination-focus-bg);\\n    outline: $pagination-focus-outline;\\n    box-shadow: var(--#{$prefix}pagination-focus-box-shadow);\\n  }\\n\\n  &.active,\\n  .active > & {\\n    z-index: 3;\\n    color: var(--#{$prefix}pagination-active-color);\\n    @include gradient-bg(var(--#{$prefix}pagination-active-bg));\\n    border-color: var(--#{$prefix}pagination-active-border-color);\\n  }\\n\\n  &.disabled,\\n  .disabled > & {\\n    color: var(--#{$prefix}pagination-disabled-color);\\n    pointer-events: none;\\n    background-color: var(--#{$prefix}pagination-disabled-bg);\\n    border-color: var(--#{$prefix}pagination-disabled-border-color);\\n  }\\n}\\n\\n.page-item {\\n  &:not(:first-child) .page-link {\\n    margin-left: $pagination-margin-start;\\n  }\\n\\n  @if $pagination-margin-start == calc($pagination-border-width * -1) {\\n    &:first-child {\\n      .page-link {\\n        @include border-start-radius(var(--#{$prefix}pagination-border-radius));\\n      }\\n    }\\n\\n    &:last-child {\\n      .page-link {\\n        @include border-end-radius(var(--#{$prefix}pagination-border-radius));\\n      }\\n    }\\n  } @else {\\n    // Add border-radius to all pageLinks in case they have left margin\\n    .page-link {\\n      @include border-radius(var(--#{$prefix}pagination-border-radius));\\n    }\\n  }\\n}\\n\\n\\n//\\n// Sizing\\n//\\n\\n.pagination-lg {\\n  @include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg);\\n}\\n\\n.pagination-sm {\\n  @include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm);\\n}\\n\",\"// Pagination\\n\\n// scss-docs-start pagination-mixin\\n@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) {\\n  --#{$prefix}pagination-padding-x: #{$padding-x};\\n  --#{$prefix}pagination-padding-y: #{$padding-y};\\n  @include rfs($font-size, --#{$prefix}pagination-font-size);\\n  --#{$prefix}pagination-border-radius: #{$border-radius};\\n}\\n// scss-docs-end pagination-mixin\\n\",\"// Base class\\n//\\n// Requires one of the contextual, color modifier classes for `color` and\\n// `background-color`.\\n\\n.badge {\\n  // scss-docs-start badge-css-vars\\n  --#{$prefix}badge-padding-x: #{$badge-padding-x};\\n  --#{$prefix}badge-padding-y: #{$badge-padding-y};\\n  @include rfs($badge-font-size, --#{$prefix}badge-font-size);\\n  --#{$prefix}badge-font-weight: #{$badge-font-weight};\\n  --#{$prefix}badge-color: #{$badge-color};\\n  --#{$prefix}badge-border-radius: #{$badge-border-radius};\\n  // scss-docs-end badge-css-vars\\n\\n  display: inline-block;\\n  padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x);\\n  @include font-size(var(--#{$prefix}badge-font-size));\\n  font-weight: var(--#{$prefix}badge-font-weight);\\n  line-height: 1;\\n  color: var(--#{$prefix}badge-color);\\n  text-align: center;\\n  white-space: nowrap;\\n  vertical-align: baseline;\\n  @include border-radius(var(--#{$prefix}badge-border-radius));\\n  @include gradient-bg();\\n\\n  // Empty badges collapse automatically\\n  &:empty {\\n    display: none;\\n  }\\n}\\n\\n// Quick fix for badges in buttons\\n.btn .badge {\\n  position: relative;\\n  top: -1px;\\n}\\n\",\"//\\n// Base styles\\n//\\n\\n.alert {\\n  // scss-docs-start alert-css-vars\\n  --#{$prefix}alert-bg: transparent;\\n  --#{$prefix}alert-padding-x: #{$alert-padding-x};\\n  --#{$prefix}alert-padding-y: #{$alert-padding-y};\\n  --#{$prefix}alert-margin-bottom: #{$alert-margin-bottom};\\n  --#{$prefix}alert-color: inherit;\\n  --#{$prefix}alert-border-color: transparent;\\n  --#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color);\\n  --#{$prefix}alert-border-radius: #{$alert-border-radius};\\n  --#{$prefix}alert-link-color: inherit;\\n  // scss-docs-end alert-css-vars\\n\\n  position: relative;\\n  padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x);\\n  margin-bottom: var(--#{$prefix}alert-margin-bottom);\\n  color: var(--#{$prefix}alert-color);\\n  background-color: var(--#{$prefix}alert-bg);\\n  border: var(--#{$prefix}alert-border);\\n  @include border-radius(var(--#{$prefix}alert-border-radius));\\n}\\n\\n// Headings for larger alerts\\n.alert-heading {\\n  // Specified to prevent conflicts of changing $headings-color\\n  color: inherit;\\n}\\n\\n// Provide class for links that match alerts\\n.alert-link {\\n  font-weight: $alert-link-font-weight;\\n  color: var(--#{$prefix}alert-link-color);\\n}\\n\\n\\n// Dismissible alerts\\n//\\n// Expand the right padding and account for the close button's positioning.\\n\\n.alert-dismissible {\\n  padding-right: $alert-dismissible-padding-r;\\n\\n  // Adjust close link position\\n  .btn-close {\\n    position: absolute;\\n    top: 0;\\n    right: 0;\\n    z-index: $stretched-link-z-index + 1;\\n    padding: $alert-padding-y * 1.25 $alert-padding-x;\\n  }\\n}\\n\\n\\n// scss-docs-start alert-modifiers\\n// Generate contextual modifier classes for colorizing the alert\\n@each $state in map-keys($theme-colors) {\\n  .alert-#{$state} {\\n    --#{$prefix}alert-color: var(--#{$prefix}#{$state}-text);\\n    --#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle);\\n    --#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle);\\n    --#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text);\\n  }\\n}\\n// scss-docs-end alert-modifiers\\n\",\"// Disable animation if transitions are disabled\\n\\n// scss-docs-start progress-keyframes\\n@if $enable-transitions {\\n  @keyframes progress-bar-stripes {\\n    0% { background-position-x: $progress-height; }\\n  }\\n}\\n// scss-docs-end progress-keyframes\\n\\n.progress,\\n.progress-stacked {\\n  // scss-docs-start progress-css-vars\\n  --#{$prefix}progress-height: #{$progress-height};\\n  @include rfs($progress-font-size, --#{$prefix}progress-font-size);\\n  --#{$prefix}progress-bg: #{$progress-bg};\\n  --#{$prefix}progress-border-radius: #{$progress-border-radius};\\n  --#{$prefix}progress-box-shadow: #{$progress-box-shadow};\\n  --#{$prefix}progress-bar-color: #{$progress-bar-color};\\n  --#{$prefix}progress-bar-bg: #{$progress-bar-bg};\\n  --#{$prefix}progress-bar-transition: #{$progress-bar-transition};\\n  // scss-docs-end progress-css-vars\\n\\n  display: flex;\\n  height: var(--#{$prefix}progress-height);\\n  overflow: hidden; // force rounded corners by cropping it\\n  @include font-size(var(--#{$prefix}progress-font-size));\\n  background-color: var(--#{$prefix}progress-bg);\\n  @include border-radius(var(--#{$prefix}progress-border-radius));\\n  @include box-shadow(var(--#{$prefix}progress-box-shadow));\\n}\\n\\n.progress-bar {\\n  display: flex;\\n  flex-direction: column;\\n  justify-content: center;\\n  overflow: hidden;\\n  color: var(--#{$prefix}progress-bar-color);\\n  text-align: center;\\n  white-space: nowrap;\\n  background-color: var(--#{$prefix}progress-bar-bg);\\n  @include transition(var(--#{$prefix}progress-bar-transition));\\n}\\n\\n.progress-bar-striped {\\n  @include gradient-striped();\\n  background-size: var(--#{$prefix}progress-height) var(--#{$prefix}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@if $enable-transitions {\\n  .progress-bar-animated {\\n    animation: $progress-bar-animation-timing progress-bar-stripes;\\n\\n    @if $enable-reduced-motion {\\n      @media (prefers-reduced-motion: reduce) {\\n        animation: none;\\n      }\\n    }\\n  }\\n}\\n\",\"// Base class\\n//\\n// Easily usable on <ul>, <ol>, or <div>.\\n\\n.list-group {\\n  // scss-docs-start list-group-css-vars\\n  --#{$prefix}list-group-color: #{$list-group-color};\\n  --#{$prefix}list-group-bg: #{$list-group-bg};\\n  --#{$prefix}list-group-border-color: #{$list-group-border-color};\\n  --#{$prefix}list-group-border-width: #{$list-group-border-width};\\n  --#{$prefix}list-group-border-radius: #{$list-group-border-radius};\\n  --#{$prefix}list-group-item-padding-x: #{$list-group-item-padding-x};\\n  --#{$prefix}list-group-item-padding-y: #{$list-group-item-padding-y};\\n  --#{$prefix}list-group-action-color: #{$list-group-action-color};\\n  --#{$prefix}list-group-action-hover-color: #{$list-group-action-hover-color};\\n  --#{$prefix}list-group-action-hover-bg: #{$list-group-hover-bg};\\n  --#{$prefix}list-group-action-active-color: #{$list-group-action-active-color};\\n  --#{$prefix}list-group-action-active-bg: #{$list-group-action-active-bg};\\n  --#{$prefix}list-group-disabled-color: #{$list-group-disabled-color};\\n  --#{$prefix}list-group-disabled-bg: #{$list-group-disabled-bg};\\n  --#{$prefix}list-group-active-color: #{$list-group-active-color};\\n  --#{$prefix}list-group-active-bg: #{$list-group-active-bg};\\n  --#{$prefix}list-group-active-border-color: #{$list-group-active-border-color};\\n  // scss-docs-end list-group-css-vars\\n\\n  display: flex;\\n  flex-direction: column;\\n\\n  // No need to set list-style: none; since .list-group-item is block level\\n  padding-left: 0; // reset padding because ul and ol\\n  margin-bottom: 0;\\n  @include border-radius(var(--#{$prefix}list-group-border-radius));\\n}\\n\\n.list-group-numbered {\\n  list-style-type: none;\\n  counter-reset: section;\\n\\n  > .list-group-item::before {\\n    // Increments only this instance of the section counter\\n    content: counters(section, \\\".\\\") \\\". \\\";\\n    counter-increment: section;\\n  }\\n}\\n\\n// Interactive list items\\n//\\n// Use anchor or button elements instead of `li`s or `div`s to create interactive\\n// list items. Includes an extra `.active` modifier class for selected items.\\n\\n.list-group-item-action {\\n  width: 100%; // For `<button>`s (anchors become 100% by default though)\\n  color: var(--#{$prefix}list-group-action-color);\\n  text-align: inherit; // For `<button>`s (anchors inherit)\\n\\n  // Hover state\\n  &:hover,\\n  &:focus {\\n    z-index: 1; // Place hover/focus items above their siblings for proper border styling\\n    color: var(--#{$prefix}list-group-action-hover-color);\\n    text-decoration: none;\\n    background-color: var(--#{$prefix}list-group-action-hover-bg);\\n  }\\n\\n  &:active {\\n    color: var(--#{$prefix}list-group-action-active-color);\\n    background-color: var(--#{$prefix}list-group-action-active-bg);\\n  }\\n}\\n\\n// Individual list items\\n//\\n// Use on `li`s or `div`s within the `.list-group` parent.\\n\\n.list-group-item {\\n  position: relative;\\n  display: block;\\n  padding: var(--#{$prefix}list-group-item-padding-y) var(--#{$prefix}list-group-item-padding-x);\\n  color: var(--#{$prefix}list-group-color);\\n  text-decoration: if($link-decoration == none, null, none);\\n  background-color: var(--#{$prefix}list-group-bg);\\n  border: var(--#{$prefix}list-group-border-width) solid var(--#{$prefix}list-group-border-color);\\n\\n  &:first-child {\\n    @include border-top-radius(inherit);\\n  }\\n\\n  &:last-child {\\n    @include border-bottom-radius(inherit);\\n  }\\n\\n  &.disabled,\\n  &:disabled {\\n    color: var(--#{$prefix}list-group-disabled-color);\\n    pointer-events: none;\\n    background-color: var(--#{$prefix}list-group-disabled-bg);\\n  }\\n\\n  // Include both here for `<a>`s and `<button>`s\\n  &.active {\\n    z-index: 2; // Place active items above their siblings for proper border styling\\n    color: var(--#{$prefix}list-group-active-color);\\n    background-color: var(--#{$prefix}list-group-active-bg);\\n    border-color: var(--#{$prefix}list-group-active-border-color);\\n  }\\n\\n  // stylelint-disable-next-line scss/selector-no-redundant-nesting-selector\\n  & + .list-group-item {\\n    border-top-width: 0;\\n\\n    &.active {\\n      margin-top: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list\\n      border-top-width: var(--#{$prefix}list-group-border-width);\\n    }\\n  }\\n}\\n\\n// Horizontal\\n//\\n// Change the layout of list group items from vertical (default) to horizontal.\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  @include media-breakpoint-up($breakpoint) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    .list-group-horizontal#{$infix} {\\n      flex-direction: row;\\n\\n      > .list-group-item {\\n        &:first-child:not(:last-child) {\\n          @include border-bottom-start-radius(var(--#{$prefix}list-group-border-radius));\\n          @include border-top-end-radius(0);\\n        }\\n\\n        &:last-child:not(:first-child) {\\n          @include border-top-end-radius(var(--#{$prefix}list-group-border-radius));\\n          @include border-bottom-start-radius(0);\\n        }\\n\\n        &.active {\\n          margin-top: 0;\\n        }\\n\\n        + .list-group-item {\\n          border-top-width: var(--#{$prefix}list-group-border-width);\\n          border-left-width: 0;\\n\\n          &.active {\\n            margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list\\n            border-left-width: var(--#{$prefix}list-group-border-width);\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n\\n\\n// Flush list items\\n//\\n// Remove borders and border-radius to keep list group items edge-to-edge. Most\\n// useful within other components (e.g., cards).\\n\\n.list-group-flush {\\n  @include border-radius(0);\\n\\n  > .list-group-item {\\n    border-width: 0 0 var(--#{$prefix}list-group-border-width);\\n\\n    &:last-child {\\n      border-bottom-width: 0;\\n    }\\n  }\\n}\\n\\n\\n// scss-docs-start list-group-modifiers\\n// List group contextual variants\\n//\\n// Add modifier classes to change text and background color on individual items.\\n// Organizationally, this must come after the `:hover` states.\\n\\n@each $state in map-keys($theme-colors) {\\n  .list-group-item-#{$state} {\\n    --#{$prefix}list-group-color: var(--#{$prefix}#{$state}-text);\\n    --#{$prefix}list-group-bg: var(--#{$prefix}#{$state}-bg-subtle);\\n    --#{$prefix}list-group-border-color: var(--#{$prefix}#{$state}-border-subtle);\\n\\n    &.list-group-item-action {\\n      &:hover,\\n      &:focus {\\n        --#{$prefix}list-group-action-hover-color: var(--#{$prefix}emphasis-color);\\n        --#{$prefix}list-group-action-hover-bg: var(--#{$prefix}#{$state}-border-subtle);\\n      }\\n\\n      &:active {\\n        --#{$prefix}list-group-active-color: var(--#{$prefix}emphasis-color);\\n        --#{$prefix}list-group-active-bg: var(--#{$prefix}#{$state}-text);\\n        --#{$prefix}list-group-active-border-color: var(--#{$prefix}#{$state}-text);\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end list-group-modifiers\\n\",\"// Transparent background and border properties included for button version.\\n// iOS requires the button element instead of an anchor tag.\\n// If you want the anchor version, it requires `href=\\\"#\\\"`.\\n// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\\n\\n.btn-close {\\n  --#{$prefix}btn-close-color: #{$btn-close-color};\\n  --#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) };\\n  --#{$prefix}btn-close-opacity: #{$btn-close-opacity};\\n  --#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity};\\n  --#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow};\\n  --#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity};\\n  --#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity};\\n  --#{$prefix}btn-close-white-filter: #{$btn-close-white-filter};\\n\\n  box-sizing: content-box;\\n  width: $btn-close-width;\\n  height: $btn-close-height;\\n  padding: $btn-close-padding-y $btn-close-padding-x;\\n  color: var(--#{$prefix}btn-close-color);\\n  background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements\\n  border: 0; // for button elements\\n  @include border-radius();\\n  opacity: var(--#{$prefix}btn-close-opacity);\\n\\n  // Override <a>'s hover style\\n  &:hover {\\n    color: var(--#{$prefix}btn-close-color);\\n    text-decoration: none;\\n    opacity: var(--#{$prefix}btn-close-hover-opacity);\\n  }\\n\\n  &:focus {\\n    outline: 0;\\n    box-shadow: var(--#{$prefix}btn-close-focus-shadow);\\n    opacity: var(--#{$prefix}btn-close-focus-opacity);\\n  }\\n\\n  &:disabled,\\n  &.disabled {\\n    pointer-events: none;\\n    user-select: none;\\n    opacity: var(--#{$prefix}btn-close-disabled-opacity);\\n  }\\n}\\n\\n@mixin btn-close-white() {\\n  filter: var(--#{$prefix}btn-close-white-filter);\\n}\\n\\n.btn-close-white {\\n  @include btn-close-white();\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .btn-close {\\n      @include btn-close-white();\\n    }\\n  }\\n}\\n\",\".toast {\\n  // scss-docs-start toast-css-vars\\n  --#{$prefix}toast-zindex: #{$zindex-toast};\\n  --#{$prefix}toast-padding-x: #{$toast-padding-x};\\n  --#{$prefix}toast-padding-y: #{$toast-padding-y};\\n  --#{$prefix}toast-spacing: #{$toast-spacing};\\n  --#{$prefix}toast-max-width: #{$toast-max-width};\\n  @include rfs($toast-font-size, --#{$prefix}toast-font-size);\\n  --#{$prefix}toast-color: #{$toast-color};\\n  --#{$prefix}toast-bg: #{$toast-background-color};\\n  --#{$prefix}toast-border-width: #{$toast-border-width};\\n  --#{$prefix}toast-border-color: #{$toast-border-color};\\n  --#{$prefix}toast-border-radius: #{$toast-border-radius};\\n  --#{$prefix}toast-box-shadow: #{$toast-box-shadow};\\n  --#{$prefix}toast-header-color: #{$toast-header-color};\\n  --#{$prefix}toast-header-bg: #{$toast-header-background-color};\\n  --#{$prefix}toast-header-border-color: #{$toast-header-border-color};\\n  // scss-docs-end toast-css-vars\\n\\n  width: var(--#{$prefix}toast-max-width);\\n  max-width: 100%;\\n  @include font-size(var(--#{$prefix}toast-font-size));\\n  color: var(--#{$prefix}toast-color);\\n  pointer-events: auto;\\n  background-color: var(--#{$prefix}toast-bg);\\n  background-clip: padding-box;\\n  border: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-border-color);\\n  box-shadow: var(--#{$prefix}toast-box-shadow);\\n  @include border-radius(var(--#{$prefix}toast-border-radius));\\n\\n  &.showing {\\n    opacity: 0;\\n  }\\n\\n  &:not(.show) {\\n    display: none;\\n  }\\n}\\n\\n.toast-container {\\n  --#{$prefix}toast-zindex: #{$zindex-toast};\\n\\n  position: absolute;\\n  z-index: var(--#{$prefix}toast-zindex);\\n  width: max-content;\\n  max-width: 100%;\\n  pointer-events: none;\\n\\n  > :not(:last-child) {\\n    margin-bottom: var(--#{$prefix}toast-spacing);\\n  }\\n}\\n\\n.toast-header {\\n  display: flex;\\n  align-items: center;\\n  padding: var(--#{$prefix}toast-padding-y) var(--#{$prefix}toast-padding-x);\\n  color: var(--#{$prefix}toast-header-color);\\n  background-color: var(--#{$prefix}toast-header-bg);\\n  background-clip: padding-box;\\n  border-bottom: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-header-border-color);\\n  @include border-top-radius(calc(var(--#{$prefix}toast-border-radius) - var(--#{$prefix}toast-border-width)));\\n\\n  .btn-close {\\n    margin-right: calc(-.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list\\n    margin-left: var(--#{$prefix}toast-padding-x);\\n  }\\n}\\n\\n.toast-body {\\n  padding: var(--#{$prefix}toast-padding-x);\\n  word-wrap: break-word;\\n}\\n\",\"// stylelint-disable function-disallowed-list\\n\\n// .modal-open      - body class for killing the scroll\\n// .modal           - container to scroll within\\n// .modal-dialog    - positioning shell for the actual modal\\n// .modal-content   - actual modal w/ bg and corners and stuff\\n\\n\\n// Container that the modal scrolls within\\n.modal {\\n  // scss-docs-start modal-css-vars\\n  --#{$prefix}modal-zindex: #{$zindex-modal};\\n  --#{$prefix}modal-width: #{$modal-md};\\n  --#{$prefix}modal-padding: #{$modal-inner-padding};\\n  --#{$prefix}modal-margin: #{$modal-dialog-margin};\\n  --#{$prefix}modal-color: #{$modal-content-color};\\n  --#{$prefix}modal-bg: #{$modal-content-bg};\\n  --#{$prefix}modal-border-color: #{$modal-content-border-color};\\n  --#{$prefix}modal-border-width: #{$modal-content-border-width};\\n  --#{$prefix}modal-border-radius: #{$modal-content-border-radius};\\n  --#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-xs};\\n  --#{$prefix}modal-inner-border-radius: #{$modal-content-inner-border-radius};\\n  --#{$prefix}modal-header-padding-x: #{$modal-header-padding-x};\\n  --#{$prefix}modal-header-padding-y: #{$modal-header-padding-y};\\n  --#{$prefix}modal-header-padding: #{$modal-header-padding}; // Todo in v6: Split this padding into x and y\\n  --#{$prefix}modal-header-border-color: #{$modal-header-border-color};\\n  --#{$prefix}modal-header-border-width: #{$modal-header-border-width};\\n  --#{$prefix}modal-title-line-height: #{$modal-title-line-height};\\n  --#{$prefix}modal-footer-gap: #{$modal-footer-margin-between};\\n  --#{$prefix}modal-footer-bg: #{$modal-footer-bg};\\n  --#{$prefix}modal-footer-border-color: #{$modal-footer-border-color};\\n  --#{$prefix}modal-footer-border-width: #{$modal-footer-border-width};\\n  // scss-docs-end modal-css-vars\\n\\n  position: fixed;\\n  top: 0;\\n  left: 0;\\n  z-index: var(--#{$prefix}modal-zindex);\\n  display: none;\\n  width: 100%;\\n  height: 100%;\\n  overflow-x: hidden;\\n  overflow-y: auto;\\n  // Prevent Chrome on Windows from adding a focus outline. For details, see\\n  // https://github.com/twbs/bootstrap/pull/10951.\\n  outline: 0;\\n  // We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a\\n  // gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342\\n  // See also https://github.com/twbs/bootstrap/issues/17695\\n}\\n\\n// Shell div to position the modal with bottom padding\\n.modal-dialog {\\n  position: relative;\\n  width: auto;\\n  margin: var(--#{$prefix}modal-margin);\\n  // allow clicks to pass through for custom click handling to close modal\\n  pointer-events: none;\\n\\n  // When fading in the modal, animate it to slide down\\n  .modal.fade & {\\n    @include transition($modal-transition);\\n    transform: $modal-fade-transform;\\n  }\\n  .modal.show & {\\n    transform: $modal-show-transform;\\n  }\\n\\n  // When trying to close, animate focus to scale\\n  .modal.modal-static & {\\n    transform: $modal-scale-transform;\\n  }\\n}\\n\\n.modal-dialog-scrollable {\\n  height: calc(100% - var(--#{$prefix}modal-margin) * 2);\\n\\n  .modal-content {\\n    max-height: 100%;\\n    overflow: hidden;\\n  }\\n\\n  .modal-body {\\n    overflow-y: auto;\\n  }\\n}\\n\\n.modal-dialog-centered {\\n  display: flex;\\n  align-items: center;\\n  min-height: calc(100% - var(--#{$prefix}modal-margin) * 2);\\n}\\n\\n// Actual modal\\n.modal-content {\\n  position: relative;\\n  display: flex;\\n  flex-direction: column;\\n  width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog`\\n  // counteract the pointer-events: none; in the .modal-dialog\\n  color: var(--#{$prefix}modal-color);\\n  pointer-events: auto;\\n  background-color: var(--#{$prefix}modal-bg);\\n  background-clip: padding-box;\\n  border: var(--#{$prefix}modal-border-width) solid var(--#{$prefix}modal-border-color);\\n  @include border-radius(var(--#{$prefix}modal-border-radius));\\n  @include box-shadow(var(--#{$prefix}modal-box-shadow));\\n  // Remove focus outline from opened modal\\n  outline: 0;\\n}\\n\\n// Modal background\\n.modal-backdrop {\\n  // scss-docs-start modal-backdrop-css-vars\\n  --#{$prefix}backdrop-zindex: #{$zindex-modal-backdrop};\\n  --#{$prefix}backdrop-bg: #{$modal-backdrop-bg};\\n  --#{$prefix}backdrop-opacity: #{$modal-backdrop-opacity};\\n  // scss-docs-end modal-backdrop-css-vars\\n\\n  @include overlay-backdrop(var(--#{$prefix}backdrop-zindex), var(--#{$prefix}backdrop-bg), var(--#{$prefix}backdrop-opacity));\\n}\\n\\n// Modal header\\n// Top section of the modal w/ title and dismiss\\n.modal-header {\\n  display: flex;\\n  flex-shrink: 0;\\n  align-items: center;\\n  justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends\\n  padding: var(--#{$prefix}modal-header-padding);\\n  border-bottom: var(--#{$prefix}modal-header-border-width) solid var(--#{$prefix}modal-header-border-color);\\n  @include border-top-radius(var(--#{$prefix}modal-inner-border-radius));\\n\\n  .btn-close {\\n    padding: calc(var(--#{$prefix}modal-header-padding-y) * .5) calc(var(--#{$prefix}modal-header-padding-x) * .5);\\n    margin: calc(-.5 * var(--#{$prefix}modal-header-padding-y)) calc(-.5 * var(--#{$prefix}modal-header-padding-x)) calc(-.5 * var(--#{$prefix}modal-header-padding-y)) auto;\\n  }\\n}\\n\\n// Title text within header\\n.modal-title {\\n  margin-bottom: 0;\\n  line-height: var(--#{$prefix}modal-title-line-height);\\n}\\n\\n// Modal body\\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\\n.modal-body {\\n  position: relative;\\n  // Enable `flex-grow: 1` so that the body take up as much space as possible\\n  // when there should be a fixed height on `.modal-dialog`.\\n  flex: 1 1 auto;\\n  padding: var(--#{$prefix}modal-padding);\\n}\\n\\n// Footer (for actions)\\n.modal-footer {\\n  display: flex;\\n  flex-shrink: 0;\\n  flex-wrap: wrap;\\n  align-items: center; // vertically center\\n  justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items\\n  padding: calc(var(--#{$prefix}modal-padding) - var(--#{$prefix}modal-footer-gap) * .5);\\n  background-color: var(--#{$prefix}modal-footer-bg);\\n  border-top: var(--#{$prefix}modal-footer-border-width) solid var(--#{$prefix}modal-footer-border-color);\\n  @include border-bottom-radius(var(--#{$prefix}modal-inner-border-radius));\\n\\n  // Place margin between footer elements\\n  // This solution is far from ideal because of the universal selector usage,\\n  // but is needed to fix https://github.com/twbs/bootstrap/issues/24800\\n  > * {\\n    margin: calc(var(--#{$prefix}modal-footer-gap) * .5); // Todo in v6: replace with gap on parent class\\n  }\\n}\\n\\n// Scale up the modal\\n@include media-breakpoint-up(sm) {\\n  .modal {\\n    --#{$prefix}modal-margin: #{$modal-dialog-margin-y-sm-up};\\n    --#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-sm-up};\\n  }\\n\\n  // Automatically set modal's width for larger viewports\\n  .modal-dialog {\\n    max-width: var(--#{$prefix}modal-width);\\n    margin-right: auto;\\n    margin-left: auto;\\n  }\\n\\n  .modal-sm {\\n    --#{$prefix}modal-width: #{$modal-sm};\\n  }\\n}\\n\\n@include media-breakpoint-up(lg) {\\n  .modal-lg,\\n  .modal-xl {\\n    --#{$prefix}modal-width: #{$modal-lg};\\n  }\\n}\\n\\n@include media-breakpoint-up(xl) {\\n  .modal-xl {\\n    --#{$prefix}modal-width: #{$modal-xl};\\n  }\\n}\\n\\n// scss-docs-start modal-fullscreen-loop\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n  $postfix: if($infix != \\\"\\\", $infix + \\\"-down\\\", \\\"\\\");\\n\\n  @include media-breakpoint-down($breakpoint) {\\n    .modal-fullscreen#{$postfix} {\\n      width: 100vw;\\n      max-width: none;\\n      height: 100%;\\n      margin: 0;\\n\\n      .modal-content {\\n        height: 100%;\\n        border: 0;\\n        @include border-radius(0);\\n      }\\n\\n      .modal-header,\\n      .modal-footer {\\n        @include border-radius(0);\\n      }\\n\\n      .modal-body {\\n        overflow-y: auto;\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end modal-fullscreen-loop\\n\",\"// Shared between modals and offcanvases\\n@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) {\\n  position: fixed;\\n  top: 0;\\n  left: 0;\\n  z-index: $zindex;\\n  width: 100vw;\\n  height: 100vh;\\n  background-color: $backdrop-bg;\\n\\n  // Fade for backdrop\\n  &.fade { opacity: 0; }\\n  &.show { opacity: $backdrop-opacity; }\\n}\\n\",\"// Base class\\n.tooltip {\\n  // scss-docs-start tooltip-css-vars\\n  --#{$prefix}tooltip-zindex: #{$zindex-tooltip};\\n  --#{$prefix}tooltip-max-width: #{$tooltip-max-width};\\n  --#{$prefix}tooltip-padding-x: #{$tooltip-padding-x};\\n  --#{$prefix}tooltip-padding-y: #{$tooltip-padding-y};\\n  --#{$prefix}tooltip-margin: #{$tooltip-margin};\\n  @include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size);\\n  --#{$prefix}tooltip-color: #{$tooltip-color};\\n  --#{$prefix}tooltip-bg: #{$tooltip-bg};\\n  --#{$prefix}tooltip-border-radius: #{$tooltip-border-radius};\\n  --#{$prefix}tooltip-opacity: #{$tooltip-opacity};\\n  --#{$prefix}tooltip-arrow-width: #{$tooltip-arrow-width};\\n  --#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height};\\n  // scss-docs-end tooltip-css-vars\\n\\n  z-index: var(--#{$prefix}tooltip-zindex);\\n  display: block;\\n  padding: var(--#{$prefix}tooltip-arrow-height);\\n  margin: var(--#{$prefix}tooltip-margin);\\n  @include deprecate(\\\"`$tooltip-margin`\\\", \\\"v5\\\", \\\"v5.x\\\", true);\\n  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\\n  // So reset our font and text properties to avoid inheriting weird values.\\n  @include reset-text();\\n  @include font-size(var(--#{$prefix}tooltip-font-size));\\n  // Allow breaking very long words so they don't overflow the tooltip's bounds\\n  word-wrap: break-word;\\n  opacity: 0;\\n\\n  &.show { opacity: var(--#{$prefix}tooltip-opacity); }\\n\\n  .tooltip-arrow {\\n    display: block;\\n    width: var(--#{$prefix}tooltip-arrow-width);\\n    height: var(--#{$prefix}tooltip-arrow-height);\\n\\n    &::before {\\n      position: absolute;\\n      content: \\\"\\\";\\n      border-color: transparent;\\n      border-style: solid;\\n    }\\n  }\\n}\\n\\n.bs-tooltip-top .tooltip-arrow {\\n  bottom: 0;\\n\\n  &::before {\\n    top: -1px;\\n    border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list\\n    border-top-color: var(--#{$prefix}tooltip-bg);\\n  }\\n}\\n\\n/* rtl:begin:ignore */\\n.bs-tooltip-end .tooltip-arrow {\\n  left: 0;\\n  width: var(--#{$prefix}tooltip-arrow-height);\\n  height: var(--#{$prefix}tooltip-arrow-width);\\n\\n  &::before {\\n    right: -1px;\\n    border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list\\n    border-right-color: var(--#{$prefix}tooltip-bg);\\n  }\\n}\\n\\n/* rtl:end:ignore */\\n\\n.bs-tooltip-bottom .tooltip-arrow {\\n  top: 0;\\n\\n  &::before {\\n    bottom: -1px;\\n    border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list\\n    border-bottom-color: var(--#{$prefix}tooltip-bg);\\n  }\\n}\\n\\n/* rtl:begin:ignore */\\n.bs-tooltip-start .tooltip-arrow {\\n  right: 0;\\n  width: var(--#{$prefix}tooltip-arrow-height);\\n  height: var(--#{$prefix}tooltip-arrow-width);\\n\\n  &::before {\\n    left: -1px;\\n    border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list\\n    border-left-color: var(--#{$prefix}tooltip-bg);\\n  }\\n}\\n\\n/* rtl:end:ignore */\\n\\n.bs-tooltip-auto {\\n  &[data-popper-placement^=\\\"top\\\"] {\\n    @extend .bs-tooltip-top;\\n  }\\n  &[data-popper-placement^=\\\"right\\\"] {\\n    @extend .bs-tooltip-end;\\n  }\\n  &[data-popper-placement^=\\\"bottom\\\"] {\\n    @extend .bs-tooltip-bottom;\\n  }\\n  &[data-popper-placement^=\\\"left\\\"] {\\n    @extend .bs-tooltip-start;\\n  }\\n}\\n\\n// Wrapper for the tooltip content\\n.tooltip-inner {\\n  max-width: var(--#{$prefix}tooltip-max-width);\\n  padding: var(--#{$prefix}tooltip-padding-y) var(--#{$prefix}tooltip-padding-x);\\n  color: var(--#{$prefix}tooltip-color);\\n  text-align: center;\\n  background-color: var(--#{$prefix}tooltip-bg);\\n  @include border-radius(var(--#{$prefix}tooltip-border-radius));\\n}\\n\",\"@mixin reset-text {\\n  font-family: $font-family-base;\\n  // We deliberately do NOT reset font-size or overflow-wrap / word-wrap.\\n  font-style: normal;\\n  font-weight: $font-weight-normal;\\n  line-height: $line-height-base;\\n  text-align: left; // Fallback for where `start` is not supported\\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}\\n\",\".popover {\\n  // scss-docs-start popover-css-vars\\n  --#{$prefix}popover-zindex: #{$zindex-popover};\\n  --#{$prefix}popover-max-width: #{$popover-max-width};\\n  @include rfs($popover-font-size, --#{$prefix}popover-font-size);\\n  --#{$prefix}popover-bg: #{$popover-bg};\\n  --#{$prefix}popover-border-width: #{$popover-border-width};\\n  --#{$prefix}popover-border-color: #{$popover-border-color};\\n  --#{$prefix}popover-border-radius: #{$popover-border-radius};\\n  --#{$prefix}popover-inner-border-radius: #{$popover-inner-border-radius};\\n  --#{$prefix}popover-box-shadow: #{$popover-box-shadow};\\n  --#{$prefix}popover-header-padding-x: #{$popover-header-padding-x};\\n  --#{$prefix}popover-header-padding-y: #{$popover-header-padding-y};\\n  @include rfs($popover-header-font-size, --#{$prefix}popover-header-font-size);\\n  --#{$prefix}popover-header-color: #{$popover-header-color};\\n  --#{$prefix}popover-header-bg: #{$popover-header-bg};\\n  --#{$prefix}popover-body-padding-x: #{$popover-body-padding-x};\\n  --#{$prefix}popover-body-padding-y: #{$popover-body-padding-y};\\n  --#{$prefix}popover-body-color: #{$popover-body-color};\\n  --#{$prefix}popover-arrow-width: #{$popover-arrow-width};\\n  --#{$prefix}popover-arrow-height: #{$popover-arrow-height};\\n  --#{$prefix}popover-arrow-border: var(--#{$prefix}popover-border-color);\\n  // scss-docs-end popover-css-vars\\n\\n  z-index: var(--#{$prefix}popover-zindex);\\n  display: block;\\n  max-width: var(--#{$prefix}popover-max-width);\\n  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\\n  // So reset our font and text properties to avoid inheriting weird values.\\n  @include reset-text();\\n  @include font-size(var(--#{$prefix}popover-font-size));\\n  // Allow breaking very long words so they don't overflow the popover's bounds\\n  word-wrap: break-word;\\n  background-color: var(--#{$prefix}popover-bg);\\n  background-clip: padding-box;\\n  border: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);\\n  @include border-radius(var(--#{$prefix}popover-border-radius));\\n  @include box-shadow(var(--#{$prefix}popover-box-shadow));\\n\\n  .popover-arrow {\\n    display: block;\\n    width: var(--#{$prefix}popover-arrow-width);\\n    height: var(--#{$prefix}popover-arrow-height);\\n\\n    &::before,\\n    &::after {\\n      position: absolute;\\n      display: block;\\n      content: \\\"\\\";\\n      border-color: transparent;\\n      border-style: solid;\\n      border-width: 0;\\n    }\\n  }\\n}\\n\\n.bs-popover-top {\\n  > .popover-arrow {\\n    bottom: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list\\n\\n    &::before,\\n    &::after {\\n      border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list\\n    }\\n\\n    &::before {\\n      bottom: 0;\\n      border-top-color: var(--#{$prefix}popover-arrow-border);\\n    }\\n\\n    &::after {\\n      bottom: var(--#{$prefix}popover-border-width);\\n      border-top-color: var(--#{$prefix}popover-bg);\\n    }\\n  }\\n}\\n\\n/* rtl:begin:ignore */\\n.bs-popover-end {\\n  > .popover-arrow {\\n    left: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list\\n    width: var(--#{$prefix}popover-arrow-height);\\n    height: var(--#{$prefix}popover-arrow-width);\\n\\n    &::before,\\n    &::after {\\n      border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list\\n    }\\n\\n    &::before {\\n      left: 0;\\n      border-right-color: var(--#{$prefix}popover-arrow-border);\\n    }\\n\\n    &::after {\\n      left: var(--#{$prefix}popover-border-width);\\n      border-right-color: var(--#{$prefix}popover-bg);\\n    }\\n  }\\n}\\n\\n/* rtl:end:ignore */\\n\\n.bs-popover-bottom {\\n  > .popover-arrow {\\n    top: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list\\n\\n    &::before,\\n    &::after {\\n      border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list\\n    }\\n\\n    &::before {\\n      top: 0;\\n      border-bottom-color: var(--#{$prefix}popover-arrow-border);\\n    }\\n\\n    &::after {\\n      top: var(--#{$prefix}popover-border-width);\\n      border-bottom-color: var(--#{$prefix}popover-bg);\\n    }\\n  }\\n\\n  // This will remove the popover-header's border just below the arrow\\n  .popover-header::before {\\n    position: absolute;\\n    top: 0;\\n    left: 50%;\\n    display: block;\\n    width: var(--#{$prefix}popover-arrow-width);\\n    margin-left: calc(-.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list\\n    content: \\\"\\\";\\n    border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg);\\n  }\\n}\\n\\n/* rtl:begin:ignore */\\n.bs-popover-start {\\n  > .popover-arrow {\\n    right: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list\\n    width: var(--#{$prefix}popover-arrow-height);\\n    height: var(--#{$prefix}popover-arrow-width);\\n\\n    &::before,\\n    &::after {\\n      border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list\\n    }\\n\\n    &::before {\\n      right: 0;\\n      border-left-color: var(--#{$prefix}popover-arrow-border);\\n    }\\n\\n    &::after {\\n      right: var(--#{$prefix}popover-border-width);\\n      border-left-color: var(--#{$prefix}popover-bg);\\n    }\\n  }\\n}\\n\\n/* rtl:end:ignore */\\n\\n.bs-popover-auto {\\n  &[data-popper-placement^=\\\"top\\\"] {\\n    @extend .bs-popover-top;\\n  }\\n  &[data-popper-placement^=\\\"right\\\"] {\\n    @extend .bs-popover-end;\\n  }\\n  &[data-popper-placement^=\\\"bottom\\\"] {\\n    @extend .bs-popover-bottom;\\n  }\\n  &[data-popper-placement^=\\\"left\\\"] {\\n    @extend .bs-popover-start;\\n  }\\n}\\n\\n// Offset the popover to account for the popover arrow\\n.popover-header {\\n  padding: var(--#{$prefix}popover-header-padding-y) var(--#{$prefix}popover-header-padding-x);\\n  margin-bottom: 0; // Reset the default from Reboot\\n  @include font-size(var(--#{$prefix}popover-header-font-size));\\n  color: var(--#{$prefix}popover-header-color);\\n  background-color: var(--#{$prefix}popover-header-bg);\\n  border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);\\n  @include border-top-radius(var(--#{$prefix}popover-inner-border-radius));\\n\\n  &:empty {\\n    display: none;\\n  }\\n}\\n\\n.popover-body {\\n  padding: var(--#{$prefix}popover-body-padding-y) var(--#{$prefix}popover-body-padding-x);\\n  color: var(--#{$prefix}popover-body-color);\\n}\\n\",\"// Notes on the classes:\\n//\\n// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically)\\n//    even when their scroll action started on a carousel, but for compatibility (with Firefox)\\n//    we're preventing all actions instead\\n// 2. The .carousel-item-start and .carousel-item-end is used to indicate where\\n//    the active slide is heading.\\n// 3. .active.carousel-item is the current slide.\\n// 4. .active.carousel-item-start and .active.carousel-item-end is the current\\n//    slide in its in-transition state. Only one of these occurs at a time.\\n// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end\\n//    is the upcoming slide in transition.\\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  @include clearfix();\\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  @include transition($carousel-transition);\\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\\n//\\n// Alternate transitions\\n//\\n\\n.carousel-fade {\\n  .carousel-item {\\n    opacity: 0;\\n    transition-property: opacity;\\n    transform: none;\\n  }\\n\\n  .carousel-item.active,\\n  .carousel-item-next.carousel-item-start,\\n  .carousel-item-prev.carousel-item-end {\\n    z-index: 1;\\n    opacity: 1;\\n  }\\n\\n  .active.carousel-item-start,\\n  .active.carousel-item-end {\\n    z-index: 0;\\n    opacity: 0;\\n    @include transition(opacity 0s $carousel-transition-duration);\\n  }\\n}\\n\\n\\n//\\n// Left/right controls for nav\\n//\\n\\n.carousel-control-prev,\\n.carousel-control-next {\\n  position: absolute;\\n  top: 0;\\n  bottom: 0;\\n  z-index: 1;\\n  // Use flex for alignment (1-3)\\n  display: flex; // 1. allow flex styles\\n  align-items: center; // 2. vertically center contents\\n  justify-content: center; // 3. horizontally center contents\\n  width: $carousel-control-width;\\n  padding: 0;\\n  color: $carousel-control-color;\\n  text-align: center;\\n  background: none;\\n  border: 0;\\n  opacity: $carousel-control-opacity;\\n  @include transition($carousel-control-transition);\\n\\n  // Hover/focus state\\n  &:hover,\\n  &:focus {\\n    color: $carousel-control-color;\\n    text-decoration: none;\\n    outline: 0;\\n    opacity: $carousel-control-hover-opacity;\\n  }\\n}\\n.carousel-control-prev {\\n  left: 0;\\n  background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);\\n}\\n.carousel-control-next {\\n  right: 0;\\n  background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);\\n}\\n\\n// Icons for within\\n.carousel-control-prev-icon,\\n.carousel-control-next-icon {\\n  display: inline-block;\\n  width: $carousel-control-icon-width;\\n  height: $carousel-control-icon-width;\\n  background-repeat: no-repeat;\\n  background-position: 50%;\\n  background-size: 100% 100%;\\n}\\n\\n/* rtl:options: {\\n  \\\"autoRename\\\": true,\\n  \\\"stringMap\\\":[ {\\n    \\\"name\\\"    : \\\"prev-next\\\",\\n    \\\"search\\\"  : \\\"prev\\\",\\n    \\\"replace\\\" : \\\"next\\\"\\n  } ]\\n} */\\n.carousel-control-prev-icon {\\n  background-image: escape-svg($carousel-control-prev-icon-bg);\\n}\\n.carousel-control-next-icon {\\n  background-image: escape-svg($carousel-control-next-icon-bg);\\n}\\n\\n// Optional indicator pips/controls\\n//\\n// Add a container (such as a list) with the following class and add an item (ideally a focusable control,\\n// like a button) with data-bs-target for each slide your carousel holds.\\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  // Use the .carousel-control's width as margin so we don't overlay those\\n  margin-right: $carousel-control-width;\\n  margin-bottom: 1rem;\\n  margin-left: $carousel-control-width;\\n  list-style: none;\\n\\n  [data-bs-target] {\\n    box-sizing: content-box;\\n    flex: 0 1 auto;\\n    width: $carousel-indicator-width;\\n    height: $carousel-indicator-height;\\n    padding: 0;\\n    margin-right: $carousel-indicator-spacer;\\n    margin-left: $carousel-indicator-spacer;\\n    text-indent: -999px;\\n    cursor: pointer;\\n    background-color: $carousel-indicator-active-bg;\\n    background-clip: padding-box;\\n    border: 0;\\n    // Use transparent borders to increase the hit area by 10px on top and bottom.\\n    border-top: $carousel-indicator-hit-area-height solid transparent;\\n    border-bottom: $carousel-indicator-hit-area-height solid transparent;\\n    opacity: $carousel-indicator-opacity;\\n    @include transition($carousel-indicator-transition);\\n  }\\n\\n  .active {\\n    opacity: $carousel-indicator-active-opacity;\\n  }\\n}\\n\\n\\n// Optional captions\\n//\\n//\\n\\n.carousel-caption {\\n  position: absolute;\\n  right: (100% - $carousel-caption-width) * .5;\\n  bottom: $carousel-caption-spacer;\\n  left: (100% - $carousel-caption-width) * .5;\\n  padding-top: $carousel-caption-padding-y;\\n  padding-bottom: $carousel-caption-padding-y;\\n  color: $carousel-caption-color;\\n  text-align: center;\\n}\\n\\n// Dark mode carousel\\n\\n@mixin carousel-dark() {\\n  .carousel-control-prev-icon,\\n  .carousel-control-next-icon {\\n    filter: $carousel-dark-control-icon-filter;\\n  }\\n\\n  .carousel-indicators [data-bs-target] {\\n    background-color: $carousel-dark-indicator-active-bg;\\n  }\\n\\n  .carousel-caption {\\n    color: $carousel-dark-caption-color;\\n  }\\n}\\n\\n.carousel-dark {\\n  @include carousel-dark();\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .carousel {\\n      @include carousel-dark();\\n    }\\n  }\\n}\\n\",\"// scss-docs-start clearfix\\n@mixin clearfix() {\\n  &::after {\\n    display: block;\\n    clear: both;\\n    content: \\\"\\\";\\n  }\\n}\\n// scss-docs-end clearfix\\n\",\"//\\n// Rotating border\\n//\\n\\n.spinner-grow,\\n.spinner-border {\\n  display: inline-block;\\n  width: var(--#{$prefix}spinner-width);\\n  height: var(--#{$prefix}spinner-height);\\n  vertical-align: var(--#{$prefix}spinner-vertical-align);\\n  // stylelint-disable-next-line property-disallowed-list\\n  border-radius: 50%;\\n  animation: var(--#{$prefix}spinner-animation-speed) linear infinite var(--#{$prefix}spinner-animation-name);\\n}\\n\\n// scss-docs-start spinner-border-keyframes\\n@keyframes spinner-border {\\n  to { transform: rotate(360deg) #{\\\"/* rtl:ignore */\\\"}; }\\n}\\n// scss-docs-end spinner-border-keyframes\\n\\n.spinner-border {\\n  // scss-docs-start spinner-border-css-vars\\n  --#{$prefix}spinner-width: #{$spinner-width};\\n  --#{$prefix}spinner-height: #{$spinner-height};\\n  --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};\\n  --#{$prefix}spinner-border-width: #{$spinner-border-width};\\n  --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};\\n  --#{$prefix}spinner-animation-name: spinner-border;\\n  // scss-docs-end spinner-border-css-vars\\n\\n  border: var(--#{$prefix}spinner-border-width) solid currentcolor;\\n  border-right-color: transparent;\\n}\\n\\n.spinner-border-sm {\\n  // scss-docs-start spinner-border-sm-css-vars\\n  --#{$prefix}spinner-width: #{$spinner-width-sm};\\n  --#{$prefix}spinner-height: #{$spinner-height-sm};\\n  --#{$prefix}spinner-border-width: #{$spinner-border-width-sm};\\n  // scss-docs-end spinner-border-sm-css-vars\\n}\\n\\n//\\n// Growing circle\\n//\\n\\n// scss-docs-start spinner-grow-keyframes\\n@keyframes spinner-grow {\\n  0% {\\n    transform: scale(0);\\n  }\\n  50% {\\n    opacity: 1;\\n    transform: none;\\n  }\\n}\\n// scss-docs-end spinner-grow-keyframes\\n\\n.spinner-grow {\\n  // scss-docs-start spinner-grow-css-vars\\n  --#{$prefix}spinner-width: #{$spinner-width};\\n  --#{$prefix}spinner-height: #{$spinner-height};\\n  --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};\\n  --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};\\n  --#{$prefix}spinner-animation-name: spinner-grow;\\n  // scss-docs-end spinner-grow-css-vars\\n\\n  background-color: currentcolor;\\n  opacity: 0;\\n}\\n\\n.spinner-grow-sm {\\n  --#{$prefix}spinner-width: #{$spinner-width-sm};\\n  --#{$prefix}spinner-height: #{$spinner-height-sm};\\n}\\n\\n@if $enable-reduced-motion {\\n  @media (prefers-reduced-motion: reduce) {\\n    .spinner-border,\\n    .spinner-grow {\\n      --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed * 2};\\n    }\\n  }\\n}\\n\",\"// stylelint-disable function-disallowed-list\\n\\n%offcanvas-css-vars {\\n  // scss-docs-start offcanvas-css-vars\\n  --#{$prefix}offcanvas-zindex: #{$zindex-offcanvas};\\n  --#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width};\\n  --#{$prefix}offcanvas-height: #{$offcanvas-vertical-height};\\n  --#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x};\\n  --#{$prefix}offcanvas-padding-y: #{$offcanvas-padding-y};\\n  --#{$prefix}offcanvas-color: #{$offcanvas-color};\\n  --#{$prefix}offcanvas-bg: #{$offcanvas-bg-color};\\n  --#{$prefix}offcanvas-border-width: #{$offcanvas-border-width};\\n  --#{$prefix}offcanvas-border-color: #{$offcanvas-border-color};\\n  --#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow};\\n  --#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out};\\n  --#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height};\\n  // scss-docs-end offcanvas-css-vars\\n}\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  $next: breakpoint-next($breakpoint, $grid-breakpoints);\\n  $infix: breakpoint-infix($next, $grid-breakpoints);\\n\\n  .offcanvas#{$infix} {\\n    @extend %offcanvas-css-vars;\\n  }\\n}\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  $next: breakpoint-next($breakpoint, $grid-breakpoints);\\n  $infix: breakpoint-infix($next, $grid-breakpoints);\\n\\n  .offcanvas#{$infix} {\\n    @include media-breakpoint-down($next) {\\n      position: fixed;\\n      bottom: 0;\\n      z-index: var(--#{$prefix}offcanvas-zindex);\\n      display: flex;\\n      flex-direction: column;\\n      max-width: 100%;\\n      color: var(--#{$prefix}offcanvas-color);\\n      visibility: hidden;\\n      background-color: var(--#{$prefix}offcanvas-bg);\\n      background-clip: padding-box;\\n      outline: 0;\\n      @include box-shadow(var(--#{$prefix}offcanvas-box-shadow));\\n      @include transition(var(--#{$prefix}offcanvas-transition));\\n\\n      &.offcanvas-start {\\n        top: 0;\\n        left: 0;\\n        width: var(--#{$prefix}offcanvas-width);\\n        border-right: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);\\n        transform: translateX(-100%);\\n      }\\n\\n      &.offcanvas-end {\\n        top: 0;\\n        right: 0;\\n        width: var(--#{$prefix}offcanvas-width);\\n        border-left: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);\\n        transform: translateX(100%);\\n      }\\n\\n      &.offcanvas-top {\\n        top: 0;\\n        right: 0;\\n        left: 0;\\n        height: var(--#{$prefix}offcanvas-height);\\n        max-height: 100%;\\n        border-bottom: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);\\n        transform: translateY(-100%);\\n      }\\n\\n      &.offcanvas-bottom {\\n        right: 0;\\n        left: 0;\\n        height: var(--#{$prefix}offcanvas-height);\\n        max-height: 100%;\\n        border-top: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);\\n        transform: translateY(100%);\\n      }\\n\\n      &.showing,\\n      &.show:not(.hiding) {\\n        transform: none;\\n      }\\n\\n      &.showing,\\n      &.hiding,\\n      &.show {\\n        visibility: visible;\\n      }\\n    }\\n\\n    @if not ($infix == \\\"\\\") {\\n      @include media-breakpoint-up($next) {\\n        --#{$prefix}offcanvas-height: auto;\\n        --#{$prefix}offcanvas-border-width: 0;\\n        background-color: transparent !important; // stylelint-disable-line declaration-no-important\\n\\n        .offcanvas-header {\\n          display: none;\\n        }\\n\\n        .offcanvas-body {\\n          display: flex;\\n          flex-grow: 0;\\n          padding: 0;\\n          overflow-y: visible;\\n          // Reset `background-color` in case `.bg-*` classes are used in offcanvas\\n          background-color: transparent !important; // stylelint-disable-line declaration-no-important\\n        }\\n      }\\n    }\\n  }\\n}\\n\\n.offcanvas-backdrop {\\n  @include overlay-backdrop($zindex-offcanvas-backdrop, $offcanvas-backdrop-bg, $offcanvas-backdrop-opacity);\\n}\\n\\n.offcanvas-header {\\n  display: flex;\\n  align-items: center;\\n  justify-content: space-between;\\n  padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x);\\n\\n  .btn-close {\\n    padding: calc(var(--#{$prefix}offcanvas-padding-y) * .5) calc(var(--#{$prefix}offcanvas-padding-x) * .5);\\n    margin-top: calc(-.5 * var(--#{$prefix}offcanvas-padding-y));\\n    margin-right: calc(-.5 * var(--#{$prefix}offcanvas-padding-x));\\n    margin-bottom: calc(-.5 * var(--#{$prefix}offcanvas-padding-y));\\n  }\\n}\\n\\n.offcanvas-title {\\n  margin-bottom: 0;\\n  line-height: var(--#{$prefix}offcanvas-title-line-height);\\n}\\n\\n.offcanvas-body {\\n  flex-grow: 1;\\n  padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x);\\n  overflow-y: auto;\\n}\\n\",\".placeholder {\\n  display: inline-block;\\n  min-height: 1em;\\n  vertical-align: middle;\\n  cursor: wait;\\n  background-color: currentcolor;\\n  opacity: $placeholder-opacity-max;\\n\\n  &.btn::before {\\n    display: inline-block;\\n    content: \\\"\\\";\\n  }\\n}\\n\\n// Sizing\\n.placeholder-xs {\\n  min-height: .6em;\\n}\\n\\n.placeholder-sm {\\n  min-height: .8em;\\n}\\n\\n.placeholder-lg {\\n  min-height: 1.2em;\\n}\\n\\n// Animation\\n.placeholder-glow {\\n  .placeholder {\\n    animation: placeholder-glow 2s ease-in-out infinite;\\n  }\\n}\\n\\n@keyframes placeholder-glow {\\n  50% {\\n    opacity: $placeholder-opacity-min;\\n  }\\n}\\n\\n.placeholder-wave {\\n  mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 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\",\"// stylelint-disable function-name-case\\n\\n// All-caps `RGBA()` function used because of this Sass bug: https://github.com/sass/node-sass/issues/2251\\n@each $color, $value in $theme-colors {\\n  $color-rgb: to-rgb($value);\\n  .text-bg-#{$color} {\\n    color: color-contrast($value) if($enable-important-utilities, !important, null);\\n    background-color: RGBA($color-rgb, var(--#{$prefix}bg-opacity, 1)) if($enable-important-utilities, !important, null);\\n  }\\n}\\n\",\"@each $color, $value in $theme-colors {\\n  .link-#{$color} {\\n    color: $value if($enable-important-utilities, !important, null);\\n\\n    @if $link-shade-percentage != 0 {\\n      &:hover,\\n      &:focus {\\n        color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage)) if($enable-important-utilities, !important, null);\\n      }\\n    }\\n  }\\n}\\n\",\"// Credit: Nicolas Gallagher and SUIT CSS.\\n\\n.ratio {\\n  position: relative;\\n  width: 100%;\\n\\n  &::before {\\n    display: block;\\n    padding-top: var(--#{$prefix}aspect-ratio);\\n    content: \\\"\\\";\\n  }\\n\\n  > * {\\n    position: absolute;\\n    top: 0;\\n    left: 0;\\n    width: 100%;\\n    height: 100%;\\n  }\\n}\\n\\n@each $key, $ratio in $aspect-ratios {\\n  .ratio-#{$key} {\\n    --#{$prefix}aspect-ratio: #{$ratio};\\n  }\\n}\\n\",\"// Shorthand\\n\\n.fixed-top {\\n  position: fixed;\\n  top: 0;\\n  right: 0;\\n  left: 0;\\n  z-index: $zindex-fixed;\\n}\\n\\n.fixed-bottom {\\n  position: fixed;\\n  right: 0;\\n  bottom: 0;\\n  left: 0;\\n  z-index: $zindex-fixed;\\n}\\n\\n// Responsive sticky top and bottom\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  @include media-breakpoint-up($breakpoint) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    .sticky#{$infix}-top {\\n      position: sticky;\\n      top: 0;\\n      z-index: $zindex-sticky;\\n    }\\n\\n    .sticky#{$infix}-bottom {\\n      position: sticky;\\n      bottom: 0;\\n      z-index: $zindex-sticky;\\n    }\\n  }\\n}\\n\",\"// scss-docs-start stacks\\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// scss-docs-end stacks\\n\",\"//\\n// Visually hidden\\n//\\n\\n.visually-hidden,\\n.visually-hidden-focusable:not(:focus):not(:focus-within) {\\n  @include visually-hidden();\\n}\\n\",\"// stylelint-disable declaration-no-important\\n\\n// Hide content visually while keeping it accessible to assistive technologies\\n//\\n// See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/\\n// See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/\\n\\n@mixin visually-hidden() {\\n  position: absolute !important;\\n  width: 1px !important;\\n  height: 1px !important;\\n  padding: 0 !important;\\n  margin: -1px !important; // Fix for https://github.com/twbs/bootstrap/issues/25686\\n  overflow: hidden !important;\\n  clip: rect(0, 0, 0, 0) !important;\\n  white-space: nowrap !important;\\n  border: 0 !important;\\n}\\n\\n// Use to only display content when it's focused, or one of its child elements is focused\\n// (i.e. when focus is within the element/container that the class was applied to)\\n//\\n// Useful for \\\"Skip to main content\\\" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\\n\\n@mixin visually-hidden-focusable() {\\n  &:not(:focus):not(:focus-within) {\\n    @include visually-hidden();\\n  }\\n}\\n\",\"//\\n// Stretched link\\n//\\n\\n.stretched-link {\\n  &::#{$stretched-link-pseudo-element} {\\n    position: absolute;\\n    top: 0;\\n    right: 0;\\n    bottom: 0;\\n    left: 0;\\n    z-index: $stretched-link-z-index;\\n    content: \\\"\\\";\\n  }\\n}\\n\",\"//\\n// Text truncation\\n//\\n\\n.text-truncate {\\n  @include text-truncate();\\n}\\n\",\"// Text truncate\\n// Requires inline-block or block for proper styling\\n\\n@mixin text-truncate() {\\n  overflow: hidden;\\n  text-overflow: ellipsis;\\n  white-space: nowrap;\\n}\\n\",\".vr {\\n  display: inline-block;\\n  align-self: stretch;\\n  width: 1px;\\n  min-height: 1em;\\n  background-color: currentcolor;\\n  opacity: $hr-opacity;\\n}\\n\",\"// Utility generator\\n// Used to generate utilities & print utilities\\n@mixin generate-utility($utility, $infix, $is-rfs-media-query: false) {\\n  $values: map-get($utility, values);\\n\\n  // If the values are a list or string, convert it into a map\\n  @if type-of($values) == \\\"string\\\" or type-of(nth($values, 1)) != \\\"list\\\" {\\n    $values: zip($values, $values);\\n  }\\n\\n  @each $key, $value in $values {\\n    $properties: map-get($utility, property);\\n\\n    // Multiple properties are possible, for example with vertical or horizontal margins or paddings\\n    @if type-of($properties) == \\\"string\\\" {\\n      $properties: append((), $properties);\\n    }\\n\\n    // Use custom class if present\\n    $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));\\n    $property-class: if($property-class == null, \\\"\\\", $property-class);\\n\\n    // Use custom CSS variable name if present, otherwise default to `class`\\n    $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class));\\n\\n    // State params to generate pseudo-classes\\n    $state: if(map-has-key($utility, state), map-get($utility, state), ());\\n\\n    $infix: if($property-class == \\\"\\\" and str-slice($infix, 1, 1) == \\\"-\\\", str-slice($infix, 2), $infix);\\n\\n    // Don't prefix if value key is null (e.g. with shadow class)\\n    $property-class-modifier: if($key, if($property-class == \\\"\\\" and $infix == \\\"\\\", \\\"\\\", \\\"-\\\") + $key, \\\"\\\");\\n\\n    @if map-get($utility, rfs) {\\n      // Inside the media query\\n      @if $is-rfs-media-query {\\n        $val: rfs-value($value);\\n\\n        // Do not render anything if fluid and non fluid values are the same\\n        $value: if($val == rfs-fluid-value($value), null, $val);\\n      }\\n      @else {\\n        $value: rfs-fluid-value($value);\\n      }\\n    }\\n\\n    $is-css-var: map-get($utility, css-var);\\n    $is-local-vars: map-get($utility, local-vars);\\n    $is-rtl: map-get($utility, rtl);\\n\\n    @if $value != null {\\n      @if $is-rtl == false {\\n        /* rtl:begin:remove */\\n      }\\n\\n      @if $is-css-var {\\n        .#{$property-class + $infix + $property-class-modifier} {\\n          --#{$prefix}#{$css-variable-name}: #{$value};\\n        }\\n\\n        @each $pseudo in $state {\\n          .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\\n            --#{$prefix}#{$css-variable-name}: #{$value};\\n          }\\n        }\\n      } @else {\\n        .#{$property-class + $infix + $property-class-modifier} {\\n          @each $property in $properties {\\n            @if $is-local-vars {\\n              @each $local-var, $variable in $is-local-vars {\\n                --#{$prefix}#{$local-var}: #{$variable};\\n              }\\n            }\\n            #{$property}: $value if($enable-important-utilities, !important, null);\\n          }\\n        }\\n\\n        @each $pseudo in $state {\\n          .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\\n            @each $property in $properties {\\n              @if $is-local-vars {\\n                @each $local-var, $variable in $is-local-vars {\\n                  --#{$prefix}#{$local-var}: #{$variable};\\n                }\\n              }\\n              #{$property}: $value if($enable-important-utilities, !important, null);\\n            }\\n          }\\n        }\\n      }\\n\\n      @if $is-rtl == false {\\n        /* rtl:end:remove */\\n      }\\n    }\\n  }\\n}\\n\",\"// Loop over each breakpoint\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n\\n  // Generate media query if needed\\n  @include media-breakpoint-up($breakpoint) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    // Loop over each utility property\\n    @each $key, $utility in $utilities {\\n      // The utility can be disabled with `false`, thus check if the utility is a map first\\n      // Only proceed if responsive media queries are enabled or if it's the base media query\\n      @if type-of($utility) == \\\"map\\\" and (map-get($utility, responsive) or $infix == \\\"\\\") {\\n        @include generate-utility($utility, $infix);\\n      }\\n    }\\n  }\\n}\\n\\n// RFS rescaling\\n@media (min-width: $rfs-mq-value) {\\n  @each $breakpoint in map-keys($grid-breakpoints) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {\\n      // Loop over each utility property\\n      @each $key, $utility in $utilities {\\n        // The utility can be disabled with `false`, thus check if the utility is a map first\\n        // Only proceed if responsive media queries are enabled or if it's the base media query\\n        @if type-of($utility) == \\\"map\\\" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == \\\"\\\") {\\n          @include generate-utility($utility, $infix, true);\\n        }\\n      }\\n    }\\n  }\\n}\\n\\n\\n// Print utilities\\n@media print {\\n  @each $key, $utility in $utilities {\\n    // The utility can be disabled with `false`, thus check if the utility is a map first\\n    // Then check if the utility needs print styles\\n    @if type-of($utility) == \\\"map\\\" and map-get($utility, print) == true {\\n      @include generate-utility($utility, \\\"-print\\\");\\n    }\\n  }\\n}\\n\"]}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/bootstrap-5.3.0/css/bootstrap.rtl.min.css",
    "content": "@charset \"UTF-8\";/*!\n * Bootstrap  v5.3.0-alpha1 (https://getbootstrap.com/)\n * Copyright 2011-2022 The Bootstrap Authors\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */: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:#0a58ca;--bs-secondary-text:#6c757d;--bs-success-text:#146c43;--bs-info-text:#087990;--bs-warning-text:#997404;--bs-danger-text:#b02a37;--bs-light-text:#6c757d;--bs-dark-text:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#f8f9fa;--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:#e9ecef;--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-body-color-rgb:33,37,41;--bs-body-bg-rgb:255,255,255;--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-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-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--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-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-2xl:2rem;--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(var(--bs-body-color-rgb), 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(var(--bs-body-color-rgb), 0.075);--bs-emphasis-color:#000;--bs-form-control-bg:var(--bs-body-bg);--bs-form-control-disabled-bg:var(--bs-secondary-bg);--bs-highlight-bg:#fff3cd;--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}[data-bs-theme=dark]{--bs-body-color:#adb5bd;--bs-body-color-rgb:173,181,189;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#f8f9fa;--bs-emphasis-color-rgb:248,249,250;--bs-secondary-color:rgba(173, 181, 189, 0.75);--bs-secondary-color-rgb:173,181,189;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(173, 181, 189, 0.5);--bs-tertiary-color-rgb:173,181,189;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-emphasis-color:#fff;--bs-primary-text:#6ea8fe;--bs-secondary-text:#dee2e6;--bs-success-text:#75b798;--bs-info-text:#6edff6;--bs-warning-text:#ffda6a;--bs-danger-text:#ea868f;--bs-light-text:#f8f9fa;--bs-dark-text:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#212529;--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:#495057;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#055160;--bs-warning-border-subtle:#664d03;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:#fff;--bs-link-color:#6ea8fe;--bs-link-hover-color:#9ec5fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:158,197,254;--bs-code-color:#e685b5;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15)}*,::after,::before{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:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color,inherit)}.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 + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .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-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.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}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{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:right}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:right;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:right}::-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]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{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-right:0;list-style:none}.list-inline{padding-right:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-left:.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-left:calc(var(--bs-gutter-x) * .5);padding-right:calc(var(--bs-gutter-x) * .5);margin-left:auto;margin-right: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}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-left:calc(-.5 * var(--bs-gutter-x));margin-right:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-left:calc(var(--bs-gutter-x) * .5);padding-right: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.3333333333%}.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.6666666667%}.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-right:8.33333333%}.offset-2{margin-right:16.66666667%}.offset-3{margin-right:25%}.offset-4{margin-right:33.33333333%}.offset-5{margin-right:41.66666667%}.offset-6{margin-right:50%}.offset-7{margin-right:58.33333333%}.offset-8{margin-right:66.66666667%}.offset-9{margin-right:75%}.offset-10{margin-right:83.33333333%}.offset-11{margin-right: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.3333333333%}.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.6666666667%}.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-right:0}.offset-sm-1{margin-right:8.33333333%}.offset-sm-2{margin-right:16.66666667%}.offset-sm-3{margin-right:25%}.offset-sm-4{margin-right:33.33333333%}.offset-sm-5{margin-right:41.66666667%}.offset-sm-6{margin-right:50%}.offset-sm-7{margin-right:58.33333333%}.offset-sm-8{margin-right:66.66666667%}.offset-sm-9{margin-right:75%}.offset-sm-10{margin-right:83.33333333%}.offset-sm-11{margin-right: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.3333333333%}.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.6666666667%}.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-right:0}.offset-md-1{margin-right:8.33333333%}.offset-md-2{margin-right:16.66666667%}.offset-md-3{margin-right:25%}.offset-md-4{margin-right:33.33333333%}.offset-md-5{margin-right:41.66666667%}.offset-md-6{margin-right:50%}.offset-md-7{margin-right:58.33333333%}.offset-md-8{margin-right:66.66666667%}.offset-md-9{margin-right:75%}.offset-md-10{margin-right:83.33333333%}.offset-md-11{margin-right: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.3333333333%}.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.6666666667%}.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-right:0}.offset-lg-1{margin-right:8.33333333%}.offset-lg-2{margin-right:16.66666667%}.offset-lg-3{margin-right:25%}.offset-lg-4{margin-right:33.33333333%}.offset-lg-5{margin-right:41.66666667%}.offset-lg-6{margin-right:50%}.offset-lg-7{margin-right:58.33333333%}.offset-lg-8{margin-right:66.66666667%}.offset-lg-9{margin-right:75%}.offset-lg-10{margin-right:83.33333333%}.offset-lg-11{margin-right: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.3333333333%}.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.6666666667%}.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-right:0}.offset-xl-1{margin-right:8.33333333%}.offset-xl-2{margin-right:16.66666667%}.offset-xl-3{margin-right:25%}.offset-xl-4{margin-right:33.33333333%}.offset-xl-5{margin-right:41.66666667%}.offset-xl-6{margin-right:50%}.offset-xl-7{margin-right:58.33333333%}.offset-xl-8{margin-right:66.66666667%}.offset-xl-9{margin-right:75%}.offset-xl-10{margin-right:83.33333333%}.offset-xl-11{margin-right: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.3333333333%}.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.6666666667%}.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-right:0}.offset-xxl-1{margin-right:8.33333333%}.offset-xxl-2{margin-right:16.66666667%}.offset-xxl-3{margin-right:25%}.offset-xxl-4{margin-right:33.33333333%}.offset-xxl-5{margin-right:41.66666667%}.offset-xxl-6{margin-right:50%}.offset-xxl-7{margin-right:58.33333333%}.offset-xxl-8{margin-right:66.66666667%}.offset-xxl-9{margin-right:75%}.offset-xxl-10{margin-right:83.33333333%}.offset-xxl-11{margin-right: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:var(--bs-body-color);--bs-table-bg:transparent;--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-body-color);--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:var(--bs-body-color);--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:var(--bs-body-color);--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:var(--bs-table-color);vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px 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-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#bacbe6;--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:#cbccce;--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:#bcd0c7;--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:#badce3;--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:#e6dbb9;--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:#dfc2c4;--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:#dfe0e1;--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:#373b3e;--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);background-color:var(--bs-form-control-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.375rem;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-form-control-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.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-form-control-disabled-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-left:0;padding-right:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:.25rem}.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:.5rem}.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:.375rem}.form-control-color::-webkit-color-swatch{border-radius:.375rem}.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 .75rem .375rem 2.25rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);background-color:var(--bs-form-control-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:left .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@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-left:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-form-control-disabled-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-right:.5rem;font-size:.875rem;border-radius:.25rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-right:1rem;font-size:1.25rem;border-radius:.5rem}[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='%23adb5bd' 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-right:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:right;margin-right:-1.5em}.form-check-reverse{padding-left:1.5em;padding-right:0;text-align:left}.form-check-reverse .form-check-input{float:left;margin-left:-1.5em;margin-right:0}.form-check-input{--bs-form-check-bg:var(--bs-form-control-bg);width:1em;height:1em;margin-top:.25em;vertical-align:top;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-appearance:none;-moz-appearance:none;appearance:none;-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-right: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-right:-2.5em;background-image:var(--bs-form-switch-bg);background-position:right 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:left 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-left:2.5em;padding-right:0}.form-switch.form-check-reverse .form-check-input{margin-left:-2.5em;margin-right:0}.form-check-inline{display:inline-block;margin-left: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;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.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;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;-webkit-appearance:none;appearance:none}@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-tertiary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;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;-moz-appearance:none;appearance:none}@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-tertiary-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::before:not(.form-control:disabled){position:absolute;top:var(--bs-border-width);right:var(--bs-border-width);width:calc(100% - (calc(calc(.375em + .1875rem) + calc(.75em + .375rem))));height:1.875em;content:\"\";background-color:var(--bs-form-control-bg);border-radius:.375rem}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;right:0;width:100%;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:100% 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{opacity:.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{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(-.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.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{color:#6c757d}.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:.375rem}.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:.5rem}.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:.25rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-left: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-left-radius:0;border-bottom-left-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-left-radius:0;border-bottom-left-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-right:calc(var(--bs-border-width) * -1);border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-success-text)}.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-success);padding-left: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:left 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-success);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-left:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) left calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-success)}.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-left:4.125rem;background-position:left .75rem center,center left 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-success);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-success)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-success-text)}.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-success-text)}.form-check-inline .form-check-input~.valid-feedback{margin-right:.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-danger-text)}.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-danger);padding-left: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:left 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-danger);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-left:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) left calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-danger)}.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-left:4.125rem;background-position:left .75rem center,center left 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-danger);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-danger)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-danger-text)}.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-danger-text)}.form-check-inline .form-check-input~.invalid-feedback{margin-right:.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:#212529;--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:0.375rem;--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.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:none;--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:0.5rem}.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:0.25rem}.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-right:.255em;vertical-align:.255em;content:\"\";border-top:.3em solid;border-left:.3em solid transparent;border-bottom:0;border-right:.3em solid transparent}.dropdown-toggle:empty::after{margin-right: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:0.375rem;--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(0.375rem - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);--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:#adb5bd;--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:right;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%;right:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{left:0;right:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{left:0;right:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{left:0;right:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{left:0;right:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{left:0;right:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{left:auto;right:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{left:0;right: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-right:.255em;vertical-align:.255em;content:\"\";border-top:0;border-left:.3em solid transparent;border-bottom:.3em solid;border-right:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-right:0}.dropend .dropdown-menu[data-bs-popper]{top:0;left:auto;right:100%;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-right:.255em;vertical-align:.255em;content:\"\";border-top:.3em solid transparent;border-left:0;border-bottom:.3em solid transparent;border-right:.3em solid}.dropend .dropdown-toggle:empty::after{margin-right:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;left:100%;right:auto;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-right:.255em;vertical-align:.255em;content:\"\"}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-left:.255em;vertical-align:.255em;content:\"\";border-top:.3em solid transparent;border-left:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-right: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:.375rem}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-right: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-left-radius:0;border-bottom-left-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-right-radius:0;border-bottom-right-radius:0}.dropdown-toggle-split{padding-left:.5625rem;padding-right:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-right:0}.dropstart .dropdown-toggle-split::before{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-left:.375rem;padding-right:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-left:.75rem;padding-right:.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-left-radius:0;border-bottom-right-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-right-radius:0;border-top-left-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-right: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;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.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));background:0 0;border:var(--bs-nav-tabs-border-width) solid transparent;border-top-right-radius:var(--bs-nav-tabs-border-radius);border-top-left-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-link.disabled,.nav-tabs .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.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-right-radius:0;border-top-left-radius:0}.nav-pills{--bs-nav-pills-border-radius:0.375rem;--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{background:0 0;border:0;border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.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-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:0.375rem;--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-left: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-right:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .show>.nav-link{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-left:var(--bs-navbar-nav-link-padding-x);padding-right: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-left:var(--bs-navbar-nav-link-padding-x);padding-right: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-left:var(--bs-navbar-nav-link-padding-x);padding-right: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-left:var(--bs-navbar-nav-link-padding-x);padding-right: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-left:var(--bs-navbar-nav-link-padding-x);padding-right: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-left:var(--bs-navbar-nav-link-padding-x);padding-right: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{--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{--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);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-left:0;margin-right:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-right-radius:var(--bs-card-inner-border-radius);border-top-left-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-left-radius:var(--bs-card-inner-border-radius);border-bottom-right-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-right: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-left:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-right: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-left:calc(-.5 * var(--bs-card-cap-padding-x));margin-right:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;left:0;bottom:0;right: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-right-radius:var(--bs-card-inner-border-radius);border-top-left-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-left-radius:var(--bs-card-inner-border-radius);border-bottom-right-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-right:0;border-right:0}.card-group>.card:not(:last-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:not(:first-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-right-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='%23212529'%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-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='%230a58ca'%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-focus-border-color:#86b7fe;--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);--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:right;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-right: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;border-color:var(--bs-accordion-btn-focus-border-color);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-right-radius:var(--bs-accordion-border-radius);border-top-left-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-right-radius:var(--bs-accordion-inner-border-radius);border-top-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-left-radius:var(--bs-accordion-border-radius);border-bottom-right-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-left-radius:var(--bs-accordion-inner-border-radius);border-bottom-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-left-radius:var(--bs-accordion-border-radius);border-bottom-right-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-left:0;border-right: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-button,.accordion-flush .accordion-item .accordion-button.collapsed{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-right:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:right;padding-left: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-right: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-right:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-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:0.5rem}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:0.25rem}.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:0.375rem;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:0.375rem;--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-left:3rem}.alert-dismissible .btn-close{position:absolute;top:0;left:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text);--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)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text);--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)}.alert-success{--bs-alert-color:var(--bs-success-text);--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)}.alert-info{--bs-alert-color:var(--bs-info-text);--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)}.alert-warning{--bs-alert-color:var(--bs-warning-text);--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)}.alert-danger{--bs-alert-color:var(--bs-danger-text);--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)}.alert-light{--bs-alert-color:var(--bs-light-text);--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)}.alert-dark{--bs-alert-color:var(--bs-dark-text);--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)}@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-right: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-right-radius:inherit;border-top-left-radius:inherit}.list-group-item:last-child{border-bottom-left-radius:inherit;border-bottom-right-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-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-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-right-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-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-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-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-right-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-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-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-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-right-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-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-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-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-right-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-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-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-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-right-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-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-right-radius:var(--bs-list-group-border-radius);border-top-left-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-left-radius:var(--bs-list-group-border-radius);border-bottom-right-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-right-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-right:calc(-1 * var(--bs-list-group-border-width));border-right-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);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle)}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle)}.list-group-item-primary.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-primary-text);--bs-list-group-active-border-color:var(--bs-primary-text)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle)}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle)}.list-group-item-secondary.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-secondary-text);--bs-list-group-active-border-color:var(--bs-secondary-text)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle)}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle)}.list-group-item-success.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-success-text);--bs-list-group-active-border-color:var(--bs-success-text)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle)}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle)}.list-group-item-info.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-info-text);--bs-list-group-active-border-color:var(--bs-info-text)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle)}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle)}.list-group-item-warning.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-warning-text);--bs-list-group-active-border-color:var(--bs-warning-text)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle)}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle)}.list-group-item-danger.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-danger-text);--bs-list-group-active-border-color:var(--bs-danger-text)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle)}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle)}.list-group-item-light.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-light-text);--bs-list-group-active-border-color:var(--bs-light-text)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle)}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle)}.list-group-item-dark.list-group-item-action:active{--bs-list-group-active-color:var(--bs-emphasis-color);--bs-list-group-active-bg:var(--bs-dark-text);--bs-list-group-active-border-color:var(--bs-dark-text)}.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-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-left:calc(-.5 * var(--bs-toast-padding-x));margin-right: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:0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);--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;right: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;right: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;justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-right-radius:var(--bs-modal-inner-border-radius);border-top-left-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)) auto calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x))}.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-left-radius:var(--bs-modal-inner-border-radius);border-bottom-right-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:0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15)}.modal-dialog{max-width:var(--bs-modal-width);margin-left:auto;margin-right: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;padding:var(--bs-tooltip-arrow-height);margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:right;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:0}.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:0;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:0}.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:0;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:0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: ;--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:right;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;right:50%;display:block;width:var(--bs-popover-arrow-width);margin-right: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-right-radius:var(--bs-popover-inner-border-radius);border-top-left-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:right;width:100%;margin-left:-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{right:0}.carousel-control-next{left: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-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='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-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='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;left:0;bottom:0;right:0;z-index:2;display:flex;justify-content:center;padding:0;margin-left:15%;margin-bottom:1rem;margin-right:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-left:3px;margin-right: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;left:15%;bottom:1.25rem;right: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{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target]{background-color:#000}[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-left-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:0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);--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;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-end{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%)}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-top{top:0;left:0;right: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%)}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-bottom{left:0;right: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%)}}@media (max-width:575.98px){.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}}@media (max-width:575.98px){.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;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}}@media (max-width:767.98px){.offcanvas-md.offcanvas-end{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%)}}@media (max-width:767.98px){.offcanvas-md.offcanvas-top{top:0;left:0;right: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%)}}@media (max-width:767.98px){.offcanvas-md.offcanvas-bottom{left:0;right: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%)}}@media (max-width:767.98px){.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}}@media (max-width:767.98px){.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;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-end{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%)}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-top{top:0;left:0;right: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%)}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-bottom{left:0;right: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%)}}@media (max-width:991.98px){.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}}@media (max-width:991.98px){.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;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-end{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%)}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-top{top:0;left:0;right: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%)}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-bottom{left:0;right: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%)}}@media (max-width:1199.98px){.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}}@media (max-width:1199.98px){.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;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-end{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%)}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-top{top:0;left:0;right: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%)}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-bottom{left:0;right: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%)}}@media (max-width:1399.98px){.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}}@media (max-width:1399.98px){.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;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-end{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-top{top:0;left:0;right: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{left:0;right: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;right: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;justify-content:space-between;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-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-left:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y))}.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(13,110,253,var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(108,117,125,var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(25,135,84,var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(13,202,240,var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(255,193,7,var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(220,53,69,var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(248,249,250,var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(33,37,41,var(--bs-bg-opacity,1))!important}.link-primary{color:#0d6efd!important}.link-primary:focus,.link-primary:hover{color:#0a58ca!important}.link-secondary{color:#6c757d!important}.link-secondary:focus,.link-secondary:hover{color:#565e64!important}.link-success{color:#198754!important}.link-success:focus,.link-success:hover{color:#146c43!important}.link-info{color:#0dcaf0!important}.link-info:focus,.link-info:hover{color:#3dd5f3!important}.link-warning{color:#ffc107!important}.link-warning:focus,.link-warning:hover{color:#ffcd39!important}.link-danger{color:#dc3545!important}.link-danger:focus,.link-danger:hover{color:#b02a37!important}.link-light{color:#f8f9fa!important}.link-light:focus,.link-light:hover{color:#f9fafb!important}.link-dark{color:#212529!important}.link-dark:focus,.link-dark:hover{color:#1a1e21!important}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:\"\"}.ratio>*{position:absolute;top:0;right: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;left:0;right:0;z-index:1030}.fixed-bottom{position:fixed;left:0;bottom:0;right: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){position:absolute!important;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}.stretched-link::after{position:absolute;top:0;left:0;bottom:0;right:0;z-index:1;content:\"\"}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:1px;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:right!important}.float-end{float:left!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-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:0 .5rem 1rem rgba(var(--bs-body-color-rgb),.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(var(--bs-body-color-rgb),.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(var(--bs-body-color-rgb),.175)!important}.shadow-none{box-shadow:none!important}.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{right:0!important}.start-50{right:50%!important}.start-100{right:100%!important}.end-0{left:0!important}.end-50{left:50%!important}.end-100{left: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-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-left: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-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-right: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-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{--bs-border-width:1px}.border-2{--bs-border-width:2px}.border-3{--bs-border-width:3px}.border-4{--bs-border-width:4px}.border-5{--bs-border-width:5px}.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-left:0!important;margin-right:0!important}.mx-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-3{margin-left:1rem!important;margin-right:1rem!important}.mx-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-5{margin-left:3rem!important;margin-right:3rem!important}.mx-auto{margin-left:auto!important;margin-right: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-left:0!important}.me-1{margin-left:.25rem!important}.me-2{margin-left:.5rem!important}.me-3{margin-left:1rem!important}.me-4{margin-left:1.5rem!important}.me-5{margin-left:3rem!important}.me-auto{margin-left: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-right:0!important}.ms-1{margin-right:.25rem!important}.ms-2{margin-right:.5rem!important}.ms-3{margin-right:1rem!important}.ms-4{margin-right:1.5rem!important}.ms-5{margin-right:3rem!important}.ms-auto{margin-right: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-left:0!important;padding-right:0!important}.px-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-3{padding-left:1rem!important;padding-right:1rem!important}.px-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-5{padding-left:3rem!important;padding-right: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-left:0!important}.pe-1{padding-left:.25rem!important}.pe-2{padding-left:.5rem!important}.pe-3{padding-left:1rem!important}.pe-4{padding-left:1.5rem!important}.pe-5{padding-left: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-right:0!important}.ps-1{padding-right:.25rem!important}.ps-2{padding-right:.5rem!important}.ps-3{padding-right:1rem!important}.ps-4{padding-right:1.5rem!important}.ps-5{padding-right: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:right!important}.text-end{text-align:left!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-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)!important}.text-secondary-emphasis{color:var(--bs-secondary-text)!important}.text-success-emphasis{color:var(--bs-success-text)!important}.text-info-emphasis{color:var(--bs-info-text)!important}.text-warning-emphasis{color:var(--bs-warning-text)!important}.text-danger-emphasis{color:var(--bs-danger-text)!important}.text-light-emphasis{color:var(--bs-light-text)!important}.text-dark-emphasis{color:var(--bs-dark-text)!important}.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-body-emphasis{--bs-bg-opacity:1;background-color:rgba(var(--bs-emphasis-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-2xl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-right-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-right-radius:0!important;border-top-left-radius:0!important}.rounded-top-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-right-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-right-radius:var(--bs-border-radius-2xl)!important;border-top-left-radius:var(--bs-border-radius-2xl)!important}.rounded-top-circle{border-top-right-radius:50%!important;border-top-left-radius:50%!important}.rounded-top-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-left-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-left-radius:0!important;border-bottom-left-radius:0!important}.rounded-end-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-left-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-left-radius:var(--bs-border-radius-2xl)!important;border-bottom-left-radius:var(--bs-border-radius-2xl)!important}.rounded-end-circle{border-top-left-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-end-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-left-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important}.rounded-bottom-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-left-radius:var(--bs-border-radius-2xl)!important;border-bottom-right-radius:var(--bs-border-radius-2xl)!important}.rounded-bottom-circle{border-bottom-left-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-bottom-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-right-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-right-radius:0!important;border-top-right-radius:0!important}.rounded-start-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-right-radius:var(--bs-border-radius-2xl)!important;border-top-right-radius:var(--bs-border-radius-2xl)!important}.rounded-start-circle{border-bottom-right-radius:50%!important;border-top-right-radius:50%!important}.rounded-start-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-top-right-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:right!important}.float-sm-end{float:left!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-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-left:0!important;margin-right:0!important}.mx-sm-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-sm-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-sm-3{margin-left:1rem!important;margin-right:1rem!important}.mx-sm-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-sm-5{margin-left:3rem!important;margin-right:3rem!important}.mx-sm-auto{margin-left:auto!important;margin-right: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-left:0!important}.me-sm-1{margin-left:.25rem!important}.me-sm-2{margin-left:.5rem!important}.me-sm-3{margin-left:1rem!important}.me-sm-4{margin-left:1.5rem!important}.me-sm-5{margin-left:3rem!important}.me-sm-auto{margin-left: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-right:0!important}.ms-sm-1{margin-right:.25rem!important}.ms-sm-2{margin-right:.5rem!important}.ms-sm-3{margin-right:1rem!important}.ms-sm-4{margin-right:1.5rem!important}.ms-sm-5{margin-right:3rem!important}.ms-sm-auto{margin-right: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-left:0!important;padding-right:0!important}.px-sm-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-sm-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-sm-3{padding-left:1rem!important;padding-right:1rem!important}.px-sm-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-sm-5{padding-left:3rem!important;padding-right: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-left:0!important}.pe-sm-1{padding-left:.25rem!important}.pe-sm-2{padding-left:.5rem!important}.pe-sm-3{padding-left:1rem!important}.pe-sm-4{padding-left:1.5rem!important}.pe-sm-5{padding-left: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-right:0!important}.ps-sm-1{padding-right:.25rem!important}.ps-sm-2{padding-right:.5rem!important}.ps-sm-3{padding-right:1rem!important}.ps-sm-4{padding-right:1.5rem!important}.ps-sm-5{padding-right: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:right!important}.text-sm-end{text-align:left!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:right!important}.float-md-end{float:left!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-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-left:0!important;margin-right:0!important}.mx-md-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-md-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-md-3{margin-left:1rem!important;margin-right:1rem!important}.mx-md-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-md-5{margin-left:3rem!important;margin-right:3rem!important}.mx-md-auto{margin-left:auto!important;margin-right: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-left:0!important}.me-md-1{margin-left:.25rem!important}.me-md-2{margin-left:.5rem!important}.me-md-3{margin-left:1rem!important}.me-md-4{margin-left:1.5rem!important}.me-md-5{margin-left:3rem!important}.me-md-auto{margin-left: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-right:0!important}.ms-md-1{margin-right:.25rem!important}.ms-md-2{margin-right:.5rem!important}.ms-md-3{margin-right:1rem!important}.ms-md-4{margin-right:1.5rem!important}.ms-md-5{margin-right:3rem!important}.ms-md-auto{margin-right: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-left:0!important;padding-right:0!important}.px-md-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-md-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-md-3{padding-left:1rem!important;padding-right:1rem!important}.px-md-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-md-5{padding-left:3rem!important;padding-right: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-left:0!important}.pe-md-1{padding-left:.25rem!important}.pe-md-2{padding-left:.5rem!important}.pe-md-3{padding-left:1rem!important}.pe-md-4{padding-left:1.5rem!important}.pe-md-5{padding-left: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-right:0!important}.ps-md-1{padding-right:.25rem!important}.ps-md-2{padding-right:.5rem!important}.ps-md-3{padding-right:1rem!important}.ps-md-4{padding-right:1.5rem!important}.ps-md-5{padding-right: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:right!important}.text-md-end{text-align:left!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:right!important}.float-lg-end{float:left!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-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-left:0!important;margin-right:0!important}.mx-lg-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-lg-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-lg-3{margin-left:1rem!important;margin-right:1rem!important}.mx-lg-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-lg-5{margin-left:3rem!important;margin-right:3rem!important}.mx-lg-auto{margin-left:auto!important;margin-right: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-left:0!important}.me-lg-1{margin-left:.25rem!important}.me-lg-2{margin-left:.5rem!important}.me-lg-3{margin-left:1rem!important}.me-lg-4{margin-left:1.5rem!important}.me-lg-5{margin-left:3rem!important}.me-lg-auto{margin-left: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-right:0!important}.ms-lg-1{margin-right:.25rem!important}.ms-lg-2{margin-right:.5rem!important}.ms-lg-3{margin-right:1rem!important}.ms-lg-4{margin-right:1.5rem!important}.ms-lg-5{margin-right:3rem!important}.ms-lg-auto{margin-right: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-left:0!important;padding-right:0!important}.px-lg-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-lg-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-lg-3{padding-left:1rem!important;padding-right:1rem!important}.px-lg-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-lg-5{padding-left:3rem!important;padding-right: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-left:0!important}.pe-lg-1{padding-left:.25rem!important}.pe-lg-2{padding-left:.5rem!important}.pe-lg-3{padding-left:1rem!important}.pe-lg-4{padding-left:1.5rem!important}.pe-lg-5{padding-left: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-right:0!important}.ps-lg-1{padding-right:.25rem!important}.ps-lg-2{padding-right:.5rem!important}.ps-lg-3{padding-right:1rem!important}.ps-lg-4{padding-right:1.5rem!important}.ps-lg-5{padding-right: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:right!important}.text-lg-end{text-align:left!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:right!important}.float-xl-end{float:left!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-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-left:0!important;margin-right:0!important}.mx-xl-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-xl-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-xl-3{margin-left:1rem!important;margin-right:1rem!important}.mx-xl-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-xl-5{margin-left:3rem!important;margin-right:3rem!important}.mx-xl-auto{margin-left:auto!important;margin-right: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-left:0!important}.me-xl-1{margin-left:.25rem!important}.me-xl-2{margin-left:.5rem!important}.me-xl-3{margin-left:1rem!important}.me-xl-4{margin-left:1.5rem!important}.me-xl-5{margin-left:3rem!important}.me-xl-auto{margin-left: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-right:0!important}.ms-xl-1{margin-right:.25rem!important}.ms-xl-2{margin-right:.5rem!important}.ms-xl-3{margin-right:1rem!important}.ms-xl-4{margin-right:1.5rem!important}.ms-xl-5{margin-right:3rem!important}.ms-xl-auto{margin-right: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-left:0!important;padding-right:0!important}.px-xl-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-xl-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-xl-3{padding-left:1rem!important;padding-right:1rem!important}.px-xl-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-xl-5{padding-left:3rem!important;padding-right: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-left:0!important}.pe-xl-1{padding-left:.25rem!important}.pe-xl-2{padding-left:.5rem!important}.pe-xl-3{padding-left:1rem!important}.pe-xl-4{padding-left:1.5rem!important}.pe-xl-5{padding-left: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-right:0!important}.ps-xl-1{padding-right:.25rem!important}.ps-xl-2{padding-right:.5rem!important}.ps-xl-3{padding-right:1rem!important}.ps-xl-4{padding-right:1.5rem!important}.ps-xl-5{padding-right: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:right!important}.text-xl-end{text-align:left!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:right!important}.float-xxl-end{float:left!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-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-left:0!important;margin-right:0!important}.mx-xxl-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-xxl-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-xxl-3{margin-left:1rem!important;margin-right:1rem!important}.mx-xxl-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-xxl-5{margin-left:3rem!important;margin-right:3rem!important}.mx-xxl-auto{margin-left:auto!important;margin-right: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-left:0!important}.me-xxl-1{margin-left:.25rem!important}.me-xxl-2{margin-left:.5rem!important}.me-xxl-3{margin-left:1rem!important}.me-xxl-4{margin-left:1.5rem!important}.me-xxl-5{margin-left:3rem!important}.me-xxl-auto{margin-left: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-right:0!important}.ms-xxl-1{margin-right:.25rem!important}.ms-xxl-2{margin-right:.5rem!important}.ms-xxl-3{margin-right:1rem!important}.ms-xxl-4{margin-right:1.5rem!important}.ms-xxl-5{margin-right:3rem!important}.ms-xxl-auto{margin-right: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-left:0!important;padding-right:0!important}.px-xxl-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-xxl-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-xxl-3{padding-left:1rem!important;padding-right:1rem!important}.px-xxl-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-xxl-5{padding-left:3rem!important;padding-right: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-left:0!important}.pe-xxl-1{padding-left:.25rem!important}.pe-xxl-2{padding-left:.5rem!important}.pe-xxl-3{padding-left:1rem!important}.pe-xxl-4{padding-left:1.5rem!important}.pe-xxl-5{padding-left: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-right:0!important}.ps-xxl-1{padding-right:.25rem!important}.ps-xxl-2{padding-right:.5rem!important}.ps-xxl-3{padding-right:1rem!important}.ps-xxl-4{padding-right:1.5rem!important}.ps-xxl-5{padding-right: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:right!important}.text-xxl-end{text-align:left!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-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}}\n/*# sourceMappingURL=bootstrap.rtl.min.css.map */"
  },
  {
    "path": "hiauth-server/src/main/resources/static/bootstrap-5.3.0/css/bootstrap.rtl.min.css.map",
    "content": "{\"version\":3,\"sources\":[\"../../scss/mixins/_banner.scss\",\"../../scss/_root.scss\",\"dist/css/bootstrap.rtl.css\",\"../../scss/vendor/_rfs.scss\",\"../../scss/mixins/_color-mode.scss\",\"../../scss/_reboot.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/_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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\",\"sourcesContent\":[\"@mixin bsBanner($file) {\\n  /*!\\n   * Bootstrap #{$file} v5.3.0-alpha1 (https://getbootstrap.com/)\\n   * Copyright 2011-2022 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: #{$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  --#{$prefix}body-color-rgb: #{to-rgb($body-color)};\\n  --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};\\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  --#{$prefix}body-color: #{$body-color};\\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\\n  @if $body-text-align != null {\\n    --#{$prefix}body-text-align: #{$body-text-align};\\n  }\\n  --#{$prefix}body-bg: #{$body-bg};\\n  --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};\\n  // scss-docs-end root-body-variables\\n\\n  @if $headings-color != null {\\n    --#{$prefix}heading-color: #{$headings-color};\\n  }\\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-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-2xl: #{$border-radius-2xl};\\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  --#{$prefix}emphasis-color: #{$emphasis-color};\\n\\n  // scss-docs-start form-control-vars\\n  --#{$prefix}form-control-bg: var(--#{$prefix}body-bg);\\n  --#{$prefix}form-control-disabled-bg: var(--#{$prefix}secondary-bg);\\n  // scss-docs-end form-control-vars\\n\\n  --#{$prefix}highlight-bg: #{$mark-bg};\\n\\n  @each $name, $value in $grid-breakpoints {\\n    --#{$prefix}breakpoint-#{$name}: #{$value};\\n  }\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark, true) {\\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    --#{$prefix}emphasis-color: #{$emphasis-color-dark};\\n\\n    --#{$prefix}primary-text: #{$primary-text-dark};\\n    --#{$prefix}secondary-text: #{$secondary-text-dark};\\n    --#{$prefix}success-text: #{$success-text-dark};\\n    --#{$prefix}info-text: #{$info-text-dark};\\n    --#{$prefix}warning-text: #{$warning-text-dark};\\n    --#{$prefix}danger-text: #{$danger-text-dark};\\n    --#{$prefix}light-text: #{$light-text-dark};\\n    --#{$prefix}dark-text: #{$dark-text-dark};\\n\\n    --#{$prefix}primary-bg-subtle: #{$primary-bg-subtle-dark};\\n    --#{$prefix}secondary-bg-subtle: #{$secondary-bg-subtle-dark};\\n    --#{$prefix}success-bg-subtle: #{$success-bg-subtle-dark};\\n    --#{$prefix}info-bg-subtle: #{$info-bg-subtle-dark};\\n    --#{$prefix}warning-bg-subtle: #{$warning-bg-subtle-dark};\\n    --#{$prefix}danger-bg-subtle: #{$danger-bg-subtle-dark};\\n    --#{$prefix}light-bg-subtle: #{$light-bg-subtle-dark};\\n    --#{$prefix}dark-bg-subtle: #{$dark-bg-subtle-dark};\\n\\n    --#{$prefix}primary-border-subtle: #{$primary-border-subtle-dark};\\n    --#{$prefix}secondary-border-subtle: #{$secondary-border-subtle-dark};\\n    --#{$prefix}success-border-subtle: #{$success-border-subtle-dark};\\n    --#{$prefix}info-border-subtle: #{$info-border-subtle-dark};\\n    --#{$prefix}warning-border-subtle: #{$warning-border-subtle-dark};\\n    --#{$prefix}danger-border-subtle: #{$danger-border-subtle-dark};\\n    --#{$prefix}light-border-subtle: #{$light-border-subtle-dark};\\n    --#{$prefix}dark-border-subtle: #{$dark-border-subtle-dark};\\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\\n    --#{$prefix}border-color: #{$border-color-dark};\\n    --#{$prefix}border-color-translucent: #{$border-color-translucent-dark};\\n    // scss-docs-end root-dark-mode-vars\\n  }\\n}\\n\",\"@charset \\\"UTF-8\\\";\\n/*!\\n * Bootstrap  v5.3.0-alpha1 (https://getbootstrap.com/)\\n * Copyright 2011-2022 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: #0a58ca;\\n  --bs-secondary-text: #6c757d;\\n  --bs-success-text: #146c43;\\n  --bs-info-text: #087990;\\n  --bs-warning-text: #997404;\\n  --bs-danger-text: #b02a37;\\n  --bs-light-text: #6c757d;\\n  --bs-dark-text: #495057;\\n  --bs-primary-bg-subtle: #cfe2ff;\\n  --bs-secondary-bg-subtle: #f8f9fa;\\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: #e9ecef;\\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-body-color-rgb: 33, 37, 41;\\n  --bs-body-bg-rgb: 255, 255, 255;\\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-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-body-bg: #fff;\\n  --bs-body-bg-rgb: 255, 255, 255;\\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-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-2xl: 2rem;\\n  --bs-border-radius-pill: 50rem;\\n  --bs-box-shadow: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);\\n  --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);\\n  --bs-box-shadow-lg: 0 1rem 3rem rgba(var(--bs-body-color-rgb), 0.175);\\n  --bs-box-shadow-inset: inset 0 1px 2px rgba(var(--bs-body-color-rgb), 0.075);\\n  --bs-emphasis-color: #000;\\n  --bs-form-control-bg: var(--bs-body-bg);\\n  --bs-form-control-disabled-bg: var(--bs-secondary-bg);\\n  --bs-highlight-bg: #fff3cd;\\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[data-bs-theme=dark] {\\n  --bs-body-color: #adb5bd;\\n  --bs-body-color-rgb: 173, 181, 189;\\n  --bs-body-bg: #212529;\\n  --bs-body-bg-rgb: 33, 37, 41;\\n  --bs-emphasis-color: #f8f9fa;\\n  --bs-emphasis-color-rgb: 248, 249, 250;\\n  --bs-secondary-color: rgba(173, 181, 189, 0.75);\\n  --bs-secondary-color-rgb: 173, 181, 189;\\n  --bs-secondary-bg: #343a40;\\n  --bs-secondary-bg-rgb: 52, 58, 64;\\n  --bs-tertiary-color: rgba(173, 181, 189, 0.5);\\n  --bs-tertiary-color-rgb: 173, 181, 189;\\n  --bs-tertiary-bg: #2b3035;\\n  --bs-tertiary-bg-rgb: 43, 48, 53;\\n  --bs-emphasis-color: #fff;\\n  --bs-primary-text: #6ea8fe;\\n  --bs-secondary-text: #dee2e6;\\n  --bs-success-text: #75b798;\\n  --bs-info-text: #6edff6;\\n  --bs-warning-text: #ffda6a;\\n  --bs-danger-text: #ea868f;\\n  --bs-light-text: #f8f9fa;\\n  --bs-dark-text: #dee2e6;\\n  --bs-primary-bg-subtle: #031633;\\n  --bs-secondary-bg-subtle: #212529;\\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: #495057;\\n  --bs-success-border-subtle: #0f5132;\\n  --bs-info-border-subtle: #055160;\\n  --bs-warning-border-subtle: #664d03;\\n  --bs-danger-border-subtle: #842029;\\n  --bs-light-border-subtle: #495057;\\n  --bs-dark-border-subtle: #343a40;\\n  --bs-heading-color: #fff;\\n  --bs-link-color: #6ea8fe;\\n  --bs-link-hover-color: #9ec5fe;\\n  --bs-link-color-rgb: 110, 168, 254;\\n  --bs-link-hover-color-rgb: 158, 197, 254;\\n  --bs-code-color: #e685b5;\\n  --bs-border-color: #495057;\\n  --bs-border-color-translucent: rgba(255, 255, 255, 0.15);\\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, inherit);\\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  -webkit-text-decoration: underline dotted;\\n  text-decoration: underline dotted;\\n  cursor: help;\\n  -webkit-text-decoration-skip-ink: none;\\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-right: 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-right: 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  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: right;\\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: right;\\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: right;\\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  outline-offset: -2px;\\n  -webkit-appearance: textfield;\\n}\\n\\n[type=\\\"tel\\\"],\\n[type=\\\"url\\\"],\\n[type=\\\"email\\\"],\\n[type=\\\"number\\\"] {\\n  direction: ltr;\\n}\\n::-webkit-search-decoration {\\n  -webkit-appearance: none;\\n}\\n\\n::-webkit-color-swatch-wrapper {\\n  padding: 0;\\n}\\n\\n::-webkit-file-upload-button {\\n  font: inherit;\\n  -webkit-appearance: button;\\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-right: 0;\\n  list-style: none;\\n}\\n\\n.list-inline {\\n  padding-right: 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-left: 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-left: calc(var(--bs-gutter-x) * 0.5);\\n  padding-right: calc(var(--bs-gutter-x) * 0.5);\\n  margin-left: auto;\\n  margin-right: 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.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-left: calc(-0.5 * var(--bs-gutter-x));\\n  margin-right: calc(-0.5 * var(--bs-gutter-x));\\n}\\n.row > * {\\n  flex-shrink: 0;\\n  width: 100%;\\n  max-width: 100%;\\n  padding-left: calc(var(--bs-gutter-x) * 0.5);\\n  padding-right: 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.3333333333%;\\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.6666666667%;\\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-right: 8.33333333%;\\n}\\n\\n.offset-2 {\\n  margin-right: 16.66666667%;\\n}\\n\\n.offset-3 {\\n  margin-right: 25%;\\n}\\n\\n.offset-4 {\\n  margin-right: 33.33333333%;\\n}\\n\\n.offset-5 {\\n  margin-right: 41.66666667%;\\n}\\n\\n.offset-6 {\\n  margin-right: 50%;\\n}\\n\\n.offset-7 {\\n  margin-right: 58.33333333%;\\n}\\n\\n.offset-8 {\\n  margin-right: 66.66666667%;\\n}\\n\\n.offset-9 {\\n  margin-right: 75%;\\n}\\n\\n.offset-10 {\\n  margin-right: 83.33333333%;\\n}\\n\\n.offset-11 {\\n  margin-right: 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.3333333333%;\\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.6666666667%;\\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-right: 0;\\n  }\\n  .offset-sm-1 {\\n    margin-right: 8.33333333%;\\n  }\\n  .offset-sm-2 {\\n    margin-right: 16.66666667%;\\n  }\\n  .offset-sm-3 {\\n    margin-right: 25%;\\n  }\\n  .offset-sm-4 {\\n    margin-right: 33.33333333%;\\n  }\\n  .offset-sm-5 {\\n    margin-right: 41.66666667%;\\n  }\\n  .offset-sm-6 {\\n    margin-right: 50%;\\n  }\\n  .offset-sm-7 {\\n    margin-right: 58.33333333%;\\n  }\\n  .offset-sm-8 {\\n    margin-right: 66.66666667%;\\n  }\\n  .offset-sm-9 {\\n    margin-right: 75%;\\n  }\\n  .offset-sm-10 {\\n    margin-right: 83.33333333%;\\n  }\\n  .offset-sm-11 {\\n    margin-right: 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.3333333333%;\\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.6666666667%;\\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-right: 0;\\n  }\\n  .offset-md-1 {\\n    margin-right: 8.33333333%;\\n  }\\n  .offset-md-2 {\\n    margin-right: 16.66666667%;\\n  }\\n  .offset-md-3 {\\n    margin-right: 25%;\\n  }\\n  .offset-md-4 {\\n    margin-right: 33.33333333%;\\n  }\\n  .offset-md-5 {\\n    margin-right: 41.66666667%;\\n  }\\n  .offset-md-6 {\\n    margin-right: 50%;\\n  }\\n  .offset-md-7 {\\n    margin-right: 58.33333333%;\\n  }\\n  .offset-md-8 {\\n    margin-right: 66.66666667%;\\n  }\\n  .offset-md-9 {\\n    margin-right: 75%;\\n  }\\n  .offset-md-10 {\\n    margin-right: 83.33333333%;\\n  }\\n  .offset-md-11 {\\n    margin-right: 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.3333333333%;\\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.6666666667%;\\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-right: 0;\\n  }\\n  .offset-lg-1 {\\n    margin-right: 8.33333333%;\\n  }\\n  .offset-lg-2 {\\n    margin-right: 16.66666667%;\\n  }\\n  .offset-lg-3 {\\n    margin-right: 25%;\\n  }\\n  .offset-lg-4 {\\n    margin-right: 33.33333333%;\\n  }\\n  .offset-lg-5 {\\n    margin-right: 41.66666667%;\\n  }\\n  .offset-lg-6 {\\n    margin-right: 50%;\\n  }\\n  .offset-lg-7 {\\n    margin-right: 58.33333333%;\\n  }\\n  .offset-lg-8 {\\n    margin-right: 66.66666667%;\\n  }\\n  .offset-lg-9 {\\n    margin-right: 75%;\\n  }\\n  .offset-lg-10 {\\n    margin-right: 83.33333333%;\\n  }\\n  .offset-lg-11 {\\n    margin-right: 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.3333333333%;\\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.6666666667%;\\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-right: 0;\\n  }\\n  .offset-xl-1 {\\n    margin-right: 8.33333333%;\\n  }\\n  .offset-xl-2 {\\n    margin-right: 16.66666667%;\\n  }\\n  .offset-xl-3 {\\n    margin-right: 25%;\\n  }\\n  .offset-xl-4 {\\n    margin-right: 33.33333333%;\\n  }\\n  .offset-xl-5 {\\n    margin-right: 41.66666667%;\\n  }\\n  .offset-xl-6 {\\n    margin-right: 50%;\\n  }\\n  .offset-xl-7 {\\n    margin-right: 58.33333333%;\\n  }\\n  .offset-xl-8 {\\n    margin-right: 66.66666667%;\\n  }\\n  .offset-xl-9 {\\n    margin-right: 75%;\\n  }\\n  .offset-xl-10 {\\n    margin-right: 83.33333333%;\\n  }\\n  .offset-xl-11 {\\n    margin-right: 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.3333333333%;\\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.6666666667%;\\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-right: 0;\\n  }\\n  .offset-xxl-1 {\\n    margin-right: 8.33333333%;\\n  }\\n  .offset-xxl-2 {\\n    margin-right: 16.66666667%;\\n  }\\n  .offset-xxl-3 {\\n    margin-right: 25%;\\n  }\\n  .offset-xxl-4 {\\n    margin-right: 33.33333333%;\\n  }\\n  .offset-xxl-5 {\\n    margin-right: 41.66666667%;\\n  }\\n  .offset-xxl-6 {\\n    margin-right: 50%;\\n  }\\n  .offset-xxl-7 {\\n    margin-right: 58.33333333%;\\n  }\\n  .offset-xxl-8 {\\n    margin-right: 66.66666667%;\\n  }\\n  .offset-xxl-9 {\\n    margin-right: 75%;\\n  }\\n  .offset-xxl-10 {\\n    margin-right: 83.33333333%;\\n  }\\n  .offset-xxl-11 {\\n    margin-right: 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: var(--bs-body-color);\\n  --bs-table-bg: transparent;\\n  --bs-table-border-color: var(--bs-border-color);\\n  --bs-table-accent-bg: transparent;\\n  --bs-table-striped-color: var(--bs-body-color);\\n  --bs-table-striped-bg: rgba(0, 0, 0, 0.05);\\n  --bs-table-active-color: var(--bs-body-color);\\n  --bs-table-active-bg: rgba(0, 0, 0, 0.1);\\n  --bs-table-hover-color: var(--bs-body-color);\\n  --bs-table-hover-bg: rgba(0, 0, 0, 0.075);\\n  width: 100%;\\n  margin-bottom: 1rem;\\n  color: var(--bs-table-color);\\n  vertical-align: top;\\n  border-color: var(--bs-table-border-color);\\n}\\n.table > :not(caption) > * > * {\\n  padding: 0.5rem 0.5rem;\\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-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-accent-bg: var(--bs-table-striped-bg);\\n  color: var(--bs-table-striped-color);\\n}\\n\\n.table-striped-columns > :not(caption) > tr > :nth-child(even) {\\n  --bs-table-accent-bg: var(--bs-table-striped-bg);\\n  color: var(--bs-table-striped-color);\\n}\\n\\n.table-active {\\n  --bs-table-accent-bg: var(--bs-table-active-bg);\\n  color: var(--bs-table-active-color);\\n}\\n\\n.table-hover > tbody > tr:hover > * {\\n  --bs-table-accent-bg: var(--bs-table-hover-bg);\\n  color: var(--bs-table-hover-color);\\n}\\n\\n.table-primary {\\n  --bs-table-color: #000;\\n  --bs-table-bg: #cfe2ff;\\n  --bs-table-border-color: #bacbe6;\\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: #cbccce;\\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: #bcd0c7;\\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: #badce3;\\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: #e6dbb9;\\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: #dfc2c4;\\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: #dfe0e1;\\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: #373b3e;\\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  background-color: var(--bs-form-control-bg);\\n  background-clip: padding-box;\\n  border: var(--bs-border-width) solid var(--bs-border-color);\\n  -webkit-appearance: none;\\n  -moz-appearance: none;\\n  appearance: none;\\n  border-radius: 0.375rem;\\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-form-control-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  height: 1.5em;\\n}\\n.form-control::-webkit-datetime-edit {\\n  display: block;\\n  padding: 0;\\n}\\n.form-control::-moz-placeholder {\\n  color: var(--bs-secondary-color);\\n  opacity: 1;\\n}\\n.form-control::placeholder {\\n  color: var(--bs-secondary-color);\\n  opacity: 1;\\n}\\n.form-control:disabled {\\n  background-color: var(--bs-form-control-disabled-bg);\\n  opacity: 1;\\n}\\n.form-control::-webkit-file-upload-button {\\n  padding: 0.375rem 0.75rem;\\n  margin: -0.375rem -0.75rem;\\n  -webkit-margin-end: 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  -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;\\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.form-control::file-selector-button {\\n  padding: 0.375rem 0.75rem;\\n  margin: -0.375rem -0.75rem;\\n  -webkit-margin-end: 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::-webkit-file-upload-button {\\n    -webkit-transition: none;\\n    transition: none;\\n  }\\n  .form-control::file-selector-button {\\n    transition: none;\\n  }\\n}\\n.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {\\n  background-color: var(--bs-secondary-bg);\\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-left: 0;\\n  padding-right: 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: 0.25rem;\\n}\\n.form-control-sm::-webkit-file-upload-button {\\n  padding: 0.25rem 0.5rem;\\n  margin: -0.25rem -0.5rem;\\n  -webkit-margin-end: 0.5rem;\\n  margin-inline-end: 0.5rem;\\n}\\n.form-control-sm::file-selector-button {\\n  padding: 0.25rem 0.5rem;\\n  margin: -0.25rem -0.5rem;\\n  -webkit-margin-end: 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: 0.5rem;\\n}\\n.form-control-lg::-webkit-file-upload-button {\\n  padding: 0.5rem 1rem;\\n  margin: -0.5rem -1rem;\\n  -webkit-margin-end: 1rem;\\n  margin-inline-end: 1rem;\\n}\\n.form-control-lg::file-selector-button {\\n  padding: 0.5rem 1rem;\\n  margin: -0.5rem -1rem;\\n  -webkit-margin-end: 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: 0.375rem;\\n}\\n.form-control-color::-webkit-color-swatch {\\n  border-radius: 0.375rem;\\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 0.75rem 0.375rem 2.25rem;\\n  -moz-padding-start: calc(0.75rem - 3px);\\n  font-size: 1rem;\\n  font-weight: 400;\\n  line-height: 1.5;\\n  color: var(--bs-body-color);\\n  background-color: var(--bs-form-control-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: left 0.75rem center;\\n  background-size: 16px 12px;\\n  border: var(--bs-border-width) solid var(--bs-border-color);\\n  border-radius: 0.375rem;\\n  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  -webkit-appearance: none;\\n  -moz-appearance: none;\\n  appearance: none;\\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-left: 0.75rem;\\n  background-image: none;\\n}\\n.form-select:disabled {\\n  background-color: var(--bs-form-control-disabled-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-right: 0.5rem;\\n  font-size: 0.875rem;\\n  border-radius: 0.25rem;\\n}\\n\\n.form-select-lg {\\n  padding-top: 0.5rem;\\n  padding-bottom: 0.5rem;\\n  padding-right: 1rem;\\n  font-size: 1.25rem;\\n  border-radius: 0.5rem;\\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='%23adb5bd' 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-right: 1.5em;\\n  margin-bottom: 0.125rem;\\n}\\n.form-check .form-check-input {\\n  float: right;\\n  margin-right: -1.5em;\\n}\\n\\n.form-check-reverse {\\n  padding-left: 1.5em;\\n  padding-right: 0;\\n  text-align: left;\\n}\\n.form-check-reverse .form-check-input {\\n  float: left;\\n  margin-left: -1.5em;\\n  margin-right: 0;\\n}\\n\\n.form-check-input {\\n  --bs-form-check-bg: var(--bs-form-control-bg);\\n  width: 1em;\\n  height: 1em;\\n  margin-top: 0.25em;\\n  vertical-align: top;\\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  -webkit-appearance: none;\\n  -moz-appearance: none;\\n  appearance: none;\\n  -webkit-print-color-adjust: exact;\\n  color-adjust: exact;\\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-right: 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-right: -2.5em;\\n  background-image: var(--bs-form-switch-bg);\\n  background-position: right 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: left 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-left: 2.5em;\\n  padding-right: 0;\\n}\\n.form-switch.form-check-reverse .form-check-input {\\n  margin-left: -2.5em;\\n  margin-right: 0;\\n}\\n\\n.form-check-inline {\\n  display: inline-block;\\n  margin-left: 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  background-color: transparent;\\n  -webkit-appearance: none;\\n  -moz-appearance: none;\\n  appearance: none;\\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  background-color: #0d6efd;\\n  border: 0;\\n  border-radius: 1rem;\\n  -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  -webkit-appearance: none;\\n  appearance: none;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n  .form-range::-webkit-slider-thumb {\\n    -webkit-transition: none;\\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-tertiary-bg);\\n  border-color: transparent;\\n  border-radius: 1rem;\\n}\\n.form-range::-moz-range-thumb {\\n  width: 1rem;\\n  height: 1rem;\\n  background-color: #0d6efd;\\n  border: 0;\\n  border-radius: 1rem;\\n  -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\\n  -moz-appearance: none;\\n  appearance: none;\\n}\\n@media (prefers-reduced-motion: reduce) {\\n  .form-range::-moz-range-thumb {\\n    -moz-transition: none;\\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-tertiary-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::before:not(.form-control:disabled) {\\n  position: absolute;\\n  top: var(--bs-border-width);\\n  right: var(--bs-border-width);\\n  width: calc(100% - (calc(calc(0.375em + 0.1875rem) + calc(0.75em + 0.375rem))));\\n  height: 1.875em;\\n  content: \\\"\\\";\\n  background-color: var(--bs-form-control-bg);\\n  border-radius: 0.375rem;\\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  line-height: 1.25;\\n}\\n.form-floating > label {\\n  position: absolute;\\n  top: 0;\\n  right: 0;\\n  width: 100%;\\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: 100% 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::-moz-placeholder, .form-floating > .form-control-plaintext::-moz-placeholder {\\n  color: transparent;\\n}\\n.form-floating > .form-control::placeholder,\\n.form-floating > .form-control-plaintext::placeholder {\\n  color: transparent;\\n}\\n.form-floating > .form-control:not(:-moz-placeholder-shown), .form-floating > .form-control-plaintext:not(:-moz-placeholder-shown) {\\n  padding-top: 1.625rem;\\n  padding-bottom: 0.625rem;\\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:not(:-moz-placeholder-shown) ~ label {\\n  opacity: 0.65;\\n  transform: scale(0.85) translateY(-0.5rem) translateX(-0.15rem);\\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  opacity: 0.65;\\n  transform: scale(0.85) translateY(-0.5rem) translateX(-0.15rem);\\n}\\n.form-floating > .form-control:-webkit-autofill ~ label {\\n  opacity: 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 > .form-control:disabled ~ label {\\n  color: #6c757d;\\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: 0.375rem;\\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: 0.5rem;\\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: 0.25rem;\\n}\\n\\n.input-group-lg > .form-select,\\n.input-group-sm > .form-select {\\n  padding-left: 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-left-radius: 0;\\n  border-bottom-left-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-left-radius: 0;\\n  border-bottom-left-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-right: calc(var(--bs-border-width) * -1);\\n  border-top-right-radius: 0;\\n  border-bottom-right-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-right-radius: 0;\\n  border-bottom-right-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-success-text);\\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-success);\\n  padding-left: 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: left 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-success);\\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-left: calc(1.5em + 0.75rem);\\n  background-position: top calc(0.375em + 0.1875rem) left calc(0.375em + 0.1875rem);\\n}\\n\\n.was-validated .form-select:valid, .form-select.is-valid {\\n  border-color: var(--bs-success);\\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-left: 4.125rem;\\n  background-position: left 0.75rem center, center left 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-success);\\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-success);\\n}\\n.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked {\\n  background-color: var(--bs-success-text);\\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-success-text);\\n}\\n\\n.form-check-inline .form-check-input ~ .valid-feedback {\\n  margin-right: 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-danger-text);\\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-danger);\\n  padding-left: 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: left 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-danger);\\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-left: calc(1.5em + 0.75rem);\\n  background-position: top calc(0.375em + 0.1875rem) left calc(0.375em + 0.1875rem);\\n}\\n\\n.was-validated .form-select:invalid, .form-select.is-invalid {\\n  border-color: var(--bs-danger);\\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-left: 4.125rem;\\n  background-position: left 0.75rem center, center left 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-danger);\\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-danger);\\n}\\n.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked {\\n  background-color: var(--bs-danger-text);\\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-danger-text);\\n}\\n\\n.form-check-inline .form-check-input ~ .invalid-feedback {\\n  margin-right: 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: #212529;\\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: 0.375rem;\\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  -webkit-user-select: none;\\n  -moz-user-select: none;\\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: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: none;\\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: 0.5rem;\\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: 0.25rem;\\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-right: 0.255em;\\n  vertical-align: 0.255em;\\n  content: \\\"\\\";\\n  border-top: 0.3em solid;\\n  border-left: 0.3em solid transparent;\\n  border-bottom: 0;\\n  border-right: 0.3em solid transparent;\\n}\\n.dropdown-toggle:empty::after {\\n  margin-right: 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: 0.375rem;\\n  --bs-dropdown-border-width: var(--bs-border-width);\\n  --bs-dropdown-inner-border-radius: calc(0.375rem - 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: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);\\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: #adb5bd;\\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: right;\\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  right: 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  left: auto;\\n  right: 0;\\n}\\n\\n.dropdown-menu-end {\\n  --bs-position: end;\\n}\\n.dropdown-menu-end[data-bs-popper] {\\n  left: 0;\\n  right: 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    left: auto;\\n    right: 0;\\n  }\\n  .dropdown-menu-sm-end {\\n    --bs-position: end;\\n  }\\n  .dropdown-menu-sm-end[data-bs-popper] {\\n    left: 0;\\n    right: 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    left: auto;\\n    right: 0;\\n  }\\n  .dropdown-menu-md-end {\\n    --bs-position: end;\\n  }\\n  .dropdown-menu-md-end[data-bs-popper] {\\n    left: 0;\\n    right: 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    left: auto;\\n    right: 0;\\n  }\\n  .dropdown-menu-lg-end {\\n    --bs-position: end;\\n  }\\n  .dropdown-menu-lg-end[data-bs-popper] {\\n    left: 0;\\n    right: 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    left: auto;\\n    right: 0;\\n  }\\n  .dropdown-menu-xl-end {\\n    --bs-position: end;\\n  }\\n  .dropdown-menu-xl-end[data-bs-popper] {\\n    left: 0;\\n    right: 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    left: auto;\\n    right: 0;\\n  }\\n  .dropdown-menu-xxl-end {\\n    --bs-position: end;\\n  }\\n  .dropdown-menu-xxl-end[data-bs-popper] {\\n    left: 0;\\n    right: 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-right: 0.255em;\\n  vertical-align: 0.255em;\\n  content: \\\"\\\";\\n  border-top: 0;\\n  border-left: 0.3em solid transparent;\\n  border-bottom: 0.3em solid;\\n  border-right: 0.3em solid transparent;\\n}\\n.dropup .dropdown-toggle:empty::after {\\n  margin-right: 0;\\n}\\n\\n.dropend .dropdown-menu[data-bs-popper] {\\n  top: 0;\\n  left: auto;\\n  right: 100%;\\n  margin-top: 0;\\n  margin-right: var(--bs-dropdown-spacer);\\n}\\n.dropend .dropdown-toggle::after {\\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-left: 0;\\n  border-bottom: 0.3em solid transparent;\\n  border-right: 0.3em solid;\\n}\\n.dropend .dropdown-toggle:empty::after {\\n  margin-right: 0;\\n}\\n.dropend .dropdown-toggle::after {\\n  vertical-align: 0;\\n}\\n\\n.dropstart .dropdown-menu[data-bs-popper] {\\n  top: 0;\\n  left: 100%;\\n  right: auto;\\n  margin-top: 0;\\n  margin-left: var(--bs-dropdown-spacer);\\n}\\n.dropstart .dropdown-toggle::after {\\n  display: inline-block;\\n  margin-right: 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-left: 0.255em;\\n  vertical-align: 0.255em;\\n  content: \\\"\\\";\\n  border-top: 0.3em solid transparent;\\n  border-left: 0.3em solid;\\n  border-bottom: 0.3em solid transparent;\\n}\\n.dropstart .dropdown-toggle:empty::after {\\n  margin-right: 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: 0.375rem;\\n}\\n.btn-group > :not(.btn-check:first-child) + .btn,\\n.btn-group > .btn-group:not(:first-child) {\\n  margin-right: 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-left-radius: 0;\\n  border-bottom-left-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-right-radius: 0;\\n  border-bottom-right-radius: 0;\\n}\\n\\n.dropdown-toggle-split {\\n  padding-left: 0.5625rem;\\n  padding-right: 0.5625rem;\\n}\\n.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after {\\n  margin-right: 0;\\n}\\n.dropstart .dropdown-toggle-split::before {\\n  margin-left: 0;\\n}\\n\\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\\n  padding-left: 0.375rem;\\n  padding-right: 0.375rem;\\n}\\n\\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\\n  padding-left: 0.75rem;\\n  padding-right: 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-left-radius: 0;\\n  border-bottom-right-radius: 0;\\n}\\n.btn-group-vertical > .btn ~ .btn,\\n.btn-group-vertical > .btn-group:not(:first-child) > .btn {\\n  border-top-right-radius: 0;\\n  border-top-left-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-right: 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  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.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  background: none;\\n  border: var(--bs-nav-tabs-border-width) solid transparent;\\n  border-top-right-radius: var(--bs-nav-tabs-border-radius);\\n  border-top-left-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.disabled, .nav-tabs .nav-link:disabled {\\n  color: var(--bs-nav-link-disabled-color);\\n  background-color: transparent;\\n  border-color: transparent;\\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-right-radius: 0;\\n  border-top-left-radius: 0;\\n}\\n\\n.nav-pills {\\n  --bs-nav-pills-border-radius: 0.375rem;\\n  --bs-nav-pills-link-active-color: #fff;\\n  --bs-nav-pills-link-active-bg: #0d6efd;\\n}\\n.nav-pills .nav-link {\\n  background: none;\\n  border: 0;\\n  border-radius: var(--bs-nav-pills-border-radius);\\n}\\n.nav-pills .nav-link:disabled {\\n  color: var(--bs-nav-link-disabled-color);\\n  background-color: transparent;\\n  border-color: transparent;\\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-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: 0.375rem;\\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-left: 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-right: 0;\\n  margin-bottom: 0;\\n  list-style: none;\\n}\\n.navbar-nav .show > .nav-link,\\n.navbar-nav .nav-link.active {\\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-left: var(--bs-navbar-nav-link-padding-x);\\n    padding-right: 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-left: var(--bs-navbar-nav-link-padding-x);\\n    padding-right: 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-left: var(--bs-navbar-nav-link-padding-x);\\n    padding-right: 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-left: var(--bs-navbar-nav-link-padding-x);\\n    padding-right: 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-left: var(--bs-navbar-nav-link-padding-x);\\n    padding-right: 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-left: var(--bs-navbar-nav-link-padding-x);\\n  padding-right: 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  --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 {\\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  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-left: 0;\\n  margin-right: 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-right-radius: var(--bs-card-inner-border-radius);\\n  border-top-left-radius: var(--bs-card-inner-border-radius);\\n}\\n.card > .list-group:last-child {\\n  border-bottom-width: 0;\\n  border-bottom-left-radius: var(--bs-card-inner-border-radius);\\n  border-bottom-right-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-right: 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-left: calc(-0.5 * var(--bs-card-cap-padding-x));\\n  margin-bottom: calc(-1 * var(--bs-card-cap-padding-y));\\n  margin-right: 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-left: calc(-0.5 * var(--bs-card-cap-padding-x));\\n  margin-right: calc(-0.5 * var(--bs-card-cap-padding-x));\\n}\\n\\n.card-img-overlay {\\n  position: absolute;\\n  top: 0;\\n  left: 0;\\n  bottom: 0;\\n  right: 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-right-radius: var(--bs-card-inner-border-radius);\\n  border-top-left-radius: var(--bs-card-inner-border-radius);\\n}\\n\\n.card-img,\\n.card-img-bottom {\\n  border-bottom-left-radius: var(--bs-card-inner-border-radius);\\n  border-bottom-right-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-right: 0;\\n    border-right: 0;\\n  }\\n  .card-group > .card:not(:last-child) {\\n    border-top-left-radius: 0;\\n    border-bottom-left-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-left-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-left-radius: 0;\\n  }\\n  .card-group > .card:not(:first-child) {\\n    border-top-right-radius: 0;\\n    border-bottom-right-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-right-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-right-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='%23212529'%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-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='%230a58ca'%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-focus-border-color: #86b7fe;\\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);\\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: right;\\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-right: 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  border-color: var(--bs-accordion-btn-focus-border-color);\\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-right-radius: var(--bs-accordion-border-radius);\\n  border-top-left-radius: var(--bs-accordion-border-radius);\\n}\\n.accordion-item:first-of-type .accordion-button {\\n  border-top-right-radius: var(--bs-accordion-inner-border-radius);\\n  border-top-left-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-left-radius: var(--bs-accordion-border-radius);\\n  border-bottom-right-radius: var(--bs-accordion-border-radius);\\n}\\n.accordion-item:last-of-type .accordion-button.collapsed {\\n  border-bottom-left-radius: var(--bs-accordion-inner-border-radius);\\n  border-bottom-right-radius: var(--bs-accordion-inner-border-radius);\\n}\\n.accordion-item:last-of-type .accordion-collapse {\\n  border-bottom-left-radius: var(--bs-accordion-border-radius);\\n  border-bottom-right-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-collapse {\\n  border-width: 0;\\n}\\n.accordion-flush .accordion-item {\\n  border-left: 0;\\n  border-right: 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-button, .accordion-flush .accordion-item .accordion-button.collapsed {\\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-right: var(--bs-breadcrumb-item-padding-x);\\n}\\n.breadcrumb-item + .breadcrumb-item::before {\\n  float: right;\\n  padding-left: var(--bs-breadcrumb-item-padding-x);\\n  color: var(--bs-breadcrumb-divider-color);\\n  content:  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-right: 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-right: calc(var(--bs-border-width) * -1);\\n}\\n.page-item:first-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.page-item:last-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\\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: 0.5rem;\\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: 0.25rem;\\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: 0.375rem;\\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: 0.375rem;\\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-left: 3rem;\\n}\\n.alert-dismissible .btn-close {\\n  position: absolute;\\n  top: 0;\\n  left: 0;\\n  z-index: 2;\\n  padding: 1.25rem 1rem;\\n}\\n\\n.alert-primary {\\n  --bs-alert-color: var(--bs-primary-text);\\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);\\n}\\n\\n.alert-secondary {\\n  --bs-alert-color: var(--bs-secondary-text);\\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);\\n}\\n\\n.alert-success {\\n  --bs-alert-color: var(--bs-success-text);\\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);\\n}\\n\\n.alert-info {\\n  --bs-alert-color: var(--bs-info-text);\\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);\\n}\\n\\n.alert-warning {\\n  --bs-alert-color: var(--bs-warning-text);\\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);\\n}\\n\\n.alert-danger {\\n  --bs-alert-color: var(--bs-danger-text);\\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);\\n}\\n\\n.alert-light {\\n  --bs-alert-color: var(--bs-light-text);\\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);\\n}\\n\\n.alert-dark {\\n  --bs-alert-color: var(--bs-dark-text);\\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);\\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-right: 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-right-radius: inherit;\\n  border-top-left-radius: inherit;\\n}\\n.list-group-item:last-child {\\n  border-bottom-left-radius: inherit;\\n  border-bottom-right-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-right-radius: var(--bs-list-group-border-radius);\\n  border-top-left-radius: 0;\\n}\\n.list-group-horizontal > .list-group-item:last-child:not(:first-child) {\\n  border-top-left-radius: var(--bs-list-group-border-radius);\\n  border-bottom-right-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-right-width: 0;\\n}\\n.list-group-horizontal > .list-group-item + .list-group-item.active {\\n  margin-right: calc(-1 * var(--bs-list-group-border-width));\\n  border-right-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-right-radius: var(--bs-list-group-border-radius);\\n    border-top-left-radius: 0;\\n  }\\n  .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) {\\n    border-top-left-radius: var(--bs-list-group-border-radius);\\n    border-bottom-right-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-right-width: 0;\\n  }\\n  .list-group-horizontal-sm > .list-group-item + .list-group-item.active {\\n    margin-right: calc(-1 * var(--bs-list-group-border-width));\\n    border-right-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-right-radius: var(--bs-list-group-border-radius);\\n    border-top-left-radius: 0;\\n  }\\n  .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) {\\n    border-top-left-radius: var(--bs-list-group-border-radius);\\n    border-bottom-right-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-right-width: 0;\\n  }\\n  .list-group-horizontal-md > .list-group-item + .list-group-item.active {\\n    margin-right: calc(-1 * var(--bs-list-group-border-width));\\n    border-right-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-right-radius: var(--bs-list-group-border-radius);\\n    border-top-left-radius: 0;\\n  }\\n  .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) {\\n    border-top-left-radius: var(--bs-list-group-border-radius);\\n    border-bottom-right-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-right-width: 0;\\n  }\\n  .list-group-horizontal-lg > .list-group-item + .list-group-item.active {\\n    margin-right: calc(-1 * var(--bs-list-group-border-width));\\n    border-right-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-right-radius: var(--bs-list-group-border-radius);\\n    border-top-left-radius: 0;\\n  }\\n  .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) {\\n    border-top-left-radius: var(--bs-list-group-border-radius);\\n    border-bottom-right-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-right-width: 0;\\n  }\\n  .list-group-horizontal-xl > .list-group-item + .list-group-item.active {\\n    margin-right: calc(-1 * var(--bs-list-group-border-width));\\n    border-right-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-right-radius: var(--bs-list-group-border-radius);\\n    border-top-left-radius: 0;\\n  }\\n  .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) {\\n    border-top-left-radius: var(--bs-list-group-border-radius);\\n    border-bottom-right-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-right-width: 0;\\n  }\\n  .list-group-horizontal-xxl > .list-group-item + .list-group-item.active {\\n    margin-right: calc(-1 * var(--bs-list-group-border-width));\\n    border-right-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);\\n  --bs-list-group-bg: var(--bs-primary-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-primary-border-subtle);\\n}\\n.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);\\n}\\n.list-group-item-primary.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-primary-text);\\n  --bs-list-group-active-border-color: var(--bs-primary-text);\\n}\\n\\n.list-group-item-secondary {\\n  --bs-list-group-color: var(--bs-secondary-text);\\n  --bs-list-group-bg: var(--bs-secondary-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-secondary-border-subtle);\\n}\\n.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);\\n}\\n.list-group-item-secondary.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-secondary-text);\\n  --bs-list-group-active-border-color: var(--bs-secondary-text);\\n}\\n\\n.list-group-item-success {\\n  --bs-list-group-color: var(--bs-success-text);\\n  --bs-list-group-bg: var(--bs-success-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-success-border-subtle);\\n}\\n.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-success-border-subtle);\\n}\\n.list-group-item-success.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-success-text);\\n  --bs-list-group-active-border-color: var(--bs-success-text);\\n}\\n\\n.list-group-item-info {\\n  --bs-list-group-color: var(--bs-info-text);\\n  --bs-list-group-bg: var(--bs-info-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-info-border-subtle);\\n}\\n.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-info-border-subtle);\\n}\\n.list-group-item-info.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-info-text);\\n  --bs-list-group-active-border-color: var(--bs-info-text);\\n}\\n\\n.list-group-item-warning {\\n  --bs-list-group-color: var(--bs-warning-text);\\n  --bs-list-group-bg: var(--bs-warning-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-warning-border-subtle);\\n}\\n.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);\\n}\\n.list-group-item-warning.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-warning-text);\\n  --bs-list-group-active-border-color: var(--bs-warning-text);\\n}\\n\\n.list-group-item-danger {\\n  --bs-list-group-color: var(--bs-danger-text);\\n  --bs-list-group-bg: var(--bs-danger-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-danger-border-subtle);\\n}\\n.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);\\n}\\n.list-group-item-danger.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-danger-text);\\n  --bs-list-group-active-border-color: var(--bs-danger-text);\\n}\\n\\n.list-group-item-light {\\n  --bs-list-group-color: var(--bs-light-text);\\n  --bs-list-group-bg: var(--bs-light-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-light-border-subtle);\\n}\\n.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-light-border-subtle);\\n}\\n.list-group-item-light.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-light-text);\\n  --bs-list-group-active-border-color: var(--bs-light-text);\\n}\\n\\n.list-group-item-dark {\\n  --bs-list-group-color: var(--bs-dark-text);\\n  --bs-list-group-bg: var(--bs-dark-bg-subtle);\\n  --bs-list-group-border-color: var(--bs-dark-border-subtle);\\n}\\n.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {\\n  --bs-list-group-action-hover-color: var(--bs-emphasis-color);\\n  --bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);\\n}\\n.list-group-item-dark.list-group-item-action:active {\\n  --bs-list-group-active-color: var(--bs-emphasis-color);\\n  --bs-list-group-active-bg: var(--bs-dark-text);\\n  --bs-list-group-active-border-color: var(--bs-dark-text);\\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  -webkit-user-select: none;\\n  -moz-user-select: 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: -webkit-max-content;\\n  width: -moz-max-content;\\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-right-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));\\n  border-top-left-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));\\n}\\n.toast-header .btn-close {\\n  margin-left: calc(-0.5 * var(--bs-toast-padding-x));\\n  margin-right: 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: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);\\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  right: 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  right: 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  justify-content: space-between;\\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-right-radius: var(--bs-modal-inner-border-radius);\\n  border-top-left-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)) auto calc(-0.5 * var(--bs-modal-header-padding-y)) calc(-0.5 * var(--bs-modal-header-padding-x));\\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-left-radius: var(--bs-modal-inner-border-radius);\\n  border-bottom-right-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: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);\\n  }\\n  .modal-dialog {\\n    max-width: var(--bs-modal-width);\\n    margin-left: auto;\\n    margin-right: 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  padding: var(--bs-tooltip-arrow-height);\\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: right;\\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: 0;\\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.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow {\\n  left: 0;\\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.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow {\\n  top: 0;\\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.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow {\\n  right: 0;\\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.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: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15);\\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: ;\\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: right;\\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.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.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  right: 50%;\\n  display: block;\\n  width: var(--bs-popover-arrow-width);\\n  margin-right: 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.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.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-right-radius: var(--bs-popover-inner-border-radius);\\n  border-top-left-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: right;\\n  width: 100%;\\n  margin-left: -100%;\\n  -webkit-backface-visibility: hidden;\\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  right: 0;\\n}\\n\\n.carousel-control-next {\\n  left: 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.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='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-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='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-indicators {\\n  position: absolute;\\n  left: 0;\\n  bottom: 0;\\n  right: 0;\\n  z-index: 2;\\n  display: flex;\\n  justify-content: center;\\n  padding: 0;\\n  margin-left: 15%;\\n  margin-bottom: 1rem;\\n  margin-right: 15%;\\n  list-style: none;\\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-left: 3px;\\n  margin-right: 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  left: 15%;\\n  bottom: 1.25rem;\\n  right: 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-next-icon,\\n.carousel-dark .carousel-control-prev-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-next-icon,\\n[data-bs-theme=dark] .carousel .carousel-control-prev-icon {\\n  filter: invert(1) grayscale(100);\\n}\\n[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target] {\\n  background-color: #000;\\n}\\n[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) ;\\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-left-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: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075);\\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    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}\\n@media (max-width: 575.98px) {\\n  .offcanvas-sm.offcanvas-end {\\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}\\n@media (max-width: 575.98px) {\\n  .offcanvas-sm.offcanvas-top {\\n    top: 0;\\n    left: 0;\\n    right: 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}\\n@media (max-width: 575.98px) {\\n  .offcanvas-sm.offcanvas-bottom {\\n    left: 0;\\n    right: 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}\\n@media (max-width: 575.98px) {\\n  .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 575.98px) {\\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    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}\\n@media (max-width: 767.98px) {\\n  .offcanvas-md.offcanvas-end {\\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}\\n@media (max-width: 767.98px) {\\n  .offcanvas-md.offcanvas-top {\\n    top: 0;\\n    left: 0;\\n    right: 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}\\n@media (max-width: 767.98px) {\\n  .offcanvas-md.offcanvas-bottom {\\n    left: 0;\\n    right: 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}\\n@media (max-width: 767.98px) {\\n  .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 767.98px) {\\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    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}\\n@media (max-width: 991.98px) {\\n  .offcanvas-lg.offcanvas-end {\\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}\\n@media (max-width: 991.98px) {\\n  .offcanvas-lg.offcanvas-top {\\n    top: 0;\\n    left: 0;\\n    right: 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}\\n@media (max-width: 991.98px) {\\n  .offcanvas-lg.offcanvas-bottom {\\n    left: 0;\\n    right: 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}\\n@media (max-width: 991.98px) {\\n  .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 991.98px) {\\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    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}\\n@media (max-width: 1199.98px) {\\n  .offcanvas-xl.offcanvas-end {\\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}\\n@media (max-width: 1199.98px) {\\n  .offcanvas-xl.offcanvas-top {\\n    top: 0;\\n    left: 0;\\n    right: 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}\\n@media (max-width: 1199.98px) {\\n  .offcanvas-xl.offcanvas-bottom {\\n    left: 0;\\n    right: 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}\\n@media (max-width: 1199.98px) {\\n  .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 1199.98px) {\\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    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}\\n@media (max-width: 1399.98px) {\\n  .offcanvas-xxl.offcanvas-end {\\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}\\n@media (max-width: 1399.98px) {\\n  .offcanvas-xxl.offcanvas-top {\\n    top: 0;\\n    left: 0;\\n    right: 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}\\n@media (max-width: 1399.98px) {\\n  .offcanvas-xxl.offcanvas-bottom {\\n    left: 0;\\n    right: 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}\\n@media (max-width: 1399.98px) {\\n  .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) {\\n    transform: none;\\n  }\\n}\\n@media (max-width: 1399.98px) {\\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  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-end {\\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-top {\\n  top: 0;\\n  left: 0;\\n  right: 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  left: 0;\\n  right: 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  right: 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  justify-content: space-between;\\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-top: calc(-0.5 * var(--bs-offcanvas-padding-y));\\n  margin-left: calc(-0.5 * var(--bs-offcanvas-padding-x));\\n  margin-bottom: calc(-0.5 * var(--bs-offcanvas-padding-y));\\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  -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\\n  mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\\n  -webkit-mask-size: 200% 100%;\\n  mask-size: 200% 100%;\\n  animation: placeholder-wave 2s linear infinite;\\n}\\n\\n@keyframes placeholder-wave {\\n  100% {\\n    -webkit-mask-position: -200% 0%;\\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(13, 110, 253, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-secondary {\\n  color: #fff !important;\\n  background-color: RGBA(108, 117, 125, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-success {\\n  color: #fff !important;\\n  background-color: RGBA(25, 135, 84, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-info {\\n  color: #000 !important;\\n  background-color: RGBA(13, 202, 240, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-warning {\\n  color: #000 !important;\\n  background-color: RGBA(255, 193, 7, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-danger {\\n  color: #fff !important;\\n  background-color: RGBA(220, 53, 69, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-light {\\n  color: #000 !important;\\n  background-color: RGBA(248, 249, 250, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.text-bg-dark {\\n  color: #fff !important;\\n  background-color: RGBA(33, 37, 41, var(--bs-bg-opacity, 1)) !important;\\n}\\n\\n.link-primary {\\n  color: #0d6efd !important;\\n}\\n.link-primary:hover, .link-primary:focus {\\n  color: #0a58ca !important;\\n}\\n\\n.link-secondary {\\n  color: #6c757d !important;\\n}\\n.link-secondary:hover, .link-secondary:focus {\\n  color: #565e64 !important;\\n}\\n\\n.link-success {\\n  color: #198754 !important;\\n}\\n.link-success:hover, .link-success:focus {\\n  color: #146c43 !important;\\n}\\n\\n.link-info {\\n  color: #0dcaf0 !important;\\n}\\n.link-info:hover, .link-info:focus {\\n  color: #3dd5f3 !important;\\n}\\n\\n.link-warning {\\n  color: #ffc107 !important;\\n}\\n.link-warning:hover, .link-warning:focus {\\n  color: #ffcd39 !important;\\n}\\n\\n.link-danger {\\n  color: #dc3545 !important;\\n}\\n.link-danger:hover, .link-danger:focus {\\n  color: #b02a37 !important;\\n}\\n\\n.link-light {\\n  color: #f8f9fa !important;\\n}\\n.link-light:hover, .link-light:focus {\\n  color: #f9fafb !important;\\n}\\n\\n.link-dark {\\n  color: #212529 !important;\\n}\\n.link-dark:hover, .link-dark:focus {\\n  color: #1a1e21 !important;\\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  right: 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  left: 0;\\n  right: 0;\\n  z-index: 1030;\\n}\\n\\n.fixed-bottom {\\n  position: fixed;\\n  left: 0;\\n  bottom: 0;\\n  right: 0;\\n  z-index: 1030;\\n}\\n\\n.sticky-top {\\n  position: -webkit-sticky;\\n  position: sticky;\\n  top: 0;\\n  z-index: 1020;\\n}\\n\\n.sticky-bottom {\\n  position: -webkit-sticky;\\n  position: sticky;\\n  bottom: 0;\\n  z-index: 1020;\\n}\\n\\n@media (min-width: 576px) {\\n  .sticky-sm-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-sm-bottom {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    bottom: 0;\\n    z-index: 1020;\\n  }\\n}\\n@media (min-width: 768px) {\\n  .sticky-md-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-md-bottom {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    bottom: 0;\\n    z-index: 1020;\\n  }\\n}\\n@media (min-width: 992px) {\\n  .sticky-lg-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-lg-bottom {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    bottom: 0;\\n    z-index: 1020;\\n  }\\n}\\n@media (min-width: 1200px) {\\n  .sticky-xl-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-xl-bottom {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    bottom: 0;\\n    z-index: 1020;\\n  }\\n}\\n@media (min-width: 1400px) {\\n  .sticky-xxl-top {\\n    position: -webkit-sticky;\\n    position: sticky;\\n    top: 0;\\n    z-index: 1020;\\n  }\\n  .sticky-xxl-bottom {\\n    position: -webkit-sticky;\\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  position: absolute !important;\\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\\n.stretched-link::after {\\n  position: absolute;\\n  top: 0;\\n  left: 0;\\n  bottom: 0;\\n  right: 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: 1px;\\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: right !important;\\n}\\n\\n.float-end {\\n  float: left !important;\\n}\\n\\n.float-none {\\n  float: none !important;\\n}\\n\\n.object-fit-contain {\\n  -o-object-fit: contain !important;\\n  object-fit: contain !important;\\n}\\n\\n.object-fit-cover {\\n  -o-object-fit: cover !important;\\n  object-fit: cover !important;\\n}\\n\\n.object-fit-fill {\\n  -o-object-fit: fill !important;\\n  object-fit: fill !important;\\n}\\n\\n.object-fit-scale {\\n  -o-object-fit: scale-down !important;\\n  object-fit: scale-down !important;\\n}\\n\\n.object-fit-none {\\n  -o-object-fit: none !important;\\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-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: 0 0.5rem 1rem rgba(var(--bs-body-color-rgb), 0.15) !important;\\n}\\n\\n.shadow-sm {\\n  box-shadow: 0 0.125rem 0.25rem rgba(var(--bs-body-color-rgb), 0.075) !important;\\n}\\n\\n.shadow-lg {\\n  box-shadow: 0 1rem 3rem rgba(var(--bs-body-color-rgb), 0.175) !important;\\n}\\n\\n.shadow-none {\\n  box-shadow: none !important;\\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: -webkit-sticky !important;\\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  right: 0 !important;\\n}\\n\\n.start-50 {\\n  right: 50% !important;\\n}\\n\\n.start-100 {\\n  right: 100% !important;\\n}\\n\\n.end-0 {\\n  left: 0 !important;\\n}\\n\\n.end-50 {\\n  left: 50% !important;\\n}\\n\\n.end-100 {\\n  left: 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-left: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\\n}\\n\\n.border-end-0 {\\n  border-left: 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-right: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important;\\n}\\n\\n.border-start-0 {\\n  border-right: 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-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  --bs-border-width: 1px;\\n}\\n\\n.border-2 {\\n  --bs-border-width: 2px;\\n}\\n\\n.border-3 {\\n  --bs-border-width: 3px;\\n}\\n\\n.border-4 {\\n  --bs-border-width: 4px;\\n}\\n\\n.border-5 {\\n  --bs-border-width: 5px;\\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-left: 0 !important;\\n  margin-right: 0 !important;\\n}\\n\\n.mx-1 {\\n  margin-left: 0.25rem !important;\\n  margin-right: 0.25rem !important;\\n}\\n\\n.mx-2 {\\n  margin-left: 0.5rem !important;\\n  margin-right: 0.5rem !important;\\n}\\n\\n.mx-3 {\\n  margin-left: 1rem !important;\\n  margin-right: 1rem !important;\\n}\\n\\n.mx-4 {\\n  margin-left: 1.5rem !important;\\n  margin-right: 1.5rem !important;\\n}\\n\\n.mx-5 {\\n  margin-left: 3rem !important;\\n  margin-right: 3rem !important;\\n}\\n\\n.mx-auto {\\n  margin-left: auto !important;\\n  margin-right: 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-left: 0 !important;\\n}\\n\\n.me-1 {\\n  margin-left: 0.25rem !important;\\n}\\n\\n.me-2 {\\n  margin-left: 0.5rem !important;\\n}\\n\\n.me-3 {\\n  margin-left: 1rem !important;\\n}\\n\\n.me-4 {\\n  margin-left: 1.5rem !important;\\n}\\n\\n.me-5 {\\n  margin-left: 3rem !important;\\n}\\n\\n.me-auto {\\n  margin-left: 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-right: 0 !important;\\n}\\n\\n.ms-1 {\\n  margin-right: 0.25rem !important;\\n}\\n\\n.ms-2 {\\n  margin-right: 0.5rem !important;\\n}\\n\\n.ms-3 {\\n  margin-right: 1rem !important;\\n}\\n\\n.ms-4 {\\n  margin-right: 1.5rem !important;\\n}\\n\\n.ms-5 {\\n  margin-right: 3rem !important;\\n}\\n\\n.ms-auto {\\n  margin-right: 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-left: 0 !important;\\n  padding-right: 0 !important;\\n}\\n\\n.px-1 {\\n  padding-left: 0.25rem !important;\\n  padding-right: 0.25rem !important;\\n}\\n\\n.px-2 {\\n  padding-left: 0.5rem !important;\\n  padding-right: 0.5rem !important;\\n}\\n\\n.px-3 {\\n  padding-left: 1rem !important;\\n  padding-right: 1rem !important;\\n}\\n\\n.px-4 {\\n  padding-left: 1.5rem !important;\\n  padding-right: 1.5rem !important;\\n}\\n\\n.px-5 {\\n  padding-left: 3rem !important;\\n  padding-right: 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-left: 0 !important;\\n}\\n\\n.pe-1 {\\n  padding-left: 0.25rem !important;\\n}\\n\\n.pe-2 {\\n  padding-left: 0.5rem !important;\\n}\\n\\n.pe-3 {\\n  padding-left: 1rem !important;\\n}\\n\\n.pe-4 {\\n  padding-left: 1.5rem !important;\\n}\\n\\n.pe-5 {\\n  padding-left: 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-right: 0 !important;\\n}\\n\\n.ps-1 {\\n  padding-right: 0.25rem !important;\\n}\\n\\n.ps-2 {\\n  padding-right: 0.5rem !important;\\n}\\n\\n.ps-3 {\\n  padding-right: 1rem !important;\\n}\\n\\n.ps-4 {\\n  padding-right: 1.5rem !important;\\n}\\n\\n.ps-5 {\\n  padding-right: 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  -moz-column-gap: 0 !important;\\n  column-gap: 0 !important;\\n}\\n\\n.column-gap-1 {\\n  -moz-column-gap: 0.25rem !important;\\n  column-gap: 0.25rem !important;\\n}\\n\\n.column-gap-2 {\\n  -moz-column-gap: 0.5rem !important;\\n  column-gap: 0.5rem !important;\\n}\\n\\n.column-gap-3 {\\n  -moz-column-gap: 1rem !important;\\n  column-gap: 1rem !important;\\n}\\n\\n.column-gap-4 {\\n  -moz-column-gap: 1.5rem !important;\\n  column-gap: 1.5rem !important;\\n}\\n\\n.column-gap-5 {\\n  -moz-column-gap: 3rem !important;\\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: right !important;\\n}\\n\\n.text-end {\\n  text-align: left !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.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) !important;\\n}\\n\\n.text-secondary-emphasis {\\n  color: var(--bs-secondary-text) !important;\\n}\\n\\n.text-success-emphasis {\\n  color: var(--bs-success-text) !important;\\n}\\n\\n.text-info-emphasis {\\n  color: var(--bs-info-text) !important;\\n}\\n\\n.text-warning-emphasis {\\n  color: var(--bs-warning-text) !important;\\n}\\n\\n.text-danger-emphasis {\\n  color: var(--bs-danger-text) !important;\\n}\\n\\n.text-light-emphasis {\\n  color: var(--bs-light-text) !important;\\n}\\n\\n.text-dark-emphasis {\\n  color: var(--bs-dark-text) !important;\\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-body-emphasis {\\n  --bs-bg-opacity: 1;\\n  background-color: rgba(var(--bs-emphasis-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  -webkit-user-select: all !important;\\n  -moz-user-select: all !important;\\n  user-select: all !important;\\n}\\n\\n.user-select-auto {\\n  -webkit-user-select: auto !important;\\n  -moz-user-select: auto !important;\\n  user-select: auto !important;\\n}\\n\\n.user-select-none {\\n  -webkit-user-select: none !important;\\n  -moz-user-select: none !important;\\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-2xl) !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-right-radius: var(--bs-border-radius) !important;\\n  border-top-left-radius: var(--bs-border-radius) !important;\\n}\\n\\n.rounded-top-0 {\\n  border-top-right-radius: 0 !important;\\n  border-top-left-radius: 0 !important;\\n}\\n\\n.rounded-top-1 {\\n  border-top-right-radius: var(--bs-border-radius-sm) !important;\\n  border-top-left-radius: var(--bs-border-radius-sm) !important;\\n}\\n\\n.rounded-top-2 {\\n  border-top-right-radius: var(--bs-border-radius) !important;\\n  border-top-left-radius: var(--bs-border-radius) !important;\\n}\\n\\n.rounded-top-3 {\\n  border-top-right-radius: var(--bs-border-radius-lg) !important;\\n  border-top-left-radius: var(--bs-border-radius-lg) !important;\\n}\\n\\n.rounded-top-4 {\\n  border-top-right-radius: var(--bs-border-radius-xl) !important;\\n  border-top-left-radius: var(--bs-border-radius-xl) !important;\\n}\\n\\n.rounded-top-5 {\\n  border-top-right-radius: var(--bs-border-radius-2xl) !important;\\n  border-top-left-radius: var(--bs-border-radius-2xl) !important;\\n}\\n\\n.rounded-top-circle {\\n  border-top-right-radius: 50% !important;\\n  border-top-left-radius: 50% !important;\\n}\\n\\n.rounded-top-pill {\\n  border-top-right-radius: var(--bs-border-radius-pill) !important;\\n  border-top-left-radius: var(--bs-border-radius-pill) !important;\\n}\\n\\n.rounded-end {\\n  border-top-left-radius: var(--bs-border-radius) !important;\\n  border-bottom-left-radius: var(--bs-border-radius) !important;\\n}\\n\\n.rounded-end-0 {\\n  border-top-left-radius: 0 !important;\\n  border-bottom-left-radius: 0 !important;\\n}\\n\\n.rounded-end-1 {\\n  border-top-left-radius: var(--bs-border-radius-sm) !important;\\n  border-bottom-left-radius: var(--bs-border-radius-sm) !important;\\n}\\n\\n.rounded-end-2 {\\n  border-top-left-radius: var(--bs-border-radius) !important;\\n  border-bottom-left-radius: var(--bs-border-radius) !important;\\n}\\n\\n.rounded-end-3 {\\n  border-top-left-radius: var(--bs-border-radius-lg) !important;\\n  border-bottom-left-radius: var(--bs-border-radius-lg) !important;\\n}\\n\\n.rounded-end-4 {\\n  border-top-left-radius: var(--bs-border-radius-xl) !important;\\n  border-bottom-left-radius: var(--bs-border-radius-xl) !important;\\n}\\n\\n.rounded-end-5 {\\n  border-top-left-radius: var(--bs-border-radius-2xl) !important;\\n  border-bottom-left-radius: var(--bs-border-radius-2xl) !important;\\n}\\n\\n.rounded-end-circle {\\n  border-top-left-radius: 50% !important;\\n  border-bottom-left-radius: 50% !important;\\n}\\n\\n.rounded-end-pill {\\n  border-top-left-radius: var(--bs-border-radius-pill) !important;\\n  border-bottom-left-radius: var(--bs-border-radius-pill) !important;\\n}\\n\\n.rounded-bottom {\\n  border-bottom-left-radius: var(--bs-border-radius) !important;\\n  border-bottom-right-radius: var(--bs-border-radius) !important;\\n}\\n\\n.rounded-bottom-0 {\\n  border-bottom-left-radius: 0 !important;\\n  border-bottom-right-radius: 0 !important;\\n}\\n\\n.rounded-bottom-1 {\\n  border-bottom-left-radius: var(--bs-border-radius-sm) !important;\\n  border-bottom-right-radius: var(--bs-border-radius-sm) !important;\\n}\\n\\n.rounded-bottom-2 {\\n  border-bottom-left-radius: var(--bs-border-radius) !important;\\n  border-bottom-right-radius: var(--bs-border-radius) !important;\\n}\\n\\n.rounded-bottom-3 {\\n  border-bottom-left-radius: var(--bs-border-radius-lg) !important;\\n  border-bottom-right-radius: var(--bs-border-radius-lg) !important;\\n}\\n\\n.rounded-bottom-4 {\\n  border-bottom-left-radius: var(--bs-border-radius-xl) !important;\\n  border-bottom-right-radius: var(--bs-border-radius-xl) !important;\\n}\\n\\n.rounded-bottom-5 {\\n  border-bottom-left-radius: var(--bs-border-radius-2xl) !important;\\n  border-bottom-right-radius: var(--bs-border-radius-2xl) !important;\\n}\\n\\n.rounded-bottom-circle {\\n  border-bottom-left-radius: 50% !important;\\n  border-bottom-right-radius: 50% !important;\\n}\\n\\n.rounded-bottom-pill {\\n  border-bottom-left-radius: var(--bs-border-radius-pill) !important;\\n  border-bottom-right-radius: var(--bs-border-radius-pill) !important;\\n}\\n\\n.rounded-start {\\n  border-bottom-right-radius: var(--bs-border-radius) !important;\\n  border-top-right-radius: var(--bs-border-radius) !important;\\n}\\n\\n.rounded-start-0 {\\n  border-bottom-right-radius: 0 !important;\\n  border-top-right-radius: 0 !important;\\n}\\n\\n.rounded-start-1 {\\n  border-bottom-right-radius: var(--bs-border-radius-sm) !important;\\n  border-top-right-radius: var(--bs-border-radius-sm) !important;\\n}\\n\\n.rounded-start-2 {\\n  border-bottom-right-radius: var(--bs-border-radius) !important;\\n  border-top-right-radius: var(--bs-border-radius) !important;\\n}\\n\\n.rounded-start-3 {\\n  border-bottom-right-radius: var(--bs-border-radius-lg) !important;\\n  border-top-right-radius: var(--bs-border-radius-lg) !important;\\n}\\n\\n.rounded-start-4 {\\n  border-bottom-right-radius: var(--bs-border-radius-xl) !important;\\n  border-top-right-radius: var(--bs-border-radius-xl) !important;\\n}\\n\\n.rounded-start-5 {\\n  border-bottom-right-radius: var(--bs-border-radius-2xl) !important;\\n  border-top-right-radius: var(--bs-border-radius-2xl) !important;\\n}\\n\\n.rounded-start-circle {\\n  border-bottom-right-radius: 50% !important;\\n  border-top-right-radius: 50% !important;\\n}\\n\\n.rounded-start-pill {\\n  border-bottom-right-radius: var(--bs-border-radius-pill) !important;\\n  border-top-right-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: right !important;\\n  }\\n  .float-sm-end {\\n    float: left !important;\\n  }\\n  .float-sm-none {\\n    float: none !important;\\n  }\\n  .object-fit-sm-contain {\\n    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-sm-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-sm-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-sm-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-sm-none {\\n    -o-object-fit: none !important;\\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-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-left: 0 !important;\\n    margin-right: 0 !important;\\n  }\\n  .mx-sm-1 {\\n    margin-left: 0.25rem !important;\\n    margin-right: 0.25rem !important;\\n  }\\n  .mx-sm-2 {\\n    margin-left: 0.5rem !important;\\n    margin-right: 0.5rem !important;\\n  }\\n  .mx-sm-3 {\\n    margin-left: 1rem !important;\\n    margin-right: 1rem !important;\\n  }\\n  .mx-sm-4 {\\n    margin-left: 1.5rem !important;\\n    margin-right: 1.5rem !important;\\n  }\\n  .mx-sm-5 {\\n    margin-left: 3rem !important;\\n    margin-right: 3rem !important;\\n  }\\n  .mx-sm-auto {\\n    margin-left: auto !important;\\n    margin-right: 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-left: 0 !important;\\n  }\\n  .me-sm-1 {\\n    margin-left: 0.25rem !important;\\n  }\\n  .me-sm-2 {\\n    margin-left: 0.5rem !important;\\n  }\\n  .me-sm-3 {\\n    margin-left: 1rem !important;\\n  }\\n  .me-sm-4 {\\n    margin-left: 1.5rem !important;\\n  }\\n  .me-sm-5 {\\n    margin-left: 3rem !important;\\n  }\\n  .me-sm-auto {\\n    margin-left: 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-right: 0 !important;\\n  }\\n  .ms-sm-1 {\\n    margin-right: 0.25rem !important;\\n  }\\n  .ms-sm-2 {\\n    margin-right: 0.5rem !important;\\n  }\\n  .ms-sm-3 {\\n    margin-right: 1rem !important;\\n  }\\n  .ms-sm-4 {\\n    margin-right: 1.5rem !important;\\n  }\\n  .ms-sm-5 {\\n    margin-right: 3rem !important;\\n  }\\n  .ms-sm-auto {\\n    margin-right: 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-left: 0 !important;\\n    padding-right: 0 !important;\\n  }\\n  .px-sm-1 {\\n    padding-left: 0.25rem !important;\\n    padding-right: 0.25rem !important;\\n  }\\n  .px-sm-2 {\\n    padding-left: 0.5rem !important;\\n    padding-right: 0.5rem !important;\\n  }\\n  .px-sm-3 {\\n    padding-left: 1rem !important;\\n    padding-right: 1rem !important;\\n  }\\n  .px-sm-4 {\\n    padding-left: 1.5rem !important;\\n    padding-right: 1.5rem !important;\\n  }\\n  .px-sm-5 {\\n    padding-left: 3rem !important;\\n    padding-right: 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-left: 0 !important;\\n  }\\n  .pe-sm-1 {\\n    padding-left: 0.25rem !important;\\n  }\\n  .pe-sm-2 {\\n    padding-left: 0.5rem !important;\\n  }\\n  .pe-sm-3 {\\n    padding-left: 1rem !important;\\n  }\\n  .pe-sm-4 {\\n    padding-left: 1.5rem !important;\\n  }\\n  .pe-sm-5 {\\n    padding-left: 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-right: 0 !important;\\n  }\\n  .ps-sm-1 {\\n    padding-right: 0.25rem !important;\\n  }\\n  .ps-sm-2 {\\n    padding-right: 0.5rem !important;\\n  }\\n  .ps-sm-3 {\\n    padding-right: 1rem !important;\\n  }\\n  .ps-sm-4 {\\n    padding-right: 1.5rem !important;\\n  }\\n  .ps-sm-5 {\\n    padding-right: 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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-sm-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-sm-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-sm-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-sm-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-sm-5 {\\n    -moz-column-gap: 3rem !important;\\n    column-gap: 3rem !important;\\n  }\\n  .text-sm-start {\\n    text-align: right !important;\\n  }\\n  .text-sm-end {\\n    text-align: left !important;\\n  }\\n  .text-sm-center {\\n    text-align: center !important;\\n  }\\n}\\n@media (min-width: 768px) {\\n  .float-md-start {\\n    float: right !important;\\n  }\\n  .float-md-end {\\n    float: left !important;\\n  }\\n  .float-md-none {\\n    float: none !important;\\n  }\\n  .object-fit-md-contain {\\n    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-md-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-md-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-md-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-md-none {\\n    -o-object-fit: none !important;\\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-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-left: 0 !important;\\n    margin-right: 0 !important;\\n  }\\n  .mx-md-1 {\\n    margin-left: 0.25rem !important;\\n    margin-right: 0.25rem !important;\\n  }\\n  .mx-md-2 {\\n    margin-left: 0.5rem !important;\\n    margin-right: 0.5rem !important;\\n  }\\n  .mx-md-3 {\\n    margin-left: 1rem !important;\\n    margin-right: 1rem !important;\\n  }\\n  .mx-md-4 {\\n    margin-left: 1.5rem !important;\\n    margin-right: 1.5rem !important;\\n  }\\n  .mx-md-5 {\\n    margin-left: 3rem !important;\\n    margin-right: 3rem !important;\\n  }\\n  .mx-md-auto {\\n    margin-left: auto !important;\\n    margin-right: 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-left: 0 !important;\\n  }\\n  .me-md-1 {\\n    margin-left: 0.25rem !important;\\n  }\\n  .me-md-2 {\\n    margin-left: 0.5rem !important;\\n  }\\n  .me-md-3 {\\n    margin-left: 1rem !important;\\n  }\\n  .me-md-4 {\\n    margin-left: 1.5rem !important;\\n  }\\n  .me-md-5 {\\n    margin-left: 3rem !important;\\n  }\\n  .me-md-auto {\\n    margin-left: 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-right: 0 !important;\\n  }\\n  .ms-md-1 {\\n    margin-right: 0.25rem !important;\\n  }\\n  .ms-md-2 {\\n    margin-right: 0.5rem !important;\\n  }\\n  .ms-md-3 {\\n    margin-right: 1rem !important;\\n  }\\n  .ms-md-4 {\\n    margin-right: 1.5rem !important;\\n  }\\n  .ms-md-5 {\\n    margin-right: 3rem !important;\\n  }\\n  .ms-md-auto {\\n    margin-right: 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-left: 0 !important;\\n    padding-right: 0 !important;\\n  }\\n  .px-md-1 {\\n    padding-left: 0.25rem !important;\\n    padding-right: 0.25rem !important;\\n  }\\n  .px-md-2 {\\n    padding-left: 0.5rem !important;\\n    padding-right: 0.5rem !important;\\n  }\\n  .px-md-3 {\\n    padding-left: 1rem !important;\\n    padding-right: 1rem !important;\\n  }\\n  .px-md-4 {\\n    padding-left: 1.5rem !important;\\n    padding-right: 1.5rem !important;\\n  }\\n  .px-md-5 {\\n    padding-left: 3rem !important;\\n    padding-right: 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-left: 0 !important;\\n  }\\n  .pe-md-1 {\\n    padding-left: 0.25rem !important;\\n  }\\n  .pe-md-2 {\\n    padding-left: 0.5rem !important;\\n  }\\n  .pe-md-3 {\\n    padding-left: 1rem !important;\\n  }\\n  .pe-md-4 {\\n    padding-left: 1.5rem !important;\\n  }\\n  .pe-md-5 {\\n    padding-left: 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-right: 0 !important;\\n  }\\n  .ps-md-1 {\\n    padding-right: 0.25rem !important;\\n  }\\n  .ps-md-2 {\\n    padding-right: 0.5rem !important;\\n  }\\n  .ps-md-3 {\\n    padding-right: 1rem !important;\\n  }\\n  .ps-md-4 {\\n    padding-right: 1.5rem !important;\\n  }\\n  .ps-md-5 {\\n    padding-right: 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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-md-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-md-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-md-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-md-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-md-5 {\\n    -moz-column-gap: 3rem !important;\\n    column-gap: 3rem !important;\\n  }\\n  .text-md-start {\\n    text-align: right !important;\\n  }\\n  .text-md-end {\\n    text-align: left !important;\\n  }\\n  .text-md-center {\\n    text-align: center !important;\\n  }\\n}\\n@media (min-width: 992px) {\\n  .float-lg-start {\\n    float: right !important;\\n  }\\n  .float-lg-end {\\n    float: left !important;\\n  }\\n  .float-lg-none {\\n    float: none !important;\\n  }\\n  .object-fit-lg-contain {\\n    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-lg-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-lg-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-lg-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-lg-none {\\n    -o-object-fit: none !important;\\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-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-left: 0 !important;\\n    margin-right: 0 !important;\\n  }\\n  .mx-lg-1 {\\n    margin-left: 0.25rem !important;\\n    margin-right: 0.25rem !important;\\n  }\\n  .mx-lg-2 {\\n    margin-left: 0.5rem !important;\\n    margin-right: 0.5rem !important;\\n  }\\n  .mx-lg-3 {\\n    margin-left: 1rem !important;\\n    margin-right: 1rem !important;\\n  }\\n  .mx-lg-4 {\\n    margin-left: 1.5rem !important;\\n    margin-right: 1.5rem !important;\\n  }\\n  .mx-lg-5 {\\n    margin-left: 3rem !important;\\n    margin-right: 3rem !important;\\n  }\\n  .mx-lg-auto {\\n    margin-left: auto !important;\\n    margin-right: 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-left: 0 !important;\\n  }\\n  .me-lg-1 {\\n    margin-left: 0.25rem !important;\\n  }\\n  .me-lg-2 {\\n    margin-left: 0.5rem !important;\\n  }\\n  .me-lg-3 {\\n    margin-left: 1rem !important;\\n  }\\n  .me-lg-4 {\\n    margin-left: 1.5rem !important;\\n  }\\n  .me-lg-5 {\\n    margin-left: 3rem !important;\\n  }\\n  .me-lg-auto {\\n    margin-left: 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-right: 0 !important;\\n  }\\n  .ms-lg-1 {\\n    margin-right: 0.25rem !important;\\n  }\\n  .ms-lg-2 {\\n    margin-right: 0.5rem !important;\\n  }\\n  .ms-lg-3 {\\n    margin-right: 1rem !important;\\n  }\\n  .ms-lg-4 {\\n    margin-right: 1.5rem !important;\\n  }\\n  .ms-lg-5 {\\n    margin-right: 3rem !important;\\n  }\\n  .ms-lg-auto {\\n    margin-right: 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-left: 0 !important;\\n    padding-right: 0 !important;\\n  }\\n  .px-lg-1 {\\n    padding-left: 0.25rem !important;\\n    padding-right: 0.25rem !important;\\n  }\\n  .px-lg-2 {\\n    padding-left: 0.5rem !important;\\n    padding-right: 0.5rem !important;\\n  }\\n  .px-lg-3 {\\n    padding-left: 1rem !important;\\n    padding-right: 1rem !important;\\n  }\\n  .px-lg-4 {\\n    padding-left: 1.5rem !important;\\n    padding-right: 1.5rem !important;\\n  }\\n  .px-lg-5 {\\n    padding-left: 3rem !important;\\n    padding-right: 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-left: 0 !important;\\n  }\\n  .pe-lg-1 {\\n    padding-left: 0.25rem !important;\\n  }\\n  .pe-lg-2 {\\n    padding-left: 0.5rem !important;\\n  }\\n  .pe-lg-3 {\\n    padding-left: 1rem !important;\\n  }\\n  .pe-lg-4 {\\n    padding-left: 1.5rem !important;\\n  }\\n  .pe-lg-5 {\\n    padding-left: 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-right: 0 !important;\\n  }\\n  .ps-lg-1 {\\n    padding-right: 0.25rem !important;\\n  }\\n  .ps-lg-2 {\\n    padding-right: 0.5rem !important;\\n  }\\n  .ps-lg-3 {\\n    padding-right: 1rem !important;\\n  }\\n  .ps-lg-4 {\\n    padding-right: 1.5rem !important;\\n  }\\n  .ps-lg-5 {\\n    padding-right: 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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-lg-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-lg-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-lg-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-lg-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-lg-5 {\\n    -moz-column-gap: 3rem !important;\\n    column-gap: 3rem !important;\\n  }\\n  .text-lg-start {\\n    text-align: right !important;\\n  }\\n  .text-lg-end {\\n    text-align: left !important;\\n  }\\n  .text-lg-center {\\n    text-align: center !important;\\n  }\\n}\\n@media (min-width: 1200px) {\\n  .float-xl-start {\\n    float: right !important;\\n  }\\n  .float-xl-end {\\n    float: left !important;\\n  }\\n  .float-xl-none {\\n    float: none !important;\\n  }\\n  .object-fit-xl-contain {\\n    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-xl-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-xl-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-xl-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-xl-none {\\n    -o-object-fit: none !important;\\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-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-left: 0 !important;\\n    margin-right: 0 !important;\\n  }\\n  .mx-xl-1 {\\n    margin-left: 0.25rem !important;\\n    margin-right: 0.25rem !important;\\n  }\\n  .mx-xl-2 {\\n    margin-left: 0.5rem !important;\\n    margin-right: 0.5rem !important;\\n  }\\n  .mx-xl-3 {\\n    margin-left: 1rem !important;\\n    margin-right: 1rem !important;\\n  }\\n  .mx-xl-4 {\\n    margin-left: 1.5rem !important;\\n    margin-right: 1.5rem !important;\\n  }\\n  .mx-xl-5 {\\n    margin-left: 3rem !important;\\n    margin-right: 3rem !important;\\n  }\\n  .mx-xl-auto {\\n    margin-left: auto !important;\\n    margin-right: 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-left: 0 !important;\\n  }\\n  .me-xl-1 {\\n    margin-left: 0.25rem !important;\\n  }\\n  .me-xl-2 {\\n    margin-left: 0.5rem !important;\\n  }\\n  .me-xl-3 {\\n    margin-left: 1rem !important;\\n  }\\n  .me-xl-4 {\\n    margin-left: 1.5rem !important;\\n  }\\n  .me-xl-5 {\\n    margin-left: 3rem !important;\\n  }\\n  .me-xl-auto {\\n    margin-left: 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-right: 0 !important;\\n  }\\n  .ms-xl-1 {\\n    margin-right: 0.25rem !important;\\n  }\\n  .ms-xl-2 {\\n    margin-right: 0.5rem !important;\\n  }\\n  .ms-xl-3 {\\n    margin-right: 1rem !important;\\n  }\\n  .ms-xl-4 {\\n    margin-right: 1.5rem !important;\\n  }\\n  .ms-xl-5 {\\n    margin-right: 3rem !important;\\n  }\\n  .ms-xl-auto {\\n    margin-right: 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-left: 0 !important;\\n    padding-right: 0 !important;\\n  }\\n  .px-xl-1 {\\n    padding-left: 0.25rem !important;\\n    padding-right: 0.25rem !important;\\n  }\\n  .px-xl-2 {\\n    padding-left: 0.5rem !important;\\n    padding-right: 0.5rem !important;\\n  }\\n  .px-xl-3 {\\n    padding-left: 1rem !important;\\n    padding-right: 1rem !important;\\n  }\\n  .px-xl-4 {\\n    padding-left: 1.5rem !important;\\n    padding-right: 1.5rem !important;\\n  }\\n  .px-xl-5 {\\n    padding-left: 3rem !important;\\n    padding-right: 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-left: 0 !important;\\n  }\\n  .pe-xl-1 {\\n    padding-left: 0.25rem !important;\\n  }\\n  .pe-xl-2 {\\n    padding-left: 0.5rem !important;\\n  }\\n  .pe-xl-3 {\\n    padding-left: 1rem !important;\\n  }\\n  .pe-xl-4 {\\n    padding-left: 1.5rem !important;\\n  }\\n  .pe-xl-5 {\\n    padding-left: 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-right: 0 !important;\\n  }\\n  .ps-xl-1 {\\n    padding-right: 0.25rem !important;\\n  }\\n  .ps-xl-2 {\\n    padding-right: 0.5rem !important;\\n  }\\n  .ps-xl-3 {\\n    padding-right: 1rem !important;\\n  }\\n  .ps-xl-4 {\\n    padding-right: 1.5rem !important;\\n  }\\n  .ps-xl-5 {\\n    padding-right: 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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-xl-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-xl-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-xl-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-xl-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-xl-5 {\\n    -moz-column-gap: 3rem !important;\\n    column-gap: 3rem !important;\\n  }\\n  .text-xl-start {\\n    text-align: right !important;\\n  }\\n  .text-xl-end {\\n    text-align: left !important;\\n  }\\n  .text-xl-center {\\n    text-align: center !important;\\n  }\\n}\\n@media (min-width: 1400px) {\\n  .float-xxl-start {\\n    float: right !important;\\n  }\\n  .float-xxl-end {\\n    float: left !important;\\n  }\\n  .float-xxl-none {\\n    float: none !important;\\n  }\\n  .object-fit-xxl-contain {\\n    -o-object-fit: contain !important;\\n    object-fit: contain !important;\\n  }\\n  .object-fit-xxl-cover {\\n    -o-object-fit: cover !important;\\n    object-fit: cover !important;\\n  }\\n  .object-fit-xxl-fill {\\n    -o-object-fit: fill !important;\\n    object-fit: fill !important;\\n  }\\n  .object-fit-xxl-scale {\\n    -o-object-fit: scale-down !important;\\n    object-fit: scale-down !important;\\n  }\\n  .object-fit-xxl-none {\\n    -o-object-fit: none !important;\\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-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-left: 0 !important;\\n    margin-right: 0 !important;\\n  }\\n  .mx-xxl-1 {\\n    margin-left: 0.25rem !important;\\n    margin-right: 0.25rem !important;\\n  }\\n  .mx-xxl-2 {\\n    margin-left: 0.5rem !important;\\n    margin-right: 0.5rem !important;\\n  }\\n  .mx-xxl-3 {\\n    margin-left: 1rem !important;\\n    margin-right: 1rem !important;\\n  }\\n  .mx-xxl-4 {\\n    margin-left: 1.5rem !important;\\n    margin-right: 1.5rem !important;\\n  }\\n  .mx-xxl-5 {\\n    margin-left: 3rem !important;\\n    margin-right: 3rem !important;\\n  }\\n  .mx-xxl-auto {\\n    margin-left: auto !important;\\n    margin-right: 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-left: 0 !important;\\n  }\\n  .me-xxl-1 {\\n    margin-left: 0.25rem !important;\\n  }\\n  .me-xxl-2 {\\n    margin-left: 0.5rem !important;\\n  }\\n  .me-xxl-3 {\\n    margin-left: 1rem !important;\\n  }\\n  .me-xxl-4 {\\n    margin-left: 1.5rem !important;\\n  }\\n  .me-xxl-5 {\\n    margin-left: 3rem !important;\\n  }\\n  .me-xxl-auto {\\n    margin-left: 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-right: 0 !important;\\n  }\\n  .ms-xxl-1 {\\n    margin-right: 0.25rem !important;\\n  }\\n  .ms-xxl-2 {\\n    margin-right: 0.5rem !important;\\n  }\\n  .ms-xxl-3 {\\n    margin-right: 1rem !important;\\n  }\\n  .ms-xxl-4 {\\n    margin-right: 1.5rem !important;\\n  }\\n  .ms-xxl-5 {\\n    margin-right: 3rem !important;\\n  }\\n  .ms-xxl-auto {\\n    margin-right: 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-left: 0 !important;\\n    padding-right: 0 !important;\\n  }\\n  .px-xxl-1 {\\n    padding-left: 0.25rem !important;\\n    padding-right: 0.25rem !important;\\n  }\\n  .px-xxl-2 {\\n    padding-left: 0.5rem !important;\\n    padding-right: 0.5rem !important;\\n  }\\n  .px-xxl-3 {\\n    padding-left: 1rem !important;\\n    padding-right: 1rem !important;\\n  }\\n  .px-xxl-4 {\\n    padding-left: 1.5rem !important;\\n    padding-right: 1.5rem !important;\\n  }\\n  .px-xxl-5 {\\n    padding-left: 3rem !important;\\n    padding-right: 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-left: 0 !important;\\n  }\\n  .pe-xxl-1 {\\n    padding-left: 0.25rem !important;\\n  }\\n  .pe-xxl-2 {\\n    padding-left: 0.5rem !important;\\n  }\\n  .pe-xxl-3 {\\n    padding-left: 1rem !important;\\n  }\\n  .pe-xxl-4 {\\n    padding-left: 1.5rem !important;\\n  }\\n  .pe-xxl-5 {\\n    padding-left: 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-right: 0 !important;\\n  }\\n  .ps-xxl-1 {\\n    padding-right: 0.25rem !important;\\n  }\\n  .ps-xxl-2 {\\n    padding-right: 0.5rem !important;\\n  }\\n  .ps-xxl-3 {\\n    padding-right: 1rem !important;\\n  }\\n  .ps-xxl-4 {\\n    padding-right: 1.5rem !important;\\n  }\\n  .ps-xxl-5 {\\n    padding-right: 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    -moz-column-gap: 0 !important;\\n    column-gap: 0 !important;\\n  }\\n  .column-gap-xxl-1 {\\n    -moz-column-gap: 0.25rem !important;\\n    column-gap: 0.25rem !important;\\n  }\\n  .column-gap-xxl-2 {\\n    -moz-column-gap: 0.5rem !important;\\n    column-gap: 0.5rem !important;\\n  }\\n  .column-gap-xxl-3 {\\n    -moz-column-gap: 1rem !important;\\n    column-gap: 1rem !important;\\n  }\\n  .column-gap-xxl-4 {\\n    -moz-column-gap: 1.5rem !important;\\n    column-gap: 1.5rem !important;\\n  }\\n  .column-gap-xxl-5 {\\n    -moz-column-gap: 3rem !important;\\n    column-gap: 3rem !important;\\n  }\\n  .text-xxl-start {\\n    text-align: right !important;\\n  }\\n  .text-xxl-end {\\n    text-align: left !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-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/*# sourceMappingURL=bootstrap.rtl.css.map */\",\"// stylelint-disable property-blacklist, scss/dollar-variable-default\\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  }\\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      }\\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    }\\n\\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      }\\n\\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    $fluidVal: rfs-fluid-value($values);\\n\\n    // Do not print the media query if responsive & non-responsive values are the same\\n    @if $val == $fluidVal {\\n      #{$property}: $val;\\n    }\\n    @else {\\n      @include _rfs-rule {\\n        #{$property}: if($rfs-mode == max-media-query, $val, $fluidVal);\\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, $fluidVal, $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, `<h1>`-`<h6>` 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, inherit);\\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 `<p>`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  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 `<td>` 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-`<button>` buttons\\n//\\n// Details at https://github.com/twbs/bootstrap/pull/30562\\n[role=\\\"button\\\"] {\\n  cursor: pointer;\\n}\\n\\nselect {\\n  // Remove the inheritance of word-wrap in Safari.\\n  // See https://github.com/twbs/bootstrap/issues/24990\\n  word-wrap: normal;\\n\\n  // Undo the opacity change from Chrome\\n  &:disabled {\\n    opacity: 1;\\n  }\\n}\\n\\n// Remove the dropdown arrow only from text type inputs built with datalists in Chrome.\\n// See https://stackoverflow.com/a/54997118\\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\\n// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`\\n//    controls in Android 4.\\n// 2. Correct the inability to style clickable types in iOS and Safari.\\n// 3. Opinionated: add \\\"hand\\\" cursor to non-disabled button elements.\\n\\nbutton,\\n[type=\\\"button\\\"], // 1\\n[type=\\\"reset\\\"],\\n[type=\\\"submit\\\"] {\\n  -webkit-appearance: button; // 2\\n\\n  @if $enable-button-pointers {\\n    &:not(:disabled) {\\n      cursor: pointer; // 3\\n    }\\n  }\\n}\\n\\n// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.\\n\\n::-moz-focus-inner {\\n  padding: 0;\\n  border-style: none;\\n}\\n\\n// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers.\\n\\ntextarea {\\n  resize: vertical; // 1\\n}\\n\\n// 1. Browsers set a default `min-width: min-content;` on fieldsets,\\n//    unlike e.g. `<div>`s, which have `min-width: 0;` by default.\\n//    So we reset that to ensure fieldsets behave more like a standard block element.\\n//    See https://github.com/twbs/bootstrap/issues/12359\\n//    and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements\\n// 2. Reset the default outline behavior of fieldsets so they don't affect page layout.\\n\\nfieldset {\\n  min-width: 0; // 1\\n  padding: 0; // 2\\n  margin: 0; // 2\\n  border: 0; // 2\\n}\\n\\n// 1. By using `float: left`, the legend will behave like a block element.\\n//    This way the border of a fieldset wraps around the legend if present.\\n// 2. Fix wrapping bug.\\n//    See https://github.com/twbs/bootstrap/issues/29712\\n\\nlegend {\\n  float: left; // 1\\n  width: 100%;\\n  padding: 0;\\n  margin-bottom: $legend-margin-bottom;\\n  @include font-size($legend-font-size);\\n  font-weight: $legend-font-weight;\\n  line-height: inherit;\\n\\n  + * {\\n    clear: left; // 2\\n  }\\n}\\n\\n// Fix height of inputs with a type of datetime-local, date, month, week, or time\\n// See https://github.com/twbs/bootstrap/issues/18842\\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// 1. Correct the outline style in Safari.\\n// 2. This overrides the extra rounded corners on search inputs in iOS so that our\\n//    `.form-control` class can properly style them. Note that this cannot simply\\n//    be added to `.form-control` as it's not specific enough. For details, see\\n//    https://github.com/twbs/bootstrap/issues/11586.\\n\\n[type=\\\"search\\\"] {\\n  outline-offset: -2px; // 1\\n  -webkit-appearance: textfield; // 2\\n}\\n\\n// 1. A few input types should stay LTR\\n// See https://rtlstyling.com/posts/rtl-styling#form-inputs\\n// 2. RTL only output\\n// See https://rtlcss.com/learn/usage-guide/control-directives/#raw\\n\\n/* rtl:raw:\\n[type=\\\"tel\\\"],\\n[type=\\\"url\\\"],\\n[type=\\\"email\\\"],\\n[type=\\\"number\\\"] {\\n  direction: ltr;\\n}\\n*/\\n\\n// Remove the inner padding in Chrome and Safari on macOS.\\n\\n::-webkit-search-decoration {\\n  -webkit-appearance: none;\\n}\\n\\n// Remove padding around color pickers in webkit browsers\\n\\n::-webkit-color-swatch-wrapper {\\n  padding: 0;\\n}\\n\\n\\n// 1. Inherit font family and line height for file input buttons\\n// 2. Correct the inability to style clickable types in iOS and Safari.\\n\\n::file-selector-button {\\n  font: inherit; // 1\\n  -webkit-appearance: button; // 2\\n}\\n\\n// Correct element displays\\n\\noutput {\\n  display: inline-block;\\n}\\n\\n// Remove border from iframe\\n\\niframe {\\n  border: 0;\\n}\\n\\n// Summary\\n//\\n// 1. Add the correct display in all browsers\\n\\nsummary {\\n  display: list-item; // 1\\n  cursor: pointer;\\n}\\n\\n\\n// Progress\\n//\\n// Add the correct vertical alignment in Chrome, Firefox, and Opera.\\n\\nprogress {\\n  vertical-align: baseline;\\n}\\n\\n\\n// Hidden attribute\\n//\\n// Always hide an element with the `hidden` HTML attribute.\\n\\n[hidden] {\\n  display: none !important;\\n}\\n\",\"// stylelint-disable property-disallowed-list\\n// Single side border-radius\\n\\n// Helper function to replace negative values with 0\\n@function valid-radius($radius) {\\n  $return: ();\\n  @each $value in $radius {\\n    @if type-of($value) == number {\\n      $return: append($return, max($value, 0));\\n    } @else {\\n      $return: append($return, $value);\\n    }\\n  }\\n  @return $return;\\n}\\n\\n// scss-docs-start border-radius-mixins\\n@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) {\\n  @if $enable-rounded {\\n    border-radius: valid-radius($radius);\\n  }\\n  @else if $fallback-border-radius != false {\\n    border-radius: $fallback-border-radius;\\n  }\\n}\\n\\n@mixin border-top-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-left-radius: valid-radius($radius);\\n    border-top-right-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-end-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-right-radius: valid-radius($radius);\\n    border-bottom-right-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-bottom-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-bottom-right-radius: valid-radius($radius);\\n    border-bottom-left-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-start-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-left-radius: valid-radius($radius);\\n    border-bottom-left-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-top-start-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-left-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-top-end-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-top-right-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-bottom-end-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-bottom-right-radius: valid-radius($radius);\\n  }\\n}\\n\\n@mixin border-bottom-start-radius($radius: $border-radius) {\\n  @if $enable-rounded {\\n    border-bottom-left-radius: valid-radius($radius);\\n  }\\n}\\n// scss-docs-end border-radius-mixins\\n\",\"//\\n// Headings\\n//\\n.h1 {\\n  @extend h1;\\n}\\n\\n.h2 {\\n  @extend h2;\\n}\\n\\n.h3 {\\n  @extend h3;\\n}\\n\\n.h4 {\\n  @extend h4;\\n}\\n\\n.h5 {\\n  @extend h5;\\n}\\n\\n.h6 {\\n  @extend h6;\\n}\\n\\n\\n.lead {\\n  @include font-size($lead-font-size);\\n  font-weight: $lead-font-weight;\\n}\\n\\n// Type display classes\\n@each $display, $font-size in $display-font-sizes {\\n  .display-#{$display} {\\n    @include font-size($font-size);\\n    font-family: $display-font-family;\\n    font-style: $display-font-style;\\n    font-weight: $display-font-weight;\\n    line-height: $display-line-height;\\n  }\\n}\\n\\n//\\n// Emphasis\\n//\\n.small {\\n  @extend small;\\n}\\n\\n.mark {\\n  @extend mark;\\n}\\n\\n//\\n// Lists\\n//\\n\\n.list-unstyled {\\n  @include list-unstyled();\\n}\\n\\n// Inline turns list items into inline-block\\n.list-inline {\\n  @include list-unstyled();\\n}\\n.list-inline-item {\\n  display: inline-block;\\n\\n  &:not(:last-child) {\\n    margin-right: $list-inline-padding;\\n  }\\n}\\n\\n\\n//\\n// Misc\\n//\\n\\n// Builds on `abbr`\\n.initialism {\\n  @include font-size($initialism-font-size);\\n  text-transform: uppercase;\\n}\\n\\n// Blockquotes\\n.blockquote {\\n  margin-bottom: $blockquote-margin-y;\\n  @include font-size($blockquote-font-size);\\n\\n  > :last-child {\\n    margin-bottom: 0;\\n  }\\n}\\n\\n.blockquote-footer {\\n  margin-top: -$blockquote-margin-y;\\n  margin-bottom: $blockquote-margin-y;\\n  @include font-size($blockquote-footer-font-size);\\n  color: $blockquote-footer-color;\\n\\n  &::before {\\n    content: \\\"\\\\2014\\\\00A0\\\"; // em dash, nbsp\\n  }\\n}\\n\",\"// Lists\\n\\n// Unstyled keeps list items block level, just removes default browser padding and list-style\\n@mixin list-unstyled {\\n  padding-left: 0;\\n  list-style: none;\\n}\\n\",\"// Responsive images (ensure images don't scale beyond their parents)\\n//\\n// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.\\n// We previously tried the \\\"images are responsive by default\\\" approach in Bootstrap v2,\\n// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)\\n// which weren't expecting the images within themselves to be involuntarily resized.\\n// See also https://github.com/twbs/bootstrap/issues/18178\\n.img-fluid {\\n  @include img-fluid();\\n}\\n\\n\\n// Image thumbnails\\n.img-thumbnail {\\n  padding: $thumbnail-padding;\\n  background-color: $thumbnail-bg;\\n  border: $thumbnail-border-width solid $thumbnail-border-color;\\n  @include border-radius($thumbnail-border-radius);\\n  @include box-shadow($thumbnail-box-shadow);\\n\\n  // Keep them at most 100% wide\\n  @include img-fluid();\\n}\\n\\n//\\n// Figures\\n//\\n\\n.figure {\\n  // Ensures the caption's text aligns with the image.\\n  display: inline-block;\\n}\\n\\n.figure-img {\\n  margin-bottom: $spacer * .5;\\n  line-height: 1;\\n}\\n\\n.figure-caption {\\n  @include font-size($figure-caption-font-size);\\n  color: $figure-caption-color;\\n}\\n\",\"// Image Mixins\\n// - Responsive image\\n// - Retina image\\n\\n\\n// Responsive image\\n//\\n// Keep images from scaling beyond the width of their parents.\\n\\n@mixin img-fluid {\\n  // Part 1: Set a maximum relative to the parent\\n  max-width: 100%;\\n  // Part 2: Override the height to auto, otherwise images will be stretched\\n  // when setting a width and height attribute on the img element.\\n  height: auto;\\n}\\n\",\"// Container widths\\n//\\n// Set the container width, and override it for fixed navbars in media queries.\\n\\n@if $enable-container-classes {\\n  // Single container class with breakpoint max-widths\\n  .container,\\n  // 100% wide container at all breakpoints\\n  .container-fluid {\\n    @include make-container();\\n  }\\n\\n  // Responsive containers that are 100% wide until a breakpoint\\n  @each $breakpoint, $container-max-width in $container-max-widths {\\n    .container-#{$breakpoint} {\\n      @extend .container-fluid;\\n    }\\n\\n    @include media-breakpoint-up($breakpoint, $grid-breakpoints) {\\n      %responsive-container-#{$breakpoint} {\\n        max-width: $container-max-width;\\n      }\\n\\n      // Extend each breakpoint which is smaller or equal to the current breakpoint\\n      $extend-breakpoint: true;\\n\\n      @each $name, $width in $grid-breakpoints {\\n        @if ($extend-breakpoint) {\\n          .container#{breakpoint-infix($name, $grid-breakpoints)} {\\n            @extend %responsive-container-#{$breakpoint};\\n          }\\n\\n          // Once the current breakpoint is reached, stop extending\\n          @if ($breakpoint == $name) {\\n            $extend-breakpoint: false;\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n\",\"// Container mixins\\n\\n@mixin make-container($gutter: $container-padding-x) {\\n  --#{$prefix}gutter-x: #{$gutter};\\n  --#{$prefix}gutter-y: 0;\\n  width: 100%;\\n  padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\\n  padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\\n  margin-right: auto;\\n  margin-left: auto;\\n}\\n\",\"// Breakpoint viewport sizes and media queries.\\n//\\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\\n//\\n//    (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)\\n//\\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\\n\\n// Name of the next breakpoint, or null for the last breakpoint.\\n//\\n//    >> breakpoint-next(sm)\\n//    md\\n//    >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    md\\n//    >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl))\\n//    md\\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\\n  $n: index($breakpoint-names, $name);\\n  @if not $n {\\n    @error \\\"breakpoint `#{$name}` not found in `#{$breakpoints}`\\\";\\n  }\\n  @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\\n}\\n\\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\\n//\\n//    >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    576px\\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\\n  $min: map-get($breakpoints, $name);\\n  @return if($min != 0, $min, null);\\n}\\n\\n// Maximum breakpoint width.\\n// The maximum value is reduced by 0.02px to work around the limitations of\\n// `min-` and `max-` prefixes and viewports with fractional widths.\\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\\n//\\n//    >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    767.98px\\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\\n  $max: map-get($breakpoints, $name);\\n  @return if($max and $max > 0, $max - .02, null);\\n}\\n\\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\\n// Useful for making responsive utilities.\\n//\\n//    >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    \\\"\\\"  (Returns a blank string)\\n//    >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))\\n//    \\\"-sm\\\"\\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\\n  @return if(breakpoint-min($name, $breakpoints) == null, \\\"\\\", \\\"-#{$name}\\\");\\n}\\n\\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\\n// Makes the @content apply to the given breakpoint and wider.\\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\\n  $min: breakpoint-min($name, $breakpoints);\\n  @if $min {\\n    @media (min-width: $min) {\\n      @content;\\n    }\\n  } @else {\\n    @content;\\n  }\\n}\\n\\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\\n// Makes the @content apply to the given breakpoint and narrower.\\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\\n  $max: breakpoint-max($name, $breakpoints);\\n  @if $max {\\n    @media (max-width: $max) {\\n      @content;\\n    }\\n  } @else {\\n    @content;\\n  }\\n}\\n\\n// Media that spans multiple breakpoint widths.\\n// Makes the @content apply between the min and max breakpoints\\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\\n  $min: breakpoint-min($lower, $breakpoints);\\n  $max: breakpoint-max($upper, $breakpoints);\\n\\n  @if $min != null and $max != null {\\n    @media (min-width: $min) and (max-width: $max) {\\n      @content;\\n    }\\n  } @else if $max == null {\\n    @include media-breakpoint-up($lower, $breakpoints) {\\n      @content;\\n    }\\n  } @else if $min == null {\\n    @include media-breakpoint-down($upper, $breakpoints) {\\n      @content;\\n    }\\n  }\\n}\\n\\n// Media between the breakpoint's minimum and maximum widths.\\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\\n  $min:  breakpoint-min($name, $breakpoints);\\n  $next: breakpoint-next($name, $breakpoints);\\n  $max:  breakpoint-max($next, $breakpoints);\\n\\n  @if $min != null and $max != null {\\n    @media (min-width: $min) and (max-width: $max) {\\n      @content;\\n    }\\n  } @else if $max == null {\\n    @include media-breakpoint-up($name, $breakpoints) {\\n      @content;\\n    }\\n  } @else if $min == null {\\n    @include media-breakpoint-down($next, $breakpoints) {\\n      @content;\\n    }\\n  }\\n}\\n\",\"// Row\\n//\\n// Rows contain your columns.\\n\\n@if $enable-grid-classes {\\n  .row {\\n    @include make-row();\\n\\n    > * {\\n      @include make-col-ready();\\n    }\\n  }\\n}\\n\\n@if $enable-cssgrid {\\n  .grid {\\n    display: grid;\\n    grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);\\n    grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);\\n    gap: var(--#{$prefix}gap, #{$grid-gutter-width});\\n\\n    @include make-cssgrid();\\n  }\\n}\\n\\n\\n// Columns\\n//\\n// Common styles for small and large grid columns\\n\\n@if $enable-grid-classes {\\n  @include make-grid-columns();\\n}\\n\",\"// Grid system\\n//\\n// Generate semantic grid columns with these mixins.\\n\\n@mixin make-row($gutter: $grid-gutter-width) {\\n  --#{$prefix}gutter-x: #{$gutter};\\n  --#{$prefix}gutter-y: 0;\\n  display: flex;\\n  flex-wrap: wrap;\\n  // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed\\n  margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list\\n  margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\\n  margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\\n}\\n\\n@mixin make-col-ready() {\\n  // Add box sizing if only the grid is loaded\\n  box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);\\n  // Prevent columns from becoming too narrow when at smaller grid tiers by\\n  // always setting `width: 100%;`. This works because we set the width\\n  // later on to override this initial width.\\n  flex-shrink: 0;\\n  width: 100%;\\n  max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid\\n  padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\\n  padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\\n  margin-top: var(--#{$prefix}gutter-y);\\n}\\n\\n@mixin make-col($size: false, $columns: $grid-columns) {\\n  @if $size {\\n    flex: 0 0 auto;\\n    width: percentage(divide($size, $columns));\\n\\n  } @else {\\n    flex: 1 1 0;\\n    max-width: 100%;\\n  }\\n}\\n\\n@mixin make-col-auto() {\\n  flex: 0 0 auto;\\n  width: auto;\\n}\\n\\n@mixin make-col-offset($size, $columns: $grid-columns) {\\n  $num: divide($size, $columns);\\n  margin-left: if($num == 0, 0, percentage($num));\\n}\\n\\n// Row columns\\n//\\n// Specify on a parent element(e.g., .row) to force immediate children into NN\\n// number of columns. Supports wrapping to new lines, but does not do a Masonry\\n// style grid.\\n@mixin row-cols($count) {\\n  > * {\\n    flex: 0 0 auto;\\n    width: divide(100%, $count);\\n  }\\n}\\n\\n// Framework grid generation\\n//\\n// Used only by Bootstrap to generate the correct number of grid classes given\\n// any value of `$grid-columns`.\\n\\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\\n  @each $breakpoint in map-keys($breakpoints) {\\n    $infix: breakpoint-infix($breakpoint, $breakpoints);\\n\\n    @include media-breakpoint-up($breakpoint, $breakpoints) {\\n      // Provide basic `.col-{bp}` classes for equal-width flexbox columns\\n      .col#{$infix} {\\n        flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\\n      }\\n\\n      .row-cols#{$infix}-auto > * {\\n        @include make-col-auto();\\n      }\\n\\n      @if $grid-row-columns > 0 {\\n        @for $i from 1 through $grid-row-columns {\\n          .row-cols#{$infix}-#{$i} {\\n            @include row-cols($i);\\n          }\\n        }\\n      }\\n\\n      .col#{$infix}-auto {\\n        @include make-col-auto();\\n      }\\n\\n      @if $columns > 0 {\\n        @for $i from 1 through $columns {\\n          .col#{$infix}-#{$i} {\\n            @include make-col($i, $columns);\\n          }\\n        }\\n\\n        // `$columns - 1` because offsetting by the width of an entire row isn't possible\\n        @for $i from 0 through ($columns - 1) {\\n          @if not ($infix == \\\"\\\" and $i == 0) { // Avoid emitting useless .offset-0\\n            .offset#{$infix}-#{$i} {\\n              @include make-col-offset($i, $columns);\\n            }\\n          }\\n        }\\n      }\\n\\n      // Gutters\\n      //\\n      // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns.\\n      @each $key, $value in $gutters {\\n        .g#{$infix}-#{$key},\\n        .gx#{$infix}-#{$key} {\\n          --#{$prefix}gutter-x: #{$value};\\n        }\\n\\n        .g#{$infix}-#{$key},\\n        .gy#{$infix}-#{$key} {\\n          --#{$prefix}gutter-y: #{$value};\\n        }\\n      }\\n    }\\n  }\\n}\\n\\n@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) {\\n  @each $breakpoint in map-keys($breakpoints) {\\n    $infix: breakpoint-infix($breakpoint, $breakpoints);\\n\\n    @include media-breakpoint-up($breakpoint, $breakpoints) {\\n      @if $columns > 0 {\\n        @for $i from 1 through $columns {\\n          .g-col#{$infix}-#{$i} {\\n            grid-column: auto / span $i;\\n          }\\n        }\\n\\n        // Start with `1` because `0` is and invalid value.\\n        // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.\\n        @for $i from 1 through ($columns - 1) {\\n          .g-start#{$infix}-#{$i} {\\n            grid-column-start: $i;\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n\",\"//\\n// Basic Bootstrap table\\n//\\n\\n.table {\\n  --#{$prefix}table-color: #{$table-color};\\n  --#{$prefix}table-bg: #{$table-bg};\\n  --#{$prefix}table-border-color: #{$table-border-color};\\n  --#{$prefix}table-accent-bg: #{$table-accent-bg};\\n  --#{$prefix}table-striped-color: #{$table-striped-color};\\n  --#{$prefix}table-striped-bg: #{$table-striped-bg};\\n  --#{$prefix}table-active-color: #{$table-active-color};\\n  --#{$prefix}table-active-bg: #{$table-active-bg};\\n  --#{$prefix}table-hover-color: #{$table-hover-color};\\n  --#{$prefix}table-hover-bg: #{$table-hover-bg};\\n\\n  width: 100%;\\n  margin-bottom: $spacer;\\n  color: var(--#{$prefix}table-color);\\n  vertical-align: $table-cell-vertical-align;\\n  border-color: var(--#{$prefix}table-border-color);\\n\\n  // Target th & td\\n  // We need the child combinator to prevent styles leaking to nested tables which doesn't have a `.table` class.\\n  // We use the universal selectors here to simplify the selector (else we would need 6 different selectors).\\n  // Another advantage is that this generates less code and makes the selector less specific making it easier to override.\\n  // stylelint-disable-next-line selector-max-universal\\n  > :not(caption) > * > * {\\n    padding: $table-cell-padding-y $table-cell-padding-x;\\n    background-color: var(--#{$prefix}table-bg);\\n    border-bottom-width: $table-border-width;\\n    box-shadow: inset 0 0 0 9999px var(--#{$prefix}table-accent-bg);\\n  }\\n\\n  > tbody {\\n    vertical-align: inherit;\\n  }\\n\\n  > thead {\\n    vertical-align: bottom;\\n  }\\n}\\n\\n.table-group-divider {\\n  border-top: calc($table-border-width * 2) solid $table-group-separator-color; // stylelint-disable-line function-disallowed-list\\n}\\n\\n//\\n// Change placement of captions with a class\\n//\\n\\n.caption-top {\\n  caption-side: top;\\n}\\n\\n\\n//\\n// Condensed table w/ half padding\\n//\\n\\n.table-sm {\\n  // stylelint-disable-next-line selector-max-universal\\n  > :not(caption) > * > * {\\n    padding: $table-cell-padding-y-sm $table-cell-padding-x-sm;\\n  }\\n}\\n\\n\\n// Border versions\\n//\\n// Add or remove borders all around the table and between all the columns.\\n//\\n// When borders are added on all sides of the cells, the corners can render odd when\\n// these borders do not have the same color or if they are semi-transparent.\\n// Therefor we add top and border bottoms to the `tr`s and left and right borders\\n// to the `td`s or `th`s\\n\\n.table-bordered {\\n  > :not(caption) > * {\\n    border-width: $table-border-width 0;\\n\\n    // stylelint-disable-next-line selector-max-universal\\n    > * {\\n      border-width: 0 $table-border-width;\\n    }\\n  }\\n}\\n\\n.table-borderless {\\n  // stylelint-disable-next-line selector-max-universal\\n  > :not(caption) > * > * {\\n    border-bottom-width: 0;\\n  }\\n\\n  > :not(:first-child) {\\n    border-top-width: 0;\\n  }\\n}\\n\\n// Zebra-striping\\n//\\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\\n\\n// For rows\\n.table-striped {\\n  > tbody > tr:nth-of-type(#{$table-striped-order}) > * {\\n    --#{$prefix}table-accent-bg: var(--#{$prefix}table-striped-bg);\\n    color: var(--#{$prefix}table-striped-color);\\n  }\\n}\\n\\n// For columns\\n.table-striped-columns {\\n  > :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) {\\n    --#{$prefix}table-accent-bg: var(--#{$prefix}table-striped-bg);\\n    color: var(--#{$prefix}table-striped-color);\\n  }\\n}\\n\\n// Active table\\n//\\n// The `.table-active` class can be added to highlight rows or cells\\n\\n.table-active {\\n  --#{$prefix}table-accent-bg: var(--#{$prefix}table-active-bg);\\n  color: var(--#{$prefix}table-active-color);\\n}\\n\\n// Hover effect\\n//\\n// Placed here since it has to come after the potential zebra striping\\n\\n.table-hover {\\n  > tbody > tr:hover > * {\\n    --#{$prefix}table-accent-bg: var(--#{$prefix}table-hover-bg);\\n    color: var(--#{$prefix}table-hover-color);\\n  }\\n}\\n\\n\\n// Table variants\\n//\\n// Table variants set the table cell backgrounds, border colors\\n// and the colors of the striped, hovered & active tables\\n\\n@each $color, $value in $table-variants {\\n  @include table-variant($color, $value);\\n}\\n\\n// Responsive tables\\n//\\n// Generate series of `.table-responsive-*` classes for configuring the screen\\n// size of where your table will overflow.\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n  @include media-breakpoint-down($breakpoint) {\\n    .table-responsive#{$infix} {\\n      overflow-x: auto;\\n      -webkit-overflow-scrolling: touch;\\n    }\\n  }\\n}\\n\",\"// scss-docs-start table-variant\\n@mixin table-variant($state, $background) {\\n  .table-#{$state} {\\n    $color: color-contrast(opaque($body-bg, $background));\\n    $hover-bg: mix($color, $background, percentage($table-hover-bg-factor));\\n    $striped-bg: mix($color, $background, percentage($table-striped-bg-factor));\\n    $active-bg: mix($color, $background, percentage($table-active-bg-factor));\\n    $table-border-color: mix($color, $background, percentage($table-border-factor));\\n\\n    --#{$prefix}table-color: #{$color};\\n    --#{$prefix}table-bg: #{$background};\\n    --#{$prefix}table-border-color: #{$table-border-color};\\n    --#{$prefix}table-striped-bg: #{$striped-bg};\\n    --#{$prefix}table-striped-color: #{color-contrast($striped-bg)};\\n    --#{$prefix}table-active-bg: #{$active-bg};\\n    --#{$prefix}table-active-color: #{color-contrast($active-bg)};\\n    --#{$prefix}table-hover-bg: #{$hover-bg};\\n    --#{$prefix}table-hover-color: #{color-contrast($hover-bg)};\\n\\n    color: var(--#{$prefix}table-color);\\n    border-color: var(--#{$prefix}table-border-color);\\n  }\\n}\\n// scss-docs-end table-variant\\n\",\"//\\n// Labels\\n//\\n\\n.form-label {\\n  margin-bottom: $form-label-margin-bottom;\\n  @include font-size($form-label-font-size);\\n  font-style: $form-label-font-style;\\n  font-weight: $form-label-font-weight;\\n  color: $form-label-color;\\n}\\n\\n// For use with horizontal and inline forms, when you need the label (or legend)\\n// text to align with the form controls.\\n.col-form-label {\\n  padding-top: add($input-padding-y, $input-border-width);\\n  padding-bottom: add($input-padding-y, $input-border-width);\\n  margin-bottom: 0; // Override the `<legend>` default\\n  @include font-size(inherit); // Override the `<legend>` default\\n  font-style: $form-label-font-style;\\n  font-weight: $form-label-font-weight;\\n  line-height: $input-line-height;\\n  color: $form-label-color;\\n}\\n\\n.col-form-label-lg {\\n  padding-top: add($input-padding-y-lg, $input-border-width);\\n  padding-bottom: add($input-padding-y-lg, $input-border-width);\\n  @include font-size($input-font-size-lg);\\n}\\n\\n.col-form-label-sm {\\n  padding-top: add($input-padding-y-sm, $input-border-width);\\n  padding-bottom: add($input-padding-y-sm, $input-border-width);\\n  @include font-size($input-font-size-sm);\\n}\\n\",\"//\\n// Form text\\n//\\n\\n.form-text {\\n  margin-top: $form-text-margin-top;\\n  @include font-size($form-text-font-size);\\n  font-style: $form-text-font-style;\\n  font-weight: $form-text-font-weight;\\n  color: $form-text-color;\\n}\\n\",\"//\\n// General form controls (plus a few specific high-level interventions)\\n//\\n\\n.form-control {\\n  display: block;\\n  width: 100%;\\n  padding: $input-padding-y $input-padding-x;\\n  font-family: $input-font-family;\\n  @include font-size($input-font-size);\\n  font-weight: $input-font-weight;\\n  line-height: $input-line-height;\\n  color: $input-color;\\n  background-color: $input-bg;\\n  background-clip: padding-box;\\n  border: $input-border-width solid $input-border-color;\\n  appearance: none; // Fix appearance for date inputs in Safari\\n\\n  // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.\\n  @include border-radius($input-border-radius, 0);\\n\\n  @include box-shadow($input-box-shadow);\\n  @include transition($input-transition);\\n\\n  &[type=\\\"file\\\"] {\\n    overflow: hidden; // prevent pseudo element button overlap\\n\\n    &:not(:disabled):not([readonly]) {\\n      cursor: pointer;\\n    }\\n  }\\n\\n  // Customize the `:focus` state to imitate native WebKit styles.\\n  &:focus {\\n    color: $input-focus-color;\\n    background-color: $input-focus-bg;\\n    border-color: $input-focus-border-color;\\n    outline: 0;\\n    @if $enable-shadows {\\n      @include box-shadow($input-box-shadow, $input-focus-box-shadow);\\n    } @else {\\n      // Avoid using mixin so we can pass custom focus shadow properly\\n      box-shadow: $input-focus-box-shadow;\\n    }\\n  }\\n\\n  // Add some height to date inputs on iOS\\n  // https://github.com/twbs/bootstrap/issues/23307\\n  // TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved\\n  &::-webkit-date-and-time-value {\\n    // Multiply line-height by 1em if it has no unit\\n    height: if(unit($input-line-height) == \\\"\\\", $input-line-height * 1em, $input-line-height);\\n  }\\n\\n  // Prevent excessive date input height in Webkit\\n  // https://github.com/twbs/bootstrap/issues/34433\\n  &::-webkit-datetime-edit {\\n    display: block;\\n    padding: 0;\\n  }\\n\\n  // Placeholder\\n  &::placeholder {\\n    color: $input-placeholder-color;\\n    // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.\\n    opacity: 1;\\n  }\\n\\n  // Disabled inputs\\n  //\\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\\n  // don't honor that edge case; we style them as disabled anyway.\\n  &:disabled {\\n    color: $input-disabled-color;\\n    background-color: $input-disabled-bg;\\n    border-color: $input-disabled-border-color;\\n    // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.\\n    opacity: 1;\\n  }\\n\\n  // File input buttons theming\\n  &::file-selector-button {\\n    padding: $input-padding-y $input-padding-x;\\n    margin: (-$input-padding-y) (-$input-padding-x);\\n    margin-inline-end: $input-padding-x;\\n    color: $form-file-button-color;\\n    @include gradient-bg($form-file-button-bg);\\n    pointer-events: none;\\n    border-color: inherit;\\n    border-style: solid;\\n    border-width: 0;\\n    border-inline-end-width: $input-border-width;\\n    border-radius: 0; // stylelint-disable-line property-disallowed-list\\n    @include transition($btn-transition);\\n  }\\n\\n  &:hover:not(:disabled):not([readonly])::file-selector-button {\\n    background-color: $form-file-button-hover-bg;\\n  }\\n}\\n\\n// Readonly controls as plain text\\n//\\n// Apply class to a readonly input to make it appear like regular plain\\n// text (without any border, background color, focus indicator)\\n\\n.form-control-plaintext {\\n  display: block;\\n  width: 100%;\\n  padding: $input-padding-y 0;\\n  margin-bottom: 0; // match inputs if this class comes on inputs with default margins\\n  line-height: $input-line-height;\\n  color: $input-plaintext-color;\\n  background-color: transparent;\\n  border: solid transparent;\\n  border-width: $input-border-width 0;\\n\\n  &:focus {\\n    outline: 0;\\n  }\\n\\n  &.form-control-sm,\\n  &.form-control-lg {\\n    padding-right: 0;\\n    padding-left: 0;\\n  }\\n}\\n\\n// Form control sizing\\n//\\n// Build on `.form-control` with modifier classes to decrease or increase the\\n// height and font-size of form controls.\\n//\\n// Repeated in `_input_group.scss` to avoid Sass extend issues.\\n\\n.form-control-sm {\\n  min-height: $input-height-sm;\\n  padding: $input-padding-y-sm $input-padding-x-sm;\\n  @include font-size($input-font-size-sm);\\n  @include border-radius($input-border-radius-sm);\\n\\n  &::file-selector-button {\\n    padding: $input-padding-y-sm $input-padding-x-sm;\\n    margin: (-$input-padding-y-sm) (-$input-padding-x-sm);\\n    margin-inline-end: $input-padding-x-sm;\\n  }\\n}\\n\\n.form-control-lg {\\n  min-height: $input-height-lg;\\n  padding: $input-padding-y-lg $input-padding-x-lg;\\n  @include font-size($input-font-size-lg);\\n  @include border-radius($input-border-radius-lg);\\n\\n  &::file-selector-button {\\n    padding: $input-padding-y-lg $input-padding-x-lg;\\n    margin: (-$input-padding-y-lg) (-$input-padding-x-lg);\\n    margin-inline-end: $input-padding-x-lg;\\n  }\\n}\\n\\n// Make sure textareas don't shrink too much when resized\\n// https://github.com/twbs/bootstrap/pull/29124\\n// stylelint-disable selector-no-qualifying-type\\ntextarea {\\n  &.form-control {\\n    min-height: $input-height;\\n  }\\n\\n  &.form-control-sm {\\n    min-height: $input-height-sm;\\n  }\\n\\n  &.form-control-lg {\\n    min-height: $input-height-lg;\\n  }\\n}\\n// stylelint-enable selector-no-qualifying-type\\n\\n.form-control-color {\\n  width: $form-color-width;\\n  height: $input-height;\\n  padding: $input-padding-y;\\n\\n  &:not(:disabled):not([readonly]) {\\n    cursor: pointer;\\n  }\\n\\n  &::-moz-color-swatch {\\n    border: 0 !important; // stylelint-disable-line declaration-no-important\\n    @include border-radius($input-border-radius);\\n  }\\n\\n  &::-webkit-color-swatch {\\n    @include border-radius($input-border-radius);\\n  }\\n\\n  &.form-control-sm { height: $input-height-sm; }\\n  &.form-control-lg { height: $input-height-lg; }\\n}\\n\",\"// stylelint-disable property-disallowed-list\\n@mixin transition($transition...) {\\n  @if length($transition) == 0 {\\n    $transition: $transition-base;\\n  }\\n\\n  @if length($transition) > 1 {\\n    @each $value in $transition {\\n      @if $value == null or $value == none {\\n        @warn \\\"The keyword 'none' or 'null' must be used as a single argument.\\\";\\n      }\\n    }\\n  }\\n\\n  @if $enable-transitions {\\n    @if nth($transition, 1) != null {\\n      transition: $transition;\\n    }\\n\\n    @if $enable-reduced-motion and nth($transition, 1) != null and nth($transition, 1) != none {\\n      @media (prefers-reduced-motion: reduce) {\\n        transition: none;\\n      }\\n    }\\n  }\\n}\\n\",\"// Gradients\\n\\n// scss-docs-start gradient-bg-mixin\\n@mixin gradient-bg($color: null) {\\n  background-color: $color;\\n\\n  @if $enable-gradients {\\n    background-image: var(--#{$prefix}gradient);\\n  }\\n}\\n// scss-docs-end gradient-bg-mixin\\n\\n// scss-docs-start gradient-mixins\\n// Horizontal gradient, from left to right\\n//\\n// Creates two color stops, start and end, by specifying a color and position for each color stop.\\n@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) {\\n  background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent);\\n}\\n\\n// Vertical gradient, from top to bottom\\n//\\n// Creates two color stops, start and end, by specifying a color and position for each color stop.\\n@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: null, $end-percent: null) {\\n  background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent);\\n}\\n\\n@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) {\\n  background-image: linear-gradient($deg, $start-color, $end-color);\\n}\\n\\n@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) {\\n  background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color);\\n}\\n\\n@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) {\\n  background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color);\\n}\\n\\n@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) {\\n  background-image: radial-gradient(circle, $inner-color, $outer-color);\\n}\\n\\n@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) {\\n  background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);\\n}\\n// scss-docs-end gradient-mixins\\n\",\"// Select\\n//\\n// Replaces the browser default select with a custom one, mostly pulled from\\n// https://primer.github.io/.\\n\\n.form-select {\\n  --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator)};\\n\\n  display: block;\\n  width: 100%;\\n  padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x;\\n  -moz-padding-start: subtract($form-select-padding-x, 3px); // See https://github.com/twbs/bootstrap/issues/32636\\n  font-family: $form-select-font-family;\\n  @include font-size($form-select-font-size);\\n  font-weight: $form-select-font-weight;\\n  line-height: $form-select-line-height;\\n  color: $form-select-color;\\n  background-color: $form-select-bg;\\n  background-image: var(--#{$prefix}form-select-bg-img), var(--#{$prefix}form-select-bg-icon, none);\\n  background-repeat: no-repeat;\\n  background-position: $form-select-bg-position;\\n  background-size: $form-select-bg-size;\\n  border: $form-select-border-width solid $form-select-border-color;\\n  @include border-radius($form-select-border-radius, 0);\\n  @include box-shadow($form-select-box-shadow);\\n  @include transition($form-select-transition);\\n  appearance: none;\\n\\n  &:focus {\\n    border-color: $form-select-focus-border-color;\\n    outline: 0;\\n    @if $enable-shadows {\\n      @include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow);\\n    } @else {\\n      // Avoid using mixin so we can pass custom focus shadow properly\\n      box-shadow: $form-select-focus-box-shadow;\\n    }\\n  }\\n\\n  &[multiple],\\n  &[size]:not([size=\\\"1\\\"]) {\\n    padding-right: $form-select-padding-x;\\n    background-image: none;\\n  }\\n\\n  &:disabled {\\n    color: $form-select-disabled-color;\\n    background-color: $form-select-disabled-bg;\\n    border-color: $form-select-disabled-border-color;\\n  }\\n\\n  // Remove outline from select box in FF\\n  &:-moz-focusring {\\n    color: transparent;\\n    text-shadow: 0 0 0 $form-select-color;\\n  }\\n}\\n\\n.form-select-sm {\\n  padding-top: $form-select-padding-y-sm;\\n  padding-bottom: $form-select-padding-y-sm;\\n  padding-left: $form-select-padding-x-sm;\\n  @include font-size($form-select-font-size-sm);\\n  @include border-radius($form-select-border-radius-sm);\\n}\\n\\n.form-select-lg {\\n  padding-top: $form-select-padding-y-lg;\\n  padding-bottom: $form-select-padding-y-lg;\\n  padding-left: $form-select-padding-x-lg;\\n  @include font-size($form-select-font-size-lg);\\n  @include border-radius($form-select-border-radius-lg);\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .form-select {\\n      --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)};\\n    }\\n  }\\n}\\n\",\"//\\n// Check/radio\\n//\\n\\n.form-check {\\n  display: block;\\n  min-height: $form-check-min-height;\\n  padding-left: $form-check-padding-start;\\n  margin-bottom: $form-check-margin-bottom;\\n\\n  .form-check-input {\\n    float: left;\\n    margin-left: $form-check-padding-start * -1;\\n  }\\n}\\n\\n.form-check-reverse {\\n  padding-right: $form-check-padding-start;\\n  padding-left: 0;\\n  text-align: right;\\n\\n  .form-check-input {\\n    float: right;\\n    margin-right: $form-check-padding-start * -1;\\n    margin-left: 0;\\n  }\\n}\\n\\n.form-check-input {\\n  --#{$prefix}form-check-bg: #{$form-check-input-bg};\\n\\n  width: $form-check-input-width;\\n  height: $form-check-input-width;\\n  margin-top: ($line-height-base - $form-check-input-width) * .5; // line-height minus check height\\n  vertical-align: top;\\n  background-color: var(--#{$prefix}form-check-bg);\\n  background-image: var(--#{$prefix}form-check-bg-image);\\n  background-repeat: no-repeat;\\n  background-position: center;\\n  background-size: contain;\\n  border: $form-check-input-border;\\n  appearance: none;\\n  print-color-adjust: exact; // Keep themed appearance for print\\n  @include transition($form-check-transition);\\n\\n  &[type=\\\"checkbox\\\"] {\\n    @include border-radius($form-check-input-border-radius);\\n  }\\n\\n  &[type=\\\"radio\\\"] {\\n    // stylelint-disable-next-line property-disallowed-list\\n    border-radius: $form-check-radio-border-radius;\\n  }\\n\\n  &:active {\\n    filter: $form-check-input-active-filter;\\n  }\\n\\n  &:focus {\\n    border-color: $form-check-input-focus-border;\\n    outline: 0;\\n    box-shadow: $form-check-input-focus-box-shadow;\\n  }\\n\\n  &:checked {\\n    background-color: $form-check-input-checked-bg-color;\\n    border-color: $form-check-input-checked-border-color;\\n\\n    &[type=\\\"checkbox\\\"] {\\n      @if $enable-gradients {\\n        --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)}, var(--#{$prefix}gradient);\\n      } @else {\\n        --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)};\\n      }\\n    }\\n\\n    &[type=\\\"radio\\\"] {\\n      @if $enable-gradients {\\n        --#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)}, var(--#{$prefix}gradient);\\n      } @else {\\n        --#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)};\\n      }\\n    }\\n  }\\n\\n  &[type=\\\"checkbox\\\"]:indeterminate {\\n    background-color: $form-check-input-indeterminate-bg-color;\\n    border-color: $form-check-input-indeterminate-border-color;\\n\\n    @if $enable-gradients {\\n      --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)}, var(--#{$prefix}gradient);\\n    } @else {\\n      --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)};\\n    }\\n  }\\n\\n  &:disabled {\\n    pointer-events: none;\\n    filter: none;\\n    opacity: $form-check-input-disabled-opacity;\\n  }\\n\\n  // Use disabled attribute in addition of :disabled pseudo-class\\n  // See: https://github.com/twbs/bootstrap/issues/28247\\n  &[disabled],\\n  &:disabled {\\n    ~ .form-check-label {\\n      cursor: default;\\n      opacity: $form-check-label-disabled-opacity;\\n    }\\n  }\\n}\\n\\n.form-check-label {\\n  color: $form-check-label-color;\\n  cursor: $form-check-label-cursor;\\n}\\n\\n//\\n// Switch\\n//\\n\\n.form-switch {\\n  padding-left: $form-switch-padding-start;\\n\\n  .form-check-input {\\n    --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image)};\\n\\n    width: $form-switch-width;\\n    margin-left: $form-switch-padding-start * -1;\\n    background-image: var(--#{$prefix}form-switch-bg);\\n    background-position: left center;\\n    @include border-radius($form-switch-border-radius);\\n    @include transition($form-switch-transition);\\n\\n    &:focus {\\n      --#{$prefix}form-switch-bg: #{escape-svg($form-switch-focus-bg-image)};\\n    }\\n\\n    &:checked {\\n      background-position: $form-switch-checked-bg-position;\\n\\n      @if $enable-gradients {\\n        --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)}, var(--#{$prefix}gradient);\\n      } @else {\\n        --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)};\\n      }\\n    }\\n  }\\n\\n  &.form-check-reverse {\\n    padding-right: $form-switch-padding-start;\\n    padding-left: 0;\\n\\n    .form-check-input {\\n      margin-right: $form-switch-padding-start * -1;\\n      margin-left: 0;\\n    }\\n  }\\n}\\n\\n.form-check-inline {\\n  display: inline-block;\\n  margin-right: $form-check-inline-margin-end;\\n}\\n\\n.btn-check {\\n  position: absolute;\\n  clip: rect(0, 0, 0, 0);\\n  pointer-events: none;\\n\\n  &[disabled],\\n  &:disabled {\\n    + .btn {\\n      pointer-events: none;\\n      filter: none;\\n      opacity: $form-check-btn-check-disabled-opacity;\\n    }\\n  }\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .form-switch .form-check-input:not(:checked):not(:focus) {\\n      --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image-dark)};\\n    }\\n  }\\n}\\n\",\"// Range\\n//\\n// Style range inputs the same across browsers. Vendor-specific rules for pseudo\\n// elements cannot be mixed. As such, there are no shared styles for focus or\\n// active states on prefixed selectors.\\n\\n.form-range {\\n  width: 100%;\\n  height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2);\\n  padding: 0; // Need to reset padding\\n  background-color: transparent;\\n  appearance: none;\\n\\n  &:focus {\\n    outline: 0;\\n\\n    // Pseudo-elements must be split across multiple rulesets to have an effect.\\n    // No box-shadow() mixin for focus accessibility.\\n    &::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }\\n    &::-moz-range-thumb     { box-shadow: $form-range-thumb-focus-box-shadow; }\\n  }\\n\\n  &::-moz-focus-outer {\\n    border: 0;\\n  }\\n\\n  &::-webkit-slider-thumb {\\n    width: $form-range-thumb-width;\\n    height: $form-range-thumb-height;\\n    margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific\\n    @include gradient-bg($form-range-thumb-bg);\\n    border: $form-range-thumb-border;\\n    @include border-radius($form-range-thumb-border-radius);\\n    @include box-shadow($form-range-thumb-box-shadow);\\n    @include transition($form-range-thumb-transition);\\n    appearance: none;\\n\\n    &:active {\\n      @include gradient-bg($form-range-thumb-active-bg);\\n    }\\n  }\\n\\n  &::-webkit-slider-runnable-track {\\n    width: $form-range-track-width;\\n    height: $form-range-track-height;\\n    color: transparent; // Why?\\n    cursor: $form-range-track-cursor;\\n    background-color: $form-range-track-bg;\\n    border-color: transparent;\\n    @include border-radius($form-range-track-border-radius);\\n    @include box-shadow($form-range-track-box-shadow);\\n  }\\n\\n  &::-moz-range-thumb {\\n    width: $form-range-thumb-width;\\n    height: $form-range-thumb-height;\\n    @include gradient-bg($form-range-thumb-bg);\\n    border: $form-range-thumb-border;\\n    @include border-radius($form-range-thumb-border-radius);\\n    @include box-shadow($form-range-thumb-box-shadow);\\n    @include transition($form-range-thumb-transition);\\n    appearance: none;\\n\\n    &:active {\\n      @include gradient-bg($form-range-thumb-active-bg);\\n    }\\n  }\\n\\n  &::-moz-range-track {\\n    width: $form-range-track-width;\\n    height: $form-range-track-height;\\n    color: transparent;\\n    cursor: $form-range-track-cursor;\\n    background-color: $form-range-track-bg;\\n    border-color: transparent; // Firefox specific?\\n    @include border-radius($form-range-track-border-radius);\\n    @include box-shadow($form-range-track-box-shadow);\\n  }\\n\\n  &:disabled {\\n    pointer-events: none;\\n\\n    &::-webkit-slider-thumb {\\n      background-color: $form-range-thumb-disabled-bg;\\n    }\\n\\n    &::-moz-range-thumb {\\n      background-color: $form-range-thumb-disabled-bg;\\n    }\\n  }\\n}\\n\",\".form-floating {\\n  position: relative;\\n\\n  &::before:not(.form-control:disabled) {\\n    position: absolute;\\n    top: $input-border-width;\\n    left: $input-border-width;\\n    width: subtract(100%, add($input-height-inner-quarter, $input-height-inner-half));\\n    height: $form-floating-label-height;\\n    content: \\\"\\\";\\n    background-color: $input-bg;\\n    @include border-radius($input-border-radius);\\n  }\\n\\n  > .form-control,\\n  > .form-control-plaintext,\\n  > .form-select {\\n    height: $form-floating-height;\\n    line-height: $form-floating-line-height;\\n  }\\n\\n  > label {\\n    position: absolute;\\n    top: 0;\\n    left: 0;\\n    width: 100%;\\n    height: 100%; // allow textareas\\n    padding: $form-floating-padding-y $form-floating-padding-x;\\n    overflow: hidden;\\n    text-align: start;\\n    text-overflow: ellipsis;\\n    white-space: nowrap;\\n    pointer-events: none;\\n    border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model\\n    transform-origin: 0 0;\\n    @include transition($form-floating-transition);\\n  }\\n\\n  > .form-control,\\n  > .form-control-plaintext {\\n    padding: $form-floating-padding-y $form-floating-padding-x;\\n\\n    &::placeholder {\\n      color: transparent;\\n    }\\n\\n    &:focus,\\n    &:not(:placeholder-shown) {\\n      padding-top: $form-floating-input-padding-t;\\n      padding-bottom: $form-floating-input-padding-b;\\n    }\\n    // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped\\n    &:-webkit-autofill {\\n      padding-top: $form-floating-input-padding-t;\\n      padding-bottom: $form-floating-input-padding-b;\\n    }\\n  }\\n\\n  > .form-select {\\n    padding-top: $form-floating-input-padding-t;\\n    padding-bottom: $form-floating-input-padding-b;\\n  }\\n\\n  > .form-control:focus,\\n  > .form-control:not(:placeholder-shown),\\n  > .form-control-plaintext,\\n  > .form-select {\\n    ~ label {\\n      opacity: $form-floating-label-opacity;\\n      transform: $form-floating-label-transform;\\n    }\\n  }\\n  // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped\\n  > .form-control:-webkit-autofill {\\n    ~ label {\\n      opacity: $form-floating-label-opacity;\\n      transform: $form-floating-label-transform;\\n    }\\n  }\\n\\n  > .form-control-plaintext {\\n    ~ label {\\n      border-width: $input-border-width 0; // Required to properly position label text - as explained above\\n    }\\n  }\\n\\n  > .form-control:disabled ~ label {\\n    color: $form-floating-label-disabled-color;\\n  }\\n}\\n\",\"//\\n// Base styles\\n//\\n\\n.input-group {\\n  position: relative;\\n  display: flex;\\n  flex-wrap: wrap; // For form validation feedback\\n  align-items: stretch;\\n  width: 100%;\\n\\n  > .form-control,\\n  > .form-select,\\n  > .form-floating {\\n    position: relative; // For focus state's z-index\\n    flex: 1 1 auto;\\n    width: 1%;\\n    min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size\\n  }\\n\\n  // Bring the \\\"active\\\" form control to the top of surrounding elements\\n  > .form-control:focus,\\n  > .form-select:focus,\\n  > .form-floating:focus-within {\\n    z-index: 5;\\n  }\\n\\n  // Ensure buttons are always above inputs for more visually pleasing borders.\\n  // This isn't needed for `.input-group-text` since it shares the same border-color\\n  // as our inputs.\\n  .btn {\\n    position: relative;\\n    z-index: 2;\\n\\n    &:focus {\\n      z-index: 5;\\n    }\\n  }\\n}\\n\\n\\n// Textual addons\\n//\\n// Serves as a catch-all element for any text or radio/checkbox input you wish\\n// to prepend or append to an input.\\n\\n.input-group-text {\\n  display: flex;\\n  align-items: center;\\n  padding: $input-group-addon-padding-y $input-group-addon-padding-x;\\n  @include font-size($input-font-size); // Match inputs\\n  font-weight: $input-group-addon-font-weight;\\n  line-height: $input-line-height;\\n  color: $input-group-addon-color;\\n  text-align: center;\\n  white-space: nowrap;\\n  background-color: $input-group-addon-bg;\\n  border: $input-border-width solid $input-group-addon-border-color;\\n  @include border-radius($input-border-radius);\\n}\\n\\n\\n// Sizing\\n//\\n// Remix the default form control sizing classes into new ones for easier\\n// manipulation.\\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: $input-padding-y-lg $input-padding-x-lg;\\n  @include font-size($input-font-size-lg);\\n  @include border-radius($input-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: $input-padding-y-sm $input-padding-x-sm;\\n  @include font-size($input-font-size-sm);\\n  @include border-radius($input-border-radius-sm);\\n}\\n\\n.input-group-lg > .form-select,\\n.input-group-sm > .form-select {\\n  padding-right: $form-select-padding-x + $form-select-indicator-padding;\\n}\\n\\n\\n// Rounded corners\\n//\\n// These rulesets must come after the sizing ones to properly override sm and lg\\n// border-radius values when extending. They're more specific than we'd like\\n// with the `.input-group >` part, but without it, we cannot override the sizing.\\n\\n// stylelint-disable-next-line no-duplicate-selectors\\n.input-group {\\n  &:not(.has-validation) {\\n    > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),\\n    > .dropdown-toggle:nth-last-child(n + 3),\\n    > .form-floating:not(:last-child) > .form-control,\\n    > .form-floating:not(:last-child) > .form-select {\\n      @include border-end-radius(0);\\n    }\\n  }\\n\\n  &.has-validation {\\n    > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),\\n    > .dropdown-toggle:nth-last-child(n + 4),\\n    > .form-floating:nth-last-child(n + 3) > .form-control,\\n    > .form-floating:nth-last-child(n + 3) > .form-select {\\n      @include border-end-radius(0);\\n    }\\n  }\\n\\n  $validation-messages: \\\"\\\";\\n  @each $state in map-keys($form-validation-states) {\\n    $validation-messages: $validation-messages + \\\":not(.\\\" + unquote($state) + \\\"-tooltip)\\\" + \\\":not(.\\\" + unquote($state) + \\\"-feedback)\\\";\\n  }\\n\\n  > :not(:first-child):not(.dropdown-menu)#{$validation-messages} {\\n    margin-left: calc($input-border-width * -1); // stylelint-disable-line function-disallowed-list\\n    @include border-start-radius(0);\\n  }\\n\\n  > .form-floating:not(:first-child) > .form-control,\\n  > .form-floating:not(:first-child) > .form-select {\\n    @include border-start-radius(0);\\n  }\\n}\\n\",\"// This mixin uses an `if()` technique to be compatible with Dart Sass\\n// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details\\n\\n// scss-docs-start form-validation-mixins\\n@mixin form-validation-state-selector($state) {\\n  @if ($state == \\\"valid\\\" or $state == \\\"invalid\\\") {\\n    .was-validated #{if(&, \\\"&\\\", \\\"\\\")}:#{$state},\\n    #{if(&, \\\"&\\\", \\\"\\\")}.is-#{$state} {\\n      @content;\\n    }\\n  } @else {\\n    #{if(&, \\\"&\\\", \\\"\\\")}.is-#{$state} {\\n      @content;\\n    }\\n  }\\n}\\n\\n@mixin form-validation-state(\\n  $state,\\n  $color,\\n  $icon,\\n  $tooltip-color: color-contrast($color),\\n  $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),\\n  $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity),\\n  $border-color: $color\\n) {\\n  .#{$state}-feedback {\\n    display: none;\\n    width: 100%;\\n    margin-top: $form-feedback-margin-top;\\n    @include font-size($form-feedback-font-size);\\n    font-style: $form-feedback-font-style;\\n    color: $color;\\n  }\\n\\n  .#{$state}-tooltip {\\n    position: absolute;\\n    top: 100%;\\n    z-index: 5;\\n    display: none;\\n    max-width: 100%; // Contain to parent when possible\\n    padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x;\\n    margin-top: .1rem;\\n    @include font-size($form-feedback-tooltip-font-size);\\n    line-height: $form-feedback-tooltip-line-height;\\n    color: $tooltip-color;\\n    background-color: $tooltip-bg-color;\\n    @include border-radius($form-feedback-tooltip-border-radius);\\n  }\\n\\n  @include form-validation-state-selector($state) {\\n    ~ .#{$state}-feedback,\\n    ~ .#{$state}-tooltip {\\n      display: block;\\n    }\\n  }\\n\\n  .form-control {\\n    @include form-validation-state-selector($state) {\\n      border-color: $border-color;\\n\\n      @if $enable-validation-icons {\\n        padding-right: $input-height-inner;\\n        background-image: escape-svg($icon);\\n        background-repeat: no-repeat;\\n        background-position: right $input-height-inner-quarter center;\\n        background-size: $input-height-inner-half $input-height-inner-half;\\n      }\\n\\n      &:focus {\\n        border-color: $border-color;\\n        box-shadow: $focus-box-shadow;\\n      }\\n    }\\n  }\\n\\n  // stylelint-disable-next-line selector-no-qualifying-type\\n  textarea.form-control {\\n    @include form-validation-state-selector($state) {\\n      @if $enable-validation-icons {\\n        padding-right: $input-height-inner;\\n        background-position: top $input-height-inner-quarter right $input-height-inner-quarter;\\n      }\\n    }\\n  }\\n\\n  .form-select {\\n    @include form-validation-state-selector($state) {\\n      border-color: $border-color;\\n\\n      @if $enable-validation-icons {\\n        &:not([multiple]):not([size]),\\n        &:not([multiple])[size=\\\"1\\\"] {\\n          --#{$prefix}form-select-bg-icon: #{escape-svg($icon)};\\n          padding-right: $form-select-feedback-icon-padding-end;\\n          background-position: $form-select-bg-position, $form-select-feedback-icon-position;\\n          background-size: $form-select-bg-size, $form-select-feedback-icon-size;\\n        }\\n      }\\n\\n      &:focus {\\n        border-color: $border-color;\\n        box-shadow: $focus-box-shadow;\\n      }\\n    }\\n  }\\n\\n  .form-control-color {\\n    @include form-validation-state-selector($state) {\\n      @if $enable-validation-icons {\\n        width: add($form-color-width, $input-height-inner);\\n      }\\n    }\\n  }\\n\\n  .form-check-input {\\n    @include form-validation-state-selector($state) {\\n      border-color: $border-color;\\n\\n      &:checked {\\n        background-color: $color;\\n      }\\n\\n      &:focus {\\n        box-shadow: $focus-box-shadow;\\n      }\\n\\n      ~ .form-check-label {\\n        color: $color;\\n      }\\n    }\\n  }\\n  .form-check-inline .form-check-input {\\n    ~ .#{$state}-feedback {\\n      margin-left: .5em;\\n    }\\n  }\\n\\n  .input-group {\\n    > .form-control:not(:focus),\\n    > .form-select:not(:focus),\\n    > .form-floating:not(:focus-within) {\\n      @include form-validation-state-selector($state) {\\n        @if $state == \\\"valid\\\" {\\n          z-index: 3;\\n        } @else if $state == \\\"invalid\\\" {\\n          z-index: 4;\\n        }\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end form-validation-mixins\\n\",\"//\\n// Base styles\\n//\\n\\n.btn {\\n  // scss-docs-start btn-css-vars\\n  --#{$prefix}btn-padding-x: #{$btn-padding-x};\\n  --#{$prefix}btn-padding-y: #{$btn-padding-y};\\n  --#{$prefix}btn-font-family: #{$btn-font-family};\\n  @include rfs($btn-font-size, --#{$prefix}btn-font-size);\\n  --#{$prefix}btn-font-weight: #{$btn-font-weight};\\n  --#{$prefix}btn-line-height: #{$btn-line-height};\\n  --#{$prefix}btn-color: #{$body-color};\\n  --#{$prefix}btn-bg: transparent;\\n  --#{$prefix}btn-border-width: #{$btn-border-width};\\n  --#{$prefix}btn-border-color: transparent;\\n  --#{$prefix}btn-border-radius: #{$btn-border-radius};\\n  --#{$prefix}btn-hover-border-color: transparent;\\n  --#{$prefix}btn-box-shadow: #{$btn-box-shadow};\\n  --#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity};\\n  --#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5);\\n  // scss-docs-end btn-css-vars\\n\\n  display: inline-block;\\n  padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x);\\n  font-family: var(--#{$prefix}btn-font-family);\\n  @include font-size(var(--#{$prefix}btn-font-size));\\n  font-weight: var(--#{$prefix}btn-font-weight);\\n  line-height: var(--#{$prefix}btn-line-height);\\n  color: var(--#{$prefix}btn-color);\\n  text-align: center;\\n  text-decoration: if($link-decoration == none, null, none);\\n  white-space: $btn-white-space;\\n  vertical-align: middle;\\n  cursor: if($enable-button-pointers, pointer, null);\\n  user-select: none;\\n  border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color);\\n  @include border-radius(var(--#{$prefix}btn-border-radius));\\n  @include gradient-bg(var(--#{$prefix}btn-bg));\\n  @include box-shadow(var(--#{$prefix}btn-box-shadow));\\n  @include transition($btn-transition);\\n\\n  &:hover {\\n    color: var(--#{$prefix}btn-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n    background-color: var(--#{$prefix}btn-hover-bg);\\n    border-color: var(--#{$prefix}btn-hover-border-color);\\n  }\\n\\n  .btn-check + &:hover {\\n    // override for the checkbox/radio buttons\\n    color: var(--#{$prefix}btn-color);\\n    background-color: var(--#{$prefix}btn-bg);\\n    border-color: var(--#{$prefix}btn-border-color);\\n  }\\n\\n  &:focus-visible {\\n    color: var(--#{$prefix}btn-hover-color);\\n    @include gradient-bg(var(--#{$prefix}btn-hover-bg));\\n    border-color: var(--#{$prefix}btn-hover-border-color);\\n    outline: 0;\\n    // Avoid using mixin so we can pass custom focus shadow properly\\n    @if $enable-shadows {\\n      box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);\\n    } @else {\\n      box-shadow: var(--#{$prefix}btn-focus-box-shadow);\\n    }\\n  }\\n\\n  .btn-check:focus-visible + & {\\n    border-color: var(--#{$prefix}btn-hover-border-color);\\n    outline: 0;\\n    // Avoid using mixin so we can pass custom focus shadow properly\\n    @if $enable-shadows {\\n      box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);\\n    } @else {\\n      box-shadow: var(--#{$prefix}btn-focus-box-shadow);\\n    }\\n  }\\n\\n  .btn-check:checked + &,\\n  :not(.btn-check) + &:active,\\n  &:first-child:active,\\n  &.active,\\n  &.show {\\n    color: var(--#{$prefix}btn-active-color);\\n    background-color: var(--#{$prefix}btn-active-bg);\\n    // Remove CSS gradients if they're enabled\\n    background-image: if($enable-gradients, none, null);\\n    border-color: var(--#{$prefix}btn-active-border-color);\\n    @include box-shadow(var(--#{$prefix}btn-active-shadow));\\n\\n    &:focus-visible {\\n      // Avoid using mixin so we can pass custom focus shadow properly\\n      @if $enable-shadows {\\n        box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow);\\n      } @else {\\n        box-shadow: var(--#{$prefix}btn-focus-box-shadow);\\n      }\\n    }\\n  }\\n\\n  &:disabled,\\n  &.disabled,\\n  fieldset:disabled & {\\n    color: var(--#{$prefix}btn-disabled-color);\\n    pointer-events: none;\\n    background-color: var(--#{$prefix}btn-disabled-bg);\\n    background-image: if($enable-gradients, none, null);\\n    border-color: var(--#{$prefix}btn-disabled-border-color);\\n    opacity: var(--#{$prefix}btn-disabled-opacity);\\n    @include box-shadow(none);\\n  }\\n}\\n\\n\\n//\\n// Alternate buttons\\n//\\n\\n// scss-docs-start btn-variant-loops\\n@each $color, $value in $theme-colors {\\n  .btn-#{$color} {\\n    @if $color == \\\"light\\\" {\\n      @include button-variant(\\n        $value,\\n        $value,\\n        $hover-background: shade-color($value, $btn-hover-bg-shade-amount),\\n        $hover-border: shade-color($value, $btn-hover-border-shade-amount),\\n        $active-background: shade-color($value, $btn-active-bg-shade-amount),\\n        $active-border: shade-color($value, $btn-active-border-shade-amount)\\n      );\\n    } @else if $color == \\\"dark\\\" {\\n      @include button-variant(\\n        $value,\\n        $value,\\n        $hover-background: tint-color($value, $btn-hover-bg-tint-amount),\\n        $hover-border: tint-color($value, $btn-hover-border-tint-amount),\\n        $active-background: tint-color($value, $btn-active-bg-tint-amount),\\n        $active-border: tint-color($value, $btn-active-border-tint-amount)\\n      );\\n    } @else {\\n      @include button-variant($value, $value);\\n    }\\n  }\\n}\\n\\n@each $color, $value in $theme-colors {\\n  .btn-outline-#{$color} {\\n    @include button-outline-variant($value);\\n  }\\n}\\n// scss-docs-end btn-variant-loops\\n\\n\\n//\\n// Link buttons\\n//\\n\\n// Make a button look and behave like a link\\n.btn-link {\\n  --#{$prefix}btn-font-weight: #{$font-weight-normal};\\n  --#{$prefix}btn-color: #{$btn-link-color};\\n  --#{$prefix}btn-bg: transparent;\\n  --#{$prefix}btn-border-color: transparent;\\n  --#{$prefix}btn-hover-color: #{$btn-link-hover-color};\\n  --#{$prefix}btn-hover-border-color: transparent;\\n  --#{$prefix}btn-active-color: #{$btn-link-hover-color};\\n  --#{$prefix}btn-active-border-color: transparent;\\n  --#{$prefix}btn-disabled-color: #{$btn-link-disabled-color};\\n  --#{$prefix}btn-disabled-border-color: transparent;\\n  --#{$prefix}btn-box-shadow: none;\\n  --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix(color-contrast($primary), $primary, 15%))};\\n\\n  text-decoration: $link-decoration;\\n  @if $enable-gradients {\\n    background-image: none;\\n  }\\n\\n  &:hover,\\n  &:focus-visible {\\n    text-decoration: $link-hover-decoration;\\n  }\\n\\n  &:focus-visible {\\n    color: var(--#{$prefix}btn-color);\\n  }\\n\\n  &:hover {\\n    color: var(--#{$prefix}btn-hover-color);\\n  }\\n\\n  // No need for an active state here\\n}\\n\\n\\n//\\n// Button Sizes\\n//\\n\\n.btn-lg {\\n  @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg);\\n}\\n\\n.btn-sm {\\n  @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm);\\n}\\n\",\"// Button variants\\n//\\n// Easily pump out default styles, as well as :hover, :focus, :active,\\n// and disabled options for all buttons\\n\\n// scss-docs-start btn-variant-mixin\\n@mixin button-variant(\\n  $background,\\n  $border,\\n  $color: color-contrast($background),\\n  $hover-background: if($color == $color-contrast-light, shade-color($background, $btn-hover-bg-shade-amount), tint-color($background, $btn-hover-bg-tint-amount)),\\n  $hover-border: if($color == $color-contrast-light, shade-color($border, $btn-hover-border-shade-amount), tint-color($border, $btn-hover-border-tint-amount)),\\n  $hover-color: color-contrast($hover-background),\\n  $active-background: if($color == $color-contrast-light, shade-color($background, $btn-active-bg-shade-amount), tint-color($background, $btn-active-bg-tint-amount)),\\n  $active-border: if($color == $color-contrast-light, shade-color($border, $btn-active-border-shade-amount), tint-color($border, $btn-active-border-tint-amount)),\\n  $active-color: color-contrast($active-background),\\n  $disabled-background: $background,\\n  $disabled-border: $border,\\n  $disabled-color: color-contrast($disabled-background)\\n) {\\n  --#{$prefix}btn-color: #{$color};\\n  --#{$prefix}btn-bg: #{$background};\\n  --#{$prefix}btn-border-color: #{$border};\\n  --#{$prefix}btn-hover-color: #{$hover-color};\\n  --#{$prefix}btn-hover-bg: #{$hover-background};\\n  --#{$prefix}btn-hover-border-color: #{$hover-border};\\n  --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix($color, $border, 15%))};\\n  --#{$prefix}btn-active-color: #{$active-color};\\n  --#{$prefix}btn-active-bg: #{$active-background};\\n  --#{$prefix}btn-active-border-color: #{$active-border};\\n  --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow};\\n  --#{$prefix}btn-disabled-color: #{$disabled-color};\\n  --#{$prefix}btn-disabled-bg: #{$disabled-background};\\n  --#{$prefix}btn-disabled-border-color: #{$disabled-border};\\n}\\n// scss-docs-end btn-variant-mixin\\n\\n// scss-docs-start btn-outline-variant-mixin\\n@mixin button-outline-variant(\\n  $color,\\n  $color-hover: color-contrast($color),\\n  $active-background: $color,\\n  $active-border: $color,\\n  $active-color: color-contrast($active-background)\\n) {\\n  --#{$prefix}btn-color: #{$color};\\n  --#{$prefix}btn-border-color: #{$color};\\n  --#{$prefix}btn-hover-color: #{$color-hover};\\n  --#{$prefix}btn-hover-bg: #{$active-background};\\n  --#{$prefix}btn-hover-border-color: #{$active-border};\\n  --#{$prefix}btn-focus-shadow-rgb: #{to-rgb($color)};\\n  --#{$prefix}btn-active-color: #{$active-color};\\n  --#{$prefix}btn-active-bg: #{$active-background};\\n  --#{$prefix}btn-active-border-color: #{$active-border};\\n  --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow};\\n  --#{$prefix}btn-disabled-color: #{$color};\\n  --#{$prefix}btn-disabled-bg: transparent;\\n  --#{$prefix}btn-disabled-border-color: #{$color};\\n  --#{$prefix}gradient: none;\\n}\\n// scss-docs-end btn-outline-variant-mixin\\n\\n// scss-docs-start btn-size-mixin\\n@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) {\\n  --#{$prefix}btn-padding-y: #{$padding-y};\\n  --#{$prefix}btn-padding-x: #{$padding-x};\\n  @include rfs($font-size, --#{$prefix}btn-font-size);\\n  --#{$prefix}btn-border-radius: #{$border-radius};\\n}\\n// scss-docs-end btn-size-mixin\\n\",\".fade {\\n  @include transition($transition-fade);\\n\\n  &:not(.show) {\\n    opacity: 0;\\n  }\\n}\\n\\n// scss-docs-start collapse-classes\\n.collapse {\\n  &:not(.show) {\\n    display: none;\\n  }\\n}\\n\\n.collapsing {\\n  height: 0;\\n  overflow: hidden;\\n  @include transition($transition-collapse);\\n\\n  &.collapse-horizontal {\\n    width: 0;\\n    height: auto;\\n    @include transition($transition-collapse-width);\\n  }\\n}\\n// scss-docs-end collapse-classes\\n\",\"// The dropdown wrapper (`<div>`)\\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  // Generate the caret automatically\\n  @include caret();\\n}\\n\\n// The dropdown menu\\n.dropdown-menu {\\n  // scss-docs-start dropdown-css-vars\\n  --#{$prefix}dropdown-zindex: #{$zindex-dropdown};\\n  --#{$prefix}dropdown-min-width: #{$dropdown-min-width};\\n  --#{$prefix}dropdown-padding-x: #{$dropdown-padding-x};\\n  --#{$prefix}dropdown-padding-y: #{$dropdown-padding-y};\\n  --#{$prefix}dropdown-spacer: #{$dropdown-spacer};\\n  @include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size);\\n  --#{$prefix}dropdown-color: #{$dropdown-color};\\n  --#{$prefix}dropdown-bg: #{$dropdown-bg};\\n  --#{$prefix}dropdown-border-color: #{$dropdown-border-color};\\n  --#{$prefix}dropdown-border-radius: #{$dropdown-border-radius};\\n  --#{$prefix}dropdown-border-width: #{$dropdown-border-width};\\n  --#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius};\\n  --#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg};\\n  --#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y};\\n  --#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow};\\n  --#{$prefix}dropdown-link-color: #{$dropdown-link-color};\\n  --#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color};\\n  --#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg};\\n  --#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color};\\n  --#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg};\\n  --#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color};\\n  --#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x};\\n  --#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y};\\n  --#{$prefix}dropdown-header-color: #{$dropdown-header-color};\\n  --#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x};\\n  --#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y};\\n  // scss-docs-end dropdown-css-vars\\n\\n  position: absolute;\\n  z-index: var(--#{$prefix}dropdown-zindex);\\n  display: none; // none by default, but block on \\\"open\\\" of the menu\\n  min-width: var(--#{$prefix}dropdown-min-width);\\n  padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x);\\n  margin: 0; // Override default margin of ul\\n  @include font-size(var(--#{$prefix}dropdown-font-size));\\n  color: var(--#{$prefix}dropdown-color);\\n  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\\n  list-style: none;\\n  background-color: var(--#{$prefix}dropdown-bg);\\n  background-clip: padding-box;\\n  border: var(--#{$prefix}dropdown-border-width) solid var(--#{$prefix}dropdown-border-color);\\n  @include border-radius(var(--#{$prefix}dropdown-border-radius));\\n  @include box-shadow(var(--#{$prefix}dropdown-box-shadow));\\n\\n  &[data-bs-popper] {\\n    top: 100%;\\n    left: 0;\\n    margin-top: var(--#{$prefix}dropdown-spacer);\\n  }\\n\\n  @if $dropdown-padding-y == 0 {\\n    > .dropdown-item:first-child,\\n    > li:first-child .dropdown-item {\\n      @include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius));\\n    }\\n    > .dropdown-item:last-child,\\n    > li:last-child .dropdown-item {\\n      @include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius));\\n    }\\n\\n  }\\n}\\n\\n// scss-docs-start responsive-breakpoints\\n// We deliberately hardcode the `bs-` prefix because we check\\n// this custom property in JS to determine Popper's positioning\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  @include media-breakpoint-up($breakpoint) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    .dropdown-menu#{$infix}-start {\\n      --bs-position: start;\\n\\n      &[data-bs-popper] {\\n        right: auto;\\n        left: 0;\\n      }\\n    }\\n\\n    .dropdown-menu#{$infix}-end {\\n      --bs-position: end;\\n\\n      &[data-bs-popper] {\\n        right: 0;\\n        left: auto;\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end responsive-breakpoints\\n\\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\\n// Just add .dropup after the standard .dropdown class and you're set.\\n.dropup {\\n  .dropdown-menu[data-bs-popper] {\\n    top: auto;\\n    bottom: 100%;\\n    margin-top: 0;\\n    margin-bottom: var(--#{$prefix}dropdown-spacer);\\n  }\\n\\n  .dropdown-toggle {\\n    @include caret(up);\\n  }\\n}\\n\\n.dropend {\\n  .dropdown-menu[data-bs-popper] {\\n    top: 0;\\n    right: auto;\\n    left: 100%;\\n    margin-top: 0;\\n    margin-left: var(--#{$prefix}dropdown-spacer);\\n  }\\n\\n  .dropdown-toggle {\\n    @include caret(end);\\n    &::after {\\n      vertical-align: 0;\\n    }\\n  }\\n}\\n\\n.dropstart {\\n  .dropdown-menu[data-bs-popper] {\\n    top: 0;\\n    right: 100%;\\n    left: auto;\\n    margin-top: 0;\\n    margin-right: var(--#{$prefix}dropdown-spacer);\\n  }\\n\\n  .dropdown-toggle {\\n    @include caret(start);\\n    &::before {\\n      vertical-align: 0;\\n    }\\n  }\\n}\\n\\n\\n// Dividers (basically an `<hr>`) within the dropdown\\n.dropdown-divider {\\n  height: 0;\\n  margin: var(--#{$prefix}dropdown-divider-margin-y) 0;\\n  overflow: hidden;\\n  border-top: 1px solid var(--#{$prefix}dropdown-divider-bg);\\n  opacity: 1; // Revisit in v6 to de-dupe styles that conflict with <hr> element\\n}\\n\\n// Links, buttons, and more within the dropdown menu\\n//\\n// `<button>`-specific styles are denoted with `// For <button>s`\\n.dropdown-item {\\n  display: block;\\n  width: 100%; // For `<button>`s\\n  padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);\\n  clear: both;\\n  font-weight: $font-weight-normal;\\n  color: var(--#{$prefix}dropdown-link-color);\\n  text-align: inherit; // For `<button>`s\\n  text-decoration: if($link-decoration == none, null, none);\\n  white-space: nowrap; // prevent links from randomly breaking onto new lines\\n  background-color: transparent; // For `<button>`s\\n  border: 0; // For `<button>`s\\n  @include border-radius(var(--#{$prefix}dropdown-item-border-radius, 0));\\n\\n  &:hover,\\n  &:focus {\\n    color: var(--#{$prefix}dropdown-link-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n    @include gradient-bg(var(--#{$prefix}dropdown-link-hover-bg));\\n  }\\n\\n  &.active,\\n  &:active {\\n    color: var(--#{$prefix}dropdown-link-active-color);\\n    text-decoration: none;\\n    @include gradient-bg(var(--#{$prefix}dropdown-link-active-bg));\\n  }\\n\\n  &.disabled,\\n  &:disabled {\\n    color: var(--#{$prefix}dropdown-link-disabled-color);\\n    pointer-events: none;\\n    background-color: transparent;\\n    // Remove CSS gradients if they're enabled\\n    background-image: if($enable-gradients, none, null);\\n  }\\n}\\n\\n.dropdown-menu.show {\\n  display: block;\\n}\\n\\n// Dropdown section headers\\n.dropdown-header {\\n  display: block;\\n  padding: var(--#{$prefix}dropdown-header-padding-y) var(--#{$prefix}dropdown-header-padding-x);\\n  margin-bottom: 0; // for use with heading elements\\n  @include font-size($font-size-sm);\\n  color: var(--#{$prefix}dropdown-header-color);\\n  white-space: nowrap; // as with > li > a\\n}\\n\\n// Dropdown text\\n.dropdown-item-text {\\n  display: block;\\n  padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);\\n  color: var(--#{$prefix}dropdown-link-color);\\n}\\n\\n// Dark dropdowns\\n.dropdown-menu-dark {\\n  // scss-docs-start dropdown-dark-css-vars\\n  --#{$prefix}dropdown-color: #{$dropdown-dark-color};\\n  --#{$prefix}dropdown-bg: #{$dropdown-dark-bg};\\n  --#{$prefix}dropdown-border-color: #{$dropdown-dark-border-color};\\n  --#{$prefix}dropdown-box-shadow: #{$dropdown-dark-box-shadow};\\n  --#{$prefix}dropdown-link-color: #{$dropdown-dark-link-color};\\n  --#{$prefix}dropdown-link-hover-color: #{$dropdown-dark-link-hover-color};\\n  --#{$prefix}dropdown-divider-bg: #{$dropdown-dark-divider-bg};\\n  --#{$prefix}dropdown-link-hover-bg: #{$dropdown-dark-link-hover-bg};\\n  --#{$prefix}dropdown-link-active-color: #{$dropdown-dark-link-active-color};\\n  --#{$prefix}dropdown-link-active-bg: #{$dropdown-dark-link-active-bg};\\n  --#{$prefix}dropdown-link-disabled-color: #{$dropdown-dark-link-disabled-color};\\n  --#{$prefix}dropdown-header-color: #{$dropdown-dark-header-color};\\n  // scss-docs-end dropdown-dark-css-vars\\n}\\n\",\"// scss-docs-start caret-mixins\\n@mixin caret-down($width: $caret-width) {\\n  border-top: $width solid;\\n  border-right: $width solid transparent;\\n  border-bottom: 0;\\n  border-left: $width solid transparent;\\n}\\n\\n@mixin caret-up($width: $caret-width) {\\n  border-top: 0;\\n  border-right: $width solid transparent;\\n  border-bottom: $width solid;\\n  border-left: $width solid transparent;\\n}\\n\\n@mixin caret-end($width: $caret-width) {\\n  border-top: $width solid transparent;\\n  border-right: 0;\\n  border-bottom: $width solid transparent;\\n  border-left: $width solid;\\n}\\n\\n@mixin caret-start($width: $caret-width) {\\n  border-top: $width solid transparent;\\n  border-right: $width solid;\\n  border-bottom: $width solid transparent;\\n}\\n\\n@mixin caret(\\n  $direction: down,\\n  $width: $caret-width,\\n  $spacing: $caret-spacing,\\n  $vertical-align: $caret-vertical-align\\n) {\\n  @if $enable-caret {\\n    &::after {\\n      display: inline-block;\\n      margin-left: $spacing;\\n      vertical-align: $vertical-align;\\n      content: \\\"\\\";\\n      @if $direction == down {\\n        @include caret-down($width);\\n      } @else if $direction == up {\\n        @include caret-up($width);\\n      } @else if $direction == end {\\n        @include caret-end($width);\\n      }\\n    }\\n\\n    @if $direction == start {\\n      &::after {\\n        display: none;\\n      }\\n\\n      &::before {\\n        display: inline-block;\\n        margin-right: $spacing;\\n        vertical-align: $vertical-align;\\n        content: \\\"\\\";\\n        @include caret-start($width);\\n      }\\n    }\\n\\n    &:empty::after {\\n      margin-left: 0;\\n    }\\n  }\\n}\\n// scss-docs-end caret-mixins\\n\",\"// Make the div behave like a button\\n.btn-group,\\n.btn-group-vertical {\\n  position: relative;\\n  display: inline-flex;\\n  vertical-align: middle; // match .btn alignment given font-size hack above\\n\\n  > .btn {\\n    position: relative;\\n    flex: 1 1 auto;\\n  }\\n\\n  // Bring the hover, focused, and \\\"active\\\" buttons to the front to overlay\\n  // the borders properly\\n  > .btn-check:checked + .btn,\\n  > .btn-check:focus + .btn,\\n  > .btn:hover,\\n  > .btn:focus,\\n  > .btn:active,\\n  > .btn.active {\\n    z-index: 1;\\n  }\\n}\\n\\n// Optional: Group multiple button groups together for a toolbar\\n.btn-toolbar {\\n  display: flex;\\n  flex-wrap: wrap;\\n  justify-content: flex-start;\\n\\n  .input-group {\\n    width: auto;\\n  }\\n}\\n\\n.btn-group {\\n  @include border-radius($btn-border-radius);\\n\\n  // Prevent double borders when buttons are next to each other\\n  > :not(.btn-check:first-child) + .btn,\\n  > .btn-group:not(:first-child) {\\n    margin-left: calc($btn-border-width * -1); // stylelint-disable-line function-disallowed-list\\n  }\\n\\n  // Reset rounded corners\\n  > .btn:not(:last-child):not(.dropdown-toggle),\\n  > .btn.dropdown-toggle-split:first-child,\\n  > .btn-group:not(:last-child) > .btn {\\n    @include border-end-radius(0);\\n  }\\n\\n  // The left radius should be 0 if the button is:\\n  // - the \\\"third or more\\\" child\\n  // - the second child and the previous element isn't `.btn-check` (making it the first child visually)\\n  // - part of a btn-group which isn't the first child\\n  > .btn:nth-child(n + 3),\\n  > :not(.btn-check) + .btn,\\n  > .btn-group:not(:first-child) > .btn {\\n    @include border-start-radius(0);\\n  }\\n}\\n\\n// Sizing\\n//\\n// Remix the default button sizing classes into new ones for easier manipulation.\\n\\n.btn-group-sm > .btn { @extend .btn-sm; }\\n.btn-group-lg > .btn { @extend .btn-lg; }\\n\\n\\n//\\n// Split button dropdowns\\n//\\n\\n.dropdown-toggle-split {\\n  padding-right: $btn-padding-x * .75;\\n  padding-left: $btn-padding-x * .75;\\n\\n  &::after,\\n  .dropup &::after,\\n  .dropend &::after {\\n    margin-left: 0;\\n  }\\n\\n  .dropstart &::before {\\n    margin-right: 0;\\n  }\\n}\\n\\n.btn-sm + .dropdown-toggle-split {\\n  padding-right: $btn-padding-x-sm * .75;\\n  padding-left: $btn-padding-x-sm * .75;\\n}\\n\\n.btn-lg + .dropdown-toggle-split {\\n  padding-right: $btn-padding-x-lg * .75;\\n  padding-left: $btn-padding-x-lg * .75;\\n}\\n\\n\\n// The clickable button for toggling the menu\\n// Set the same inset shadow as the :active state\\n.btn-group.show .dropdown-toggle {\\n  @include box-shadow($btn-active-box-shadow);\\n\\n  // Show no shadow for `.btn-link` since it has no other button styles.\\n  &.btn-link {\\n    @include box-shadow(none);\\n  }\\n}\\n\\n\\n//\\n// Vertical button groups\\n//\\n\\n.btn-group-vertical {\\n  flex-direction: column;\\n  align-items: flex-start;\\n  justify-content: center;\\n\\n  > .btn,\\n  > .btn-group {\\n    width: 100%;\\n  }\\n\\n  > .btn:not(:first-child),\\n  > .btn-group:not(:first-child) {\\n    margin-top: calc($btn-border-width * -1); // stylelint-disable-line function-disallowed-list\\n  }\\n\\n  // Reset rounded corners\\n  > .btn:not(:last-child):not(.dropdown-toggle),\\n  > .btn-group:not(:last-child) > .btn {\\n    @include border-bottom-radius(0);\\n  }\\n\\n  > .btn ~ .btn,\\n  > .btn-group:not(:first-child) > .btn {\\n    @include border-top-radius(0);\\n  }\\n}\\n\",\"// Base class\\n//\\n// Kickstart any navigation component with a set of style resets. Works with\\n// `<nav>`s, `<ul>`s or `<ol>`s.\\n\\n.nav {\\n  // scss-docs-start nav-css-vars\\n  --#{$prefix}nav-link-padding-x: #{$nav-link-padding-x};\\n  --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};\\n  @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);\\n  --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};\\n  --#{$prefix}nav-link-color: #{$nav-link-color};\\n  --#{$prefix}nav-link-hover-color: #{$nav-link-hover-color};\\n  --#{$prefix}nav-link-disabled-color: #{$nav-link-disabled-color};\\n  // scss-docs-end nav-css-vars\\n\\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(--#{$prefix}nav-link-padding-y) var(--#{$prefix}nav-link-padding-x);\\n  @include font-size(var(--#{$prefix}nav-link-font-size));\\n  font-weight: var(--#{$prefix}nav-link-font-weight);\\n  color: var(--#{$prefix}nav-link-color);\\n  text-decoration: if($link-decoration == none, null, none);\\n  @include transition($nav-link-transition);\\n\\n  &:hover,\\n  &:focus {\\n    color: var(--#{$prefix}nav-link-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n  }\\n\\n  // Disabled state lightens text\\n  &.disabled {\\n    color: var(--#{$prefix}nav-link-disabled-color);\\n    pointer-events: none;\\n    cursor: default;\\n  }\\n}\\n\\n//\\n// Tabs\\n//\\n\\n.nav-tabs {\\n  // scss-docs-start nav-tabs-css-vars\\n  --#{$prefix}nav-tabs-border-width: #{$nav-tabs-border-width};\\n  --#{$prefix}nav-tabs-border-color: #{$nav-tabs-border-color};\\n  --#{$prefix}nav-tabs-border-radius: #{$nav-tabs-border-radius};\\n  --#{$prefix}nav-tabs-link-hover-border-color: #{$nav-tabs-link-hover-border-color};\\n  --#{$prefix}nav-tabs-link-active-color: #{$nav-tabs-link-active-color};\\n  --#{$prefix}nav-tabs-link-active-bg: #{$nav-tabs-link-active-bg};\\n  --#{$prefix}nav-tabs-link-active-border-color: #{$nav-tabs-link-active-border-color};\\n  // scss-docs-end nav-tabs-css-vars\\n\\n  border-bottom: var(--#{$prefix}nav-tabs-border-width) solid var(--#{$prefix}nav-tabs-border-color);\\n\\n  .nav-link {\\n    margin-bottom: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list\\n    background: none;\\n    border: var(--#{$prefix}nav-tabs-border-width) solid transparent;\\n    @include border-top-radius(var(--#{$prefix}nav-tabs-border-radius));\\n\\n    &:hover,\\n    &:focus {\\n      // Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link\\n      isolation: isolate;\\n      border-color: var(--#{$prefix}nav-tabs-link-hover-border-color);\\n    }\\n\\n    &.disabled,\\n    &:disabled {\\n      color: var(--#{$prefix}nav-link-disabled-color);\\n      background-color: transparent;\\n      border-color: transparent;\\n    }\\n  }\\n\\n  .nav-link.active,\\n  .nav-item.show .nav-link {\\n    color: var(--#{$prefix}nav-tabs-link-active-color);\\n    background-color: var(--#{$prefix}nav-tabs-link-active-bg);\\n    border-color: var(--#{$prefix}nav-tabs-link-active-border-color);\\n  }\\n\\n  .dropdown-menu {\\n    // Make dropdown border overlap tab border\\n    margin-top: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list\\n    // Remove the top rounded corners here since there is a hard edge above the menu\\n    @include border-top-radius(0);\\n  }\\n}\\n\\n\\n//\\n// Pills\\n//\\n\\n.nav-pills {\\n  // scss-docs-start nav-pills-css-vars\\n  --#{$prefix}nav-pills-border-radius: #{$nav-pills-border-radius};\\n  --#{$prefix}nav-pills-link-active-color: #{$nav-pills-link-active-color};\\n  --#{$prefix}nav-pills-link-active-bg: #{$nav-pills-link-active-bg};\\n  // scss-docs-end nav-pills-css-vars\\n\\n  .nav-link {\\n    background: none;\\n    border: 0;\\n    @include border-radius(var(--#{$prefix}nav-pills-border-radius));\\n\\n    &:disabled {\\n      color: var(--#{$prefix}nav-link-disabled-color);\\n      background-color: transparent;\\n      border-color: transparent;\\n    }\\n  }\\n\\n  .nav-link.active,\\n  .show > .nav-link {\\n    color: var(--#{$prefix}nav-pills-link-active-color);\\n    @include gradient-bg(var(--#{$prefix}nav-pills-link-active-bg));\\n  }\\n}\\n\\n\\n//\\n// Justified variants\\n//\\n\\n.nav-fill {\\n  > .nav-link,\\n  .nav-item {\\n    flex: 1 1 auto;\\n    text-align: center;\\n  }\\n}\\n\\n.nav-justified {\\n  > .nav-link,\\n  .nav-item {\\n    flex-basis: 0;\\n    flex-grow: 1;\\n    text-align: center;\\n  }\\n}\\n\\n.nav-fill,\\n.nav-justified {\\n  .nav-item .nav-link {\\n    width: 100%; // Make sure button will grow\\n  }\\n}\\n\\n\\n// Tabbable tabs\\n//\\n// Hide tabbable panes to start, show them when `.active`\\n\\n.tab-content {\\n  > .tab-pane {\\n    display: none;\\n  }\\n  > .active {\\n    display: block;\\n  }\\n}\\n\",\"// Navbar\\n//\\n// Provide a static navbar from which we expand to create full-width, fixed, and\\n// other navbar variations.\\n\\n.navbar {\\n  // scss-docs-start navbar-css-vars\\n  --#{$prefix}navbar-padding-x: #{if($navbar-padding-x == null, 0, $navbar-padding-x)};\\n  --#{$prefix}navbar-padding-y: #{$navbar-padding-y};\\n  --#{$prefix}navbar-color: #{$navbar-light-color};\\n  --#{$prefix}navbar-hover-color: #{$navbar-light-hover-color};\\n  --#{$prefix}navbar-disabled-color: #{$navbar-light-disabled-color};\\n  --#{$prefix}navbar-active-color: #{$navbar-light-active-color};\\n  --#{$prefix}navbar-brand-padding-y: #{$navbar-brand-padding-y};\\n  --#{$prefix}navbar-brand-margin-end: #{$navbar-brand-margin-end};\\n  --#{$prefix}navbar-brand-font-size: #{$navbar-brand-font-size};\\n  --#{$prefix}navbar-brand-color: #{$navbar-light-brand-color};\\n  --#{$prefix}navbar-brand-hover-color: #{$navbar-light-brand-hover-color};\\n  --#{$prefix}navbar-nav-link-padding-x: #{$navbar-nav-link-padding-x};\\n  --#{$prefix}navbar-toggler-padding-y: #{$navbar-toggler-padding-y};\\n  --#{$prefix}navbar-toggler-padding-x: #{$navbar-toggler-padding-x};\\n  --#{$prefix}navbar-toggler-font-size: #{$navbar-toggler-font-size};\\n  --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-light-toggler-icon-bg)};\\n  --#{$prefix}navbar-toggler-border-color: #{$navbar-light-toggler-border-color};\\n  --#{$prefix}navbar-toggler-border-radius: #{$navbar-toggler-border-radius};\\n  --#{$prefix}navbar-toggler-focus-width: #{$navbar-toggler-focus-width};\\n  --#{$prefix}navbar-toggler-transition: #{$navbar-toggler-transition};\\n  // scss-docs-end navbar-css-vars\\n\\n  position: relative;\\n  display: flex;\\n  flex-wrap: wrap; // allow us to do the line break for collapsing content\\n  align-items: center;\\n  justify-content: space-between; // space out brand from logo\\n  padding: var(--#{$prefix}navbar-padding-y) var(--#{$prefix}navbar-padding-x);\\n  @include gradient-bg();\\n\\n  // Because flex properties aren't inherited, we need to redeclare these first\\n  // few properties so that content nested within behave properly.\\n  // The `flex-wrap` property is inherited to simplify the expanded navbars\\n  %container-flex-properties {\\n    display: flex;\\n    flex-wrap: inherit;\\n    align-items: center;\\n    justify-content: space-between;\\n  }\\n\\n  > .container,\\n  > .container-fluid {\\n    @extend %container-flex-properties;\\n  }\\n\\n  @each $breakpoint, $container-max-width in $container-max-widths {\\n    > .container#{breakpoint-infix($breakpoint, $container-max-widths)} {\\n      @extend %container-flex-properties;\\n    }\\n  }\\n}\\n\\n\\n// Navbar brand\\n//\\n// Used for brand, project, or site names.\\n\\n.navbar-brand {\\n  padding-top: var(--#{$prefix}navbar-brand-padding-y);\\n  padding-bottom: var(--#{$prefix}navbar-brand-padding-y);\\n  margin-right: var(--#{$prefix}navbar-brand-margin-end);\\n  @include font-size(var(--#{$prefix}navbar-brand-font-size));\\n  color: var(--#{$prefix}navbar-brand-color);\\n  text-decoration: if($link-decoration == none, null, none);\\n  white-space: nowrap;\\n\\n  &:hover,\\n  &:focus {\\n    color: var(--#{$prefix}navbar-brand-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n  }\\n}\\n\\n\\n// Navbar nav\\n//\\n// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).\\n\\n.navbar-nav {\\n  // scss-docs-start navbar-nav-css-vars\\n  --#{$prefix}nav-link-padding-x: 0;\\n  --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};\\n  @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);\\n  --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};\\n  --#{$prefix}nav-link-color: var(--#{$prefix}navbar-color);\\n  --#{$prefix}nav-link-hover-color: var(--#{$prefix}navbar-hover-color);\\n  --#{$prefix}nav-link-disabled-color: var(--#{$prefix}navbar-disabled-color);\\n  // scss-docs-end navbar-nav-css-vars\\n\\n  display: flex;\\n  flex-direction: column; // cannot use `inherit` to get the `.navbar`s value\\n  padding-left: 0;\\n  margin-bottom: 0;\\n  list-style: none;\\n\\n  .show > .nav-link,\\n  .nav-link.active {\\n    color: var(--#{$prefix}navbar-active-color);\\n  }\\n\\n  .dropdown-menu {\\n    position: static;\\n  }\\n}\\n\\n\\n// Navbar text\\n//\\n//\\n\\n.navbar-text {\\n  padding-top: $nav-link-padding-y;\\n  padding-bottom: $nav-link-padding-y;\\n  color: var(--#{$prefix}navbar-color);\\n\\n  a,\\n  a:hover,\\n  a:focus  {\\n    color: var(--#{$prefix}navbar-active-color);\\n  }\\n}\\n\\n\\n// Responsive navbar\\n//\\n// Custom styles for responsive collapsing and toggling of navbar contents.\\n// Powered by the collapse Bootstrap JavaScript plugin.\\n\\n// When collapsed, prevent the toggleable navbar contents from appearing in\\n// the default flexbox row orientation. Requires the use of `flex-wrap: wrap`\\n// on the `.navbar` parent.\\n.navbar-collapse {\\n  flex-basis: 100%;\\n  flex-grow: 1;\\n  // For always expanded or extra full navbars, ensure content aligns itself\\n  // properly vertically. Can be easily overridden with flex utilities.\\n  align-items: center;\\n}\\n\\n// Button for toggling the navbar when in its collapsed state\\n.navbar-toggler {\\n  padding: var(--#{$prefix}navbar-toggler-padding-y) var(--#{$prefix}navbar-toggler-padding-x);\\n  @include font-size(var(--#{$prefix}navbar-toggler-font-size));\\n  line-height: 1;\\n  color: var(--#{$prefix}navbar-color);\\n  background-color: transparent; // remove default button style\\n  border: var(--#{$prefix}border-width) solid var(--#{$prefix}navbar-toggler-border-color); // remove default button style\\n  @include border-radius(var(--#{$prefix}navbar-toggler-border-radius));\\n  @include transition(var(--#{$prefix}navbar-toggler-transition));\\n\\n  &:hover {\\n    text-decoration: none;\\n  }\\n\\n  &:focus {\\n    text-decoration: none;\\n    outline: 0;\\n    box-shadow: 0 0 0 var(--#{$prefix}navbar-toggler-focus-width);\\n  }\\n}\\n\\n// Keep as a separate element so folks can easily override it with another icon\\n// or image file as needed.\\n.navbar-toggler-icon {\\n  display: inline-block;\\n  width: 1.5em;\\n  height: 1.5em;\\n  vertical-align: middle;\\n  background-image: var(--#{$prefix}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(--#{$prefix}scroll-height, 75vh);\\n  overflow-y: auto;\\n}\\n\\n// scss-docs-start navbar-expand-loop\\n// Generate series of `.navbar-expand-*` responsive classes for configuring\\n// where your navbar collapses.\\n.navbar-expand {\\n  @each $breakpoint in map-keys($grid-breakpoints) {\\n    $next: breakpoint-next($breakpoint, $grid-breakpoints);\\n    $infix: breakpoint-infix($next, $grid-breakpoints);\\n\\n    // stylelint-disable-next-line scss/selector-no-union-class-name\\n    &#{$infix} {\\n      @include media-breakpoint-up($next) {\\n        flex-wrap: nowrap;\\n        justify-content: flex-start;\\n\\n        .navbar-nav {\\n          flex-direction: row;\\n\\n          .dropdown-menu {\\n            position: absolute;\\n          }\\n\\n          .nav-link {\\n            padding-right: var(--#{$prefix}navbar-nav-link-padding-x);\\n            padding-left: var(--#{$prefix}navbar-nav-link-padding-x);\\n          }\\n        }\\n\\n        .navbar-nav-scroll {\\n          overflow: visible;\\n        }\\n\\n        .navbar-collapse {\\n          display: flex !important; // stylelint-disable-line declaration-no-important\\n          flex-basis: auto;\\n        }\\n\\n        .navbar-toggler {\\n          display: none;\\n        }\\n\\n        .offcanvas {\\n          // stylelint-disable declaration-no-important\\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          @include box-shadow(none);\\n          @include transition(none);\\n          // stylelint-enable declaration-no-important\\n\\n          .offcanvas-header {\\n            display: none;\\n          }\\n\\n          .offcanvas-body {\\n            display: flex;\\n            flex-grow: 0;\\n            padding: 0;\\n            overflow-y: visible;\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end navbar-expand-loop\\n\\n// Navbar themes\\n//\\n// Styles for switching between navbars with light or dark background.\\n\\n.navbar-light {\\n  @include deprecate(\\\"`.navbar-light`\\\", \\\"v5.2.0\\\", \\\"v6.0.0\\\", true);\\n}\\n\\n.navbar-dark {\\n  // scss-docs-start navbar-dark-css-vars\\n  --#{$prefix}navbar-color: #{$navbar-dark-color};\\n  --#{$prefix}navbar-hover-color: #{$navbar-dark-hover-color};\\n  --#{$prefix}navbar-disabled-color: #{$navbar-dark-disabled-color};\\n  --#{$prefix}navbar-active-color: #{$navbar-dark-active-color};\\n  --#{$prefix}navbar-brand-color: #{$navbar-dark-brand-color};\\n  --#{$prefix}navbar-brand-hover-color: #{$navbar-dark-brand-hover-color};\\n  --#{$prefix}navbar-toggler-border-color: #{$navbar-dark-toggler-border-color};\\n  --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};\\n  // scss-docs-end navbar-dark-css-vars\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .navbar {\\n      --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};\\n    }\\n  }\\n}\\n\",\"//\\n// Base styles\\n//\\n\\n.card {\\n  // scss-docs-start card-css-vars\\n  --#{$prefix}card-spacer-y: #{$card-spacer-y};\\n  --#{$prefix}card-spacer-x: #{$card-spacer-x};\\n  --#{$prefix}card-title-spacer-y: #{$card-title-spacer-y};\\n  --#{$prefix}card-title-color: #{$card-title-color};\\n  --#{$prefix}card-subtitle-color: #{$card-subtitle-color};\\n  --#{$prefix}card-border-width: #{$card-border-width};\\n  --#{$prefix}card-border-color: #{$card-border-color};\\n  --#{$prefix}card-border-radius: #{$card-border-radius};\\n  --#{$prefix}card-box-shadow: #{$card-box-shadow};\\n  --#{$prefix}card-inner-border-radius: #{$card-inner-border-radius};\\n  --#{$prefix}card-cap-padding-y: #{$card-cap-padding-y};\\n  --#{$prefix}card-cap-padding-x: #{$card-cap-padding-x};\\n  --#{$prefix}card-cap-bg: #{$card-cap-bg};\\n  --#{$prefix}card-cap-color: #{$card-cap-color};\\n  --#{$prefix}card-height: #{$card-height};\\n  --#{$prefix}card-color: #{$card-color};\\n  --#{$prefix}card-bg: #{$card-bg};\\n  --#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding};\\n  --#{$prefix}card-group-margin: #{$card-group-margin};\\n  // scss-docs-end card-css-vars\\n\\n  position: relative;\\n  display: flex;\\n  flex-direction: column;\\n  min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106\\n  height: var(--#{$prefix}card-height);\\n  word-wrap: break-word;\\n  background-color: var(--#{$prefix}card-bg);\\n  background-clip: border-box;\\n  border: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);\\n  @include border-radius(var(--#{$prefix}card-border-radius));\\n  @include box-shadow(var(--#{$prefix}card-box-shadow));\\n\\n  > hr {\\n    margin-right: 0;\\n    margin-left: 0;\\n  }\\n\\n  > .list-group {\\n    border-top: inherit;\\n    border-bottom: inherit;\\n\\n    &:first-child {\\n      border-top-width: 0;\\n      @include border-top-radius(var(--#{$prefix}card-inner-border-radius));\\n    }\\n\\n    &:last-child  {\\n      border-bottom-width: 0;\\n      @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));\\n    }\\n  }\\n\\n  // Due to specificity of the above selector (`.card > .list-group`), we must\\n  // use a child selector here to prevent double borders.\\n  > .card-header + .list-group,\\n  > .list-group + .card-footer {\\n    border-top: 0;\\n  }\\n}\\n\\n.card-body {\\n  // Enable `flex-grow: 1` for decks and groups so that card blocks take up\\n  // as much space as possible, ensuring footers are aligned to the bottom.\\n  flex: 1 1 auto;\\n  padding: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x);\\n  color: var(--#{$prefix}card-color);\\n}\\n\\n.card-title {\\n  margin-bottom: var(--#{$prefix}card-title-spacer-y);\\n  color: var(--#{$prefix}card-title-color);\\n}\\n\\n.card-subtitle {\\n  margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list\\n  margin-bottom: 0;\\n  color: var(--#{$prefix}card-subtitle-color);\\n}\\n\\n.card-text:last-child {\\n  margin-bottom: 0;\\n}\\n\\n.card-link {\\n  &:hover {\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n  }\\n\\n  + .card-link {\\n    margin-left: var(--#{$prefix}card-spacer-x);\\n  }\\n}\\n\\n//\\n// Optional textual caps\\n//\\n\\n.card-header {\\n  padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);\\n  margin-bottom: 0; // Removes the default margin-bottom of <hN>\\n  color: var(--#{$prefix}card-cap-color);\\n  background-color: var(--#{$prefix}card-cap-bg);\\n  border-bottom: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);\\n\\n  &:first-child {\\n    @include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0);\\n  }\\n}\\n\\n.card-footer {\\n  padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);\\n  color: var(--#{$prefix}card-cap-color);\\n  background-color: var(--#{$prefix}card-cap-bg);\\n  border-top: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);\\n\\n  &:last-child {\\n    @include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius));\\n  }\\n}\\n\\n\\n//\\n// Header navs\\n//\\n\\n.card-header-tabs {\\n  margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list\\n  margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list\\n  margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list\\n  border-bottom: 0;\\n\\n  .nav-link.active {\\n    background-color: var(--#{$prefix}card-bg);\\n    border-bottom-color: var(--#{$prefix}card-bg);\\n  }\\n}\\n\\n.card-header-pills {\\n  margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list\\n  margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list\\n}\\n\\n// Card image\\n.card-img-overlay {\\n  position: absolute;\\n  top: 0;\\n  right: 0;\\n  bottom: 0;\\n  left: 0;\\n  padding: var(--#{$prefix}card-img-overlay-padding);\\n  @include border-radius(var(--#{$prefix}card-inner-border-radius));\\n}\\n\\n.card-img,\\n.card-img-top,\\n.card-img-bottom {\\n  width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch\\n}\\n\\n.card-img,\\n.card-img-top {\\n  @include border-top-radius(var(--#{$prefix}card-inner-border-radius));\\n}\\n\\n.card-img,\\n.card-img-bottom {\\n  @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));\\n}\\n\\n\\n//\\n// Card groups\\n//\\n\\n.card-group {\\n  // The child selector allows nested `.card` within `.card-group`\\n  // to display properly.\\n  > .card {\\n    margin-bottom: var(--#{$prefix}card-group-margin);\\n  }\\n\\n  @include media-breakpoint-up(sm) {\\n    display: flex;\\n    flex-flow: row wrap;\\n    // The child selector allows nested `.card` within `.card-group`\\n    // to display properly.\\n    > .card {\\n      // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\\n      flex: 1 0 0%;\\n      margin-bottom: 0;\\n\\n      + .card {\\n        margin-left: 0;\\n        border-left: 0;\\n      }\\n\\n      // Handle rounded corners\\n      @if $enable-rounded {\\n        &:not(:last-child) {\\n          @include border-end-radius(0);\\n\\n          .card-img-top,\\n          .card-header {\\n            // stylelint-disable-next-line property-disallowed-list\\n            border-top-right-radius: 0;\\n          }\\n          .card-img-bottom,\\n          .card-footer {\\n            // stylelint-disable-next-line property-disallowed-list\\n            border-bottom-right-radius: 0;\\n          }\\n        }\\n\\n        &:not(:first-child) {\\n          @include border-start-radius(0);\\n\\n          .card-img-top,\\n          .card-header {\\n            // stylelint-disable-next-line property-disallowed-list\\n            border-top-left-radius: 0;\\n          }\\n          .card-img-bottom,\\n          .card-footer {\\n            // stylelint-disable-next-line property-disallowed-list\\n            border-bottom-left-radius: 0;\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n\",\"//\\n// Base styles\\n//\\n\\n.accordion {\\n  // scss-docs-start accordion-css-vars\\n  --#{$prefix}accordion-color: #{$accordion-color};\\n  --#{$prefix}accordion-bg: #{$accordion-bg};\\n  --#{$prefix}accordion-transition: #{$accordion-transition};\\n  --#{$prefix}accordion-border-color: #{$accordion-border-color};\\n  --#{$prefix}accordion-border-width: #{$accordion-border-width};\\n  --#{$prefix}accordion-border-radius: #{$accordion-border-radius};\\n  --#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius};\\n  --#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x};\\n  --#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y};\\n  --#{$prefix}accordion-btn-color: #{$accordion-button-color};\\n  --#{$prefix}accordion-btn-bg: #{$accordion-button-bg};\\n  --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)};\\n  --#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width};\\n  --#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform};\\n  --#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition};\\n  --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon)};\\n  --#{$prefix}accordion-btn-focus-border-color: #{$accordion-button-focus-border-color};\\n  --#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow};\\n  --#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x};\\n  --#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y};\\n  --#{$prefix}accordion-active-color: #{$accordion-button-active-color};\\n  --#{$prefix}accordion-active-bg: #{$accordion-button-active-bg};\\n  // scss-docs-end accordion-css-vars\\n}\\n\\n.accordion-button {\\n  position: relative;\\n  display: flex;\\n  align-items: center;\\n  width: 100%;\\n  padding: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x);\\n  @include font-size($font-size-base);\\n  color: var(--#{$prefix}accordion-btn-color);\\n  text-align: left; // Reset button style\\n  background-color: var(--#{$prefix}accordion-btn-bg);\\n  border: 0;\\n  @include border-radius(0);\\n  overflow-anchor: none;\\n  @include transition(var(--#{$prefix}accordion-transition));\\n\\n  &:not(.collapsed) {\\n    color: var(--#{$prefix}accordion-active-color);\\n    background-color: var(--#{$prefix}accordion-active-bg);\\n    box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list\\n\\n    &::after {\\n      background-image: var(--#{$prefix}accordion-btn-active-icon);\\n      transform: var(--#{$prefix}accordion-btn-icon-transform);\\n    }\\n  }\\n\\n  // Accordion icon\\n  &::after {\\n    flex-shrink: 0;\\n    width: var(--#{$prefix}accordion-btn-icon-width);\\n    height: var(--#{$prefix}accordion-btn-icon-width);\\n    margin-left: auto;\\n    content: \\\"\\\";\\n    background-image: var(--#{$prefix}accordion-btn-icon);\\n    background-repeat: no-repeat;\\n    background-size: var(--#{$prefix}accordion-btn-icon-width);\\n    @include transition(var(--#{$prefix}accordion-btn-icon-transition));\\n  }\\n\\n  &:hover {\\n    z-index: 2;\\n  }\\n\\n  &:focus {\\n    z-index: 3;\\n    border-color: var(--#{$prefix}accordion-btn-focus-border-color);\\n    outline: 0;\\n    box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow);\\n  }\\n}\\n\\n.accordion-header {\\n  margin-bottom: 0;\\n}\\n\\n.accordion-item {\\n  color: var(--#{$prefix}accordion-color);\\n  background-color: var(--#{$prefix}accordion-bg);\\n  border: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color);\\n\\n  &:first-of-type {\\n    @include border-top-radius(var(--#{$prefix}accordion-border-radius));\\n\\n    .accordion-button {\\n      @include border-top-radius(var(--#{$prefix}accordion-inner-border-radius));\\n    }\\n  }\\n\\n  &:not(:first-of-type) {\\n    border-top: 0;\\n  }\\n\\n  // Only set a border-radius on the last item if the accordion is collapsed\\n  &:last-of-type {\\n    @include border-bottom-radius(var(--#{$prefix}accordion-border-radius));\\n\\n    .accordion-button {\\n      &.collapsed {\\n        @include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius));\\n      }\\n    }\\n\\n    .accordion-collapse {\\n      @include border-bottom-radius(var(--#{$prefix}accordion-border-radius));\\n    }\\n  }\\n}\\n\\n.accordion-body {\\n  padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x);\\n}\\n\\n\\n// Flush accordion items\\n//\\n// Remove borders and border-radius to keep accordion items edge-to-edge.\\n\\n.accordion-flush {\\n  .accordion-collapse {\\n    border-width: 0;\\n  }\\n\\n  .accordion-item {\\n    border-right: 0;\\n    border-left: 0;\\n    @include border-radius(0);\\n\\n    &:first-child { border-top: 0; }\\n    &:last-child { border-bottom: 0; }\\n\\n    .accordion-button {\\n      &,\\n      &.collapsed {\\n        @include border-radius(0);\\n      }\\n    }\\n  }\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .accordion-button::after {\\n      --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)};\\n      --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon-dark)};\\n    }\\n  }\\n}\\n\",\".breadcrumb {\\n  // scss-docs-start breadcrumb-css-vars\\n  --#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x};\\n  --#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y};\\n  --#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom};\\n  @include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size);\\n  --#{$prefix}breadcrumb-bg: #{$breadcrumb-bg};\\n  --#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius};\\n  --#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color};\\n  --#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x};\\n  --#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color};\\n  // scss-docs-end breadcrumb-css-vars\\n\\n  display: flex;\\n  flex-wrap: wrap;\\n  padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x);\\n  margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom);\\n  @include font-size(var(--#{$prefix}breadcrumb-font-size));\\n  list-style: none;\\n  background-color: var(--#{$prefix}breadcrumb-bg);\\n  @include border-radius(var(--#{$prefix}breadcrumb-border-radius));\\n}\\n\\n.breadcrumb-item {\\n  // The separator between breadcrumbs (by default, a forward-slash: \\\"/\\\")\\n  + .breadcrumb-item {\\n    padding-left: var(--#{$prefix}breadcrumb-item-padding-x);\\n\\n    &::before {\\n      float: left; // Suppress inline spacings and underlining of the separator\\n      padding-right: var(--#{$prefix}breadcrumb-item-padding-x);\\n      color: var(--#{$prefix}breadcrumb-divider-color);\\n      content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{\\\"/* rtl:\\\"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{\\\"*/\\\"};\\n    }\\n  }\\n\\n  &.active {\\n    color: var(--#{$prefix}breadcrumb-item-active-color);\\n  }\\n}\\n\",\".pagination {\\n  // scss-docs-start pagination-css-vars\\n  --#{$prefix}pagination-padding-x: #{$pagination-padding-x};\\n  --#{$prefix}pagination-padding-y: #{$pagination-padding-y};\\n  @include rfs($pagination-font-size, --#{$prefix}pagination-font-size);\\n  --#{$prefix}pagination-color: #{$pagination-color};\\n  --#{$prefix}pagination-bg: #{$pagination-bg};\\n  --#{$prefix}pagination-border-width: #{$pagination-border-width};\\n  --#{$prefix}pagination-border-color: #{$pagination-border-color};\\n  --#{$prefix}pagination-border-radius: #{$pagination-border-radius};\\n  --#{$prefix}pagination-hover-color: #{$pagination-hover-color};\\n  --#{$prefix}pagination-hover-bg: #{$pagination-hover-bg};\\n  --#{$prefix}pagination-hover-border-color: #{$pagination-hover-border-color};\\n  --#{$prefix}pagination-focus-color: #{$pagination-focus-color};\\n  --#{$prefix}pagination-focus-bg: #{$pagination-focus-bg};\\n  --#{$prefix}pagination-focus-box-shadow: #{$pagination-focus-box-shadow};\\n  --#{$prefix}pagination-active-color: #{$pagination-active-color};\\n  --#{$prefix}pagination-active-bg: #{$pagination-active-bg};\\n  --#{$prefix}pagination-active-border-color: #{$pagination-active-border-color};\\n  --#{$prefix}pagination-disabled-color: #{$pagination-disabled-color};\\n  --#{$prefix}pagination-disabled-bg: #{$pagination-disabled-bg};\\n  --#{$prefix}pagination-disabled-border-color: #{$pagination-disabled-border-color};\\n  // scss-docs-end pagination-css-vars\\n\\n  display: flex;\\n  @include list-unstyled();\\n}\\n\\n.page-link {\\n  position: relative;\\n  display: block;\\n  padding: var(--#{$prefix}pagination-padding-y) var(--#{$prefix}pagination-padding-x);\\n  @include font-size(var(--#{$prefix}pagination-font-size));\\n  color: var(--#{$prefix}pagination-color);\\n  text-decoration: if($link-decoration == none, null, none);\\n  background-color: var(--#{$prefix}pagination-bg);\\n  border: var(--#{$prefix}pagination-border-width) solid var(--#{$prefix}pagination-border-color);\\n  @include transition($pagination-transition);\\n\\n  &:hover {\\n    z-index: 2;\\n    color: var(--#{$prefix}pagination-hover-color);\\n    text-decoration: if($link-hover-decoration == underline, none, null);\\n    background-color: var(--#{$prefix}pagination-hover-bg);\\n    border-color: var(--#{$prefix}pagination-hover-border-color);\\n  }\\n\\n  &:focus {\\n    z-index: 3;\\n    color: var(--#{$prefix}pagination-focus-color);\\n    background-color: var(--#{$prefix}pagination-focus-bg);\\n    outline: $pagination-focus-outline;\\n    box-shadow: var(--#{$prefix}pagination-focus-box-shadow);\\n  }\\n\\n  &.active,\\n  .active > & {\\n    z-index: 3;\\n    color: var(--#{$prefix}pagination-active-color);\\n    @include gradient-bg(var(--#{$prefix}pagination-active-bg));\\n    border-color: var(--#{$prefix}pagination-active-border-color);\\n  }\\n\\n  &.disabled,\\n  .disabled > & {\\n    color: var(--#{$prefix}pagination-disabled-color);\\n    pointer-events: none;\\n    background-color: var(--#{$prefix}pagination-disabled-bg);\\n    border-color: var(--#{$prefix}pagination-disabled-border-color);\\n  }\\n}\\n\\n.page-item {\\n  &:not(:first-child) .page-link {\\n    margin-left: $pagination-margin-start;\\n  }\\n\\n  @if $pagination-margin-start == calc($pagination-border-width * -1) {\\n    &:first-child {\\n      .page-link {\\n        @include border-start-radius(var(--#{$prefix}pagination-border-radius));\\n      }\\n    }\\n\\n    &:last-child {\\n      .page-link {\\n        @include border-end-radius(var(--#{$prefix}pagination-border-radius));\\n      }\\n    }\\n  } @else {\\n    // Add border-radius to all pageLinks in case they have left margin\\n    .page-link {\\n      @include border-radius(var(--#{$prefix}pagination-border-radius));\\n    }\\n  }\\n}\\n\\n\\n//\\n// Sizing\\n//\\n\\n.pagination-lg {\\n  @include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg);\\n}\\n\\n.pagination-sm {\\n  @include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm);\\n}\\n\",\"// Pagination\\n\\n// scss-docs-start pagination-mixin\\n@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) {\\n  --#{$prefix}pagination-padding-x: #{$padding-x};\\n  --#{$prefix}pagination-padding-y: #{$padding-y};\\n  @include rfs($font-size, --#{$prefix}pagination-font-size);\\n  --#{$prefix}pagination-border-radius: #{$border-radius};\\n}\\n// scss-docs-end pagination-mixin\\n\",\"// Base class\\n//\\n// Requires one of the contextual, color modifier classes for `color` and\\n// `background-color`.\\n\\n.badge {\\n  // scss-docs-start badge-css-vars\\n  --#{$prefix}badge-padding-x: #{$badge-padding-x};\\n  --#{$prefix}badge-padding-y: #{$badge-padding-y};\\n  @include rfs($badge-font-size, --#{$prefix}badge-font-size);\\n  --#{$prefix}badge-font-weight: #{$badge-font-weight};\\n  --#{$prefix}badge-color: #{$badge-color};\\n  --#{$prefix}badge-border-radius: #{$badge-border-radius};\\n  // scss-docs-end badge-css-vars\\n\\n  display: inline-block;\\n  padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x);\\n  @include font-size(var(--#{$prefix}badge-font-size));\\n  font-weight: var(--#{$prefix}badge-font-weight);\\n  line-height: 1;\\n  color: var(--#{$prefix}badge-color);\\n  text-align: center;\\n  white-space: nowrap;\\n  vertical-align: baseline;\\n  @include border-radius(var(--#{$prefix}badge-border-radius));\\n  @include gradient-bg();\\n\\n  // Empty badges collapse automatically\\n  &:empty {\\n    display: none;\\n  }\\n}\\n\\n// Quick fix for badges in buttons\\n.btn .badge {\\n  position: relative;\\n  top: -1px;\\n}\\n\",\"//\\n// Base styles\\n//\\n\\n.alert {\\n  // scss-docs-start alert-css-vars\\n  --#{$prefix}alert-bg: transparent;\\n  --#{$prefix}alert-padding-x: #{$alert-padding-x};\\n  --#{$prefix}alert-padding-y: #{$alert-padding-y};\\n  --#{$prefix}alert-margin-bottom: #{$alert-margin-bottom};\\n  --#{$prefix}alert-color: inherit;\\n  --#{$prefix}alert-border-color: transparent;\\n  --#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color);\\n  --#{$prefix}alert-border-radius: #{$alert-border-radius};\\n  --#{$prefix}alert-link-color: inherit;\\n  // scss-docs-end alert-css-vars\\n\\n  position: relative;\\n  padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x);\\n  margin-bottom: var(--#{$prefix}alert-margin-bottom);\\n  color: var(--#{$prefix}alert-color);\\n  background-color: var(--#{$prefix}alert-bg);\\n  border: var(--#{$prefix}alert-border);\\n  @include border-radius(var(--#{$prefix}alert-border-radius));\\n}\\n\\n// Headings for larger alerts\\n.alert-heading {\\n  // Specified to prevent conflicts of changing $headings-color\\n  color: inherit;\\n}\\n\\n// Provide class for links that match alerts\\n.alert-link {\\n  font-weight: $alert-link-font-weight;\\n  color: var(--#{$prefix}alert-link-color);\\n}\\n\\n\\n// Dismissible alerts\\n//\\n// Expand the right padding and account for the close button's positioning.\\n\\n.alert-dismissible {\\n  padding-right: $alert-dismissible-padding-r;\\n\\n  // Adjust close link position\\n  .btn-close {\\n    position: absolute;\\n    top: 0;\\n    right: 0;\\n    z-index: $stretched-link-z-index + 1;\\n    padding: $alert-padding-y * 1.25 $alert-padding-x;\\n  }\\n}\\n\\n\\n// scss-docs-start alert-modifiers\\n// Generate contextual modifier classes for colorizing the alert\\n@each $state in map-keys($theme-colors) {\\n  .alert-#{$state} {\\n    --#{$prefix}alert-color: var(--#{$prefix}#{$state}-text);\\n    --#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle);\\n    --#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle);\\n    --#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text);\\n  }\\n}\\n// scss-docs-end alert-modifiers\\n\",\"// Disable animation if transitions are disabled\\n\\n// scss-docs-start progress-keyframes\\n@if $enable-transitions {\\n  @keyframes progress-bar-stripes {\\n    0% { background-position-x: $progress-height; }\\n  }\\n}\\n// scss-docs-end progress-keyframes\\n\\n.progress,\\n.progress-stacked {\\n  // scss-docs-start progress-css-vars\\n  --#{$prefix}progress-height: #{$progress-height};\\n  @include rfs($progress-font-size, --#{$prefix}progress-font-size);\\n  --#{$prefix}progress-bg: #{$progress-bg};\\n  --#{$prefix}progress-border-radius: #{$progress-border-radius};\\n  --#{$prefix}progress-box-shadow: #{$progress-box-shadow};\\n  --#{$prefix}progress-bar-color: #{$progress-bar-color};\\n  --#{$prefix}progress-bar-bg: #{$progress-bar-bg};\\n  --#{$prefix}progress-bar-transition: #{$progress-bar-transition};\\n  // scss-docs-end progress-css-vars\\n\\n  display: flex;\\n  height: var(--#{$prefix}progress-height);\\n  overflow: hidden; // force rounded corners by cropping it\\n  @include font-size(var(--#{$prefix}progress-font-size));\\n  background-color: var(--#{$prefix}progress-bg);\\n  @include border-radius(var(--#{$prefix}progress-border-radius));\\n  @include box-shadow(var(--#{$prefix}progress-box-shadow));\\n}\\n\\n.progress-bar {\\n  display: flex;\\n  flex-direction: column;\\n  justify-content: center;\\n  overflow: hidden;\\n  color: var(--#{$prefix}progress-bar-color);\\n  text-align: center;\\n  white-space: nowrap;\\n  background-color: var(--#{$prefix}progress-bar-bg);\\n  @include transition(var(--#{$prefix}progress-bar-transition));\\n}\\n\\n.progress-bar-striped {\\n  @include gradient-striped();\\n  background-size: var(--#{$prefix}progress-height) var(--#{$prefix}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@if $enable-transitions {\\n  .progress-bar-animated {\\n    animation: $progress-bar-animation-timing progress-bar-stripes;\\n\\n    @if $enable-reduced-motion {\\n      @media (prefers-reduced-motion: reduce) {\\n        animation: none;\\n      }\\n    }\\n  }\\n}\\n\",\"// Base class\\n//\\n// Easily usable on <ul>, <ol>, or <div>.\\n\\n.list-group {\\n  // scss-docs-start list-group-css-vars\\n  --#{$prefix}list-group-color: #{$list-group-color};\\n  --#{$prefix}list-group-bg: #{$list-group-bg};\\n  --#{$prefix}list-group-border-color: #{$list-group-border-color};\\n  --#{$prefix}list-group-border-width: #{$list-group-border-width};\\n  --#{$prefix}list-group-border-radius: #{$list-group-border-radius};\\n  --#{$prefix}list-group-item-padding-x: #{$list-group-item-padding-x};\\n  --#{$prefix}list-group-item-padding-y: #{$list-group-item-padding-y};\\n  --#{$prefix}list-group-action-color: #{$list-group-action-color};\\n  --#{$prefix}list-group-action-hover-color: #{$list-group-action-hover-color};\\n  --#{$prefix}list-group-action-hover-bg: #{$list-group-hover-bg};\\n  --#{$prefix}list-group-action-active-color: #{$list-group-action-active-color};\\n  --#{$prefix}list-group-action-active-bg: #{$list-group-action-active-bg};\\n  --#{$prefix}list-group-disabled-color: #{$list-group-disabled-color};\\n  --#{$prefix}list-group-disabled-bg: #{$list-group-disabled-bg};\\n  --#{$prefix}list-group-active-color: #{$list-group-active-color};\\n  --#{$prefix}list-group-active-bg: #{$list-group-active-bg};\\n  --#{$prefix}list-group-active-border-color: #{$list-group-active-border-color};\\n  // scss-docs-end list-group-css-vars\\n\\n  display: flex;\\n  flex-direction: column;\\n\\n  // No need to set list-style: none; since .list-group-item is block level\\n  padding-left: 0; // reset padding because ul and ol\\n  margin-bottom: 0;\\n  @include border-radius(var(--#{$prefix}list-group-border-radius));\\n}\\n\\n.list-group-numbered {\\n  list-style-type: none;\\n  counter-reset: section;\\n\\n  > .list-group-item::before {\\n    // Increments only this instance of the section counter\\n    content: counters(section, \\\".\\\") \\\". \\\";\\n    counter-increment: section;\\n  }\\n}\\n\\n// Interactive list items\\n//\\n// Use anchor or button elements instead of `li`s or `div`s to create interactive\\n// list items. Includes an extra `.active` modifier class for selected items.\\n\\n.list-group-item-action {\\n  width: 100%; // For `<button>`s (anchors become 100% by default though)\\n  color: var(--#{$prefix}list-group-action-color);\\n  text-align: inherit; // For `<button>`s (anchors inherit)\\n\\n  // Hover state\\n  &:hover,\\n  &:focus {\\n    z-index: 1; // Place hover/focus items above their siblings for proper border styling\\n    color: var(--#{$prefix}list-group-action-hover-color);\\n    text-decoration: none;\\n    background-color: var(--#{$prefix}list-group-action-hover-bg);\\n  }\\n\\n  &:active {\\n    color: var(--#{$prefix}list-group-action-active-color);\\n    background-color: var(--#{$prefix}list-group-action-active-bg);\\n  }\\n}\\n\\n// Individual list items\\n//\\n// Use on `li`s or `div`s within the `.list-group` parent.\\n\\n.list-group-item {\\n  position: relative;\\n  display: block;\\n  padding: var(--#{$prefix}list-group-item-padding-y) var(--#{$prefix}list-group-item-padding-x);\\n  color: var(--#{$prefix}list-group-color);\\n  text-decoration: if($link-decoration == none, null, none);\\n  background-color: var(--#{$prefix}list-group-bg);\\n  border: var(--#{$prefix}list-group-border-width) solid var(--#{$prefix}list-group-border-color);\\n\\n  &:first-child {\\n    @include border-top-radius(inherit);\\n  }\\n\\n  &:last-child {\\n    @include border-bottom-radius(inherit);\\n  }\\n\\n  &.disabled,\\n  &:disabled {\\n    color: var(--#{$prefix}list-group-disabled-color);\\n    pointer-events: none;\\n    background-color: var(--#{$prefix}list-group-disabled-bg);\\n  }\\n\\n  // Include both here for `<a>`s and `<button>`s\\n  &.active {\\n    z-index: 2; // Place active items above their siblings for proper border styling\\n    color: var(--#{$prefix}list-group-active-color);\\n    background-color: var(--#{$prefix}list-group-active-bg);\\n    border-color: var(--#{$prefix}list-group-active-border-color);\\n  }\\n\\n  // stylelint-disable-next-line scss/selector-no-redundant-nesting-selector\\n  & + .list-group-item {\\n    border-top-width: 0;\\n\\n    &.active {\\n      margin-top: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list\\n      border-top-width: var(--#{$prefix}list-group-border-width);\\n    }\\n  }\\n}\\n\\n// Horizontal\\n//\\n// Change the layout of list group items from vertical (default) to horizontal.\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  @include media-breakpoint-up($breakpoint) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    .list-group-horizontal#{$infix} {\\n      flex-direction: row;\\n\\n      > .list-group-item {\\n        &:first-child:not(:last-child) {\\n          @include border-bottom-start-radius(var(--#{$prefix}list-group-border-radius));\\n          @include border-top-end-radius(0);\\n        }\\n\\n        &:last-child:not(:first-child) {\\n          @include border-top-end-radius(var(--#{$prefix}list-group-border-radius));\\n          @include border-bottom-start-radius(0);\\n        }\\n\\n        &.active {\\n          margin-top: 0;\\n        }\\n\\n        + .list-group-item {\\n          border-top-width: var(--#{$prefix}list-group-border-width);\\n          border-left-width: 0;\\n\\n          &.active {\\n            margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list\\n            border-left-width: var(--#{$prefix}list-group-border-width);\\n          }\\n        }\\n      }\\n    }\\n  }\\n}\\n\\n\\n// Flush list items\\n//\\n// Remove borders and border-radius to keep list group items edge-to-edge. Most\\n// useful within other components (e.g., cards).\\n\\n.list-group-flush {\\n  @include border-radius(0);\\n\\n  > .list-group-item {\\n    border-width: 0 0 var(--#{$prefix}list-group-border-width);\\n\\n    &:last-child {\\n      border-bottom-width: 0;\\n    }\\n  }\\n}\\n\\n\\n// scss-docs-start list-group-modifiers\\n// List group contextual variants\\n//\\n// Add modifier classes to change text and background color on individual items.\\n// Organizationally, this must come after the `:hover` states.\\n\\n@each $state in map-keys($theme-colors) {\\n  .list-group-item-#{$state} {\\n    --#{$prefix}list-group-color: var(--#{$prefix}#{$state}-text);\\n    --#{$prefix}list-group-bg: var(--#{$prefix}#{$state}-bg-subtle);\\n    --#{$prefix}list-group-border-color: var(--#{$prefix}#{$state}-border-subtle);\\n\\n    &.list-group-item-action {\\n      &:hover,\\n      &:focus {\\n        --#{$prefix}list-group-action-hover-color: var(--#{$prefix}emphasis-color);\\n        --#{$prefix}list-group-action-hover-bg: var(--#{$prefix}#{$state}-border-subtle);\\n      }\\n\\n      &:active {\\n        --#{$prefix}list-group-active-color: var(--#{$prefix}emphasis-color);\\n        --#{$prefix}list-group-active-bg: var(--#{$prefix}#{$state}-text);\\n        --#{$prefix}list-group-active-border-color: var(--#{$prefix}#{$state}-text);\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end list-group-modifiers\\n\",\"// Transparent background and border properties included for button version.\\n// iOS requires the button element instead of an anchor tag.\\n// If you want the anchor version, it requires `href=\\\"#\\\"`.\\n// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\\n\\n.btn-close {\\n  --#{$prefix}btn-close-color: #{$btn-close-color};\\n  --#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) };\\n  --#{$prefix}btn-close-opacity: #{$btn-close-opacity};\\n  --#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity};\\n  --#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow};\\n  --#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity};\\n  --#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity};\\n  --#{$prefix}btn-close-white-filter: #{$btn-close-white-filter};\\n\\n  box-sizing: content-box;\\n  width: $btn-close-width;\\n  height: $btn-close-height;\\n  padding: $btn-close-padding-y $btn-close-padding-x;\\n  color: var(--#{$prefix}btn-close-color);\\n  background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements\\n  border: 0; // for button elements\\n  @include border-radius();\\n  opacity: var(--#{$prefix}btn-close-opacity);\\n\\n  // Override <a>'s hover style\\n  &:hover {\\n    color: var(--#{$prefix}btn-close-color);\\n    text-decoration: none;\\n    opacity: var(--#{$prefix}btn-close-hover-opacity);\\n  }\\n\\n  &:focus {\\n    outline: 0;\\n    box-shadow: var(--#{$prefix}btn-close-focus-shadow);\\n    opacity: var(--#{$prefix}btn-close-focus-opacity);\\n  }\\n\\n  &:disabled,\\n  &.disabled {\\n    pointer-events: none;\\n    user-select: none;\\n    opacity: var(--#{$prefix}btn-close-disabled-opacity);\\n  }\\n}\\n\\n@mixin btn-close-white() {\\n  filter: var(--#{$prefix}btn-close-white-filter);\\n}\\n\\n.btn-close-white {\\n  @include btn-close-white();\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .btn-close {\\n      @include btn-close-white();\\n    }\\n  }\\n}\\n\",\".toast {\\n  // scss-docs-start toast-css-vars\\n  --#{$prefix}toast-zindex: #{$zindex-toast};\\n  --#{$prefix}toast-padding-x: #{$toast-padding-x};\\n  --#{$prefix}toast-padding-y: #{$toast-padding-y};\\n  --#{$prefix}toast-spacing: #{$toast-spacing};\\n  --#{$prefix}toast-max-width: #{$toast-max-width};\\n  @include rfs($toast-font-size, --#{$prefix}toast-font-size);\\n  --#{$prefix}toast-color: #{$toast-color};\\n  --#{$prefix}toast-bg: #{$toast-background-color};\\n  --#{$prefix}toast-border-width: #{$toast-border-width};\\n  --#{$prefix}toast-border-color: #{$toast-border-color};\\n  --#{$prefix}toast-border-radius: #{$toast-border-radius};\\n  --#{$prefix}toast-box-shadow: #{$toast-box-shadow};\\n  --#{$prefix}toast-header-color: #{$toast-header-color};\\n  --#{$prefix}toast-header-bg: #{$toast-header-background-color};\\n  --#{$prefix}toast-header-border-color: #{$toast-header-border-color};\\n  // scss-docs-end toast-css-vars\\n\\n  width: var(--#{$prefix}toast-max-width);\\n  max-width: 100%;\\n  @include font-size(var(--#{$prefix}toast-font-size));\\n  color: var(--#{$prefix}toast-color);\\n  pointer-events: auto;\\n  background-color: var(--#{$prefix}toast-bg);\\n  background-clip: padding-box;\\n  border: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-border-color);\\n  box-shadow: var(--#{$prefix}toast-box-shadow);\\n  @include border-radius(var(--#{$prefix}toast-border-radius));\\n\\n  &.showing {\\n    opacity: 0;\\n  }\\n\\n  &:not(.show) {\\n    display: none;\\n  }\\n}\\n\\n.toast-container {\\n  --#{$prefix}toast-zindex: #{$zindex-toast};\\n\\n  position: absolute;\\n  z-index: var(--#{$prefix}toast-zindex);\\n  width: max-content;\\n  max-width: 100%;\\n  pointer-events: none;\\n\\n  > :not(:last-child) {\\n    margin-bottom: var(--#{$prefix}toast-spacing);\\n  }\\n}\\n\\n.toast-header {\\n  display: flex;\\n  align-items: center;\\n  padding: var(--#{$prefix}toast-padding-y) var(--#{$prefix}toast-padding-x);\\n  color: var(--#{$prefix}toast-header-color);\\n  background-color: var(--#{$prefix}toast-header-bg);\\n  background-clip: padding-box;\\n  border-bottom: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-header-border-color);\\n  @include border-top-radius(calc(var(--#{$prefix}toast-border-radius) - var(--#{$prefix}toast-border-width)));\\n\\n  .btn-close {\\n    margin-right: calc(-.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list\\n    margin-left: var(--#{$prefix}toast-padding-x);\\n  }\\n}\\n\\n.toast-body {\\n  padding: var(--#{$prefix}toast-padding-x);\\n  word-wrap: break-word;\\n}\\n\",\"// stylelint-disable function-disallowed-list\\n\\n// .modal-open      - body class for killing the scroll\\n// .modal           - container to scroll within\\n// .modal-dialog    - positioning shell for the actual modal\\n// .modal-content   - actual modal w/ bg and corners and stuff\\n\\n\\n// Container that the modal scrolls within\\n.modal {\\n  // scss-docs-start modal-css-vars\\n  --#{$prefix}modal-zindex: #{$zindex-modal};\\n  --#{$prefix}modal-width: #{$modal-md};\\n  --#{$prefix}modal-padding: #{$modal-inner-padding};\\n  --#{$prefix}modal-margin: #{$modal-dialog-margin};\\n  --#{$prefix}modal-color: #{$modal-content-color};\\n  --#{$prefix}modal-bg: #{$modal-content-bg};\\n  --#{$prefix}modal-border-color: #{$modal-content-border-color};\\n  --#{$prefix}modal-border-width: #{$modal-content-border-width};\\n  --#{$prefix}modal-border-radius: #{$modal-content-border-radius};\\n  --#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-xs};\\n  --#{$prefix}modal-inner-border-radius: #{$modal-content-inner-border-radius};\\n  --#{$prefix}modal-header-padding-x: #{$modal-header-padding-x};\\n  --#{$prefix}modal-header-padding-y: #{$modal-header-padding-y};\\n  --#{$prefix}modal-header-padding: #{$modal-header-padding}; // Todo in v6: Split this padding into x and y\\n  --#{$prefix}modal-header-border-color: #{$modal-header-border-color};\\n  --#{$prefix}modal-header-border-width: #{$modal-header-border-width};\\n  --#{$prefix}modal-title-line-height: #{$modal-title-line-height};\\n  --#{$prefix}modal-footer-gap: #{$modal-footer-margin-between};\\n  --#{$prefix}modal-footer-bg: #{$modal-footer-bg};\\n  --#{$prefix}modal-footer-border-color: #{$modal-footer-border-color};\\n  --#{$prefix}modal-footer-border-width: #{$modal-footer-border-width};\\n  // scss-docs-end modal-css-vars\\n\\n  position: fixed;\\n  top: 0;\\n  left: 0;\\n  z-index: var(--#{$prefix}modal-zindex);\\n  display: none;\\n  width: 100%;\\n  height: 100%;\\n  overflow-x: hidden;\\n  overflow-y: auto;\\n  // Prevent Chrome on Windows from adding a focus outline. For details, see\\n  // https://github.com/twbs/bootstrap/pull/10951.\\n  outline: 0;\\n  // We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a\\n  // gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342\\n  // See also https://github.com/twbs/bootstrap/issues/17695\\n}\\n\\n// Shell div to position the modal with bottom padding\\n.modal-dialog {\\n  position: relative;\\n  width: auto;\\n  margin: var(--#{$prefix}modal-margin);\\n  // allow clicks to pass through for custom click handling to close modal\\n  pointer-events: none;\\n\\n  // When fading in the modal, animate it to slide down\\n  .modal.fade & {\\n    @include transition($modal-transition);\\n    transform: $modal-fade-transform;\\n  }\\n  .modal.show & {\\n    transform: $modal-show-transform;\\n  }\\n\\n  // When trying to close, animate focus to scale\\n  .modal.modal-static & {\\n    transform: $modal-scale-transform;\\n  }\\n}\\n\\n.modal-dialog-scrollable {\\n  height: calc(100% - var(--#{$prefix}modal-margin) * 2);\\n\\n  .modal-content {\\n    max-height: 100%;\\n    overflow: hidden;\\n  }\\n\\n  .modal-body {\\n    overflow-y: auto;\\n  }\\n}\\n\\n.modal-dialog-centered {\\n  display: flex;\\n  align-items: center;\\n  min-height: calc(100% - var(--#{$prefix}modal-margin) * 2);\\n}\\n\\n// Actual modal\\n.modal-content {\\n  position: relative;\\n  display: flex;\\n  flex-direction: column;\\n  width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog`\\n  // counteract the pointer-events: none; in the .modal-dialog\\n  color: var(--#{$prefix}modal-color);\\n  pointer-events: auto;\\n  background-color: var(--#{$prefix}modal-bg);\\n  background-clip: padding-box;\\n  border: var(--#{$prefix}modal-border-width) solid var(--#{$prefix}modal-border-color);\\n  @include border-radius(var(--#{$prefix}modal-border-radius));\\n  @include box-shadow(var(--#{$prefix}modal-box-shadow));\\n  // Remove focus outline from opened modal\\n  outline: 0;\\n}\\n\\n// Modal background\\n.modal-backdrop {\\n  // scss-docs-start modal-backdrop-css-vars\\n  --#{$prefix}backdrop-zindex: #{$zindex-modal-backdrop};\\n  --#{$prefix}backdrop-bg: #{$modal-backdrop-bg};\\n  --#{$prefix}backdrop-opacity: #{$modal-backdrop-opacity};\\n  // scss-docs-end modal-backdrop-css-vars\\n\\n  @include overlay-backdrop(var(--#{$prefix}backdrop-zindex), var(--#{$prefix}backdrop-bg), var(--#{$prefix}backdrop-opacity));\\n}\\n\\n// Modal header\\n// Top section of the modal w/ title and dismiss\\n.modal-header {\\n  display: flex;\\n  flex-shrink: 0;\\n  align-items: center;\\n  justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends\\n  padding: var(--#{$prefix}modal-header-padding);\\n  border-bottom: var(--#{$prefix}modal-header-border-width) solid var(--#{$prefix}modal-header-border-color);\\n  @include border-top-radius(var(--#{$prefix}modal-inner-border-radius));\\n\\n  .btn-close {\\n    padding: calc(var(--#{$prefix}modal-header-padding-y) * .5) calc(var(--#{$prefix}modal-header-padding-x) * .5);\\n    margin: calc(-.5 * var(--#{$prefix}modal-header-padding-y)) calc(-.5 * var(--#{$prefix}modal-header-padding-x)) calc(-.5 * var(--#{$prefix}modal-header-padding-y)) auto;\\n  }\\n}\\n\\n// Title text within header\\n.modal-title {\\n  margin-bottom: 0;\\n  line-height: var(--#{$prefix}modal-title-line-height);\\n}\\n\\n// Modal body\\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\\n.modal-body {\\n  position: relative;\\n  // Enable `flex-grow: 1` so that the body take up as much space as possible\\n  // when there should be a fixed height on `.modal-dialog`.\\n  flex: 1 1 auto;\\n  padding: var(--#{$prefix}modal-padding);\\n}\\n\\n// Footer (for actions)\\n.modal-footer {\\n  display: flex;\\n  flex-shrink: 0;\\n  flex-wrap: wrap;\\n  align-items: center; // vertically center\\n  justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items\\n  padding: calc(var(--#{$prefix}modal-padding) - var(--#{$prefix}modal-footer-gap) * .5);\\n  background-color: var(--#{$prefix}modal-footer-bg);\\n  border-top: var(--#{$prefix}modal-footer-border-width) solid var(--#{$prefix}modal-footer-border-color);\\n  @include border-bottom-radius(var(--#{$prefix}modal-inner-border-radius));\\n\\n  // Place margin between footer elements\\n  // This solution is far from ideal because of the universal selector usage,\\n  // but is needed to fix https://github.com/twbs/bootstrap/issues/24800\\n  > * {\\n    margin: calc(var(--#{$prefix}modal-footer-gap) * .5); // Todo in v6: replace with gap on parent class\\n  }\\n}\\n\\n// Scale up the modal\\n@include media-breakpoint-up(sm) {\\n  .modal {\\n    --#{$prefix}modal-margin: #{$modal-dialog-margin-y-sm-up};\\n    --#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-sm-up};\\n  }\\n\\n  // Automatically set modal's width for larger viewports\\n  .modal-dialog {\\n    max-width: var(--#{$prefix}modal-width);\\n    margin-right: auto;\\n    margin-left: auto;\\n  }\\n\\n  .modal-sm {\\n    --#{$prefix}modal-width: #{$modal-sm};\\n  }\\n}\\n\\n@include media-breakpoint-up(lg) {\\n  .modal-lg,\\n  .modal-xl {\\n    --#{$prefix}modal-width: #{$modal-lg};\\n  }\\n}\\n\\n@include media-breakpoint-up(xl) {\\n  .modal-xl {\\n    --#{$prefix}modal-width: #{$modal-xl};\\n  }\\n}\\n\\n// scss-docs-start modal-fullscreen-loop\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n  $postfix: if($infix != \\\"\\\", $infix + \\\"-down\\\", \\\"\\\");\\n\\n  @include media-breakpoint-down($breakpoint) {\\n    .modal-fullscreen#{$postfix} {\\n      width: 100vw;\\n      max-width: none;\\n      height: 100%;\\n      margin: 0;\\n\\n      .modal-content {\\n        height: 100%;\\n        border: 0;\\n        @include border-radius(0);\\n      }\\n\\n      .modal-header,\\n      .modal-footer {\\n        @include border-radius(0);\\n      }\\n\\n      .modal-body {\\n        overflow-y: auto;\\n      }\\n    }\\n  }\\n}\\n// scss-docs-end modal-fullscreen-loop\\n\",\"// Shared between modals and offcanvases\\n@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) {\\n  position: fixed;\\n  top: 0;\\n  left: 0;\\n  z-index: $zindex;\\n  width: 100vw;\\n  height: 100vh;\\n  background-color: $backdrop-bg;\\n\\n  // Fade for backdrop\\n  &.fade { opacity: 0; }\\n  &.show { opacity: $backdrop-opacity; }\\n}\\n\",\"// Base class\\n.tooltip {\\n  // scss-docs-start tooltip-css-vars\\n  --#{$prefix}tooltip-zindex: #{$zindex-tooltip};\\n  --#{$prefix}tooltip-max-width: #{$tooltip-max-width};\\n  --#{$prefix}tooltip-padding-x: #{$tooltip-padding-x};\\n  --#{$prefix}tooltip-padding-y: #{$tooltip-padding-y};\\n  --#{$prefix}tooltip-margin: #{$tooltip-margin};\\n  @include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size);\\n  --#{$prefix}tooltip-color: #{$tooltip-color};\\n  --#{$prefix}tooltip-bg: #{$tooltip-bg};\\n  --#{$prefix}tooltip-border-radius: #{$tooltip-border-radius};\\n  --#{$prefix}tooltip-opacity: #{$tooltip-opacity};\\n  --#{$prefix}tooltip-arrow-width: #{$tooltip-arrow-width};\\n  --#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height};\\n  // scss-docs-end tooltip-css-vars\\n\\n  z-index: var(--#{$prefix}tooltip-zindex);\\n  display: block;\\n  padding: var(--#{$prefix}tooltip-arrow-height);\\n  margin: var(--#{$prefix}tooltip-margin);\\n  @include deprecate(\\\"`$tooltip-margin`\\\", \\\"v5\\\", \\\"v5.x\\\", true);\\n  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\\n  // So reset our font and text properties to avoid inheriting weird values.\\n  @include reset-text();\\n  @include font-size(var(--#{$prefix}tooltip-font-size));\\n  // Allow breaking very long words so they don't overflow the tooltip's bounds\\n  word-wrap: break-word;\\n  opacity: 0;\\n\\n  &.show { opacity: var(--#{$prefix}tooltip-opacity); }\\n\\n  .tooltip-arrow {\\n    display: block;\\n    width: var(--#{$prefix}tooltip-arrow-width);\\n    height: var(--#{$prefix}tooltip-arrow-height);\\n\\n    &::before {\\n      position: absolute;\\n      content: \\\"\\\";\\n      border-color: transparent;\\n      border-style: solid;\\n    }\\n  }\\n}\\n\\n.bs-tooltip-top .tooltip-arrow {\\n  bottom: 0;\\n\\n  &::before {\\n    top: -1px;\\n    border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list\\n    border-top-color: var(--#{$prefix}tooltip-bg);\\n  }\\n}\\n\\n/* rtl:begin:ignore */\\n.bs-tooltip-end .tooltip-arrow {\\n  left: 0;\\n  width: var(--#{$prefix}tooltip-arrow-height);\\n  height: var(--#{$prefix}tooltip-arrow-width);\\n\\n  &::before {\\n    right: -1px;\\n    border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list\\n    border-right-color: var(--#{$prefix}tooltip-bg);\\n  }\\n}\\n\\n/* rtl:end:ignore */\\n\\n.bs-tooltip-bottom .tooltip-arrow {\\n  top: 0;\\n\\n  &::before {\\n    bottom: -1px;\\n    border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list\\n    border-bottom-color: var(--#{$prefix}tooltip-bg);\\n  }\\n}\\n\\n/* rtl:begin:ignore */\\n.bs-tooltip-start .tooltip-arrow {\\n  right: 0;\\n  width: var(--#{$prefix}tooltip-arrow-height);\\n  height: var(--#{$prefix}tooltip-arrow-width);\\n\\n  &::before {\\n    left: -1px;\\n    border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list\\n    border-left-color: var(--#{$prefix}tooltip-bg);\\n  }\\n}\\n\\n/* rtl:end:ignore */\\n\\n.bs-tooltip-auto {\\n  &[data-popper-placement^=\\\"top\\\"] {\\n    @extend .bs-tooltip-top;\\n  }\\n  &[data-popper-placement^=\\\"right\\\"] {\\n    @extend .bs-tooltip-end;\\n  }\\n  &[data-popper-placement^=\\\"bottom\\\"] {\\n    @extend .bs-tooltip-bottom;\\n  }\\n  &[data-popper-placement^=\\\"left\\\"] {\\n    @extend .bs-tooltip-start;\\n  }\\n}\\n\\n// Wrapper for the tooltip content\\n.tooltip-inner {\\n  max-width: var(--#{$prefix}tooltip-max-width);\\n  padding: var(--#{$prefix}tooltip-padding-y) var(--#{$prefix}tooltip-padding-x);\\n  color: var(--#{$prefix}tooltip-color);\\n  text-align: center;\\n  background-color: var(--#{$prefix}tooltip-bg);\\n  @include border-radius(var(--#{$prefix}tooltip-border-radius));\\n}\\n\",\"@mixin reset-text {\\n  font-family: $font-family-base;\\n  // We deliberately do NOT reset font-size or overflow-wrap / word-wrap.\\n  font-style: normal;\\n  font-weight: $font-weight-normal;\\n  line-height: $line-height-base;\\n  text-align: left; // Fallback for where `start` is not supported\\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}\\n\",\".popover {\\n  // scss-docs-start popover-css-vars\\n  --#{$prefix}popover-zindex: #{$zindex-popover};\\n  --#{$prefix}popover-max-width: #{$popover-max-width};\\n  @include rfs($popover-font-size, --#{$prefix}popover-font-size);\\n  --#{$prefix}popover-bg: #{$popover-bg};\\n  --#{$prefix}popover-border-width: #{$popover-border-width};\\n  --#{$prefix}popover-border-color: #{$popover-border-color};\\n  --#{$prefix}popover-border-radius: #{$popover-border-radius};\\n  --#{$prefix}popover-inner-border-radius: #{$popover-inner-border-radius};\\n  --#{$prefix}popover-box-shadow: #{$popover-box-shadow};\\n  --#{$prefix}popover-header-padding-x: #{$popover-header-padding-x};\\n  --#{$prefix}popover-header-padding-y: #{$popover-header-padding-y};\\n  @include rfs($popover-header-font-size, --#{$prefix}popover-header-font-size);\\n  --#{$prefix}popover-header-color: #{$popover-header-color};\\n  --#{$prefix}popover-header-bg: #{$popover-header-bg};\\n  --#{$prefix}popover-body-padding-x: #{$popover-body-padding-x};\\n  --#{$prefix}popover-body-padding-y: #{$popover-body-padding-y};\\n  --#{$prefix}popover-body-color: #{$popover-body-color};\\n  --#{$prefix}popover-arrow-width: #{$popover-arrow-width};\\n  --#{$prefix}popover-arrow-height: #{$popover-arrow-height};\\n  --#{$prefix}popover-arrow-border: var(--#{$prefix}popover-border-color);\\n  // scss-docs-end popover-css-vars\\n\\n  z-index: var(--#{$prefix}popover-zindex);\\n  display: block;\\n  max-width: var(--#{$prefix}popover-max-width);\\n  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\\n  // So reset our font and text properties to avoid inheriting weird values.\\n  @include reset-text();\\n  @include font-size(var(--#{$prefix}popover-font-size));\\n  // Allow breaking very long words so they don't overflow the popover's bounds\\n  word-wrap: break-word;\\n  background-color: var(--#{$prefix}popover-bg);\\n  background-clip: padding-box;\\n  border: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);\\n  @include border-radius(var(--#{$prefix}popover-border-radius));\\n  @include box-shadow(var(--#{$prefix}popover-box-shadow));\\n\\n  .popover-arrow {\\n    display: block;\\n    width: var(--#{$prefix}popover-arrow-width);\\n    height: var(--#{$prefix}popover-arrow-height);\\n\\n    &::before,\\n    &::after {\\n      position: absolute;\\n      display: block;\\n      content: \\\"\\\";\\n      border-color: transparent;\\n      border-style: solid;\\n      border-width: 0;\\n    }\\n  }\\n}\\n\\n.bs-popover-top {\\n  > .popover-arrow {\\n    bottom: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list\\n\\n    &::before,\\n    &::after {\\n      border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list\\n    }\\n\\n    &::before {\\n      bottom: 0;\\n      border-top-color: var(--#{$prefix}popover-arrow-border);\\n    }\\n\\n    &::after {\\n      bottom: var(--#{$prefix}popover-border-width);\\n      border-top-color: var(--#{$prefix}popover-bg);\\n    }\\n  }\\n}\\n\\n/* rtl:begin:ignore */\\n.bs-popover-end {\\n  > .popover-arrow {\\n    left: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list\\n    width: var(--#{$prefix}popover-arrow-height);\\n    height: var(--#{$prefix}popover-arrow-width);\\n\\n    &::before,\\n    &::after {\\n      border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list\\n    }\\n\\n    &::before {\\n      left: 0;\\n      border-right-color: var(--#{$prefix}popover-arrow-border);\\n    }\\n\\n    &::after {\\n      left: var(--#{$prefix}popover-border-width);\\n      border-right-color: var(--#{$prefix}popover-bg);\\n    }\\n  }\\n}\\n\\n/* rtl:end:ignore */\\n\\n.bs-popover-bottom {\\n  > .popover-arrow {\\n    top: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list\\n\\n    &::before,\\n    &::after {\\n      border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list\\n    }\\n\\n    &::before {\\n      top: 0;\\n      border-bottom-color: var(--#{$prefix}popover-arrow-border);\\n    }\\n\\n    &::after {\\n      top: var(--#{$prefix}popover-border-width);\\n      border-bottom-color: var(--#{$prefix}popover-bg);\\n    }\\n  }\\n\\n  // This will remove the popover-header's border just below the arrow\\n  .popover-header::before {\\n    position: absolute;\\n    top: 0;\\n    left: 50%;\\n    display: block;\\n    width: var(--#{$prefix}popover-arrow-width);\\n    margin-left: calc(-.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list\\n    content: \\\"\\\";\\n    border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg);\\n  }\\n}\\n\\n/* rtl:begin:ignore */\\n.bs-popover-start {\\n  > .popover-arrow {\\n    right: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list\\n    width: var(--#{$prefix}popover-arrow-height);\\n    height: var(--#{$prefix}popover-arrow-width);\\n\\n    &::before,\\n    &::after {\\n      border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list\\n    }\\n\\n    &::before {\\n      right: 0;\\n      border-left-color: var(--#{$prefix}popover-arrow-border);\\n    }\\n\\n    &::after {\\n      right: var(--#{$prefix}popover-border-width);\\n      border-left-color: var(--#{$prefix}popover-bg);\\n    }\\n  }\\n}\\n\\n/* rtl:end:ignore */\\n\\n.bs-popover-auto {\\n  &[data-popper-placement^=\\\"top\\\"] {\\n    @extend .bs-popover-top;\\n  }\\n  &[data-popper-placement^=\\\"right\\\"] {\\n    @extend .bs-popover-end;\\n  }\\n  &[data-popper-placement^=\\\"bottom\\\"] {\\n    @extend .bs-popover-bottom;\\n  }\\n  &[data-popper-placement^=\\\"left\\\"] {\\n    @extend .bs-popover-start;\\n  }\\n}\\n\\n// Offset the popover to account for the popover arrow\\n.popover-header {\\n  padding: var(--#{$prefix}popover-header-padding-y) var(--#{$prefix}popover-header-padding-x);\\n  margin-bottom: 0; // Reset the default from Reboot\\n  @include font-size(var(--#{$prefix}popover-header-font-size));\\n  color: var(--#{$prefix}popover-header-color);\\n  background-color: var(--#{$prefix}popover-header-bg);\\n  border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);\\n  @include border-top-radius(var(--#{$prefix}popover-inner-border-radius));\\n\\n  &:empty {\\n    display: none;\\n  }\\n}\\n\\n.popover-body {\\n  padding: var(--#{$prefix}popover-body-padding-y) var(--#{$prefix}popover-body-padding-x);\\n  color: var(--#{$prefix}popover-body-color);\\n}\\n\",\"// Notes on the classes:\\n//\\n// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically)\\n//    even when their scroll action started on a carousel, but for compatibility (with Firefox)\\n//    we're preventing all actions instead\\n// 2. The .carousel-item-start and .carousel-item-end is used to indicate where\\n//    the active slide is heading.\\n// 3. .active.carousel-item is the current slide.\\n// 4. .active.carousel-item-start and .active.carousel-item-end is the current\\n//    slide in its in-transition state. Only one of these occurs at a time.\\n// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end\\n//    is the upcoming slide in transition.\\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  @include clearfix();\\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  @include transition($carousel-transition);\\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\\n//\\n// Alternate transitions\\n//\\n\\n.carousel-fade {\\n  .carousel-item {\\n    opacity: 0;\\n    transition-property: opacity;\\n    transform: none;\\n  }\\n\\n  .carousel-item.active,\\n  .carousel-item-next.carousel-item-start,\\n  .carousel-item-prev.carousel-item-end {\\n    z-index: 1;\\n    opacity: 1;\\n  }\\n\\n  .active.carousel-item-start,\\n  .active.carousel-item-end {\\n    z-index: 0;\\n    opacity: 0;\\n    @include transition(opacity 0s $carousel-transition-duration);\\n  }\\n}\\n\\n\\n//\\n// Left/right controls for nav\\n//\\n\\n.carousel-control-prev,\\n.carousel-control-next {\\n  position: absolute;\\n  top: 0;\\n  bottom: 0;\\n  z-index: 1;\\n  // Use flex for alignment (1-3)\\n  display: flex; // 1. allow flex styles\\n  align-items: center; // 2. vertically center contents\\n  justify-content: center; // 3. horizontally center contents\\n  width: $carousel-control-width;\\n  padding: 0;\\n  color: $carousel-control-color;\\n  text-align: center;\\n  background: none;\\n  border: 0;\\n  opacity: $carousel-control-opacity;\\n  @include transition($carousel-control-transition);\\n\\n  // Hover/focus state\\n  &:hover,\\n  &:focus {\\n    color: $carousel-control-color;\\n    text-decoration: none;\\n    outline: 0;\\n    opacity: $carousel-control-hover-opacity;\\n  }\\n}\\n.carousel-control-prev {\\n  left: 0;\\n  background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);\\n}\\n.carousel-control-next {\\n  right: 0;\\n  background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);\\n}\\n\\n// Icons for within\\n.carousel-control-prev-icon,\\n.carousel-control-next-icon {\\n  display: inline-block;\\n  width: $carousel-control-icon-width;\\n  height: $carousel-control-icon-width;\\n  background-repeat: no-repeat;\\n  background-position: 50%;\\n  background-size: 100% 100%;\\n}\\n\\n/* rtl:options: {\\n  \\\"autoRename\\\": true,\\n  \\\"stringMap\\\":[ {\\n    \\\"name\\\"    : \\\"prev-next\\\",\\n    \\\"search\\\"  : \\\"prev\\\",\\n    \\\"replace\\\" : \\\"next\\\"\\n  } ]\\n} */\\n.carousel-control-prev-icon {\\n  background-image: escape-svg($carousel-control-prev-icon-bg);\\n}\\n.carousel-control-next-icon {\\n  background-image: escape-svg($carousel-control-next-icon-bg);\\n}\\n\\n// Optional indicator pips/controls\\n//\\n// Add a container (such as a list) with the following class and add an item (ideally a focusable control,\\n// like a button) with data-bs-target for each slide your carousel holds.\\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  // Use the .carousel-control's width as margin so we don't overlay those\\n  margin-right: $carousel-control-width;\\n  margin-bottom: 1rem;\\n  margin-left: $carousel-control-width;\\n  list-style: none;\\n\\n  [data-bs-target] {\\n    box-sizing: content-box;\\n    flex: 0 1 auto;\\n    width: $carousel-indicator-width;\\n    height: $carousel-indicator-height;\\n    padding: 0;\\n    margin-right: $carousel-indicator-spacer;\\n    margin-left: $carousel-indicator-spacer;\\n    text-indent: -999px;\\n    cursor: pointer;\\n    background-color: $carousel-indicator-active-bg;\\n    background-clip: padding-box;\\n    border: 0;\\n    // Use transparent borders to increase the hit area by 10px on top and bottom.\\n    border-top: $carousel-indicator-hit-area-height solid transparent;\\n    border-bottom: $carousel-indicator-hit-area-height solid transparent;\\n    opacity: $carousel-indicator-opacity;\\n    @include transition($carousel-indicator-transition);\\n  }\\n\\n  .active {\\n    opacity: $carousel-indicator-active-opacity;\\n  }\\n}\\n\\n\\n// Optional captions\\n//\\n//\\n\\n.carousel-caption {\\n  position: absolute;\\n  right: (100% - $carousel-caption-width) * .5;\\n  bottom: $carousel-caption-spacer;\\n  left: (100% - $carousel-caption-width) * .5;\\n  padding-top: $carousel-caption-padding-y;\\n  padding-bottom: $carousel-caption-padding-y;\\n  color: $carousel-caption-color;\\n  text-align: center;\\n}\\n\\n// Dark mode carousel\\n\\n@mixin carousel-dark() {\\n  .carousel-control-prev-icon,\\n  .carousel-control-next-icon {\\n    filter: $carousel-dark-control-icon-filter;\\n  }\\n\\n  .carousel-indicators [data-bs-target] {\\n    background-color: $carousel-dark-indicator-active-bg;\\n  }\\n\\n  .carousel-caption {\\n    color: $carousel-dark-caption-color;\\n  }\\n}\\n\\n.carousel-dark {\\n  @include carousel-dark();\\n}\\n\\n@if $enable-dark-mode {\\n  @include color-mode(dark) {\\n    .carousel {\\n      @include carousel-dark();\\n    }\\n  }\\n}\\n\",\"// scss-docs-start clearfix\\n@mixin clearfix() {\\n  &::after {\\n    display: block;\\n    clear: both;\\n    content: \\\"\\\";\\n  }\\n}\\n// scss-docs-end clearfix\\n\",\"//\\n// Rotating border\\n//\\n\\n.spinner-grow,\\n.spinner-border {\\n  display: inline-block;\\n  width: var(--#{$prefix}spinner-width);\\n  height: var(--#{$prefix}spinner-height);\\n  vertical-align: var(--#{$prefix}spinner-vertical-align);\\n  // stylelint-disable-next-line property-disallowed-list\\n  border-radius: 50%;\\n  animation: var(--#{$prefix}spinner-animation-speed) linear infinite var(--#{$prefix}spinner-animation-name);\\n}\\n\\n// scss-docs-start spinner-border-keyframes\\n@keyframes spinner-border {\\n  to { transform: rotate(360deg) #{\\\"/* rtl:ignore */\\\"}; }\\n}\\n// scss-docs-end spinner-border-keyframes\\n\\n.spinner-border {\\n  // scss-docs-start spinner-border-css-vars\\n  --#{$prefix}spinner-width: #{$spinner-width};\\n  --#{$prefix}spinner-height: #{$spinner-height};\\n  --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};\\n  --#{$prefix}spinner-border-width: #{$spinner-border-width};\\n  --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};\\n  --#{$prefix}spinner-animation-name: spinner-border;\\n  // scss-docs-end spinner-border-css-vars\\n\\n  border: var(--#{$prefix}spinner-border-width) solid currentcolor;\\n  border-right-color: transparent;\\n}\\n\\n.spinner-border-sm {\\n  // scss-docs-start spinner-border-sm-css-vars\\n  --#{$prefix}spinner-width: #{$spinner-width-sm};\\n  --#{$prefix}spinner-height: #{$spinner-height-sm};\\n  --#{$prefix}spinner-border-width: #{$spinner-border-width-sm};\\n  // scss-docs-end spinner-border-sm-css-vars\\n}\\n\\n//\\n// Growing circle\\n//\\n\\n// scss-docs-start spinner-grow-keyframes\\n@keyframes spinner-grow {\\n  0% {\\n    transform: scale(0);\\n  }\\n  50% {\\n    opacity: 1;\\n    transform: none;\\n  }\\n}\\n// scss-docs-end spinner-grow-keyframes\\n\\n.spinner-grow {\\n  // scss-docs-start spinner-grow-css-vars\\n  --#{$prefix}spinner-width: #{$spinner-width};\\n  --#{$prefix}spinner-height: #{$spinner-height};\\n  --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};\\n  --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};\\n  --#{$prefix}spinner-animation-name: spinner-grow;\\n  // scss-docs-end spinner-grow-css-vars\\n\\n  background-color: currentcolor;\\n  opacity: 0;\\n}\\n\\n.spinner-grow-sm {\\n  --#{$prefix}spinner-width: #{$spinner-width-sm};\\n  --#{$prefix}spinner-height: #{$spinner-height-sm};\\n}\\n\\n@if $enable-reduced-motion {\\n  @media (prefers-reduced-motion: reduce) {\\n    .spinner-border,\\n    .spinner-grow {\\n      --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed * 2};\\n    }\\n  }\\n}\\n\",\"// stylelint-disable function-disallowed-list\\n\\n%offcanvas-css-vars {\\n  // scss-docs-start offcanvas-css-vars\\n  --#{$prefix}offcanvas-zindex: #{$zindex-offcanvas};\\n  --#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width};\\n  --#{$prefix}offcanvas-height: #{$offcanvas-vertical-height};\\n  --#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x};\\n  --#{$prefix}offcanvas-padding-y: #{$offcanvas-padding-y};\\n  --#{$prefix}offcanvas-color: #{$offcanvas-color};\\n  --#{$prefix}offcanvas-bg: #{$offcanvas-bg-color};\\n  --#{$prefix}offcanvas-border-width: #{$offcanvas-border-width};\\n  --#{$prefix}offcanvas-border-color: #{$offcanvas-border-color};\\n  --#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow};\\n  --#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out};\\n  --#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height};\\n  // scss-docs-end offcanvas-css-vars\\n}\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  $next: breakpoint-next($breakpoint, $grid-breakpoints);\\n  $infix: breakpoint-infix($next, $grid-breakpoints);\\n\\n  .offcanvas#{$infix} {\\n    @extend %offcanvas-css-vars;\\n  }\\n}\\n\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  $next: breakpoint-next($breakpoint, $grid-breakpoints);\\n  $infix: breakpoint-infix($next, $grid-breakpoints);\\n\\n  .offcanvas#{$infix} {\\n    @include media-breakpoint-down($next) {\\n      position: fixed;\\n      bottom: 0;\\n      z-index: var(--#{$prefix}offcanvas-zindex);\\n      display: flex;\\n      flex-direction: column;\\n      max-width: 100%;\\n      color: var(--#{$prefix}offcanvas-color);\\n      visibility: hidden;\\n      background-color: var(--#{$prefix}offcanvas-bg);\\n      background-clip: padding-box;\\n      outline: 0;\\n      @include box-shadow(var(--#{$prefix}offcanvas-box-shadow));\\n      @include transition(var(--#{$prefix}offcanvas-transition));\\n\\n      &.offcanvas-start {\\n        top: 0;\\n        left: 0;\\n        width: var(--#{$prefix}offcanvas-width);\\n        border-right: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);\\n        transform: translateX(-100%);\\n      }\\n\\n      &.offcanvas-end {\\n        top: 0;\\n        right: 0;\\n        width: var(--#{$prefix}offcanvas-width);\\n        border-left: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);\\n        transform: translateX(100%);\\n      }\\n\\n      &.offcanvas-top {\\n        top: 0;\\n        right: 0;\\n        left: 0;\\n        height: var(--#{$prefix}offcanvas-height);\\n        max-height: 100%;\\n        border-bottom: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);\\n        transform: translateY(-100%);\\n      }\\n\\n      &.offcanvas-bottom {\\n        right: 0;\\n        left: 0;\\n        height: var(--#{$prefix}offcanvas-height);\\n        max-height: 100%;\\n        border-top: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);\\n        transform: translateY(100%);\\n      }\\n\\n      &.showing,\\n      &.show:not(.hiding) {\\n        transform: none;\\n      }\\n\\n      &.showing,\\n      &.hiding,\\n      &.show {\\n        visibility: visible;\\n      }\\n    }\\n\\n    @if not ($infix == \\\"\\\") {\\n      @include media-breakpoint-up($next) {\\n        --#{$prefix}offcanvas-height: auto;\\n        --#{$prefix}offcanvas-border-width: 0;\\n        background-color: transparent !important; // stylelint-disable-line declaration-no-important\\n\\n        .offcanvas-header {\\n          display: none;\\n        }\\n\\n        .offcanvas-body {\\n          display: flex;\\n          flex-grow: 0;\\n          padding: 0;\\n          overflow-y: visible;\\n          // Reset `background-color` in case `.bg-*` classes are used in offcanvas\\n          background-color: transparent !important; // stylelint-disable-line declaration-no-important\\n        }\\n      }\\n    }\\n  }\\n}\\n\\n.offcanvas-backdrop {\\n  @include overlay-backdrop($zindex-offcanvas-backdrop, $offcanvas-backdrop-bg, $offcanvas-backdrop-opacity);\\n}\\n\\n.offcanvas-header {\\n  display: flex;\\n  align-items: center;\\n  justify-content: space-between;\\n  padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x);\\n\\n  .btn-close {\\n    padding: calc(var(--#{$prefix}offcanvas-padding-y) * .5) calc(var(--#{$prefix}offcanvas-padding-x) * .5);\\n    margin-top: calc(-.5 * var(--#{$prefix}offcanvas-padding-y));\\n    margin-right: calc(-.5 * var(--#{$prefix}offcanvas-padding-x));\\n    margin-bottom: calc(-.5 * var(--#{$prefix}offcanvas-padding-y));\\n  }\\n}\\n\\n.offcanvas-title {\\n  margin-bottom: 0;\\n  line-height: var(--#{$prefix}offcanvas-title-line-height);\\n}\\n\\n.offcanvas-body {\\n  flex-grow: 1;\\n  padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x);\\n  overflow-y: auto;\\n}\\n\",\".placeholder {\\n  display: inline-block;\\n  min-height: 1em;\\n  vertical-align: middle;\\n  cursor: wait;\\n  background-color: currentcolor;\\n  opacity: $placeholder-opacity-max;\\n\\n  &.btn::before {\\n    display: inline-block;\\n    content: \\\"\\\";\\n  }\\n}\\n\\n// Sizing\\n.placeholder-xs {\\n  min-height: .6em;\\n}\\n\\n.placeholder-sm {\\n  min-height: .8em;\\n}\\n\\n.placeholder-lg {\\n  min-height: 1.2em;\\n}\\n\\n// Animation\\n.placeholder-glow {\\n  .placeholder {\\n    animation: placeholder-glow 2s ease-in-out infinite;\\n  }\\n}\\n\\n@keyframes placeholder-glow {\\n  50% {\\n    opacity: $placeholder-opacity-min;\\n  }\\n}\\n\\n.placeholder-wave {\\n  mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 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\",\"// stylelint-disable function-name-case\\n\\n// All-caps `RGBA()` function used because of this Sass bug: https://github.com/sass/node-sass/issues/2251\\n@each $color, $value in $theme-colors {\\n  $color-rgb: to-rgb($value);\\n  .text-bg-#{$color} {\\n    color: color-contrast($value) if($enable-important-utilities, !important, null);\\n    background-color: RGBA($color-rgb, var(--#{$prefix}bg-opacity, 1)) if($enable-important-utilities, !important, null);\\n  }\\n}\\n\",\"@each $color, $value in $theme-colors {\\n  .link-#{$color} {\\n    color: $value if($enable-important-utilities, !important, null);\\n\\n    @if $link-shade-percentage != 0 {\\n      &:hover,\\n      &:focus {\\n        color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage)) if($enable-important-utilities, !important, null);\\n      }\\n    }\\n  }\\n}\\n\",\"// Credit: Nicolas Gallagher and SUIT CSS.\\n\\n.ratio {\\n  position: relative;\\n  width: 100%;\\n\\n  &::before {\\n    display: block;\\n    padding-top: var(--#{$prefix}aspect-ratio);\\n    content: \\\"\\\";\\n  }\\n\\n  > * {\\n    position: absolute;\\n    top: 0;\\n    left: 0;\\n    width: 100%;\\n    height: 100%;\\n  }\\n}\\n\\n@each $key, $ratio in $aspect-ratios {\\n  .ratio-#{$key} {\\n    --#{$prefix}aspect-ratio: #{$ratio};\\n  }\\n}\\n\",\"// Shorthand\\n\\n.fixed-top {\\n  position: fixed;\\n  top: 0;\\n  right: 0;\\n  left: 0;\\n  z-index: $zindex-fixed;\\n}\\n\\n.fixed-bottom {\\n  position: fixed;\\n  right: 0;\\n  bottom: 0;\\n  left: 0;\\n  z-index: $zindex-fixed;\\n}\\n\\n// Responsive sticky top and bottom\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n  @include media-breakpoint-up($breakpoint) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    .sticky#{$infix}-top {\\n      position: sticky;\\n      top: 0;\\n      z-index: $zindex-sticky;\\n    }\\n\\n    .sticky#{$infix}-bottom {\\n      position: sticky;\\n      bottom: 0;\\n      z-index: $zindex-sticky;\\n    }\\n  }\\n}\\n\",\"// scss-docs-start stacks\\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// scss-docs-end stacks\\n\",\"//\\n// Visually hidden\\n//\\n\\n.visually-hidden,\\n.visually-hidden-focusable:not(:focus):not(:focus-within) {\\n  @include visually-hidden();\\n}\\n\",\"// stylelint-disable declaration-no-important\\n\\n// Hide content visually while keeping it accessible to assistive technologies\\n//\\n// See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/\\n// See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/\\n\\n@mixin visually-hidden() {\\n  position: absolute !important;\\n  width: 1px !important;\\n  height: 1px !important;\\n  padding: 0 !important;\\n  margin: -1px !important; // Fix for https://github.com/twbs/bootstrap/issues/25686\\n  overflow: hidden !important;\\n  clip: rect(0, 0, 0, 0) !important;\\n  white-space: nowrap !important;\\n  border: 0 !important;\\n}\\n\\n// Use to only display content when it's focused, or one of its child elements is focused\\n// (i.e. when focus is within the element/container that the class was applied to)\\n//\\n// Useful for \\\"Skip to main content\\\" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\\n\\n@mixin visually-hidden-focusable() {\\n  &:not(:focus):not(:focus-within) {\\n    @include visually-hidden();\\n  }\\n}\\n\",\"//\\n// Stretched link\\n//\\n\\n.stretched-link {\\n  &::#{$stretched-link-pseudo-element} {\\n    position: absolute;\\n    top: 0;\\n    right: 0;\\n    bottom: 0;\\n    left: 0;\\n    z-index: $stretched-link-z-index;\\n    content: \\\"\\\";\\n  }\\n}\\n\",\"//\\n// Text truncation\\n//\\n\\n.text-truncate {\\n  @include text-truncate();\\n}\\n\",\"// Text truncate\\n// Requires inline-block or block for proper styling\\n\\n@mixin text-truncate() {\\n  overflow: hidden;\\n  text-overflow: ellipsis;\\n  white-space: nowrap;\\n}\\n\",\".vr {\\n  display: inline-block;\\n  align-self: stretch;\\n  width: 1px;\\n  min-height: 1em;\\n  background-color: currentcolor;\\n  opacity: $hr-opacity;\\n}\\n\",\"// Utility generator\\n// Used to generate utilities & print utilities\\n@mixin generate-utility($utility, $infix, $is-rfs-media-query: false) {\\n  $values: map-get($utility, values);\\n\\n  // If the values are a list or string, convert it into a map\\n  @if type-of($values) == \\\"string\\\" or type-of(nth($values, 1)) != \\\"list\\\" {\\n    $values: zip($values, $values);\\n  }\\n\\n  @each $key, $value in $values {\\n    $properties: map-get($utility, property);\\n\\n    // Multiple properties are possible, for example with vertical or horizontal margins or paddings\\n    @if type-of($properties) == \\\"string\\\" {\\n      $properties: append((), $properties);\\n    }\\n\\n    // Use custom class if present\\n    $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));\\n    $property-class: if($property-class == null, \\\"\\\", $property-class);\\n\\n    // Use custom CSS variable name if present, otherwise default to `class`\\n    $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class));\\n\\n    // State params to generate pseudo-classes\\n    $state: if(map-has-key($utility, state), map-get($utility, state), ());\\n\\n    $infix: if($property-class == \\\"\\\" and str-slice($infix, 1, 1) == \\\"-\\\", str-slice($infix, 2), $infix);\\n\\n    // Don't prefix if value key is null (e.g. with shadow class)\\n    $property-class-modifier: if($key, if($property-class == \\\"\\\" and $infix == \\\"\\\", \\\"\\\", \\\"-\\\") + $key, \\\"\\\");\\n\\n    @if map-get($utility, rfs) {\\n      // Inside the media query\\n      @if $is-rfs-media-query {\\n        $val: rfs-value($value);\\n\\n        // Do not render anything if fluid and non fluid values are the same\\n        $value: if($val == rfs-fluid-value($value), null, $val);\\n      }\\n      @else {\\n        $value: rfs-fluid-value($value);\\n      }\\n    }\\n\\n    $is-css-var: map-get($utility, css-var);\\n    $is-local-vars: map-get($utility, local-vars);\\n    $is-rtl: map-get($utility, rtl);\\n\\n    @if $value != null {\\n      @if $is-rtl == false {\\n        /* rtl:begin:remove */\\n      }\\n\\n      @if $is-css-var {\\n        .#{$property-class + $infix + $property-class-modifier} {\\n          --#{$prefix}#{$css-variable-name}: #{$value};\\n        }\\n\\n        @each $pseudo in $state {\\n          .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\\n            --#{$prefix}#{$css-variable-name}: #{$value};\\n          }\\n        }\\n      } @else {\\n        .#{$property-class + $infix + $property-class-modifier} {\\n          @each $property in $properties {\\n            @if $is-local-vars {\\n              @each $local-var, $variable in $is-local-vars {\\n                --#{$prefix}#{$local-var}: #{$variable};\\n              }\\n            }\\n            #{$property}: $value if($enable-important-utilities, !important, null);\\n          }\\n        }\\n\\n        @each $pseudo in $state {\\n          .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\\n            @each $property in $properties {\\n              @if $is-local-vars {\\n                @each $local-var, $variable in $is-local-vars {\\n                  --#{$prefix}#{$local-var}: #{$variable};\\n                }\\n              }\\n              #{$property}: $value if($enable-important-utilities, !important, null);\\n            }\\n          }\\n        }\\n      }\\n\\n      @if $is-rtl == false {\\n        /* rtl:end:remove */\\n      }\\n    }\\n  }\\n}\\n\",\"// Loop over each breakpoint\\n@each $breakpoint in map-keys($grid-breakpoints) {\\n\\n  // Generate media query if needed\\n  @include media-breakpoint-up($breakpoint) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    // Loop over each utility property\\n    @each $key, $utility in $utilities {\\n      // The utility can be disabled with `false`, thus check if the utility is a map first\\n      // Only proceed if responsive media queries are enabled or if it's the base media query\\n      @if type-of($utility) == \\\"map\\\" and (map-get($utility, responsive) or $infix == \\\"\\\") {\\n        @include generate-utility($utility, $infix);\\n      }\\n    }\\n  }\\n}\\n\\n// RFS rescaling\\n@media (min-width: $rfs-mq-value) {\\n  @each $breakpoint in map-keys($grid-breakpoints) {\\n    $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\\n\\n    @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {\\n      // Loop over each utility property\\n      @each $key, $utility in $utilities {\\n        // The utility can be disabled with `false`, thus check if the utility is a map first\\n        // Only proceed if responsive media queries are enabled or if it's the base media query\\n        @if type-of($utility) == \\\"map\\\" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == \\\"\\\") {\\n          @include generate-utility($utility, $infix, true);\\n        }\\n      }\\n    }\\n  }\\n}\\n\\n\\n// Print utilities\\n@media print {\\n  @each $key, $utility in $utilities {\\n    // The utility can be disabled with `false`, thus check if the utility is a map first\\n    // Then check if the utility needs print styles\\n    @if type-of($utility) == \\\"map\\\" and map-get($utility, print) == true {\\n      @include generate-utility($utility, \\\"-print\\\");\\n    }\\n  }\\n}\\n\"]}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/bootstrap-5.3.0/js/bootstrap.bundle.min.js",
    "content": "/*!\n  * Bootstrap v5.3.0-alpha1 (https://getbootstrap.com/)\n  * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n  */\n!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).bootstrap=e()}(this,(function(){\"use strict\";const t=\"transitionend\",e=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\\s\"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),i=e=>{e.dispatchEvent(new Event(t))},n=t=>!(!t||\"object\"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),s=t=>n(t)?t.jquery?t[0]:t:\"string\"==typeof t&&t.length>0?document.querySelector(e(t)):null,o=t=>{if(!n(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},r=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains(\"disabled\")||(void 0!==t.disabled?t.disabled:t.hasAttribute(\"disabled\")&&\"false\"!==t.getAttribute(\"disabled\")),a=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?a(t.parentNode):null},l=()=>{},c=t=>{t.offsetHeight},h=()=>window.jQuery&&!document.body.hasAttribute(\"data-bs-no-jquery\")?window.jQuery:null,d=[],u=()=>\"rtl\"===document.documentElement.dir,f=t=>{var e;e=()=>{const e=h();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?(d.length||document.addEventListener(\"DOMContentLoaded\",(()=>{for(const t of d)t()})),d.push(e)):e()},p=(t,e=[],i=t)=>\"function\"==typeof t?t(...e):i,m=(e,n,s=!0)=>{if(!s)return void p(e);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})(n)+5;let r=!1;const a=({target:i})=>{i===n&&(r=!0,n.removeEventListener(t,a),p(e))};n.addEventListener(t,a),setTimeout((()=>{r||i(n)}),o)},g=(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))])},_=/[^.]*(?=\\..*)\\.|.*/,b=/\\..*/,v=/::\\d+$/,y={};let w=1;const A={mouseenter:\"mouseover\",mouseleave:\"mouseout\"},E=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 T(t,e){return e&&`${e}::${w++}`||t.uidEvent||w++}function C(t){const e=T(t);return t.uidEvent=e,y[e]=y[e]||{},y[e]}function O(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function x(t,e,i){const n=\"string\"==typeof e,s=n?i:e||i;let o=D(t);return E.has(o)||(o=t),[n,s,o]}function k(t,e,i,n,s){if(\"string\"!=typeof e||!t)return;let[o,r,a]=x(e,i,n);if(e in A){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=C(t),c=l[a]||(l[a]={}),h=O(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=T(r,e.replace(_,\"\")),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 N(s,{delegateTarget:r}),n.oneOff&&I.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return N(n,{delegateTarget:t}),i.oneOff&&I.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 L(t,e,i,n,s){const o=O(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function S(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&L(t,e,i,r.callable,r.delegationSelector)}function D(t){return t=t.replace(b,\"\"),A[t]||t}const I={on(t,e,i,n){k(t,e,i,n,!1)},one(t,e,i,n){k(t,e,i,n,!0)},off(t,e,i,n){if(\"string\"!=typeof e||!t)return;const[s,o,r]=x(e,i,n),a=r!==e,l=C(t),c=l[r]||{},h=e.startsWith(\".\");if(void 0===o){if(h)for(const i of Object.keys(l))S(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(v,\"\");a&&!e.includes(s)||L(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;L(t,l,r,o,s?i:null)}},trigger(t,e,i){if(\"string\"!=typeof e||!t)return null;const n=h();let s=null,o=!0,r=!0,a=!1;e!==D(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());let l=new Event(e,{bubbles:o,cancelable:!0});return l=N(l,i),a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function N(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}const P=new Map,j={set(t,e,i){P.has(t)||P.set(t,new Map);const n=P.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>P.has(t)&&P.get(t).get(e)||null,remove(t,e){if(!P.has(t))return;const i=P.get(t);i.delete(e),0===i.size&&P.delete(t)}};function M(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 F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const H={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(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]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${F(e)}`))};class ${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=n(e)?H.getDataAttribute(e,\"config\"):{};return{...this.constructor.Default,...\"object\"==typeof i?i:{},...n(e)?H.getDataAttributes(e):{},...\"object\"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[s,o]of Object.entries(e)){const e=t[s],r=n(e)?\"element\":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(o).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option \"${s}\" provided type \"${r}\" but expected type \"${o}\".`)}var i}}class W extends ${constructor(t,e){super(),(t=s(t))&&(this._element=t,this._config=this._getConfig(e),j.set(this._element,this.constructor.DATA_KEY,this))}dispose(){j.remove(this._element,this.constructor.DATA_KEY),I.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){m(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return j.get(s(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.0-alpha1\"}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 i=t.getAttribute(\"data-bs-target\");if(!i||\"#\"===i){let e=t.getAttribute(\"href\");if(!e||!e.includes(\"#\")&&!e.startsWith(\".\"))return null;e.includes(\"#\")&&!e.startsWith(\"#\")&&(e=`#${e.split(\"#\")[1]}`),i=e&&\"#\"!==e?e.trim():null}return e(i)},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=>!r(t)&&o(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;I.on(document,i,`[data-bs-dismiss=\"${n}\"]`,(function(i){if([\"A\",\"AREA\"].includes(this.tagName)&&i.preventDefault(),r(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))};class q extends W{static get NAME(){return\"alert\"}close(){if(I.trigger(this._element,\"close.bs.alert\").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(),I.trigger(this._element,\"closed.bs.alert\"),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\"),f(q);const V='[data-bs-toggle=\"button\"]';class K 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=K.getOrCreateInstance(this);\"toggle\"===t&&e[t]()}))}}I.on(document,\"click.bs.button.data-api\",V,(t=>{t.preventDefault();const e=t.target.closest(V);K.getOrCreateInstance(e).toggle()})),f(K);const Q={endCallback:null,leftCallback:null,rightCallback:null},X={endCallback:\"(function|null)\",leftCallback:\"(function|null)\",rightCallback:\"(function|null)\"};class Y extends ${constructor(t,e){super(),this._element=t,t&&Y.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return Q}static get DefaultType(){return X}static get NAME(){return\"swipe\"}dispose(){I.off(this._element,\".bs.swipe\")}_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(),p(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&&p(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(I.on(this._element,\"pointerdown.bs.swipe\",(t=>this._start(t))),I.on(this._element,\"pointerup.bs.swipe\",(t=>this._end(t))),this._element.classList.add(\"pointer-event\")):(I.on(this._element,\"touchstart.bs.swipe\",(t=>this._start(t))),I.on(this._element,\"touchmove.bs.swipe\",(t=>this._move(t))),I.on(this._element,\"touchend.bs.swipe\",(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 U=\"next\",G=\"prev\",J=\"left\",Z=\"right\",tt=\"slid.bs.carousel\",et=\"carousel\",it=\"active\",nt={ArrowLeft:Z,ArrowRight:J},st={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 rt 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===et&&this.cycle()}static get Default(){return st}static get DefaultType(){return ot}static get NAME(){return\"carousel\"}next(){this._slide(U)}nextWhenVisible(){!document.hidden&&o(this._element)&&this.next()}prev(){this._slide(G)}pause(){this._isSliding&&i(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?I.one(this._element,tt,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void I.one(this._element,tt,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?U:G;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&&I.on(this._element,\"keydown.bs.carousel\",(t=>this._keydown(t))),\"hover\"===this._config.pause&&(I.on(this._element,\"mouseenter.bs.carousel\",(()=>this.pause())),I.on(this._element,\"mouseleave.bs.carousel\",(()=>this._maybeEnableCycle()))),this._config.touch&&Y.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(\".carousel-item img\",this._element))I.on(t,\"dragstart.bs.carousel\",(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(J)),rightCallback:()=>this._slide(this._directionToOrder(Z)),endCallback:()=>{\"hover\"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new Y(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=nt[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(\".active\",this._indicatorsElement);e.classList.remove(it),e.removeAttribute(\"aria-current\");const i=z.findOne(`[data-bs-slide-to=\"${t}\"]`,this._indicatorsElement);i&&(i.classList.add(it),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===U,s=e||g(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>I.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(\"slide.bs.carousel\").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\",h=n?\"carousel-item-next\":\"carousel-item-prev\";s.classList.add(h),c(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,h),s.classList.add(it),i.classList.remove(it,h,l),this._isSliding=!1,r(tt)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains(\"slide\")}_getActive(){return z.findOne(\".active.carousel-item\",this._element)}_getItems(){return z.find(\".carousel-item\",this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return u()?t===J?G:U:t===J?U:G}_orderToDirection(t){return u()?t===G?J:Z:t===G?Z:J}static jQueryInterface(t){return this.each((function(){const e=rt.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)}))}}I.on(document,\"click.bs.carousel.data-api\",\"[data-bs-slide], [data-bs-slide-to]\",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(et))return;t.preventDefault();const i=rt.getOrCreateInstance(e),n=this.getAttribute(\"data-bs-slide-to\");return n?(i.to(n),void i._maybeEnableCycle()):\"next\"===H.getDataAttribute(this,\"slide\")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),I.on(window,\"load.bs.carousel.data-api\",(()=>{const t=z.find('[data-bs-ride=\"carousel\"]');for(const e of t)rt.getOrCreateInstance(e)})),f(rt);const at=\"show\",lt=\"collapse\",ct=\"collapsing\",ht='[data-bs-toggle=\"collapse\"]',dt={parent:null,toggle:!0},ut={parent:\"(null|element)\",toggle:\"boolean\"};class ft extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(ht);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 dt}static get DefaultType(){return ut}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=>ft.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(I.trigger(this._element,\"show.bs.collapse\").defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(lt),this._element.classList.add(ct),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(ct),this._element.classList.add(lt,at),this._element.style[e]=\"\",I.trigger(this._element,\"shown.bs.collapse\")}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(I.trigger(this._element,\"hide.bs.collapse\").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,c(this._element),this._element.classList.add(ct),this._element.classList.remove(lt,at);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(ct),this._element.classList.add(lt),I.trigger(this._element,\"hidden.bs.collapse\")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(at)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=s(t.parent),t}_getDimension(){return this._element.classList.contains(\"collapse-horizontal\")?\"width\":\"height\"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(ht);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(\":scope .collapse .collapse\",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=ft.getOrCreateInstance(this,e);if(\"string\"==typeof t){if(void 0===i[t])throw new TypeError(`No method named \"${t}\"`);i[t]()}}))}}I.on(document,\"click.bs.collapse.data-api\",ht,(function(t){(\"A\"===t.target.tagName||t.delegateTarget&&\"A\"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))ft.getOrCreateInstance(t,{toggle:!1}).toggle()})),f(ft);var pt=\"top\",mt=\"bottom\",gt=\"right\",_t=\"left\",bt=\"auto\",vt=[pt,mt,gt,_t],yt=\"start\",wt=\"end\",At=\"clippingParents\",Et=\"viewport\",Tt=\"popper\",Ct=\"reference\",Ot=vt.reduce((function(t,e){return t.concat([e+\"-\"+yt,e+\"-\"+wt])}),[]),xt=[].concat(vt,[bt]).reduce((function(t,e){return t.concat([e,e+\"-\"+yt,e+\"-\"+wt])}),[]),kt=\"beforeRead\",Lt=\"read\",St=\"afterRead\",Dt=\"beforeMain\",It=\"main\",Nt=\"afterMain\",Pt=\"beforeWrite\",jt=\"write\",Mt=\"afterWrite\",Ft=[kt,Lt,St,Dt,It,Nt,Pt,jt,Mt];function Ht(t){return t?(t.nodeName||\"\").toLowerCase():null}function $t(t){if(null==t)return window;if(\"[object Window]\"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function Wt(t){return t instanceof $t(t).Element||t instanceof Element}function Bt(t){return t instanceof $t(t).HTMLElement||t instanceof HTMLElement}function zt(t){return\"undefined\"!=typeof ShadowRoot&&(t instanceof $t(t).ShadowRoot||t instanceof ShadowRoot)}const Rt={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];Bt(s)&&Ht(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}),{});Bt(n)&&Ht(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:[\"computeStyles\"]};function qt(t){return t.split(\"-\")[0]}var Vt=Math.max,Kt=Math.min,Qt=Math.round;function Xt(){var t=navigator.userAgentData;return null!=t&&t.brands?t.brands.map((function(t){return t.brand+\"/\"+t.version})).join(\" \"):navigator.userAgent}function Yt(){return!/^((?!chrome|android).)*safari/i.test(Xt())}function Ut(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&Bt(t)&&(s=t.offsetWidth>0&&Qt(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&Qt(n.height)/t.offsetHeight||1);var r=(Wt(t)?$t(t):window).visualViewport,a=!Yt()&&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 Gt(t){var e=Ut(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 Jt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&zt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Zt(t){return $t(t).getComputedStyle(t)}function te(t){return[\"table\",\"td\",\"th\"].indexOf(Ht(t))>=0}function ee(t){return((Wt(t)?t.ownerDocument:t.document)||window.document).documentElement}function ie(t){return\"html\"===Ht(t)?t:t.assignedSlot||t.parentNode||(zt(t)?t.host:null)||ee(t)}function ne(t){return Bt(t)&&\"fixed\"!==Zt(t).position?t.offsetParent:null}function se(t){for(var e=$t(t),i=ne(t);i&&te(i)&&\"static\"===Zt(i).position;)i=ne(i);return i&&(\"html\"===Ht(i)||\"body\"===Ht(i)&&\"static\"===Zt(i).position)?e:i||function(t){var e=/firefox/i.test(Xt());if(/Trident/i.test(Xt())&&Bt(t)&&\"fixed\"===Zt(t).position)return null;var i=ie(t);for(zt(i)&&(i=i.host);Bt(i)&&[\"html\",\"body\"].indexOf(Ht(i))<0;){var n=Zt(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 oe(t){return[\"top\",\"bottom\"].indexOf(t)>=0?\"x\":\"y\"}function re(t,e,i){return Vt(t,Kt(e,i))}function ae(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function le(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const ce={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=qt(i.placement),l=oe(a),c=[_t,gt].indexOf(a)>=0?\"height\":\"width\";if(o&&r){var h=function(t,e){return ae(\"number\"!=typeof(t=\"function\"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:le(t,vt))}(s.padding,i),d=Gt(o),u=\"y\"===l?pt:_t,f=\"y\"===l?mt:gt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=se(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=re(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)))&&Jt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:[\"popperOffsets\"],requiresIfExists:[\"preventOverflow\"]};function he(t){return t.split(\"-\")[1]}var de={top:\"auto\",right:\"auto\",bottom:\"auto\",left:\"auto\"};function ue(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=_t,y=pt,w=window;if(c){var A=se(i),E=\"clientHeight\",T=\"clientWidth\";A===$t(i)&&\"static\"!==Zt(A=ee(i)).position&&\"absolute\"===a&&(E=\"scrollHeight\",T=\"scrollWidth\"),(s===pt||(s===_t||s===gt)&&o===wt)&&(y=mt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==_t&&(s!==pt&&s!==mt||o!==wt)||(v=gt,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&&de),x=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:Qt(e*n)/n||0,y:Qt(i*n)/n||0}}({x:f,y:m}):{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 fe={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:qt(e.placement),variation:he(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,ue(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,ue(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 pe={passive:!0};const me={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=$t(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener(\"scroll\",i.update,pe)})),a&&l.addEventListener(\"resize\",i.update,pe),function(){o&&c.forEach((function(t){t.removeEventListener(\"scroll\",i.update,pe)})),a&&l.removeEventListener(\"resize\",i.update,pe)}},data:{}};var ge={left:\"right\",right:\"left\",bottom:\"top\",top:\"bottom\"};function _e(t){return t.replace(/left|right|bottom|top/g,(function(t){return ge[t]}))}var be={start:\"end\",end:\"start\"};function ve(t){return t.replace(/start|end/g,(function(t){return be[t]}))}function ye(t){var e=$t(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function we(t){return Ut(ee(t)).left+ye(t).scrollLeft}function Ae(t){var e=Zt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return[\"html\",\"body\",\"#document\"].indexOf(Ht(t))>=0?t.ownerDocument.body:Bt(t)&&Ae(t)?t:Ee(ie(t))}function Te(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=$t(n),r=s?[o].concat(o.visualViewport||[],Ae(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Te(ie(r)))}function Ce(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e,i){return e===Et?Ce(function(t,e){var i=$t(t),n=ee(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Yt();(c||!c&&\"fixed\"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+we(t),y:l}}(t,i)):Wt(e)?function(t,e){var i=Ut(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):Ce(function(t){var e,i=ee(t),n=ye(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=Vt(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=Vt(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+we(t),l=-n.scrollTop;return\"rtl\"===Zt(s||i).direction&&(a+=Vt(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(ee(t)))}function xe(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?qt(s):null,r=s?he(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case pt:e={x:a,y:i.y-n.height};break;case mt:e={x:a,y:i.y+i.height};break;case gt:e={x:i.x+i.width,y:l};break;case _t:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?oe(o):null;if(null!=c){var h=\"y\"===c?\"height\":\"width\";switch(r){case yt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case wt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(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?At:a,c=i.rootBoundary,h=void 0===c?Et:c,d=i.elementContext,u=void 0===d?Tt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=ae(\"number\"!=typeof g?g:le(g,vt)),b=u===Tt?Ct:Tt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s=\"clippingParents\"===e?function(t){var e=Te(ie(t)),i=[\"absolute\",\"fixed\"].indexOf(Zt(t).position)>=0&&Bt(t)?se(t):t;return Wt(i)?e.filter((function(t){return Wt(t)&&Jt(t,i)&&\"body\"!==Ht(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=Oe(t,i,n);return e.top=Vt(s.top,e.top),e.right=Kt(s.right,e.right),e.bottom=Kt(s.bottom,e.bottom),e.left=Vt(s.left,e.left),e}),Oe(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}(Wt(y)?y:y.contextElement||ee(t.elements.popper),l,h,r),A=Ut(t.elements.reference),E=xe({reference:A,element:v,strategy:\"absolute\",placement:s}),T=Ce(Object.assign({},v,E)),C=u===Tt?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===Tt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[gt,mt].indexOf(t)>=0?1:-1,i=[pt,mt].indexOf(t)>=0?\"y\":\"x\";O[t]+=k[i]*e}))}return O}function Le(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?xt:l,h=he(n),d=h?a?Ot:Ot.filter((function(t){return he(t)===h})):vt,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]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[qt(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const Se={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,_=qt(g),b=l||(_!==g&&p?function(t){if(qt(t)===bt)return[];var e=_e(t);return[ve(t),e,ve(e)]}(g):[_e(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(qt(i)===bt?Le(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<v.length;C++){var O=v[C],x=qt(O),k=he(O)===yt,L=[pt,mt].indexOf(x)>=0,S=L?\"width\":\"height\",D=ke(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),I=L?k?gt:_t:k?mt:pt;y[S]>w[S]&&(I=_e(I));var N=_e(I),P=[];if(o&&P.push(D[x]<=0),a&&P.push(D[I]<=0,D[N]<=0),P.every((function(t){return t}))){T=O,E=!1;break}A.set(O,P)}if(E)for(var j=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\"},M=p?3:1;M>0&&\"break\"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:[\"offset\"],data:{_skip:!1}};function De(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 Ie(t){return[pt,gt,mt,_t].some((function(e){return t[e]>=0}))}const Ne={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=ke(e,{elementContext:\"reference\"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Ie(l),d=Ie(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})}},Pe={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=xt.reduce((function(t,i){return t[i]=function(t,e,i){var n=qt(t),s=[_t,pt].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,[_t,gt].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}},je={name:\"popperOffsets\",enabled:!0,phase:\"read\",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=xe({reference:e.rects.reference,element:e.rects.popper,strategy:\"absolute\",placement:e.placement})},data:{}},Me={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=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=qt(e.placement),b=he(e.placement),v=!b,y=oe(_),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?pt:_t,D=\"y\"===y?mt:gt,I=\"y\"===y?\"height\":\"width\",N=A[y],P=N+g[S],j=N-g[D],M=f?-T[I]/2:0,F=b===yt?E[I]:T[I],H=b===yt?-T[I]:-E[I],$=e.elements.arrow,W=f&&$?Gt($):{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=re(0,E[I],W[I]),V=v?E[I]/2-M-q-z-O.mainAxis:F-q-z-O.mainAxis,K=v?-E[I]/2+M+q+R+O.mainAxis:H+q+R+O.mainAxis,Q=e.elements.arrow&&se(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=N+K-Y,G=re(f?Kt(P,N+V-Y-X):P,N,f?Vt(j,U):j);A[y]=G,k[y]=G-N}if(a){var J,Z=\"x\"===y?pt:_t,tt=\"x\"===y?mt:gt,et=A[w],it=\"y\"===w?\"height\":\"width\",nt=et+g[Z],st=et-g[tt],ot=-1!==[pt,_t].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=re(t,e,i);return n>i?i:n}(at,et,lt):re(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:[\"offset\"]};function Fe(t,e,i){void 0===i&&(i=!1);var n,s,o=Bt(e),r=Bt(e)&&function(t){var e=t.getBoundingClientRect(),i=Qt(e.width)/t.offsetWidth||1,n=Qt(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=ee(e),l=Ut(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&((\"body\"!==Ht(e)||Ae(a))&&(c=(n=e)!==$t(n)&&Bt(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:ye(n)),Bt(e)?((h=Ut(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=we(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function He(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 $e={placement:\"bottom\",modifiers:[],strategy:\"absolute\"};function We(){for(var t=arguments.length,e=new Array(t),i=0;i<t;i++)e[i]=arguments[i];return!e.some((function(t){return!(t&&\"function\"==typeof t.getBoundingClientRect)}))}function Be(t){void 0===t&&(t={});var e=t,i=e.defaultModifiers,n=void 0===i?[]:i,s=e.defaultOptions,o=void 0===s?$e:s;return function(t,e,i){void 0===i&&(i=o);var s,r,a={placement:\"bottom\",orderedModifiers:[],options:Object.assign({},$e,o),modifiersData:{},elements:{reference:t,popper:e},attributes:{},styles:{}},l=[],c=!1,h={state:a,setOptions:function(i){var s=\"function\"==typeof i?i(a.options):i;d(),a.options=Object.assign({},o,a.options,s),a.scrollParents={reference:Wt(t)?Te(t):t.contextElement?Te(t.contextElement):[],popper:Te(e)};var r,c,u=function(t){var e=He(t);return Ft.reduce((function(t,i){return t.concat(e.filter((function(t){return t.phase===i})))}),[])}((r=[].concat(n,a.options.modifiers),c=r.reduce((function(t,e){var i=t[e.name];return t[e.name]=i?Object.assign({},i,e,{options:Object.assign({},i.options,e.options),data:Object.assign({},i.data,e.data)}):e,t}),{}),Object.keys(c).map((function(t){return c[t]}))));return a.orderedModifiers=u.filter((function(t){return t.enabled})),a.orderedModifiers.forEach((function(t){var e=t.name,i=t.options,n=void 0===i?{}:i,s=t.effect;if(\"function\"==typeof s){var o=s({state:a,name:e,instance:h,options:n});l.push(o||function(){})}})),h.update()},forceUpdate:function(){if(!c){var t=a.elements,e=t.reference,i=t.popper;if(We(e,i)){a.rects={reference:Fe(e,se(i),\"fixed\"===a.options.strategy),popper:Gt(i)},a.reset=!1,a.placement=a.options.placement,a.orderedModifiers.forEach((function(t){return a.modifiersData[t.name]=Object.assign({},t.data)}));for(var n=0;n<a.orderedModifiers.length;n++)if(!0!==a.reset){var s=a.orderedModifiers[n],o=s.fn,r=s.options,l=void 0===r?{}:r,d=s.name;\"function\"==typeof o&&(a=o({state:a,options:l,name:d,instance:h})||a)}else a.reset=!1,n=-1}}},update:(s=function(){return new Promise((function(t){h.forceUpdate(),t(a)}))},function(){return r||(r=new Promise((function(t){Promise.resolve().then((function(){r=void 0,t(s())}))}))),r}),destroy:function(){d(),c=!0}};if(!We(t,e))return h;function d(){l.forEach((function(t){return t()})),l=[]}return h.setOptions(i).then((function(t){!c&&i.onFirstUpdate&&i.onFirstUpdate(t)})),h}}var ze=Be(),Re=Be({defaultModifiers:[me,je,fe,Rt]}),qe=Be({defaultModifiers:[me,je,fe,Rt,Pe,Se,Me,ce,Ne]});const Ve=Object.freeze(Object.defineProperty({__proto__:null,popperGenerator:Be,detectOverflow:ke,createPopperBase:ze,createPopper:qe,createPopperLite:Re,top:pt,bottom:mt,right:gt,left:_t,auto:bt,basePlacements:vt,start:yt,end:wt,clippingParents:At,viewport:Et,popper:Tt,reference:Ct,variationPlacements:Ot,placements:xt,beforeRead:kt,read:Lt,afterRead:St,beforeMain:Dt,main:It,afterMain:Nt,beforeWrite:Pt,write:jt,afterWrite:Mt,modifierPhases:Ft,applyStyles:Rt,arrow:ce,computeStyles:fe,eventListeners:me,flip:Se,hide:Ne,offset:Pe,popperOffsets:je,preventOverflow:Me},Symbol.toStringTag,{value:\"Module\"})),Ke=\"dropdown\",Qe=\"ArrowUp\",Xe=\"ArrowDown\",Ye=\"click.bs.dropdown.data-api\",Ue=\"keydown.bs.dropdown.data-api\",Ge=\"show\",Je='[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)',Ze=`${Je}.show`,ti=\".dropdown-menu\",ei=u()?\"top-end\":\"top-start\",ii=u()?\"top-start\":\"top-end\",ni=u()?\"bottom-end\":\"bottom-start\",si=u()?\"bottom-start\":\"bottom-end\",oi=u()?\"left-start\":\"right-start\",ri=u()?\"right-start\":\"left-start\",ai={autoClose:!0,boundary:\"clippingParents\",display:\"dynamic\",offset:[0,2],popperConfig:null,reference:\"toggle\"},li={autoClose:\"(boolean|string)\",boundary:\"(string|element)\",display:\"string\",offset:\"(array|string|function)\",popperConfig:\"(null|object|function)\",reference:\"(string|element|object)\"};class ci extends W{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=z.next(this._element,ti)[0]||z.prev(this._element,ti)[0]||z.findOne(ti,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return ai}static get DefaultType(){return li}static get NAME(){return Ke}toggle(){return this._isShown()?this.hide():this.show()}show(){if(r(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!I.trigger(this._element,\"show.bs.dropdown\",t).defaultPrevented){if(this._createPopper(),\"ontouchstart\"in document.documentElement&&!this._parent.closest(\".navbar-nav\"))for(const t of[].concat(...document.body.children))I.on(t,\"mouseover\",l);this._element.focus(),this._element.setAttribute(\"aria-expanded\",!0),this._menu.classList.add(Ge),this._element.classList.add(Ge),I.trigger(this._element,\"shown.bs.dropdown\",t)}}hide(){if(r(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!I.trigger(this._element,\"hide.bs.dropdown\",t).defaultPrevented){if(\"ontouchstart\"in document.documentElement)for(const t of[].concat(...document.body.children))I.off(t,\"mouseover\",l);this._popper&&this._popper.destroy(),this._menu.classList.remove(Ge),this._element.classList.remove(Ge),this._element.setAttribute(\"aria-expanded\",\"false\"),H.removeDataAttribute(this._menu,\"popper\"),I.trigger(this._element,\"hidden.bs.dropdown\",t)}}_getConfig(t){if(\"object\"==typeof(t=super._getConfig(t)).reference&&!n(t.reference)&&\"function\"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ke.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`);return t}_createPopper(){if(void 0===Ve)throw new TypeError(\"Bootstrap's dropdowns require Popper (https://popper.js.org)\");let t=this._element;\"parent\"===this._config.reference?t=this._parent:n(this._config.reference)?t=s(this._config.reference):\"object\"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=qe(t,this._menu,e)}_isShown(){return this._menu.classList.contains(Ge)}_getPlacement(){const t=this._parent;if(t.classList.contains(\"dropend\"))return oi;if(t.classList.contains(\"dropstart\"))return ri;if(t.classList.contains(\"dropup-center\"))return\"top\";if(t.classList.contains(\"dropdown-center\"))return\"bottom\";const e=\"end\"===getComputedStyle(this._menu).getPropertyValue(\"--bs-position\").trim();return t.classList.contains(\"dropup\")?e?ii:ei:e?si:ni}_detectNavbar(){return null!==this._element.closest(\".navbar\")}_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}_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)&&(H.setDataAttribute(this._menu,\"popper\",\"static\"),t.modifiers=[{name:\"applyStyles\",enabled:!1}]),{...t,...p(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=>o(t)));i.length&&g(i,e,t===Xe,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=ci.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(Ze);for(const i of e){const e=ci.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=[Qe,Xe].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Je)?this:z.prev(this,Je)[0]||z.next(this,Je)[0]||z.findOne(Je,t.delegateTarget.parentNode),o=ci.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}I.on(document,Ue,Je,ci.dataApiKeydownHandler),I.on(document,Ue,ti,ci.dataApiKeydownHandler),I.on(document,Ye,ci.clearMenus),I.on(document,\"keyup.bs.dropdown.data-api\",ci.clearMenus),I.on(document,Ye,Je,(function(t){t.preventDefault(),ci.getOrCreateInstance(this).toggle()})),f(ci);const hi=\".fixed-top, .fixed-bottom, .is-fixed, .sticky-top\",di=\".sticky-top\",ui=\"padding-right\",fi=\"margin-right\";class pi{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,ui,(e=>e+t)),this._setElementAttributes(hi,ui,(e=>e+t)),this._setElementAttributes(di,fi,(e=>e-t))}reset(){this._resetElementAttributes(this._element,\"overflow\"),this._resetElementAttributes(this._element,ui),this._resetElementAttributes(hi,ui),this._resetElementAttributes(di,fi)}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&&H.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=H.getDataAttribute(t,e);null!==i?(H.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(n(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const mi=\"show\",gi=\"mousedown.bs.backdrop\",_i={className:\"modal-backdrop\",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:\"body\"},bi={className:\"string\",clickCallback:\"(function|null)\",isAnimated:\"boolean\",isVisible:\"boolean\",rootElement:\"(element|string)\"};class vi extends ${constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return _i}static get DefaultType(){return bi}static get NAME(){return\"backdrop\"}show(t){if(!this._config.isVisible)return void p(t);this._append();const e=this._getElement();this._config.isAnimated&&c(e),e.classList.add(mi),this._emulateAnimation((()=>{p(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(mi),this._emulateAnimation((()=>{this.dispose(),p(t)}))):p(t)}dispose(){this._isAppended&&(I.off(this._element,gi),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=s(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),I.on(t,gi,(()=>{p(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){m(t,this._getElement(),this._config.isAnimated)}}const yi=\".bs.focustrap\",wi=\"backward\",Ai={autofocus:!0,trapElement:null},Ei={autofocus:\"boolean\",trapElement:\"element\"};class Ti extends ${constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return Ai}static get DefaultType(){return Ei}static get NAME(){return\"focustrap\"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),I.off(document,yi),I.on(document,\"focusin.bs.focustrap\",(t=>this._handleFocusin(t))),I.on(document,\"keydown.tab.bs.focustrap\",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,I.off(document,yi))}_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===wi?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){\"Tab\"===t.key&&(this._lastTabNavDirection=t.shiftKey?wi:\"forward\")}}const Ci=\"hidden.bs.modal\",Oi=\"show.bs.modal\",xi=\"modal-open\",ki=\"show\",Li=\"modal-static\",Si={backdrop:!0,focus:!0,keyboard:!0},Di={backdrop:\"(boolean|string)\",focus:\"boolean\",keyboard:\"boolean\"};class Ii 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 pi,this._addEventListeners()}static get Default(){return Si}static get DefaultType(){return Di}static get NAME(){return\"modal\"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||I.trigger(this._element,Oi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(xi),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(I.trigger(this._element,\"hide.bs.modal\").defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(ki),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){for(const t of[window,this._dialog])I.off(t,\".bs.modal\");this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new vi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ti({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),c(this._element),this._element.classList.add(ki),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,I.trigger(this._element,\"shown.bs.modal\",{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){I.on(this._element,\"keydown.dismiss.bs.modal\",(t=>{if(\"Escape\"===t.key)return this._config.keyboard?(t.preventDefault(),void this.hide()):void this._triggerBackdropTransition()})),I.on(window,\"resize.bs.modal\",(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),I.on(this._element,\"mousedown.dismiss.bs.modal\",(t=>{I.one(this._element,\"click.dismiss.bs.modal\",(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(xi),this._resetAdjustments(),this._scrollBar.reset(),I.trigger(this._element,Ci)}))}_isAnimated(){return this._element.classList.contains(\"fade\")}_triggerBackdropTransition(){if(I.trigger(this._element,\"hidePrevented.bs.modal\").defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;\"hidden\"===e||this._element.classList.contains(Li)||(t||(this._element.style.overflowY=\"hidden\"),this._element.classList.add(Li),this._queueCallback((()=>{this._element.classList.remove(Li),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=u()?\"paddingLeft\":\"paddingRight\";this._element.style[t]=`${e}px`}if(!i&&t){const t=u()?\"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=Ii.getOrCreateInstance(this,t);if(\"string\"==typeof t){if(void 0===i[t])throw new TypeError(`No method named \"${t}\"`);i[t](e)}}))}}I.on(document,\"click.bs.modal.data-api\",'[data-bs-toggle=\"modal\"]',(function(t){const e=z.getElementFromSelector(this);[\"A\",\"AREA\"].includes(this.tagName)&&t.preventDefault(),I.one(e,Oi,(t=>{t.defaultPrevented||I.one(e,Ci,(()=>{o(this)&&this.focus()}))}));const i=z.findOne(\".modal.show\");i&&Ii.getInstance(i).hide(),Ii.getOrCreateInstance(e).toggle(this)})),R(Ii),f(Ii);const Ni=\"show\",Pi=\"showing\",ji=\"hiding\",Mi=\".offcanvas.show\",Fi=\"hidePrevented.bs.offcanvas\",Hi=\"hidden.bs.offcanvas\",$i={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:\"(boolean|string)\",keyboard:\"boolean\",scroll:\"boolean\"};class Bi 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 $i}static get DefaultType(){return Wi}static get NAME(){return\"offcanvas\"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||I.trigger(this._element,\"show.bs.offcanvas\",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new pi).hide(),this._element.setAttribute(\"aria-modal\",!0),this._element.setAttribute(\"role\",\"dialog\"),this._element.classList.add(Pi),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Ni),this._element.classList.remove(Pi),I.trigger(this._element,\"shown.bs.offcanvas\",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(I.trigger(this._element,\"hide.bs.offcanvas\").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(ji),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Ni,ji),this._element.removeAttribute(\"aria-modal\"),this._element.removeAttribute(\"role\"),this._config.scroll||(new pi).reset(),I.trigger(this._element,Hi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new vi({className:\"offcanvas-backdrop\",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{\"static\"!==this._config.backdrop?this.hide():I.trigger(this._element,Fi)}:null})}_initializeFocusTrap(){return new Ti({trapElement:this._element})}_addEventListeners(){I.on(this._element,\"keydown.dismiss.bs.offcanvas\",(t=>{\"Escape\"===t.key&&(this._config.keyboard?this.hide():I.trigger(this._element,Fi))}))}static jQueryInterface(t){return this.each((function(){const e=Bi.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)}}))}}I.on(document,\"click.bs.offcanvas.data-api\",'[data-bs-toggle=\"offcanvas\"]',(function(t){const e=z.getElementFromSelector(this);if([\"A\",\"AREA\"].includes(this.tagName)&&t.preventDefault(),r(this))return;I.one(e,Hi,(()=>{o(this)&&this.focus()}));const i=z.findOne(Mi);i&&i!==e&&Bi.getInstance(i).hide(),Bi.getOrCreateInstance(e).toggle(this)})),I.on(window,\"load.bs.offcanvas.data-api\",(()=>{for(const t of z.find(Mi))Bi.getOrCreateInstance(t).show()})),I.on(window,\"resize.bs.offcanvas\",(()=>{for(const t of z.find(\"[aria-modal][class*=show][class*=offcanvas-]\"))\"fixed\"!==getComputedStyle(t).position&&Bi.getOrCreateInstance(t).hide()})),R(Bi),f(Bi);const zi=new Set([\"background\",\"cite\",\"href\",\"itemtype\",\"longdesc\",\"poster\",\"src\",\"xlink:href\"]),Ri=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,qi=/^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[\\d+/a-z]+=*$/i,Vi=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!zi.has(i)||Boolean(Ri.test(t.nodeValue)||qi.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Ki={\"*\":[\"class\",\"dir\",\"id\",\"lang\",\"role\",/^aria-[\\w-]*$/i],a:[\"target\",\"href\",\"title\",\"rel\"],area:[],b:[],br:[],col:[],code:[],div:[],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:[]},Qi={allowList:Ki,content:{},extraClass:\"\",html:!1,sanitize:!0,sanitizeFn:null,template:\"<div></div>\"},Xi={allowList:\"object\",content:\"object\",extraClass:\"(string|function)\",html:\"boolean\",sanitize:\"boolean\",sanitizeFn:\"(null|function)\",template:\"string\"},Yi={entry:\"(string|element|function|null)\",selector:\"(string|element)\"};class Ui extends ${constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Qi}static get DefaultType(){return Xi}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},Yi)}_setContent(t,e,i){const o=z.findOne(i,t);o&&((e=this._resolvePossibleFunction(e))?n(e)?this._putElementInTemplate(s(e),o):this._config.html?o.innerHTML=this._maybeSanitize(e):o.textContent=e:o.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)Vi(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return p(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML=\"\",void e.append(t);e.textContent=t.textContent}}const Gi=new Set([\"sanitize\",\"allowList\",\"sanitizeFn\"]),Ji=\"fade\",Zi=\"show\",tn=\".modal\",en=\"hide.bs.modal\",nn=\"hover\",sn=\"focus\",on={AUTO:\"auto\",TOP:\"top\",RIGHT:u()?\"left\":\"right\",BOTTOM:\"bottom\",LEFT:u()?\"right\":\"left\"},rn={allowList:Ki,animation:!0,boundary:\"clippingParents\",container:!1,customClass:\"\",delay:0,fallbackPlacements:[\"top\",\"right\",\"bottom\",\"left\"],html:!1,offset:[0,0],placement:\"top\",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',title:\"\",trigger:\"hover focus\"},an={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 ln extends W{constructor(t,e){if(void 0===Ve)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 rn}static get DefaultType(){return an}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),I.off(this._element.closest(tn),en,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=I.trigger(this._element,this.constructor.eventName(\"show\")),e=(a(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),I.trigger(this._element,this.constructor.eventName(\"inserted\"))),this._popper=this._createPopper(i),i.classList.add(Zi),\"ontouchstart\"in document.documentElement)for(const t of[].concat(...document.body.children))I.on(t,\"mouseover\",l);this._queueCallback((()=>{I.trigger(this._element,this.constructor.eventName(\"shown\")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!I.trigger(this._element,this.constructor.eventName(\"hide\")).defaultPrevented){if(this._getTipElement().classList.remove(Zi),\"ontouchstart\"in document.documentElement)for(const t of[].concat(...document.body.children))I.off(t,\"mouseover\",l);this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute(\"aria-describedby\"),I.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(Ji,Zi),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(Ji),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Ui({...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(Ji)}_isShown(){return this.tip&&this.tip.classList.contains(Zi)}_createPopper(t){const e=p(this._config.placement,[this,t,this._element]),i=on[e.toUpperCase()];return qe(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 p(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,...p(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(\" \");for(const e of t)if(\"click\"===e)I.on(this._element,this.constructor.eventName(\"click\"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if(\"manual\"!==e){const t=e===nn?this.constructor.eventName(\"mouseenter\"):this.constructor.eventName(\"focusin\"),i=e===nn?this.constructor.eventName(\"mouseleave\"):this.constructor.eventName(\"focusout\");I.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[\"focusin\"===t.type?sn:nn]=!0,e._enter()})),I.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[\"focusout\"===t.type?sn:nn]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},I.on(this._element.closest(tn),en,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=H.getDataAttributes(this._element);for(const t of Object.keys(e))Gi.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:s(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=ln.getOrCreateInstance(this,t);if(\"string\"==typeof t){if(void 0===e[t])throw new TypeError(`No method named \"${t}\"`);e[t]()}}))}}f(ln);const cn={...ln.Default,content:\"\",offset:[0,8],placement:\"right\",template:'<div class=\"popover\" role=\"tooltip\"><div class=\"popover-arrow\"></div><h3 class=\"popover-header\"></h3><div class=\"popover-body\"></div></div>',trigger:\"click\"},hn={...ln.DefaultType,content:\"(null|string|element|function)\"};class dn extends ln{static get Default(){return cn}static get DefaultType(){return hn}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=dn.getOrCreateInstance(this,t);if(\"string\"==typeof t){if(void 0===e[t])throw new TypeError(`No method named \"${t}\"`);e[t]()}}))}}f(dn);const un=\"click.bs.scrollspy\",fn=\"active\",pn=\"[href]\",mn={offset:null,rootMargin:\"0px 0px -25%\",smoothScroll:!1,target:null,threshold:[.1,.5,1]},gn={offset:\"(number|null)\",rootMargin:\"string\",smoothScroll:\"boolean\",target:\"element\",threshold:\"array\"};class _n 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 mn}static get DefaultType(){return gn}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=s(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&&(I.off(this._config.target,un),I.on(this._config.target,un,pn,(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(pn,this._config.target);for(const e of t){if(!e.hash||r(e))continue;const t=z.findOne(e.hash,this._element);o(t)&&(this._targetLinks.set(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(fn),this._activateParents(t),I.trigger(this._element,\"activate.bs.scrollspy\",{relatedTarget:t}))}_activateParents(t){if(t.classList.contains(\"dropdown-item\"))z.findOne(\".dropdown-toggle\",t.closest(\".dropdown\")).classList.add(fn);else for(const e of z.parents(t,\".nav, .list-group\"))for(const t of z.prev(e,\".nav-link, .nav-item > .nav-link, .list-group-item\"))t.classList.add(fn)}_clearActiveClass(t){t.classList.remove(fn);const e=z.find(\"[href].active\",t);for(const t of e)t.classList.remove(fn)}static jQueryInterface(t){return this.each((function(){const e=_n.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]()}}))}}I.on(window,\"load.bs.scrollspy.data-api\",(()=>{for(const t of z.find('[data-bs-spy=\"scroll\"]'))_n.getOrCreateInstance(t)})),f(_n);const bn=\"ArrowLeft\",vn=\"ArrowRight\",yn=\"ArrowUp\",wn=\"ArrowDown\",An=\"active\",En=\"fade\",Tn=\"show\",Cn='[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]',On=`.nav-link:not(.dropdown-toggle), .list-group-item:not(.dropdown-toggle), [role=\"tab\"]:not(.dropdown-toggle), ${Cn}`;class xn extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role=\"tablist\"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),I.on(this._element,\"keydown.bs.tab\",(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?I.trigger(e,\"hide.bs.tab\",{relatedTarget:t}):null;I.trigger(t,\"show.bs.tab\",{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(An),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{\"tab\"===t.getAttribute(\"role\")?(t.removeAttribute(\"tabindex\"),t.setAttribute(\"aria-selected\",!0),this._toggleDropDown(t,!0),I.trigger(t,\"shown.bs.tab\",{relatedTarget:e})):t.classList.add(Tn)}),t,t.classList.contains(En)))}_deactivate(t,e){t&&(t.classList.remove(An),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),I.trigger(t,\"hidden.bs.tab\",{relatedTarget:e})):t.classList.remove(Tn)}),t,t.classList.contains(En)))}_keydown(t){if(![bn,vn,yn,wn].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=[vn,wn].includes(t.key),i=g(this._getChildren().filter((t=>!r(t))),t.target,e,!0);i&&(i.focus({preventScroll:!0}),xn.getOrCreateInstance(i).show())}_getChildren(){return z.find(On,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(\".dropdown-toggle\",An),n(\".dropdown-menu\",Tn),i.setAttribute(\"aria-expanded\",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(An)}_getInnerElement(t){return t.matches(On)?t:z.findOne(On,t)}_getOuterElement(t){return t.closest(\".nav-item, .list-group-item\")||t}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if(\"string\"==typeof t){if(void 0===e[t]||t.startsWith(\"_\")||\"constructor\"===t)throw new TypeError(`No method named \"${t}\"`);e[t]()}}))}}I.on(document,\"click.bs.tab\",Cn,(function(t){[\"A\",\"AREA\"].includes(this.tagName)&&t.preventDefault(),r(this)||xn.getOrCreateInstance(this).show()})),I.on(window,\"load.bs.tab\",(()=>{for(const t of z.find('.active[data-bs-toggle=\"tab\"], .active[data-bs-toggle=\"pill\"], .active[data-bs-toggle=\"list\"]'))xn.getOrCreateInstance(t)})),f(xn);const kn=\"hide\",Ln=\"show\",Sn=\"showing\",Dn={animation:\"boolean\",autohide:\"boolean\",delay:\"number\"},In={animation:!0,autohide:!0,delay:5e3};class Nn extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return In}static get DefaultType(){return Dn}static get NAME(){return\"toast\"}show(){I.trigger(this._element,\"show.bs.toast\").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add(\"fade\"),this._element.classList.remove(kn),c(this._element),this._element.classList.add(Ln,Sn),this._queueCallback((()=>{this._element.classList.remove(Sn),I.trigger(this._element,\"shown.bs.toast\"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(I.trigger(this._element,\"hide.bs.toast\").defaultPrevented||(this._element.classList.add(Sn),this._queueCallback((()=>{this._element.classList.add(kn),this._element.classList.remove(Sn,Ln),I.trigger(this._element,\"hidden.bs.toast\")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(Ln),super.dispose()}isShown(){return this._element.classList.contains(Ln)}_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(){I.on(this._element,\"mouseover.bs.toast\",(t=>this._onInteraction(t,!0))),I.on(this._element,\"mouseout.bs.toast\",(t=>this._onInteraction(t,!1))),I.on(this._element,\"focusin.bs.toast\",(t=>this._onInteraction(t,!0))),I.on(this._element,\"focusout.bs.toast\",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Nn.getOrCreateInstance(this,t);if(\"string\"==typeof t){if(void 0===e[t])throw new TypeError(`No method named \"${t}\"`);e[t](this)}}))}}return R(Nn),f(Nn),{Alert:q,Button:K,Carousel:rt,Collapse:ft,Dropdown:ci,Modal:Ii,Offcanvas:Bi,Popover:dn,ScrollSpy:_n,Tab:xn,Toast:Nn,Tooltip:ln}}));\n//# sourceMappingURL=bootstrap.bundle.min.js.map"
  },
  {
    "path": "hiauth-server/src/main/resources/static/bootstrap-5.3.0/js/bootstrap.bundle.min.js.map",
    "content": "{\"version\":3,\"names\":[\"TRANSITION_END\",\"parseSelector\",\"selector\",\"window\",\"CSS\",\"escape\",\"replace\",\"match\",\"id\",\"triggerTransitionEnd\",\"element\",\"dispatchEvent\",\"Event\",\"isElement\",\"object\",\"jquery\",\"nodeType\",\"getElement\",\"length\",\"document\",\"querySelector\",\"isVisible\",\"getClientRects\",\"elementIsVisible\",\"getComputedStyle\",\"getPropertyValue\",\"closedDetails\",\"closest\",\"summary\",\"parentNode\",\"isDisabled\",\"Node\",\"ELEMENT_NODE\",\"classList\",\"contains\",\"disabled\",\"hasAttribute\",\"getAttribute\",\"findShadowRoot\",\"documentElement\",\"attachShadow\",\"getRootNode\",\"root\",\"ShadowRoot\",\"noop\",\"reflow\",\"offsetHeight\",\"getjQuery\",\"jQuery\",\"body\",\"DOMContentLoadedCallbacks\",\"isRTL\",\"dir\",\"defineJQueryPlugin\",\"plugin\",\"callback\",\"$\",\"name\",\"NAME\",\"JQUERY_NO_CONFLICT\",\"fn\",\"jQueryInterface\",\"Constructor\",\"noConflict\",\"readyState\",\"addEventListener\",\"push\",\"execute\",\"possibleCallback\",\"args\",\"defaultValue\",\"executeAfterTransition\",\"transitionElement\",\"waitForTransition\",\"emulatedDuration\",\"transitionDuration\",\"transitionDelay\",\"floatTransitionDuration\",\"Number\",\"parseFloat\",\"floatTransitionDelay\",\"split\",\"getTransitionDurationFromElement\",\"called\",\"handler\",\"target\",\"removeEventListener\",\"setTimeout\",\"getNextActiveElement\",\"list\",\"activeElement\",\"shouldGetNext\",\"isCycleAllowed\",\"listLength\",\"index\",\"indexOf\",\"Math\",\"max\",\"min\",\"namespaceRegex\",\"stripNameRegex\",\"stripUidRegex\",\"eventRegistry\",\"uidEvent\",\"customEvents\",\"mouseenter\",\"mouseleave\",\"nativeEvents\",\"Set\",\"makeEventUid\",\"uid\",\"getElementEvents\",\"findHandler\",\"events\",\"callable\",\"delegationSelector\",\"Object\",\"values\",\"find\",\"event\",\"normalizeParameters\",\"originalTypeEvent\",\"delegationFunction\",\"isDelegated\",\"typeEvent\",\"getTypeEvent\",\"has\",\"addHandler\",\"oneOff\",\"wrapFunction\",\"relatedTarget\",\"delegateTarget\",\"call\",\"this\",\"handlers\",\"previousFunction\",\"domElements\",\"querySelectorAll\",\"domElement\",\"hydrateObj\",\"EventHandler\",\"off\",\"type\",\"apply\",\"bootstrapDelegationHandler\",\"bootstrapHandler\",\"removeHandler\",\"Boolean\",\"removeNamespacedHandlers\",\"namespace\",\"storeElementEvent\",\"handlerKey\",\"entries\",\"includes\",\"on\",\"one\",\"inNamespace\",\"isNamespace\",\"startsWith\",\"elementEvent\",\"keys\",\"slice\",\"keyHandlers\",\"trigger\",\"jQueryEvent\",\"bubbles\",\"nativeDispatch\",\"defaultPrevented\",\"isPropagationStopped\",\"isImmediatePropagationStopped\",\"isDefaultPrevented\",\"evt\",\"cancelable\",\"preventDefault\",\"obj\",\"meta\",\"key\",\"value\",\"_unused\",\"defineProperty\",\"configurable\",\"get\",\"elementMap\",\"Map\",\"Data\",\"set\",\"instance\",\"instanceMap\",\"size\",\"console\",\"error\",\"Array\",\"from\",\"remove\",\"delete\",\"normalizeData\",\"toString\",\"JSON\",\"parse\",\"decodeURIComponent\",\"normalizeDataKey\",\"chr\",\"toLowerCase\",\"Manipulator\",\"setDataAttribute\",\"setAttribute\",\"removeDataAttribute\",\"removeAttribute\",\"getDataAttributes\",\"attributes\",\"bsKeys\",\"dataset\",\"filter\",\"pureKey\",\"charAt\",\"getDataAttribute\",\"Config\",\"Default\",\"DefaultType\",\"Error\",\"_getConfig\",\"config\",\"_mergeConfigObj\",\"_configAfterMerge\",\"_typeCheckConfig\",\"jsonConfig\",\"constructor\",\"configTypes\",\"property\",\"expectedTypes\",\"valueType\",\"prototype\",\"RegExp\",\"test\",\"TypeError\",\"toUpperCase\",\"BaseComponent\",\"super\",\"_element\",\"_config\",\"DATA_KEY\",\"dispose\",\"EVENT_KEY\",\"propertyName\",\"getOwnPropertyNames\",\"_queueCallback\",\"isAnimated\",\"static\",\"getInstance\",\"VERSION\",\"getSelector\",\"hrefAttribute\",\"trim\",\"SelectorEngine\",\"concat\",\"Element\",\"findOne\",\"children\",\"child\",\"matches\",\"parents\",\"ancestor\",\"prev\",\"previous\",\"previousElementSibling\",\"next\",\"nextElementSibling\",\"focusableChildren\",\"focusables\",\"map\",\"join\",\"el\",\"getSelectorFromElement\",\"getElementFromSelector\",\"getMultipleElementsFromSelector\",\"enableDismissTrigger\",\"component\",\"method\",\"clickEvent\",\"tagName\",\"getOrCreateInstance\",\"Alert\",\"close\",\"_destroyElement\",\"each\",\"data\",\"undefined\",\"SELECTOR_DATA_TOGGLE\",\"Button\",\"toggle\",\"button\",\"endCallback\",\"leftCallback\",\"rightCallback\",\"Swipe\",\"isSupported\",\"_deltaX\",\"_supportPointerEvents\",\"PointerEvent\",\"_initEvents\",\"_start\",\"_eventIsPointerPenTouch\",\"clientX\",\"touches\",\"_end\",\"_handleSwipe\",\"_move\",\"absDeltaX\",\"abs\",\"direction\",\"add\",\"pointerType\",\"navigator\",\"maxTouchPoints\",\"ORDER_NEXT\",\"ORDER_PREV\",\"DIRECTION_LEFT\",\"DIRECTION_RIGHT\",\"EVENT_SLID\",\"CLASS_NAME_CAROUSEL\",\"CLASS_NAME_ACTIVE\",\"KEY_TO_DIRECTION\",\"ArrowLeft\",\"ArrowRight\",\"interval\",\"keyboard\",\"pause\",\"ride\",\"touch\",\"wrap\",\"Carousel\",\"_interval\",\"_activeElement\",\"_isSliding\",\"touchTimeout\",\"_swipeHelper\",\"_indicatorsElement\",\"_addEventListeners\",\"cycle\",\"_slide\",\"nextWhenVisible\",\"hidden\",\"_clearInterval\",\"_updateInterval\",\"setInterval\",\"_maybeEnableCycle\",\"to\",\"items\",\"_getItems\",\"activeIndex\",\"_getItemIndex\",\"_getActive\",\"order\",\"defaultInterval\",\"_keydown\",\"_addTouchEventListeners\",\"img\",\"swipeConfig\",\"_directionToOrder\",\"clearTimeout\",\"_setActiveIndicatorElement\",\"activeIndicator\",\"newActiveIndicator\",\"elementInterval\",\"parseInt\",\"isNext\",\"nextElement\",\"nextElementIndex\",\"triggerEvent\",\"eventName\",\"_orderToDirection\",\"isCycling\",\"directionalClassName\",\"orderClassName\",\"_isAnimated\",\"SELECTOR_ACTIVE\",\"clearInterval\",\"carousel\",\"slideIndex\",\"carousels\",\"CLASS_NAME_SHOW\",\"CLASS_NAME_COLLAPSE\",\"CLASS_NAME_COLLAPSING\",\"parent\",\"Collapse\",\"_isTransitioning\",\"_triggerArray\",\"toggleList\",\"elem\",\"filterElement\",\"foundElement\",\"_initializeChildren\",\"_addAriaAndCollapsedClass\",\"_isShown\",\"hide\",\"show\",\"activeChildren\",\"_getFirstLevelChildren\",\"activeInstance\",\"dimension\",\"_getDimension\",\"style\",\"scrollSize\",\"getBoundingClientRect\",\"selected\",\"triggerArray\",\"isOpen\",\"top\",\"bottom\",\"right\",\"left\",\"auto\",\"basePlacements\",\"start\",\"end\",\"clippingParents\",\"viewport\",\"popper\",\"reference\",\"variationPlacements\",\"reduce\",\"acc\",\"placement\",\"placements\",\"beforeRead\",\"read\",\"afterRead\",\"beforeMain\",\"main\",\"afterMain\",\"beforeWrite\",\"write\",\"afterWrite\",\"modifierPhases\",\"getNodeName\",\"nodeName\",\"getWindow\",\"node\",\"ownerDocument\",\"defaultView\",\"isHTMLElement\",\"HTMLElement\",\"isShadowRoot\",\"applyStyles$1\",\"enabled\",\"phase\",\"_ref\",\"state\",\"elements\",\"forEach\",\"styles\",\"assign\",\"effect\",\"_ref2\",\"initialStyles\",\"position\",\"options\",\"strategy\",\"margin\",\"arrow\",\"hasOwnProperty\",\"attribute\",\"requires\",\"getBasePlacement\",\"round\",\"getUAString\",\"uaData\",\"userAgentData\",\"brands\",\"item\",\"brand\",\"version\",\"userAgent\",\"isLayoutViewport\",\"includeScale\",\"isFixedStrategy\",\"clientRect\",\"scaleX\",\"scaleY\",\"offsetWidth\",\"width\",\"height\",\"visualViewport\",\"addVisualOffsets\",\"x\",\"offsetLeft\",\"y\",\"offsetTop\",\"getLayoutRect\",\"rootNode\",\"isSameNode\",\"host\",\"isTableElement\",\"getDocumentElement\",\"getParentNode\",\"assignedSlot\",\"getTrueOffsetParent\",\"offsetParent\",\"getOffsetParent\",\"isFirefox\",\"currentNode\",\"css\",\"transform\",\"perspective\",\"contain\",\"willChange\",\"getContainingBlock\",\"getMainAxisFromPlacement\",\"within\",\"mathMax\",\"mathMin\",\"mergePaddingObject\",\"paddingObject\",\"expandToHashMap\",\"hashMap\",\"arrow$1\",\"_state$modifiersData$\",\"arrowElement\",\"popperOffsets\",\"modifiersData\",\"basePlacement\",\"axis\",\"len\",\"padding\",\"rects\",\"toPaddingObject\",\"arrowRect\",\"minProp\",\"maxProp\",\"endDiff\",\"startDiff\",\"arrowOffsetParent\",\"clientSize\",\"clientHeight\",\"clientWidth\",\"centerToReference\",\"center\",\"offset\",\"axisProp\",\"centerOffset\",\"_options$element\",\"requiresIfExists\",\"getVariation\",\"unsetSides\",\"mapToStyles\",\"_Object$assign2\",\"popperRect\",\"variation\",\"offsets\",\"gpuAcceleration\",\"adaptive\",\"roundOffsets\",\"isFixed\",\"_offsets$x\",\"_offsets$y\",\"_ref3\",\"hasX\",\"hasY\",\"sideX\",\"sideY\",\"win\",\"heightProp\",\"widthProp\",\"_Object$assign\",\"commonStyles\",\"_ref4\",\"dpr\",\"devicePixelRatio\",\"roundOffsetsByDPR\",\"computeStyles$1\",\"_ref5\",\"_options$gpuAccelerat\",\"_options$adaptive\",\"_options$roundOffsets\",\"passive\",\"eventListeners\",\"_options$scroll\",\"scroll\",\"_options$resize\",\"resize\",\"scrollParents\",\"scrollParent\",\"update\",\"hash\",\"getOppositePlacement\",\"matched\",\"getOppositeVariationPlacement\",\"getWindowScroll\",\"scrollLeft\",\"pageXOffset\",\"scrollTop\",\"pageYOffset\",\"getWindowScrollBarX\",\"isScrollParent\",\"_getComputedStyle\",\"overflow\",\"overflowX\",\"overflowY\",\"getScrollParent\",\"listScrollParents\",\"_element$ownerDocumen\",\"isBody\",\"updatedList\",\"rectToClientRect\",\"rect\",\"getClientRectFromMixedType\",\"clippingParent\",\"html\",\"layoutViewport\",\"getViewportRect\",\"clientTop\",\"clientLeft\",\"getInnerBoundingClientRect\",\"winScroll\",\"scrollWidth\",\"scrollHeight\",\"getDocumentRect\",\"computeOffsets\",\"commonX\",\"commonY\",\"mainAxis\",\"detectOverflow\",\"_options\",\"_options$placement\",\"_options$strategy\",\"_options$boundary\",\"boundary\",\"_options$rootBoundary\",\"rootBoundary\",\"_options$elementConte\",\"elementContext\",\"_options$altBoundary\",\"altBoundary\",\"_options$padding\",\"altContext\",\"clippingClientRect\",\"mainClippingParents\",\"clipperElement\",\"getClippingParents\",\"firstClippingParent\",\"clippingRect\",\"accRect\",\"getClippingRect\",\"contextElement\",\"referenceClientRect\",\"popperClientRect\",\"elementClientRect\",\"overflowOffsets\",\"offsetData\",\"multiply\",\"computeAutoPlacement\",\"flipVariations\",\"_options$allowedAutoP\",\"allowedAutoPlacements\",\"allPlacements\",\"allowedPlacements\",\"overflows\",\"sort\",\"a\",\"b\",\"flip$1\",\"_skip\",\"_options$mainAxis\",\"checkMainAxis\",\"_options$altAxis\",\"altAxis\",\"checkAltAxis\",\"specifiedFallbackPlacements\",\"fallbackPlacements\",\"_options$flipVariatio\",\"preferredPlacement\",\"oppositePlacement\",\"getExpandedFallbackPlacements\",\"referenceRect\",\"checksMap\",\"makeFallbackChecks\",\"firstFittingPlacement\",\"i\",\"_basePlacement\",\"isStartVariation\",\"isVertical\",\"mainVariationSide\",\"altVariationSide\",\"checks\",\"every\",\"check\",\"_loop\",\"_i\",\"fittingPlacement\",\"reset\",\"getSideOffsets\",\"preventedOffsets\",\"isAnySideFullyClipped\",\"some\",\"side\",\"hide$1\",\"preventOverflow\",\"referenceOverflow\",\"popperAltOverflow\",\"referenceClippingOffsets\",\"popperEscapeOffsets\",\"isReferenceHidden\",\"hasPopperEscaped\",\"offset$1\",\"_options$offset\",\"invertDistance\",\"skidding\",\"distance\",\"distanceAndSkiddingToXY\",\"_data$state$placement\",\"popperOffsets$1\",\"preventOverflow$1\",\"_options$tether\",\"tether\",\"_options$tetherOffset\",\"tetherOffset\",\"isBasePlacement\",\"tetherOffsetValue\",\"normalizedTetherOffsetValue\",\"offsetModifierState\",\"_offsetModifierState$\",\"mainSide\",\"altSide\",\"additive\",\"minLen\",\"maxLen\",\"arrowPaddingObject\",\"arrowPaddingMin\",\"arrowPaddingMax\",\"arrowLen\",\"minOffset\",\"maxOffset\",\"clientOffset\",\"offsetModifierValue\",\"tetherMax\",\"preventedOffset\",\"_offsetModifierState$2\",\"_mainSide\",\"_altSide\",\"_offset\",\"_len\",\"_min\",\"_max\",\"isOriginSide\",\"_offsetModifierValue\",\"_tetherMin\",\"_tetherMax\",\"_preventedOffset\",\"v\",\"withinMaxClamp\",\"getCompositeRect\",\"elementOrVirtualElement\",\"isOffsetParentAnElement\",\"offsetParentIsScaled\",\"isElementScaled\",\"modifiers\",\"visited\",\"result\",\"modifier\",\"dep\",\"depModifier\",\"DEFAULT_OPTIONS\",\"areValidElements\",\"arguments\",\"_key\",\"popperGenerator\",\"generatorOptions\",\"_generatorOptions\",\"_generatorOptions$def\",\"defaultModifiers\",\"_generatorOptions$def2\",\"defaultOptions\",\"pending\",\"orderedModifiers\",\"effectCleanupFns\",\"isDestroyed\",\"setOptions\",\"setOptionsAction\",\"cleanupModifierEffects\",\"merged\",\"orderModifiers\",\"current\",\"existing\",\"m\",\"_ref3$options\",\"cleanupFn\",\"forceUpdate\",\"_state$elements\",\"_state$orderedModifie\",\"_state$orderedModifie2\",\"Promise\",\"resolve\",\"then\",\"destroy\",\"onFirstUpdate\",\"createPopper\",\"computeStyles\",\"applyStyles\",\"flip\",\"ARROW_UP_KEY\",\"ARROW_DOWN_KEY\",\"EVENT_CLICK_DATA_API\",\"EVENT_KEYDOWN_DATA_API\",\"SELECTOR_DATA_TOGGLE_SHOWN\",\"SELECTOR_MENU\",\"PLACEMENT_TOP\",\"PLACEMENT_TOPEND\",\"PLACEMENT_BOTTOM\",\"PLACEMENT_BOTTOMEND\",\"PLACEMENT_RIGHT\",\"PLACEMENT_LEFT\",\"autoClose\",\"display\",\"popperConfig\",\"Dropdown\",\"_popper\",\"_parent\",\"_menu\",\"_inNavbar\",\"_detectNavbar\",\"_createPopper\",\"focus\",\"_completeHide\",\"Popper\",\"referenceElement\",\"_getPopperConfig\",\"_getPlacement\",\"parentDropdown\",\"isEnd\",\"_getOffset\",\"popperData\",\"defaultBsPopperConfig\",\"_selectMenuItem\",\"openToggles\",\"context\",\"composedPath\",\"isMenuTarget\",\"isInput\",\"isEscapeEvent\",\"isUpOrDownEvent\",\"getToggleButton\",\"stopPropagation\",\"dataApiKeydownHandler\",\"clearMenus\",\"SELECTOR_FIXED_CONTENT\",\"SELECTOR_STICKY_CONTENT\",\"PROPERTY_PADDING\",\"PROPERTY_MARGIN\",\"ScrollBarHelper\",\"getWidth\",\"documentWidth\",\"innerWidth\",\"_disableOverFlow\",\"_setElementAttributes\",\"calculatedValue\",\"_resetElementAttributes\",\"isOverflowing\",\"_saveInitialAttribute\",\"styleProperty\",\"scrollbarWidth\",\"_applyManipulationCallback\",\"setProperty\",\"actualValue\",\"removeProperty\",\"callBack\",\"sel\",\"EVENT_MOUSEDOWN\",\"className\",\"clickCallback\",\"rootElement\",\"Backdrop\",\"_isAppended\",\"_append\",\"_getElement\",\"_emulateAnimation\",\"backdrop\",\"createElement\",\"append\",\"TAB_NAV_BACKWARD\",\"autofocus\",\"trapElement\",\"FocusTrap\",\"_isActive\",\"_lastTabNavDirection\",\"activate\",\"_handleFocusin\",\"_handleKeydown\",\"deactivate\",\"shiftKey\",\"EVENT_HIDDEN\",\"EVENT_SHOW\",\"CLASS_NAME_OPEN\",\"CLASS_NAME_STATIC\",\"Modal\",\"_dialog\",\"_backdrop\",\"_initializeBackDrop\",\"_focustrap\",\"_initializeFocusTrap\",\"_scrollBar\",\"_adjustDialog\",\"_showElement\",\"_hideModal\",\"htmlElement\",\"handleUpdate\",\"modalBody\",\"_triggerBackdropTransition\",\"event2\",\"_resetAdjustments\",\"isModalOverflowing\",\"initialOverflowY\",\"isBodyOverflowing\",\"paddingLeft\",\"paddingRight\",\"showEvent\",\"alreadyOpen\",\"CLASS_NAME_SHOWING\",\"CLASS_NAME_HIDING\",\"OPEN_SELECTOR\",\"EVENT_HIDE_PREVENTED\",\"Offcanvas\",\"blur\",\"uriAttributes\",\"SAFE_URL_PATTERN\",\"DATA_URL_PATTERN\",\"allowedAttribute\",\"allowedAttributeList\",\"attributeName\",\"nodeValue\",\"attributeRegex\",\"regex\",\"DefaultAllowlist\",\"area\",\"br\",\"col\",\"code\",\"div\",\"em\",\"hr\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"li\",\"ol\",\"p\",\"pre\",\"s\",\"small\",\"span\",\"sub\",\"sup\",\"strong\",\"u\",\"ul\",\"allowList\",\"content\",\"extraClass\",\"sanitize\",\"sanitizeFn\",\"template\",\"DefaultContentType\",\"entry\",\"TemplateFactory\",\"getContent\",\"_resolvePossibleFunction\",\"hasContent\",\"changeContent\",\"_checkContent\",\"toHtml\",\"templateWrapper\",\"innerHTML\",\"_maybeSanitize\",\"text\",\"_setContent\",\"arg\",\"templateElement\",\"_putElementInTemplate\",\"textContent\",\"unsafeHtml\",\"sanitizeFunction\",\"createdDocument\",\"DOMParser\",\"parseFromString\",\"elementName\",\"attributeList\",\"allowedAttributes\",\"sanitizeHtml\",\"DISALLOWED_ATTRIBUTES\",\"CLASS_NAME_FADE\",\"SELECTOR_MODAL\",\"EVENT_MODAL_HIDE\",\"TRIGGER_HOVER\",\"TRIGGER_FOCUS\",\"AttachmentMap\",\"AUTO\",\"TOP\",\"RIGHT\",\"BOTTOM\",\"LEFT\",\"animation\",\"container\",\"customClass\",\"delay\",\"title\",\"Tooltip\",\"_isEnabled\",\"_timeout\",\"_isHovered\",\"_activeTrigger\",\"_templateFactory\",\"_newContent\",\"tip\",\"_setListeners\",\"_fixTitle\",\"enable\",\"disable\",\"toggleEnabled\",\"click\",\"_leave\",\"_enter\",\"_hideModalHandler\",\"_disposePopper\",\"_isWithContent\",\"isInTheDom\",\"_getTipElement\",\"_isWithActiveTrigger\",\"_getTitle\",\"_createTipElement\",\"_getContentForTemplate\",\"_getTemplateFactory\",\"tipId\",\"prefix\",\"floor\",\"random\",\"getElementById\",\"getUID\",\"setContent\",\"_initializeOnDelegatedTarget\",\"_getDelegateConfig\",\"attachment\",\"triggers\",\"eventIn\",\"eventOut\",\"_setTimeout\",\"timeout\",\"dataAttributes\",\"dataAttribute\",\"Popover\",\"_getContent\",\"EVENT_CLICK\",\"SELECTOR_TARGET_LINKS\",\"rootMargin\",\"smoothScroll\",\"threshold\",\"ScrollSpy\",\"_targetLinks\",\"_observableSections\",\"_rootElement\",\"_activeTarget\",\"_observer\",\"_previousScrollData\",\"visibleEntryTop\",\"parentScrollTop\",\"refresh\",\"_initializeTargetsAndObservables\",\"_maybeEnableSmoothScroll\",\"disconnect\",\"_getNewObserver\",\"section\",\"observe\",\"observableSection\",\"scrollTo\",\"behavior\",\"IntersectionObserver\",\"_observerCallback\",\"targetElement\",\"_process\",\"userScrollsDown\",\"isIntersecting\",\"_clearActiveClass\",\"entryIsLowerThanPrevious\",\"targetLinks\",\"anchor\",\"_activateParents\",\"listGroup\",\"activeNodes\",\"spy\",\"ARROW_LEFT_KEY\",\"ARROW_RIGHT_KEY\",\"SELECTOR_INNER_ELEM\",\"Tab\",\"_setInitialAttributes\",\"_getChildren\",\"innerElem\",\"_elemIsActive\",\"active\",\"_getActiveElem\",\"hideEvent\",\"_deactivate\",\"_activate\",\"relatedElem\",\"_toggleDropDown\",\"nextActiveElement\",\"preventScroll\",\"_setAttributeIfNotExists\",\"_setInitialAttributesOnChild\",\"_getInnerElement\",\"isActive\",\"outerElem\",\"_getOuterElement\",\"_setInitialAttributesOnTargetPanel\",\"open\",\"CLASS_NAME_HIDE\",\"autohide\",\"Toast\",\"_hasMouseInteraction\",\"_hasKeyboardInteraction\",\"_clearTimeout\",\"_maybeScheduleHide\",\"isShown\",\"_onInteraction\",\"isInteracting\"],\"sources\":[\"../../js/src/util/index.js\",\"../../js/src/dom/event-handler.js\",\"../../js/src/dom/data.js\",\"../../js/src/dom/manipulator.js\",\"../../js/src/util/config.js\",\"../../js/src/base-component.js\",\"../../js/src/dom/selector-engine.js\",\"../../js/src/util/component-functions.js\",\"../../js/src/alert.js\",\"../../js/src/button.js\",\"../../js/src/util/swipe.js\",\"../../js/src/carousel.js\",\"../../js/src/collapse.js\",\"../../node_modules/@popperjs/core/lib/enums.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js\",\"../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js\",\"../../node_modules/@popperjs/core/lib/utils/getBasePlacement.js\",\"../../node_modules/@popperjs/core/lib/utils/math.js\",\"../../node_modules/@popperjs/core/lib/utils/userAgent.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/contains.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/isTableElement.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getParentNode.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js\",\"../../node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js\",\"../../node_modules/@popperjs/core/lib/utils/within.js\",\"../../node_modules/@popperjs/core/lib/utils/mergePaddingObject.js\",\"../../node_modules/@popperjs/core/lib/utils/getFreshSideObject.js\",\"../../node_modules/@popperjs/core/lib/utils/expandToHashMap.js\",\"../../node_modules/@popperjs/core/lib/modifiers/arrow.js\",\"../../node_modules/@popperjs/core/lib/utils/getVariation.js\",\"../../node_modules/@popperjs/core/lib/modifiers/computeStyles.js\",\"../../node_modules/@popperjs/core/lib/modifiers/eventListeners.js\",\"../../node_modules/@popperjs/core/lib/utils/getOppositePlacement.js\",\"../../node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js\",\"../../node_modules/@popperjs/core/lib/utils/rectToClientRect.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js\",\"../../node_modules/@popperjs/core/lib/utils/computeOffsets.js\",\"../../node_modules/@popperjs/core/lib/utils/detectOverflow.js\",\"../../node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js\",\"../../node_modules/@popperjs/core/lib/modifiers/flip.js\",\"../../node_modules/@popperjs/core/lib/modifiers/hide.js\",\"../../node_modules/@popperjs/core/lib/modifiers/offset.js\",\"../../node_modules/@popperjs/core/lib/modifiers/popperOffsets.js\",\"../../node_modules/@popperjs/core/lib/modifiers/preventOverflow.js\",\"../../node_modules/@popperjs/core/lib/utils/getAltAxis.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js\",\"../../node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js\",\"../../node_modules/@popperjs/core/lib/utils/orderModifiers.js\",\"../../node_modules/@popperjs/core/lib/createPopper.js\",\"../../node_modules/@popperjs/core/lib/utils/debounce.js\",\"../../node_modules/@popperjs/core/lib/utils/mergeByName.js\",\"../../node_modules/@popperjs/core/lib/popper-lite.js\",\"../../node_modules/@popperjs/core/lib/popper.js\",\"../../js/src/dropdown.js\",\"../../js/src/util/scrollbar.js\",\"../../js/src/util/backdrop.js\",\"../../js/src/util/focustrap.js\",\"../../js/src/modal.js\",\"../../js/src/offcanvas.js\",\"../../js/src/util/sanitizer.js\",\"../../js/src/util/template-factory.js\",\"../../js/src/tooltip.js\",\"../../js/src/popover.js\",\"../../js/src/scrollspy.js\",\"../../js/src/tab.js\",\"../../js/src/toast.js\",\"../../js/index.umd.js\"],\"sourcesContent\":[\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/index.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nconst MAX_UID = 1_000_000\\nconst MILLISECONDS_MULTIPLIER = 1000\\nconst TRANSITION_END = 'transitionend'\\n\\n/**\\n * Properly escape IDs selectors to handle weird IDs\\n * @param {string} selector\\n * @returns {string}\\n */\\nconst parseSelector = selector => {\\n  if (selector && window.CSS && window.CSS.escape) {\\n    // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\\n    selector = selector.replace(/#([^\\\\s\\\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\\n  }\\n\\n  return selector\\n}\\n\\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\\nconst toType = object => {\\n  if (object === null || object === undefined) {\\n    return `${object}`\\n  }\\n\\n  return Object.prototype.toString.call(object).match(/\\\\s([a-z]+)/i)[1].toLowerCase()\\n}\\n\\n/**\\n * Public Util API\\n */\\n\\nconst getUID = prefix => {\\n  do {\\n    prefix += Math.floor(Math.random() * MAX_UID)\\n  } while (document.getElementById(prefix))\\n\\n  return prefix\\n}\\n\\nconst getTransitionDurationFromElement = element => {\\n  if (!element) {\\n    return 0\\n  }\\n\\n  // Get transition-duration of the element\\n  let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\\n\\n  const floatTransitionDuration = Number.parseFloat(transitionDuration)\\n  const floatTransitionDelay = Number.parseFloat(transitionDelay)\\n\\n  // Return 0 if element or transition duration is not found\\n  if (!floatTransitionDuration && !floatTransitionDelay) {\\n    return 0\\n  }\\n\\n  // If multiple durations are defined, take the first\\n  transitionDuration = transitionDuration.split(',')[0]\\n  transitionDelay = transitionDelay.split(',')[0]\\n\\n  return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\\n}\\n\\nconst triggerTransitionEnd = element => {\\n  element.dispatchEvent(new Event(TRANSITION_END))\\n}\\n\\nconst isElement = object => {\\n  if (!object || typeof object !== 'object') {\\n    return false\\n  }\\n\\n  if (typeof object.jquery !== 'undefined') {\\n    object = object[0]\\n  }\\n\\n  return typeof object.nodeType !== 'undefined'\\n}\\n\\nconst getElement = object => {\\n  // it's a jQuery object or a node element\\n  if (isElement(object)) {\\n    return object.jquery ? object[0] : object\\n  }\\n\\n  if (typeof object === 'string' && object.length > 0) {\\n    return document.querySelector(parseSelector(object))\\n  }\\n\\n  return null\\n}\\n\\nconst isVisible = element => {\\n  if (!isElement(element) || element.getClientRects().length === 0) {\\n    return false\\n  }\\n\\n  const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\\n  // Handle `details` element as its content may falsie appear visible when it is closed\\n  const closedDetails = element.closest('details:not([open])')\\n\\n  if (!closedDetails) {\\n    return elementIsVisible\\n  }\\n\\n  if (closedDetails !== element) {\\n    const summary = element.closest('summary')\\n    if (summary && summary.parentNode !== closedDetails) {\\n      return false\\n    }\\n\\n    if (summary === null) {\\n      return false\\n    }\\n  }\\n\\n  return elementIsVisible\\n}\\n\\nconst isDisabled = element => {\\n  if (!element || element.nodeType !== Node.ELEMENT_NODE) {\\n    return true\\n  }\\n\\n  if (element.classList.contains('disabled')) {\\n    return true\\n  }\\n\\n  if (typeof element.disabled !== 'undefined') {\\n    return element.disabled\\n  }\\n\\n  return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\\n}\\n\\nconst findShadowRoot = element => {\\n  if (!document.documentElement.attachShadow) {\\n    return null\\n  }\\n\\n  // Can find the shadow root otherwise it'll return the document\\n  if (typeof element.getRootNode === 'function') {\\n    const root = element.getRootNode()\\n    return root instanceof ShadowRoot ? root : null\\n  }\\n\\n  if (element instanceof ShadowRoot) {\\n    return element\\n  }\\n\\n  // when we don't find a shadow root\\n  if (!element.parentNode) {\\n    return null\\n  }\\n\\n  return findShadowRoot(element.parentNode)\\n}\\n\\nconst noop = () => {}\\n\\n/**\\n * Trick to restart an element's animation\\n *\\n * @param {HTMLElement} element\\n * @return void\\n *\\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\\n */\\nconst reflow = element => {\\n  element.offsetHeight // eslint-disable-line no-unused-expressions\\n}\\n\\nconst getjQuery = () => {\\n  if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\\n    return window.jQuery\\n  }\\n\\n  return null\\n}\\n\\nconst DOMContentLoadedCallbacks = []\\n\\nconst onDOMContentLoaded = callback => {\\n  if (document.readyState === 'loading') {\\n    // add listener on the first call when the document is in loading state\\n    if (!DOMContentLoadedCallbacks.length) {\\n      document.addEventListener('DOMContentLoaded', () => {\\n        for (const callback of DOMContentLoadedCallbacks) {\\n          callback()\\n        }\\n      })\\n    }\\n\\n    DOMContentLoadedCallbacks.push(callback)\\n  } else {\\n    callback()\\n  }\\n}\\n\\nconst isRTL = () => document.documentElement.dir === 'rtl'\\n\\nconst defineJQueryPlugin = plugin => {\\n  onDOMContentLoaded(() => {\\n    const $ = getjQuery()\\n    /* istanbul ignore if */\\n    if ($) {\\n      const name = plugin.NAME\\n      const JQUERY_NO_CONFLICT = $.fn[name]\\n      $.fn[name] = plugin.jQueryInterface\\n      $.fn[name].Constructor = plugin\\n      $.fn[name].noConflict = () => {\\n        $.fn[name] = JQUERY_NO_CONFLICT\\n        return plugin.jQueryInterface\\n      }\\n    }\\n  })\\n}\\n\\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\\n  return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue\\n}\\n\\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\\n  if (!waitForTransition) {\\n    execute(callback)\\n    return\\n  }\\n\\n  const durationPadding = 5\\n  const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\\n\\n  let called = false\\n\\n  const handler = ({ target }) => {\\n    if (target !== transitionElement) {\\n      return\\n    }\\n\\n    called = true\\n    transitionElement.removeEventListener(TRANSITION_END, handler)\\n    execute(callback)\\n  }\\n\\n  transitionElement.addEventListener(TRANSITION_END, handler)\\n  setTimeout(() => {\\n    if (!called) {\\n      triggerTransitionEnd(transitionElement)\\n    }\\n  }, emulatedDuration)\\n}\\n\\n/**\\n * Return the previous/next element of a list.\\n *\\n * @param {array} list    The list of elements\\n * @param activeElement   The active element\\n * @param shouldGetNext   Choose to get next or previous element\\n * @param isCycleAllowed\\n * @return {Element|elem} The proper element\\n */\\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\\n  const listLength = list.length\\n  let index = list.indexOf(activeElement)\\n\\n  // if the element does not exist in the list return an element\\n  // depending on the direction and if cycle is allowed\\n  if (index === -1) {\\n    return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\\n  }\\n\\n  index += shouldGetNext ? 1 : -1\\n\\n  if (isCycleAllowed) {\\n    index = (index + listLength) % listLength\\n  }\\n\\n  return list[Math.max(0, Math.min(index, listLength - 1))]\\n}\\n\\nexport {\\n  defineJQueryPlugin,\\n  execute,\\n  executeAfterTransition,\\n  findShadowRoot,\\n  getElement,\\n  getjQuery,\\n  getNextActiveElement,\\n  getTransitionDurationFromElement,\\n  getUID,\\n  isDisabled,\\n  isElement,\\n  isRTL,\\n  isVisible,\\n  noop,\\n  onDOMContentLoaded,\\n  parseSelector,\\n  reflow,\\n  triggerTransitionEnd,\\n  toType\\n}\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): dom/event-handler.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { getjQuery } from '../util/index.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst namespaceRegex = /[^.]*(?=\\\\..*)\\\\.|.*/\\nconst stripNameRegex = /\\\\..*/\\nconst stripUidRegex = /::\\\\d+$/\\nconst eventRegistry = {} // Events storage\\nlet uidEvent = 1\\nconst customEvents = {\\n  mouseenter: 'mouseover',\\n  mouseleave: 'mouseout'\\n}\\n\\nconst nativeEvents = new Set([\\n  'click',\\n  'dblclick',\\n  'mouseup',\\n  'mousedown',\\n  'contextmenu',\\n  'mousewheel',\\n  'DOMMouseScroll',\\n  'mouseover',\\n  'mouseout',\\n  'mousemove',\\n  'selectstart',\\n  'selectend',\\n  'keydown',\\n  'keypress',\\n  'keyup',\\n  'orientationchange',\\n  'touchstart',\\n  'touchmove',\\n  'touchend',\\n  'touchcancel',\\n  'pointerdown',\\n  'pointermove',\\n  'pointerup',\\n  'pointerleave',\\n  'pointercancel',\\n  'gesturestart',\\n  'gesturechange',\\n  'gestureend',\\n  'focus',\\n  'blur',\\n  'change',\\n  'reset',\\n  'select',\\n  'submit',\\n  'focusin',\\n  'focusout',\\n  'load',\\n  'unload',\\n  'beforeunload',\\n  'resize',\\n  'move',\\n  'DOMContentLoaded',\\n  'readystatechange',\\n  'error',\\n  'abort',\\n  'scroll'\\n])\\n\\n/**\\n * Private methods\\n */\\n\\nfunction makeEventUid(element, uid) {\\n  return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\\n}\\n\\nfunction getElementEvents(element) {\\n  const uid = makeEventUid(element)\\n\\n  element.uidEvent = uid\\n  eventRegistry[uid] = eventRegistry[uid] || {}\\n\\n  return eventRegistry[uid]\\n}\\n\\nfunction bootstrapHandler(element, fn) {\\n  return function handler(event) {\\n    hydrateObj(event, { delegateTarget: element })\\n\\n    if (handler.oneOff) {\\n      EventHandler.off(element, event.type, fn)\\n    }\\n\\n    return fn.apply(element, [event])\\n  }\\n}\\n\\nfunction bootstrapDelegationHandler(element, selector, fn) {\\n  return function handler(event) {\\n    const domElements = element.querySelectorAll(selector)\\n\\n    for (let { target } = event; target && target !== this; target = target.parentNode) {\\n      for (const domElement of domElements) {\\n        if (domElement !== target) {\\n          continue\\n        }\\n\\n        hydrateObj(event, { delegateTarget: target })\\n\\n        if (handler.oneOff) {\\n          EventHandler.off(element, event.type, selector, fn)\\n        }\\n\\n        return fn.apply(target, [event])\\n      }\\n    }\\n  }\\n}\\n\\nfunction findHandler(events, callable, delegationSelector = null) {\\n  return Object.values(events)\\n    .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\\n}\\n\\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\\n  const isDelegated = typeof handler === 'string'\\n  // todo: tooltip passes `false` instead of selector, so we need to check\\n  const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\\n  let typeEvent = getTypeEvent(originalTypeEvent)\\n\\n  if (!nativeEvents.has(typeEvent)) {\\n    typeEvent = originalTypeEvent\\n  }\\n\\n  return [isDelegated, callable, typeEvent]\\n}\\n\\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\\n  if (typeof originalTypeEvent !== 'string' || !element) {\\n    return\\n  }\\n\\n  let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\\n\\n  // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\\n  // this prevents the handler from being dispatched the same way as mouseover or mouseout does\\n  if (originalTypeEvent in customEvents) {\\n    const wrapFunction = fn => {\\n      return function (event) {\\n        if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\\n          return fn.call(this, event)\\n        }\\n      }\\n    }\\n\\n    callable = wrapFunction(callable)\\n  }\\n\\n  const events = getElementEvents(element)\\n  const handlers = events[typeEvent] || (events[typeEvent] = {})\\n  const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\\n\\n  if (previousFunction) {\\n    previousFunction.oneOff = previousFunction.oneOff && oneOff\\n\\n    return\\n  }\\n\\n  const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\\n  const fn = isDelegated ?\\n    bootstrapDelegationHandler(element, handler, callable) :\\n    bootstrapHandler(element, callable)\\n\\n  fn.delegationSelector = isDelegated ? handler : null\\n  fn.callable = callable\\n  fn.oneOff = oneOff\\n  fn.uidEvent = uid\\n  handlers[uid] = fn\\n\\n  element.addEventListener(typeEvent, fn, isDelegated)\\n}\\n\\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\\n  const fn = findHandler(events[typeEvent], handler, delegationSelector)\\n\\n  if (!fn) {\\n    return\\n  }\\n\\n  element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\\n  delete events[typeEvent][fn.uidEvent]\\n}\\n\\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\\n  const storeElementEvent = events[typeEvent] || {}\\n\\n  for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\\n    if (handlerKey.includes(namespace)) {\\n      removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\\n    }\\n  }\\n}\\n\\nfunction getTypeEvent(event) {\\n  // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\\n  event = event.replace(stripNameRegex, '')\\n  return customEvents[event] || event\\n}\\n\\nconst EventHandler = {\\n  on(element, event, handler, delegationFunction) {\\n    addHandler(element, event, handler, delegationFunction, false)\\n  },\\n\\n  one(element, event, handler, delegationFunction) {\\n    addHandler(element, event, handler, delegationFunction, true)\\n  },\\n\\n  off(element, originalTypeEvent, handler, delegationFunction) {\\n    if (typeof originalTypeEvent !== 'string' || !element) {\\n      return\\n    }\\n\\n    const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\\n    const inNamespace = typeEvent !== originalTypeEvent\\n    const events = getElementEvents(element)\\n    const storeElementEvent = events[typeEvent] || {}\\n    const isNamespace = originalTypeEvent.startsWith('.')\\n\\n    if (typeof callable !== 'undefined') {\\n      // Simplest case: handler is passed, remove that listener ONLY.\\n      if (!Object.keys(storeElementEvent).length) {\\n        return\\n      }\\n\\n      removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\\n      return\\n    }\\n\\n    if (isNamespace) {\\n      for (const elementEvent of Object.keys(events)) {\\n        removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\\n      }\\n    }\\n\\n    for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\\n      const handlerKey = keyHandlers.replace(stripUidRegex, '')\\n\\n      if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\\n        removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\\n      }\\n    }\\n  },\\n\\n  trigger(element, event, args) {\\n    if (typeof event !== 'string' || !element) {\\n      return null\\n    }\\n\\n    const $ = getjQuery()\\n    const typeEvent = getTypeEvent(event)\\n    const inNamespace = event !== typeEvent\\n\\n    let jQueryEvent = null\\n    let bubbles = true\\n    let nativeDispatch = true\\n    let defaultPrevented = false\\n\\n    if (inNamespace && $) {\\n      jQueryEvent = $.Event(event, args)\\n\\n      $(element).trigger(jQueryEvent)\\n      bubbles = !jQueryEvent.isPropagationStopped()\\n      nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\\n      defaultPrevented = jQueryEvent.isDefaultPrevented()\\n    }\\n\\n    let evt = new Event(event, { bubbles, cancelable: true })\\n    evt = hydrateObj(evt, args)\\n\\n    if (defaultPrevented) {\\n      evt.preventDefault()\\n    }\\n\\n    if (nativeDispatch) {\\n      element.dispatchEvent(evt)\\n    }\\n\\n    if (evt.defaultPrevented && jQueryEvent) {\\n      jQueryEvent.preventDefault()\\n    }\\n\\n    return evt\\n  }\\n}\\n\\nfunction hydrateObj(obj, meta = {}) {\\n  for (const [key, value] of Object.entries(meta)) {\\n    try {\\n      obj[key] = value\\n    } catch {\\n      Object.defineProperty(obj, key, {\\n        configurable: true,\\n        get() {\\n          return value\\n        }\\n      })\\n    }\\n  }\\n\\n  return obj\\n}\\n\\nexport default EventHandler\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): dom/data.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\n/**\\n * Constants\\n */\\n\\nconst elementMap = new Map()\\n\\nexport default {\\n  set(element, key, instance) {\\n    if (!elementMap.has(element)) {\\n      elementMap.set(element, new Map())\\n    }\\n\\n    const instanceMap = elementMap.get(element)\\n\\n    // make it clear we only want one instance per element\\n    // can be removed later when multiple key/instances are fine to be used\\n    if (!instanceMap.has(key) && instanceMap.size !== 0) {\\n      // eslint-disable-next-line no-console\\n      console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\\n      return\\n    }\\n\\n    instanceMap.set(key, instance)\\n  },\\n\\n  get(element, key) {\\n    if (elementMap.has(element)) {\\n      return elementMap.get(element).get(key) || null\\n    }\\n\\n    return null\\n  },\\n\\n  remove(element, key) {\\n    if (!elementMap.has(element)) {\\n      return\\n    }\\n\\n    const instanceMap = elementMap.get(element)\\n\\n    instanceMap.delete(key)\\n\\n    // free up element references if there are no instances left for an element\\n    if (instanceMap.size === 0) {\\n      elementMap.delete(element)\\n    }\\n  }\\n}\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): dom/manipulator.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nfunction normalizeData(value) {\\n  if (value === 'true') {\\n    return true\\n  }\\n\\n  if (value === 'false') {\\n    return false\\n  }\\n\\n  if (value === Number(value).toString()) {\\n    return Number(value)\\n  }\\n\\n  if (value === '' || value === 'null') {\\n    return null\\n  }\\n\\n  if (typeof value !== 'string') {\\n    return value\\n  }\\n\\n  try {\\n    return JSON.parse(decodeURIComponent(value))\\n  } catch {\\n    return value\\n  }\\n}\\n\\nfunction normalizeDataKey(key) {\\n  return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\\n}\\n\\nconst Manipulator = {\\n  setDataAttribute(element, key, value) {\\n    element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\\n  },\\n\\n  removeDataAttribute(element, key) {\\n    element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\\n  },\\n\\n  getDataAttributes(element) {\\n    if (!element) {\\n      return {}\\n    }\\n\\n    const attributes = {}\\n    const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\\n\\n    for (const key of bsKeys) {\\n      let pureKey = key.replace(/^bs/, '')\\n      pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\\n      attributes[pureKey] = normalizeData(element.dataset[key])\\n    }\\n\\n    return attributes\\n  },\\n\\n  getDataAttribute(element, key) {\\n    return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\\n  }\\n}\\n\\nexport default Manipulator\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/config.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { isElement, toType } from './index.js'\\nimport Manipulator from '../dom/manipulator.js'\\n\\n/**\\n * Class definition\\n */\\n\\nclass Config {\\n  // Getters\\n  static get Default() {\\n    return {}\\n  }\\n\\n  static get DefaultType() {\\n    return {}\\n  }\\n\\n  static get NAME() {\\n    throw new Error('You have to implement the static method \\\"NAME\\\", for each component!')\\n  }\\n\\n  _getConfig(config) {\\n    config = this._mergeConfigObj(config)\\n    config = this._configAfterMerge(config)\\n    this._typeCheckConfig(config)\\n    return config\\n  }\\n\\n  _configAfterMerge(config) {\\n    return config\\n  }\\n\\n  _mergeConfigObj(config, element) {\\n    const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\\n\\n    return {\\n      ...this.constructor.Default,\\n      ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\\n      ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\\n      ...(typeof config === 'object' ? config : {})\\n    }\\n  }\\n\\n  _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\\n    for (const [property, expectedTypes] of Object.entries(configTypes)) {\\n      const value = config[property]\\n      const valueType = isElement(value) ? 'element' : toType(value)\\n\\n      if (!new RegExp(expectedTypes).test(valueType)) {\\n        throw new TypeError(\\n          `${this.constructor.NAME.toUpperCase()}: Option \\\"${property}\\\" provided type \\\"${valueType}\\\" but expected type \\\"${expectedTypes}\\\".`\\n        )\\n      }\\n    }\\n  }\\n}\\n\\nexport default Config\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): base-component.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport Data from './dom/data.js'\\nimport { executeAfterTransition, getElement } from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport Config from './util/config.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst VERSION = '5.3.0-alpha1'\\n\\n/**\\n * Class definition\\n */\\n\\nclass BaseComponent extends Config {\\n  constructor(element, config) {\\n    super()\\n\\n    element = getElement(element)\\n    if (!element) {\\n      return\\n    }\\n\\n    this._element = element\\n    this._config = this._getConfig(config)\\n\\n    Data.set(this._element, this.constructor.DATA_KEY, this)\\n  }\\n\\n  // Public\\n  dispose() {\\n    Data.remove(this._element, this.constructor.DATA_KEY)\\n    EventHandler.off(this._element, this.constructor.EVENT_KEY)\\n\\n    for (const propertyName of Object.getOwnPropertyNames(this)) {\\n      this[propertyName] = null\\n    }\\n  }\\n\\n  _queueCallback(callback, element, isAnimated = true) {\\n    executeAfterTransition(callback, element, isAnimated)\\n  }\\n\\n  _getConfig(config) {\\n    config = this._mergeConfigObj(config, this._element)\\n    config = this._configAfterMerge(config)\\n    this._typeCheckConfig(config)\\n    return config\\n  }\\n\\n  // Static\\n  static getInstance(element) {\\n    return Data.get(getElement(element), this.DATA_KEY)\\n  }\\n\\n  static getOrCreateInstance(element, config = {}) {\\n    return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\\n  }\\n\\n  static get VERSION() {\\n    return VERSION\\n  }\\n\\n  static get DATA_KEY() {\\n    return `bs.${this.NAME}`\\n  }\\n\\n  static get EVENT_KEY() {\\n    return `.${this.DATA_KEY}`\\n  }\\n\\n  static eventName(name) {\\n    return `${name}${this.EVENT_KEY}`\\n  }\\n}\\n\\nexport default BaseComponent\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): dom/selector-engine.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\\n\\nconst getSelector = element => {\\n  let selector = element.getAttribute('data-bs-target')\\n\\n  if (!selector || selector === '#') {\\n    let hrefAttribute = element.getAttribute('href')\\n\\n    // The only valid content that could double as a selector are IDs or classes,\\n    // so everything starting with `#` or `.`. If a \\\"real\\\" URL is used as the selector,\\n    // `document.querySelector` will rightfully complain it is invalid.\\n    // See https://github.com/twbs/bootstrap/issues/32273\\n    if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\\n      return null\\n    }\\n\\n    // Just in case some CMS puts out a full URL with the anchor appended\\n    if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\\n      hrefAttribute = `#${hrefAttribute.split('#')[1]}`\\n    }\\n\\n    selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\\n  }\\n\\n  return parseSelector(selector)\\n}\\n\\nconst SelectorEngine = {\\n  find(selector, element = document.documentElement) {\\n    return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\\n  },\\n\\n  findOne(selector, element = document.documentElement) {\\n    return Element.prototype.querySelector.call(element, selector)\\n  },\\n\\n  children(element, selector) {\\n    return [].concat(...element.children).filter(child => child.matches(selector))\\n  },\\n\\n  parents(element, selector) {\\n    const parents = []\\n    let ancestor = element.parentNode.closest(selector)\\n\\n    while (ancestor) {\\n      parents.push(ancestor)\\n      ancestor = ancestor.parentNode.closest(selector)\\n    }\\n\\n    return parents\\n  },\\n\\n  prev(element, selector) {\\n    let previous = element.previousElementSibling\\n\\n    while (previous) {\\n      if (previous.matches(selector)) {\\n        return [previous]\\n      }\\n\\n      previous = previous.previousElementSibling\\n    }\\n\\n    return []\\n  },\\n  // TODO: this is now unused; remove later along with prev()\\n  next(element, selector) {\\n    let next = element.nextElementSibling\\n\\n    while (next) {\\n      if (next.matches(selector)) {\\n        return [next]\\n      }\\n\\n      next = next.nextElementSibling\\n    }\\n\\n    return []\\n  },\\n\\n  focusableChildren(element) {\\n    const focusables = [\\n      'a',\\n      'button',\\n      'input',\\n      'textarea',\\n      'select',\\n      'details',\\n      '[tabindex]',\\n      '[contenteditable=\\\"true\\\"]'\\n    ].map(selector => `${selector}:not([tabindex^=\\\"-\\\"])`).join(',')\\n\\n    return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\\n  },\\n\\n  getSelectorFromElement(element) {\\n    const selector = getSelector(element)\\n\\n    if (selector) {\\n      return SelectorEngine.findOne(selector) ? selector : null\\n    }\\n\\n    return null\\n  },\\n\\n  getElementFromSelector(element) {\\n    const selector = getSelector(element)\\n\\n    return selector ? SelectorEngine.findOne(selector) : null\\n  },\\n\\n  getMultipleElementsFromSelector(element) {\\n    const selector = getSelector(element)\\n\\n    return selector ? SelectorEngine.find(selector) : []\\n  }\\n}\\n\\nexport default SelectorEngine\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/component-functions.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport EventHandler from '../dom/event-handler.js'\\nimport { isDisabled } from './index.js'\\nimport SelectorEngine from '../dom/selector-engine.js'\\n\\nconst enableDismissTrigger = (component, method = 'hide') => {\\n  const clickEvent = `click.dismiss${component.EVENT_KEY}`\\n  const name = component.NAME\\n\\n  EventHandler.on(document, clickEvent, `[data-bs-dismiss=\\\"${name}\\\"]`, function (event) {\\n    if (['A', 'AREA'].includes(this.tagName)) {\\n      event.preventDefault()\\n    }\\n\\n    if (isDisabled(this)) {\\n      return\\n    }\\n\\n    const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\\n    const instance = component.getOrCreateInstance(target)\\n\\n    // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\\n    instance[method]()\\n  })\\n}\\n\\nexport {\\n  enableDismissTrigger\\n}\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): alert.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { defineJQueryPlugin } from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport BaseComponent from './base-component.js'\\nimport { enableDismissTrigger } from './util/component-functions.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'alert'\\nconst DATA_KEY = 'bs.alert'\\nconst EVENT_KEY = `.${DATA_KEY}`\\n\\nconst EVENT_CLOSE = `close${EVENT_KEY}`\\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\\nconst CLASS_NAME_FADE = 'fade'\\nconst CLASS_NAME_SHOW = 'show'\\n\\n/**\\n * Class definition\\n */\\n\\nclass Alert extends BaseComponent {\\n  // Getters\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  close() {\\n    const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\\n\\n    if (closeEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    this._element.classList.remove(CLASS_NAME_SHOW)\\n\\n    const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\\n    this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\\n  }\\n\\n  // Private\\n  _destroyElement() {\\n    this._element.remove()\\n    EventHandler.trigger(this._element, EVENT_CLOSED)\\n    this.dispose()\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Alert.getOrCreateInstance(this)\\n\\n      if (typeof config !== 'string') {\\n        return\\n      }\\n\\n      if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\\n        throw new TypeError(`No method named \\\"${config}\\\"`)\\n      }\\n\\n      data[config](this)\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nenableDismissTrigger(Alert, 'close')\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Alert)\\n\\nexport default Alert\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): button.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { defineJQueryPlugin } from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport BaseComponent from './base-component.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'button'\\nconst DATA_KEY = 'bs.button'\\nconst EVENT_KEY = `.${DATA_KEY}`\\nconst DATA_API_KEY = '.data-api'\\n\\nconst CLASS_NAME_ACTIVE = 'active'\\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\\\"button\\\"]'\\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\\n\\n/**\\n * Class definition\\n */\\n\\nclass Button extends BaseComponent {\\n  // Getters\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  toggle() {\\n    // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\\n    this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Button.getOrCreateInstance(this)\\n\\n      if (config === 'toggle') {\\n        data[config]()\\n      }\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\\n  event.preventDefault()\\n\\n  const button = event.target.closest(SELECTOR_DATA_TOGGLE)\\n  const data = Button.getOrCreateInstance(button)\\n\\n  data.toggle()\\n})\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Button)\\n\\nexport default Button\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/swipe.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport Config from './config.js'\\nimport EventHandler from '../dom/event-handler.js'\\nimport { execute } from './index.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'swipe'\\nconst EVENT_KEY = '.bs.swipe'\\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\\nconst POINTER_TYPE_TOUCH = 'touch'\\nconst POINTER_TYPE_PEN = 'pen'\\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\\nconst SWIPE_THRESHOLD = 40\\n\\nconst Default = {\\n  endCallback: null,\\n  leftCallback: null,\\n  rightCallback: null\\n}\\n\\nconst DefaultType = {\\n  endCallback: '(function|null)',\\n  leftCallback: '(function|null)',\\n  rightCallback: '(function|null)'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Swipe extends Config {\\n  constructor(element, config) {\\n    super()\\n    this._element = element\\n\\n    if (!element || !Swipe.isSupported()) {\\n      return\\n    }\\n\\n    this._config = this._getConfig(config)\\n    this._deltaX = 0\\n    this._supportPointerEvents = Boolean(window.PointerEvent)\\n    this._initEvents()\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  dispose() {\\n    EventHandler.off(this._element, EVENT_KEY)\\n  }\\n\\n  // Private\\n  _start(event) {\\n    if (!this._supportPointerEvents) {\\n      this._deltaX = event.touches[0].clientX\\n\\n      return\\n    }\\n\\n    if (this._eventIsPointerPenTouch(event)) {\\n      this._deltaX = event.clientX\\n    }\\n  }\\n\\n  _end(event) {\\n    if (this._eventIsPointerPenTouch(event)) {\\n      this._deltaX = event.clientX - this._deltaX\\n    }\\n\\n    this._handleSwipe()\\n    execute(this._config.endCallback)\\n  }\\n\\n  _move(event) {\\n    this._deltaX = event.touches && event.touches.length > 1 ?\\n      0 :\\n      event.touches[0].clientX - this._deltaX\\n  }\\n\\n  _handleSwipe() {\\n    const absDeltaX = Math.abs(this._deltaX)\\n\\n    if (absDeltaX <= SWIPE_THRESHOLD) {\\n      return\\n    }\\n\\n    const direction = absDeltaX / this._deltaX\\n\\n    this._deltaX = 0\\n\\n    if (!direction) {\\n      return\\n    }\\n\\n    execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\\n  }\\n\\n  _initEvents() {\\n    if (this._supportPointerEvents) {\\n      EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\\n      EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\\n\\n      this._element.classList.add(CLASS_NAME_POINTER_EVENT)\\n    } else {\\n      EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\\n      EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\\n      EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\\n    }\\n  }\\n\\n  _eventIsPointerPenTouch(event) {\\n    return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\\n  }\\n\\n  // Static\\n  static isSupported() {\\n    return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\\n  }\\n}\\n\\nexport default Swipe\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): carousel.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport {\\n  defineJQueryPlugin,\\n  getNextActiveElement,\\n  isRTL,\\n  isVisible,\\n  reflow,\\n  triggerTransitionEnd\\n} from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport Manipulator from './dom/manipulator.js'\\nimport SelectorEngine from './dom/selector-engine.js'\\nimport Swipe from './util/swipe.js'\\nimport BaseComponent from './base-component.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'carousel'\\nconst DATA_KEY = 'bs.carousel'\\nconst EVENT_KEY = `.${DATA_KEY}`\\nconst DATA_API_KEY = '.data-api'\\n\\nconst ARROW_LEFT_KEY = 'ArrowLeft'\\nconst ARROW_RIGHT_KEY = 'ArrowRight'\\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\\n\\nconst ORDER_NEXT = 'next'\\nconst ORDER_PREV = 'prev'\\nconst DIRECTION_LEFT = 'left'\\nconst DIRECTION_RIGHT = 'right'\\n\\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\\nconst EVENT_SLID = `slid${EVENT_KEY}`\\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\\n\\nconst CLASS_NAME_CAROUSEL = 'carousel'\\nconst CLASS_NAME_ACTIVE = 'active'\\nconst CLASS_NAME_SLIDE = 'slide'\\nconst CLASS_NAME_END = 'carousel-item-end'\\nconst CLASS_NAME_START = 'carousel-item-start'\\nconst CLASS_NAME_NEXT = 'carousel-item-next'\\nconst CLASS_NAME_PREV = 'carousel-item-prev'\\n\\nconst SELECTOR_ACTIVE = '.active'\\nconst SELECTOR_ITEM = '.carousel-item'\\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\\nconst SELECTOR_INDICATORS = '.carousel-indicators'\\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\\\"carousel\\\"]'\\n\\nconst KEY_TO_DIRECTION = {\\n  [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\\n  [ARROW_RIGHT_KEY]: DIRECTION_LEFT\\n}\\n\\nconst Default = {\\n  interval: 5000,\\n  keyboard: true,\\n  pause: 'hover',\\n  ride: false,\\n  touch: true,\\n  wrap: true\\n}\\n\\nconst DefaultType = {\\n  interval: '(number|boolean)', // TODO:v6 remove boolean support\\n  keyboard: 'boolean',\\n  pause: '(string|boolean)',\\n  ride: '(boolean|string)',\\n  touch: 'boolean',\\n  wrap: 'boolean'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Carousel extends BaseComponent {\\n  constructor(element, config) {\\n    super(element, config)\\n\\n    this._interval = null\\n    this._activeElement = null\\n    this._isSliding = false\\n    this.touchTimeout = null\\n    this._swipeHelper = null\\n\\n    this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\\n    this._addEventListeners()\\n\\n    if (this._config.ride === CLASS_NAME_CAROUSEL) {\\n      this.cycle()\\n    }\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  next() {\\n    this._slide(ORDER_NEXT)\\n  }\\n\\n  nextWhenVisible() {\\n    // FIXME TODO use `document.visibilityState`\\n    // Don't call next when the page isn't visible\\n    // or the carousel or its parent isn't visible\\n    if (!document.hidden && isVisible(this._element)) {\\n      this.next()\\n    }\\n  }\\n\\n  prev() {\\n    this._slide(ORDER_PREV)\\n  }\\n\\n  pause() {\\n    if (this._isSliding) {\\n      triggerTransitionEnd(this._element)\\n    }\\n\\n    this._clearInterval()\\n  }\\n\\n  cycle() {\\n    this._clearInterval()\\n    this._updateInterval()\\n\\n    this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\\n  }\\n\\n  _maybeEnableCycle() {\\n    if (!this._config.ride) {\\n      return\\n    }\\n\\n    if (this._isSliding) {\\n      EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\\n      return\\n    }\\n\\n    this.cycle()\\n  }\\n\\n  to(index) {\\n    const items = this._getItems()\\n    if (index > items.length - 1 || index < 0) {\\n      return\\n    }\\n\\n    if (this._isSliding) {\\n      EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\\n      return\\n    }\\n\\n    const activeIndex = this._getItemIndex(this._getActive())\\n    if (activeIndex === index) {\\n      return\\n    }\\n\\n    const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\\n\\n    this._slide(order, items[index])\\n  }\\n\\n  dispose() {\\n    if (this._swipeHelper) {\\n      this._swipeHelper.dispose()\\n    }\\n\\n    super.dispose()\\n  }\\n\\n  // Private\\n  _configAfterMerge(config) {\\n    config.defaultInterval = config.interval\\n    return config\\n  }\\n\\n  _addEventListeners() {\\n    if (this._config.keyboard) {\\n      EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\\n    }\\n\\n    if (this._config.pause === 'hover') {\\n      EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\\n      EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\\n    }\\n\\n    if (this._config.touch && Swipe.isSupported()) {\\n      this._addTouchEventListeners()\\n    }\\n  }\\n\\n  _addTouchEventListeners() {\\n    for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\\n      EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\\n    }\\n\\n    const endCallBack = () => {\\n      if (this._config.pause !== 'hover') {\\n        return\\n      }\\n\\n      // If it's a touch-enabled device, mouseenter/leave are fired as\\n      // part of the mouse compatibility events on first tap - the carousel\\n      // would stop cycling until user tapped out of it;\\n      // here, we listen for touchend, explicitly pause the carousel\\n      // (as if it's the second time we tap on it, mouseenter compat event\\n      // is NOT fired) and after a timeout (to allow for mouse compatibility\\n      // events to fire) we explicitly restart cycling\\n\\n      this.pause()\\n      if (this.touchTimeout) {\\n        clearTimeout(this.touchTimeout)\\n      }\\n\\n      this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\\n    }\\n\\n    const swipeConfig = {\\n      leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\\n      rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\\n      endCallback: endCallBack\\n    }\\n\\n    this._swipeHelper = new Swipe(this._element, swipeConfig)\\n  }\\n\\n  _keydown(event) {\\n    if (/input|textarea/i.test(event.target.tagName)) {\\n      return\\n    }\\n\\n    const direction = KEY_TO_DIRECTION[event.key]\\n    if (direction) {\\n      event.preventDefault()\\n      this._slide(this._directionToOrder(direction))\\n    }\\n  }\\n\\n  _getItemIndex(element) {\\n    return this._getItems().indexOf(element)\\n  }\\n\\n  _setActiveIndicatorElement(index) {\\n    if (!this._indicatorsElement) {\\n      return\\n    }\\n\\n    const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\\n\\n    activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\\n    activeIndicator.removeAttribute('aria-current')\\n\\n    const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\\\"${index}\\\"]`, this._indicatorsElement)\\n\\n    if (newActiveIndicator) {\\n      newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\\n      newActiveIndicator.setAttribute('aria-current', 'true')\\n    }\\n  }\\n\\n  _updateInterval() {\\n    const element = this._activeElement || this._getActive()\\n\\n    if (!element) {\\n      return\\n    }\\n\\n    const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\\n\\n    this._config.interval = elementInterval || this._config.defaultInterval\\n  }\\n\\n  _slide(order, element = null) {\\n    if (this._isSliding) {\\n      return\\n    }\\n\\n    const activeElement = this._getActive()\\n    const isNext = order === ORDER_NEXT\\n    const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\\n\\n    if (nextElement === activeElement) {\\n      return\\n    }\\n\\n    const nextElementIndex = this._getItemIndex(nextElement)\\n\\n    const triggerEvent = eventName => {\\n      return EventHandler.trigger(this._element, eventName, {\\n        relatedTarget: nextElement,\\n        direction: this._orderToDirection(order),\\n        from: this._getItemIndex(activeElement),\\n        to: nextElementIndex\\n      })\\n    }\\n\\n    const slideEvent = triggerEvent(EVENT_SLIDE)\\n\\n    if (slideEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    if (!activeElement || !nextElement) {\\n      // Some weirdness is happening, so we bail\\n      // todo: change tests that use empty divs to avoid this check\\n      return\\n    }\\n\\n    const isCycling = Boolean(this._interval)\\n    this.pause()\\n\\n    this._isSliding = true\\n\\n    this._setActiveIndicatorElement(nextElementIndex)\\n    this._activeElement = nextElement\\n\\n    const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\\n    const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\\n\\n    nextElement.classList.add(orderClassName)\\n\\n    reflow(nextElement)\\n\\n    activeElement.classList.add(directionalClassName)\\n    nextElement.classList.add(directionalClassName)\\n\\n    const completeCallBack = () => {\\n      nextElement.classList.remove(directionalClassName, orderClassName)\\n      nextElement.classList.add(CLASS_NAME_ACTIVE)\\n\\n      activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\\n\\n      this._isSliding = false\\n\\n      triggerEvent(EVENT_SLID)\\n    }\\n\\n    this._queueCallback(completeCallBack, activeElement, this._isAnimated())\\n\\n    if (isCycling) {\\n      this.cycle()\\n    }\\n  }\\n\\n  _isAnimated() {\\n    return this._element.classList.contains(CLASS_NAME_SLIDE)\\n  }\\n\\n  _getActive() {\\n    return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\\n  }\\n\\n  _getItems() {\\n    return SelectorEngine.find(SELECTOR_ITEM, this._element)\\n  }\\n\\n  _clearInterval() {\\n    if (this._interval) {\\n      clearInterval(this._interval)\\n      this._interval = null\\n    }\\n  }\\n\\n  _directionToOrder(direction) {\\n    if (isRTL()) {\\n      return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\\n    }\\n\\n    return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\\n  }\\n\\n  _orderToDirection(order) {\\n    if (isRTL()) {\\n      return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\\n    }\\n\\n    return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Carousel.getOrCreateInstance(this, config)\\n\\n      if (typeof config === 'number') {\\n        data.to(config)\\n        return\\n      }\\n\\n      if (typeof config === 'string') {\\n        if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\\n          throw new TypeError(`No method named \\\"${config}\\\"`)\\n        }\\n\\n        data[config]()\\n      }\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\\n  const target = SelectorEngine.getElementFromSelector(this)\\n\\n  if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\\n    return\\n  }\\n\\n  event.preventDefault()\\n\\n  const carousel = Carousel.getOrCreateInstance(target)\\n  const slideIndex = this.getAttribute('data-bs-slide-to')\\n\\n  if (slideIndex) {\\n    carousel.to(slideIndex)\\n    carousel._maybeEnableCycle()\\n    return\\n  }\\n\\n  if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\\n    carousel.next()\\n    carousel._maybeEnableCycle()\\n    return\\n  }\\n\\n  carousel.prev()\\n  carousel._maybeEnableCycle()\\n})\\n\\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\\n  const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\\n\\n  for (const carousel of carousels) {\\n    Carousel.getOrCreateInstance(carousel)\\n  }\\n})\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Carousel)\\n\\nexport default Carousel\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): collapse.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport {\\n  defineJQueryPlugin,\\n  getElement,\\n  reflow\\n} from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport SelectorEngine from './dom/selector-engine.js'\\nimport BaseComponent from './base-component.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'collapse'\\nconst DATA_KEY = 'bs.collapse'\\nconst EVENT_KEY = `.${DATA_KEY}`\\nconst DATA_API_KEY = '.data-api'\\n\\nconst EVENT_SHOW = `show${EVENT_KEY}`\\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\\nconst EVENT_HIDE = `hide${EVENT_KEY}`\\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\\n\\nconst CLASS_NAME_SHOW = 'show'\\nconst CLASS_NAME_COLLAPSE = 'collapse'\\nconst CLASS_NAME_COLLAPSING = 'collapsing'\\nconst CLASS_NAME_COLLAPSED = 'collapsed'\\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\\n\\nconst WIDTH = 'width'\\nconst HEIGHT = 'height'\\n\\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\\\"collapse\\\"]'\\n\\nconst Default = {\\n  parent: null,\\n  toggle: true\\n}\\n\\nconst DefaultType = {\\n  parent: '(null|element)',\\n  toggle: 'boolean'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Collapse extends BaseComponent {\\n  constructor(element, config) {\\n    super(element, config)\\n\\n    this._isTransitioning = false\\n    this._triggerArray = []\\n\\n    const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\\n\\n    for (const elem of toggleList) {\\n      const selector = SelectorEngine.getSelectorFromElement(elem)\\n      const filterElement = SelectorEngine.find(selector)\\n        .filter(foundElement => foundElement === this._element)\\n\\n      if (selector !== null && filterElement.length) {\\n        this._triggerArray.push(elem)\\n      }\\n    }\\n\\n    this._initializeChildren()\\n\\n    if (!this._config.parent) {\\n      this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\\n    }\\n\\n    if (this._config.toggle) {\\n      this.toggle()\\n    }\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  toggle() {\\n    if (this._isShown()) {\\n      this.hide()\\n    } else {\\n      this.show()\\n    }\\n  }\\n\\n  show() {\\n    if (this._isTransitioning || this._isShown()) {\\n      return\\n    }\\n\\n    let activeChildren = []\\n\\n    // find active children\\n    if (this._config.parent) {\\n      activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\\n        .filter(element => element !== this._element)\\n        .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\\n    }\\n\\n    if (activeChildren.length && activeChildren[0]._isTransitioning) {\\n      return\\n    }\\n\\n    const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\\n    if (startEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    for (const activeInstance of activeChildren) {\\n      activeInstance.hide()\\n    }\\n\\n    const dimension = this._getDimension()\\n\\n    this._element.classList.remove(CLASS_NAME_COLLAPSE)\\n    this._element.classList.add(CLASS_NAME_COLLAPSING)\\n\\n    this._element.style[dimension] = 0\\n\\n    this._addAriaAndCollapsedClass(this._triggerArray, true)\\n    this._isTransitioning = true\\n\\n    const complete = () => {\\n      this._isTransitioning = false\\n\\n      this._element.classList.remove(CLASS_NAME_COLLAPSING)\\n      this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\\n\\n      this._element.style[dimension] = ''\\n\\n      EventHandler.trigger(this._element, EVENT_SHOWN)\\n    }\\n\\n    const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\\n    const scrollSize = `scroll${capitalizedDimension}`\\n\\n    this._queueCallback(complete, this._element, true)\\n    this._element.style[dimension] = `${this._element[scrollSize]}px`\\n  }\\n\\n  hide() {\\n    if (this._isTransitioning || !this._isShown()) {\\n      return\\n    }\\n\\n    const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\\n    if (startEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    const dimension = this._getDimension()\\n\\n    this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\\n\\n    reflow(this._element)\\n\\n    this._element.classList.add(CLASS_NAME_COLLAPSING)\\n    this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\\n\\n    for (const trigger of this._triggerArray) {\\n      const element = SelectorEngine.getElementFromSelector(trigger)\\n\\n      if (element && !this._isShown(element)) {\\n        this._addAriaAndCollapsedClass([trigger], false)\\n      }\\n    }\\n\\n    this._isTransitioning = true\\n\\n    const complete = () => {\\n      this._isTransitioning = false\\n      this._element.classList.remove(CLASS_NAME_COLLAPSING)\\n      this._element.classList.add(CLASS_NAME_COLLAPSE)\\n      EventHandler.trigger(this._element, EVENT_HIDDEN)\\n    }\\n\\n    this._element.style[dimension] = ''\\n\\n    this._queueCallback(complete, this._element, true)\\n  }\\n\\n  _isShown(element = this._element) {\\n    return element.classList.contains(CLASS_NAME_SHOW)\\n  }\\n\\n  // Private\\n  _configAfterMerge(config) {\\n    config.toggle = Boolean(config.toggle) // Coerce string values\\n    config.parent = getElement(config.parent)\\n    return config\\n  }\\n\\n  _getDimension() {\\n    return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\\n  }\\n\\n  _initializeChildren() {\\n    if (!this._config.parent) {\\n      return\\n    }\\n\\n    const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\\n\\n    for (const element of children) {\\n      const selected = SelectorEngine.getElementFromSelector(element)\\n\\n      if (selected) {\\n        this._addAriaAndCollapsedClass([element], this._isShown(selected))\\n      }\\n    }\\n  }\\n\\n  _getFirstLevelChildren(selector) {\\n    const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\\n    // remove children if greater depth\\n    return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\\n  }\\n\\n  _addAriaAndCollapsedClass(triggerArray, isOpen) {\\n    if (!triggerArray.length) {\\n      return\\n    }\\n\\n    for (const element of triggerArray) {\\n      element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\\n      element.setAttribute('aria-expanded', isOpen)\\n    }\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    const _config = {}\\n    if (typeof config === 'string' && /show|hide/.test(config)) {\\n      _config.toggle = false\\n    }\\n\\n    return this.each(function () {\\n      const data = Collapse.getOrCreateInstance(this, _config)\\n\\n      if (typeof config === 'string') {\\n        if (typeof data[config] === 'undefined') {\\n          throw new TypeError(`No method named \\\"${config}\\\"`)\\n        }\\n\\n        data[config]()\\n      }\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\\n  // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\\n  if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\\n    event.preventDefault()\\n  }\\n\\n  for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\\n    Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\\n  }\\n})\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Collapse)\\n\\nexport default Collapse\\n\",\"export var top = 'top';\\nexport var bottom = 'bottom';\\nexport var right = 'right';\\nexport var left = 'left';\\nexport var auto = 'auto';\\nexport var basePlacements = [top, bottom, right, left];\\nexport var start = 'start';\\nexport var end = 'end';\\nexport var clippingParents = 'clippingParents';\\nexport var viewport = 'viewport';\\nexport var popper = 'popper';\\nexport var reference = 'reference';\\nexport var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\\n  return acc.concat([placement + \\\"-\\\" + start, placement + \\\"-\\\" + end]);\\n}, []);\\nexport var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\\n  return acc.concat([placement, placement + \\\"-\\\" + start, placement + \\\"-\\\" + end]);\\n}, []); // modifiers that need to read the DOM\\n\\nexport var beforeRead = 'beforeRead';\\nexport var read = 'read';\\nexport var afterRead = 'afterRead'; // pure-logic modifiers\\n\\nexport var beforeMain = 'beforeMain';\\nexport var main = 'main';\\nexport var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\\n\\nexport var beforeWrite = 'beforeWrite';\\nexport var write = 'write';\\nexport var afterWrite = 'afterWrite';\\nexport var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];\",\"export default function getNodeName(element) {\\n  return element ? (element.nodeName || '').toLowerCase() : null;\\n}\",\"export default function getWindow(node) {\\n  if (node == null) {\\n    return window;\\n  }\\n\\n  if (node.toString() !== '[object Window]') {\\n    var ownerDocument = node.ownerDocument;\\n    return ownerDocument ? ownerDocument.defaultView || window : window;\\n  }\\n\\n  return node;\\n}\",\"import getWindow from \\\"./getWindow.js\\\";\\n\\nfunction isElement(node) {\\n  var OwnElement = getWindow(node).Element;\\n  return node instanceof OwnElement || node instanceof Element;\\n}\\n\\nfunction isHTMLElement(node) {\\n  var OwnElement = getWindow(node).HTMLElement;\\n  return node instanceof OwnElement || node instanceof HTMLElement;\\n}\\n\\nfunction isShadowRoot(node) {\\n  // IE 11 has no ShadowRoot\\n  if (typeof ShadowRoot === 'undefined') {\\n    return false;\\n  }\\n\\n  var OwnElement = getWindow(node).ShadowRoot;\\n  return node instanceof OwnElement || node instanceof ShadowRoot;\\n}\\n\\nexport { isElement, isHTMLElement, isShadowRoot };\",\"import getNodeName from \\\"../dom-utils/getNodeName.js\\\";\\nimport { isHTMLElement } from \\\"../dom-utils/instanceOf.js\\\"; // This modifier takes the styles prepared by the `computeStyles` modifier\\n// and applies them to the HTMLElements such as popper and arrow\\n\\nfunction applyStyles(_ref) {\\n  var state = _ref.state;\\n  Object.keys(state.elements).forEach(function (name) {\\n    var style = state.styles[name] || {};\\n    var attributes = state.attributes[name] || {};\\n    var element = state.elements[name]; // arrow is optional + virtual elements\\n\\n    if (!isHTMLElement(element) || !getNodeName(element)) {\\n      return;\\n    } // Flow doesn't support to extend this property, but it's the most\\n    // effective way to apply styles to an HTMLElement\\n    // $FlowFixMe[cannot-write]\\n\\n\\n    Object.assign(element.style, style);\\n    Object.keys(attributes).forEach(function (name) {\\n      var value = attributes[name];\\n\\n      if (value === false) {\\n        element.removeAttribute(name);\\n      } else {\\n        element.setAttribute(name, value === true ? '' : value);\\n      }\\n    });\\n  });\\n}\\n\\nfunction effect(_ref2) {\\n  var state = _ref2.state;\\n  var initialStyles = {\\n    popper: {\\n      position: state.options.strategy,\\n      left: '0',\\n      top: '0',\\n      margin: '0'\\n    },\\n    arrow: {\\n      position: 'absolute'\\n    },\\n    reference: {}\\n  };\\n  Object.assign(state.elements.popper.style, initialStyles.popper);\\n  state.styles = initialStyles;\\n\\n  if (state.elements.arrow) {\\n    Object.assign(state.elements.arrow.style, initialStyles.arrow);\\n  }\\n\\n  return function () {\\n    Object.keys(state.elements).forEach(function (name) {\\n      var element = state.elements[name];\\n      var attributes = state.attributes[name] || {};\\n      var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\\n\\n      var style = styleProperties.reduce(function (style, property) {\\n        style[property] = '';\\n        return style;\\n      }, {}); // arrow is optional + virtual elements\\n\\n      if (!isHTMLElement(element) || !getNodeName(element)) {\\n        return;\\n      }\\n\\n      Object.assign(element.style, style);\\n      Object.keys(attributes).forEach(function (attribute) {\\n        element.removeAttribute(attribute);\\n      });\\n    });\\n  };\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'applyStyles',\\n  enabled: true,\\n  phase: 'write',\\n  fn: applyStyles,\\n  effect: effect,\\n  requires: ['computeStyles']\\n};\",\"import { auto } from \\\"../enums.js\\\";\\nexport default function getBasePlacement(placement) {\\n  return placement.split('-')[0];\\n}\",\"export var max = Math.max;\\nexport var min = Math.min;\\nexport var round = Math.round;\",\"export default function getUAString() {\\n  var uaData = navigator.userAgentData;\\n\\n  if (uaData != null && uaData.brands) {\\n    return uaData.brands.map(function (item) {\\n      return item.brand + \\\"/\\\" + item.version;\\n    }).join(' ');\\n  }\\n\\n  return navigator.userAgent;\\n}\",\"import getUAString from \\\"../utils/userAgent.js\\\";\\nexport default function isLayoutViewport() {\\n  return !/^((?!chrome|android).)*safari/i.test(getUAString());\\n}\",\"import { isElement, isHTMLElement } from \\\"./instanceOf.js\\\";\\nimport { round } from \\\"../utils/math.js\\\";\\nimport getWindow from \\\"./getWindow.js\\\";\\nimport isLayoutViewport from \\\"./isLayoutViewport.js\\\";\\nexport default function getBoundingClientRect(element, includeScale, isFixedStrategy) {\\n  if (includeScale === void 0) {\\n    includeScale = false;\\n  }\\n\\n  if (isFixedStrategy === void 0) {\\n    isFixedStrategy = false;\\n  }\\n\\n  var clientRect = element.getBoundingClientRect();\\n  var scaleX = 1;\\n  var scaleY = 1;\\n\\n  if (includeScale && isHTMLElement(element)) {\\n    scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;\\n    scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;\\n  }\\n\\n  var _ref = isElement(element) ? getWindow(element) : window,\\n      visualViewport = _ref.visualViewport;\\n\\n  var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;\\n  var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;\\n  var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;\\n  var width = clientRect.width / scaleX;\\n  var height = clientRect.height / scaleY;\\n  return {\\n    width: width,\\n    height: height,\\n    top: y,\\n    right: x + width,\\n    bottom: y + height,\\n    left: x,\\n    x: x,\\n    y: y\\n  };\\n}\",\"import getBoundingClientRect from \\\"./getBoundingClientRect.js\\\"; // Returns the layout rect of an element relative to its offsetParent. Layout\\n// means it doesn't take into account transforms.\\n\\nexport default function getLayoutRect(element) {\\n  var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\\n  // Fixes https://github.com/popperjs/popper-core/issues/1223\\n\\n  var width = element.offsetWidth;\\n  var height = element.offsetHeight;\\n\\n  if (Math.abs(clientRect.width - width) <= 1) {\\n    width = clientRect.width;\\n  }\\n\\n  if (Math.abs(clientRect.height - height) <= 1) {\\n    height = clientRect.height;\\n  }\\n\\n  return {\\n    x: element.offsetLeft,\\n    y: element.offsetTop,\\n    width: width,\\n    height: height\\n  };\\n}\",\"import { isShadowRoot } from \\\"./instanceOf.js\\\";\\nexport default function contains(parent, child) {\\n  var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\\n\\n  if (parent.contains(child)) {\\n    return true;\\n  } // then fallback to custom implementation with Shadow DOM support\\n  else if (rootNode && isShadowRoot(rootNode)) {\\n      var next = child;\\n\\n      do {\\n        if (next && parent.isSameNode(next)) {\\n          return true;\\n        } // $FlowFixMe[prop-missing]: need a better way to handle this...\\n\\n\\n        next = next.parentNode || next.host;\\n      } while (next);\\n    } // Give up, the result is false\\n\\n\\n  return false;\\n}\",\"import getWindow from \\\"./getWindow.js\\\";\\nexport default function getComputedStyle(element) {\\n  return getWindow(element).getComputedStyle(element);\\n}\",\"import getNodeName from \\\"./getNodeName.js\\\";\\nexport default function isTableElement(element) {\\n  return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\\n}\",\"import { isElement } from \\\"./instanceOf.js\\\";\\nexport default function getDocumentElement(element) {\\n  // $FlowFixMe[incompatible-return]: assume body is always available\\n  return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\\n  element.document) || window.document).documentElement;\\n}\",\"import getNodeName from \\\"./getNodeName.js\\\";\\nimport getDocumentElement from \\\"./getDocumentElement.js\\\";\\nimport { isShadowRoot } from \\\"./instanceOf.js\\\";\\nexport default function getParentNode(element) {\\n  if (getNodeName(element) === 'html') {\\n    return element;\\n  }\\n\\n  return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\\n    // $FlowFixMe[incompatible-return]\\n    // $FlowFixMe[prop-missing]\\n    element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\\n    element.parentNode || ( // DOM Element detected\\n    isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\\n    // $FlowFixMe[incompatible-call]: HTMLElement is a Node\\n    getDocumentElement(element) // fallback\\n\\n  );\\n}\",\"import getWindow from \\\"./getWindow.js\\\";\\nimport getNodeName from \\\"./getNodeName.js\\\";\\nimport getComputedStyle from \\\"./getComputedStyle.js\\\";\\nimport { isHTMLElement, isShadowRoot } from \\\"./instanceOf.js\\\";\\nimport isTableElement from \\\"./isTableElement.js\\\";\\nimport getParentNode from \\\"./getParentNode.js\\\";\\nimport getUAString from \\\"../utils/userAgent.js\\\";\\n\\nfunction getTrueOffsetParent(element) {\\n  if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\\n  getComputedStyle(element).position === 'fixed') {\\n    return null;\\n  }\\n\\n  return element.offsetParent;\\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\\n// return the containing block\\n\\n\\nfunction getContainingBlock(element) {\\n  var isFirefox = /firefox/i.test(getUAString());\\n  var isIE = /Trident/i.test(getUAString());\\n\\n  if (isIE && isHTMLElement(element)) {\\n    // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\\n    var elementCss = getComputedStyle(element);\\n\\n    if (elementCss.position === 'fixed') {\\n      return null;\\n    }\\n  }\\n\\n  var currentNode = getParentNode(element);\\n\\n  if (isShadowRoot(currentNode)) {\\n    currentNode = currentNode.host;\\n  }\\n\\n  while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\\n    var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\\n    // create a containing block.\\n    // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\\n\\n    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') {\\n      return currentNode;\\n    } else {\\n      currentNode = currentNode.parentNode;\\n    }\\n  }\\n\\n  return null;\\n} // Gets the closest ancestor positioned element. Handles some edge cases,\\n// such as table ancestors and cross browser bugs.\\n\\n\\nexport default function getOffsetParent(element) {\\n  var window = getWindow(element);\\n  var offsetParent = getTrueOffsetParent(element);\\n\\n  while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\\n    offsetParent = getTrueOffsetParent(offsetParent);\\n  }\\n\\n  if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {\\n    return window;\\n  }\\n\\n  return offsetParent || getContainingBlock(element) || window;\\n}\",\"export default function getMainAxisFromPlacement(placement) {\\n  return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\\n}\",\"import { max as mathMax, min as mathMin } from \\\"./math.js\\\";\\nexport function within(min, value, max) {\\n  return mathMax(min, mathMin(value, max));\\n}\\nexport function withinMaxClamp(min, value, max) {\\n  var v = within(min, value, max);\\n  return v > max ? max : v;\\n}\",\"import getFreshSideObject from \\\"./getFreshSideObject.js\\\";\\nexport default function mergePaddingObject(paddingObject) {\\n  return Object.assign({}, getFreshSideObject(), paddingObject);\\n}\",\"export default function getFreshSideObject() {\\n  return {\\n    top: 0,\\n    right: 0,\\n    bottom: 0,\\n    left: 0\\n  };\\n}\",\"export default function expandToHashMap(value, keys) {\\n  return keys.reduce(function (hashMap, key) {\\n    hashMap[key] = value;\\n    return hashMap;\\n  }, {});\\n}\",\"import getBasePlacement from \\\"../utils/getBasePlacement.js\\\";\\nimport getLayoutRect from \\\"../dom-utils/getLayoutRect.js\\\";\\nimport contains from \\\"../dom-utils/contains.js\\\";\\nimport getOffsetParent from \\\"../dom-utils/getOffsetParent.js\\\";\\nimport getMainAxisFromPlacement from \\\"../utils/getMainAxisFromPlacement.js\\\";\\nimport { within } from \\\"../utils/within.js\\\";\\nimport mergePaddingObject from \\\"../utils/mergePaddingObject.js\\\";\\nimport expandToHashMap from \\\"../utils/expandToHashMap.js\\\";\\nimport { left, right, basePlacements, top, bottom } from \\\"../enums.js\\\";\\nimport { isHTMLElement } from \\\"../dom-utils/instanceOf.js\\\"; // eslint-disable-next-line import/no-unused-modules\\n\\nvar toPaddingObject = function toPaddingObject(padding, state) {\\n  padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\\n    placement: state.placement\\n  })) : padding;\\n  return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\\n};\\n\\nfunction arrow(_ref) {\\n  var _state$modifiersData$;\\n\\n  var state = _ref.state,\\n      name = _ref.name,\\n      options = _ref.options;\\n  var arrowElement = state.elements.arrow;\\n  var popperOffsets = state.modifiersData.popperOffsets;\\n  var basePlacement = getBasePlacement(state.placement);\\n  var axis = getMainAxisFromPlacement(basePlacement);\\n  var isVertical = [left, right].indexOf(basePlacement) >= 0;\\n  var len = isVertical ? 'height' : 'width';\\n\\n  if (!arrowElement || !popperOffsets) {\\n    return;\\n  }\\n\\n  var paddingObject = toPaddingObject(options.padding, state);\\n  var arrowRect = getLayoutRect(arrowElement);\\n  var minProp = axis === 'y' ? top : left;\\n  var maxProp = axis === 'y' ? bottom : right;\\n  var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\\n  var startDiff = popperOffsets[axis] - state.rects.reference[axis];\\n  var arrowOffsetParent = getOffsetParent(arrowElement);\\n  var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\\n  var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\\n  // outside of the popper bounds\\n\\n  var min = paddingObject[minProp];\\n  var max = clientSize - arrowRect[len] - paddingObject[maxProp];\\n  var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\\n  var offset = within(min, center, max); // Prevents breaking syntax highlighting...\\n\\n  var axisProp = axis;\\n  state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\\n}\\n\\nfunction effect(_ref2) {\\n  var state = _ref2.state,\\n      options = _ref2.options;\\n  var _options$element = options.element,\\n      arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\\n\\n  if (arrowElement == null) {\\n    return;\\n  } // CSS selector\\n\\n\\n  if (typeof arrowElement === 'string') {\\n    arrowElement = state.elements.popper.querySelector(arrowElement);\\n\\n    if (!arrowElement) {\\n      return;\\n    }\\n  }\\n\\n  if (process.env.NODE_ENV !== \\\"production\\\") {\\n    if (!isHTMLElement(arrowElement)) {\\n      console.error(['Popper: \\\"arrow\\\" element must be an HTMLElement (not an SVGElement).', 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', 'the arrow.'].join(' '));\\n    }\\n  }\\n\\n  if (!contains(state.elements.popper, arrowElement)) {\\n    if (process.env.NODE_ENV !== \\\"production\\\") {\\n      console.error(['Popper: \\\"arrow\\\" modifier\\\\'s `element` must be a child of the popper', 'element.'].join(' '));\\n    }\\n\\n    return;\\n  }\\n\\n  state.elements.arrow = arrowElement;\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'arrow',\\n  enabled: true,\\n  phase: 'main',\\n  fn: arrow,\\n  effect: effect,\\n  requires: ['popperOffsets'],\\n  requiresIfExists: ['preventOverflow']\\n};\",\"export default function getVariation(placement) {\\n  return placement.split('-')[1];\\n}\",\"import { top, left, right, bottom, end } from \\\"../enums.js\\\";\\nimport getOffsetParent from \\\"../dom-utils/getOffsetParent.js\\\";\\nimport getWindow from \\\"../dom-utils/getWindow.js\\\";\\nimport getDocumentElement from \\\"../dom-utils/getDocumentElement.js\\\";\\nimport getComputedStyle from \\\"../dom-utils/getComputedStyle.js\\\";\\nimport getBasePlacement from \\\"../utils/getBasePlacement.js\\\";\\nimport getVariation from \\\"../utils/getVariation.js\\\";\\nimport { round } from \\\"../utils/math.js\\\"; // eslint-disable-next-line import/no-unused-modules\\n\\nvar unsetSides = {\\n  top: 'auto',\\n  right: 'auto',\\n  bottom: 'auto',\\n  left: 'auto'\\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\\n// Zooming can change the DPR, but it seems to report a value that will\\n// cleanly divide the values into the appropriate subpixels.\\n\\nfunction roundOffsetsByDPR(_ref) {\\n  var x = _ref.x,\\n      y = _ref.y;\\n  var win = window;\\n  var dpr = win.devicePixelRatio || 1;\\n  return {\\n    x: round(x * dpr) / dpr || 0,\\n    y: round(y * dpr) / dpr || 0\\n  };\\n}\\n\\nexport function mapToStyles(_ref2) {\\n  var _Object$assign2;\\n\\n  var popper = _ref2.popper,\\n      popperRect = _ref2.popperRect,\\n      placement = _ref2.placement,\\n      variation = _ref2.variation,\\n      offsets = _ref2.offsets,\\n      position = _ref2.position,\\n      gpuAcceleration = _ref2.gpuAcceleration,\\n      adaptive = _ref2.adaptive,\\n      roundOffsets = _ref2.roundOffsets,\\n      isFixed = _ref2.isFixed;\\n  var _offsets$x = offsets.x,\\n      x = _offsets$x === void 0 ? 0 : _offsets$x,\\n      _offsets$y = offsets.y,\\n      y = _offsets$y === void 0 ? 0 : _offsets$y;\\n\\n  var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({\\n    x: x,\\n    y: y\\n  }) : {\\n    x: x,\\n    y: y\\n  };\\n\\n  x = _ref3.x;\\n  y = _ref3.y;\\n  var hasX = offsets.hasOwnProperty('x');\\n  var hasY = offsets.hasOwnProperty('y');\\n  var sideX = left;\\n  var sideY = top;\\n  var win = window;\\n\\n  if (adaptive) {\\n    var offsetParent = getOffsetParent(popper);\\n    var heightProp = 'clientHeight';\\n    var widthProp = 'clientWidth';\\n\\n    if (offsetParent === getWindow(popper)) {\\n      offsetParent = getDocumentElement(popper);\\n\\n      if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\\n        heightProp = 'scrollHeight';\\n        widthProp = 'scrollWidth';\\n      }\\n    } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\\n\\n\\n    offsetParent = offsetParent;\\n\\n    if (placement === top || (placement === left || placement === right) && variation === end) {\\n      sideY = bottom;\\n      var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]\\n      offsetParent[heightProp];\\n      y -= offsetY - popperRect.height;\\n      y *= gpuAcceleration ? 1 : -1;\\n    }\\n\\n    if (placement === left || (placement === top || placement === bottom) && variation === end) {\\n      sideX = right;\\n      var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]\\n      offsetParent[widthProp];\\n      x -= offsetX - popperRect.width;\\n      x *= gpuAcceleration ? 1 : -1;\\n    }\\n  }\\n\\n  var commonStyles = Object.assign({\\n    position: position\\n  }, adaptive && unsetSides);\\n\\n  var _ref4 = roundOffsets === true ? roundOffsetsByDPR({\\n    x: x,\\n    y: y\\n  }) : {\\n    x: x,\\n    y: y\\n  };\\n\\n  x = _ref4.x;\\n  y = _ref4.y;\\n\\n  if (gpuAcceleration) {\\n    var _Object$assign;\\n\\n    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));\\n  }\\n\\n  return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \\\"px\\\" : '', _Object$assign2[sideX] = hasX ? x + \\\"px\\\" : '', _Object$assign2.transform = '', _Object$assign2));\\n}\\n\\nfunction computeStyles(_ref5) {\\n  var state = _ref5.state,\\n      options = _ref5.options;\\n  var _options$gpuAccelerat = options.gpuAcceleration,\\n      gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\\n      _options$adaptive = options.adaptive,\\n      adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\\n      _options$roundOffsets = options.roundOffsets,\\n      roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\\n\\n  if (process.env.NODE_ENV !== \\\"production\\\") {\\n    var transitionProperty = getComputedStyle(state.elements.popper).transitionProperty || '';\\n\\n    if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) {\\n      return transitionProperty.indexOf(property) >= 0;\\n    })) {\\n      console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: \\\"transform\\\", \\\"top\\\", \\\"right\\\", \\\"bottom\\\", \\\"left\\\".', '\\\\n\\\\n', 'Disable the \\\"computeStyles\\\" modifier\\\\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\\\\n\\\\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' '));\\n    }\\n  }\\n\\n  var commonStyles = {\\n    placement: getBasePlacement(state.placement),\\n    variation: getVariation(state.placement),\\n    popper: state.elements.popper,\\n    popperRect: state.rects.popper,\\n    gpuAcceleration: gpuAcceleration,\\n    isFixed: state.options.strategy === 'fixed'\\n  };\\n\\n  if (state.modifiersData.popperOffsets != null) {\\n    state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\\n      offsets: state.modifiersData.popperOffsets,\\n      position: state.options.strategy,\\n      adaptive: adaptive,\\n      roundOffsets: roundOffsets\\n    })));\\n  }\\n\\n  if (state.modifiersData.arrow != null) {\\n    state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\\n      offsets: state.modifiersData.arrow,\\n      position: 'absolute',\\n      adaptive: false,\\n      roundOffsets: roundOffsets\\n    })));\\n  }\\n\\n  state.attributes.popper = Object.assign({}, state.attributes.popper, {\\n    'data-popper-placement': state.placement\\n  });\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'computeStyles',\\n  enabled: true,\\n  phase: 'beforeWrite',\\n  fn: computeStyles,\\n  data: {}\\n};\",\"import getWindow from \\\"../dom-utils/getWindow.js\\\"; // eslint-disable-next-line import/no-unused-modules\\n\\nvar passive = {\\n  passive: true\\n};\\n\\nfunction effect(_ref) {\\n  var state = _ref.state,\\n      instance = _ref.instance,\\n      options = _ref.options;\\n  var _options$scroll = options.scroll,\\n      scroll = _options$scroll === void 0 ? true : _options$scroll,\\n      _options$resize = options.resize,\\n      resize = _options$resize === void 0 ? true : _options$resize;\\n  var window = getWindow(state.elements.popper);\\n  var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\\n\\n  if (scroll) {\\n    scrollParents.forEach(function (scrollParent) {\\n      scrollParent.addEventListener('scroll', instance.update, passive);\\n    });\\n  }\\n\\n  if (resize) {\\n    window.addEventListener('resize', instance.update, passive);\\n  }\\n\\n  return function () {\\n    if (scroll) {\\n      scrollParents.forEach(function (scrollParent) {\\n        scrollParent.removeEventListener('scroll', instance.update, passive);\\n      });\\n    }\\n\\n    if (resize) {\\n      window.removeEventListener('resize', instance.update, passive);\\n    }\\n  };\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'eventListeners',\\n  enabled: true,\\n  phase: 'write',\\n  fn: function fn() {},\\n  effect: effect,\\n  data: {}\\n};\",\"var hash = {\\n  left: 'right',\\n  right: 'left',\\n  bottom: 'top',\\n  top: 'bottom'\\n};\\nexport default function getOppositePlacement(placement) {\\n  return placement.replace(/left|right|bottom|top/g, function (matched) {\\n    return hash[matched];\\n  });\\n}\",\"var hash = {\\n  start: 'end',\\n  end: 'start'\\n};\\nexport default function getOppositeVariationPlacement(placement) {\\n  return placement.replace(/start|end/g, function (matched) {\\n    return hash[matched];\\n  });\\n}\",\"import getWindow from \\\"./getWindow.js\\\";\\nexport default function getWindowScroll(node) {\\n  var win = getWindow(node);\\n  var scrollLeft = win.pageXOffset;\\n  var scrollTop = win.pageYOffset;\\n  return {\\n    scrollLeft: scrollLeft,\\n    scrollTop: scrollTop\\n  };\\n}\",\"import getBoundingClientRect from \\\"./getBoundingClientRect.js\\\";\\nimport getDocumentElement from \\\"./getDocumentElement.js\\\";\\nimport getWindowScroll from \\\"./getWindowScroll.js\\\";\\nexport default function getWindowScrollBarX(element) {\\n  // If <html> has a CSS width greater than the viewport, then this will be\\n  // incorrect for RTL.\\n  // Popper 1 is broken in this case and never had a bug report so let's assume\\n  // it's not an issue. I don't think anyone ever specifies width on <html>\\n  // anyway.\\n  // Browsers where the left scrollbar doesn't cause an issue report `0` for\\n  // this (e.g. Edge 2019, IE11, Safari)\\n  return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\\n}\",\"import getComputedStyle from \\\"./getComputedStyle.js\\\";\\nexport default function isScrollParent(element) {\\n  // Firefox wants us to check `-x` and `-y` variations as well\\n  var _getComputedStyle = getComputedStyle(element),\\n      overflow = _getComputedStyle.overflow,\\n      overflowX = _getComputedStyle.overflowX,\\n      overflowY = _getComputedStyle.overflowY;\\n\\n  return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\\n}\",\"import getParentNode from \\\"./getParentNode.js\\\";\\nimport isScrollParent from \\\"./isScrollParent.js\\\";\\nimport getNodeName from \\\"./getNodeName.js\\\";\\nimport { isHTMLElement } from \\\"./instanceOf.js\\\";\\nexport default function getScrollParent(node) {\\n  if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\\n    // $FlowFixMe[incompatible-return]: assume body is always available\\n    return node.ownerDocument.body;\\n  }\\n\\n  if (isHTMLElement(node) && isScrollParent(node)) {\\n    return node;\\n  }\\n\\n  return getScrollParent(getParentNode(node));\\n}\",\"import getScrollParent from \\\"./getScrollParent.js\\\";\\nimport getParentNode from \\\"./getParentNode.js\\\";\\nimport getWindow from \\\"./getWindow.js\\\";\\nimport isScrollParent from \\\"./isScrollParent.js\\\";\\n/*\\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\\nuntil we get to the top window object. This list is what we attach scroll listeners\\nto, because if any of these parent elements scroll, we'll need to re-calculate the\\nreference element's position.\\n*/\\n\\nexport default function listScrollParents(element, list) {\\n  var _element$ownerDocumen;\\n\\n  if (list === void 0) {\\n    list = [];\\n  }\\n\\n  var scrollParent = getScrollParent(element);\\n  var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\\n  var win = getWindow(scrollParent);\\n  var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\\n  var updatedList = list.concat(target);\\n  return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\\n  updatedList.concat(listScrollParents(getParentNode(target)));\\n}\",\"export default function rectToClientRect(rect) {\\n  return Object.assign({}, rect, {\\n    left: rect.x,\\n    top: rect.y,\\n    right: rect.x + rect.width,\\n    bottom: rect.y + rect.height\\n  });\\n}\",\"import { viewport } from \\\"../enums.js\\\";\\nimport getViewportRect from \\\"./getViewportRect.js\\\";\\nimport getDocumentRect from \\\"./getDocumentRect.js\\\";\\nimport listScrollParents from \\\"./listScrollParents.js\\\";\\nimport getOffsetParent from \\\"./getOffsetParent.js\\\";\\nimport getDocumentElement from \\\"./getDocumentElement.js\\\";\\nimport getComputedStyle from \\\"./getComputedStyle.js\\\";\\nimport { isElement, isHTMLElement } from \\\"./instanceOf.js\\\";\\nimport getBoundingClientRect from \\\"./getBoundingClientRect.js\\\";\\nimport getParentNode from \\\"./getParentNode.js\\\";\\nimport contains from \\\"./contains.js\\\";\\nimport getNodeName from \\\"./getNodeName.js\\\";\\nimport rectToClientRect from \\\"../utils/rectToClientRect.js\\\";\\nimport { max, min } from \\\"../utils/math.js\\\";\\n\\nfunction getInnerBoundingClientRect(element, strategy) {\\n  var rect = getBoundingClientRect(element, false, strategy === 'fixed');\\n  rect.top = rect.top + element.clientTop;\\n  rect.left = rect.left + element.clientLeft;\\n  rect.bottom = rect.top + element.clientHeight;\\n  rect.right = rect.left + element.clientWidth;\\n  rect.width = element.clientWidth;\\n  rect.height = element.clientHeight;\\n  rect.x = rect.left;\\n  rect.y = rect.top;\\n  return rect;\\n}\\n\\nfunction getClientRectFromMixedType(element, clippingParent, strategy) {\\n  return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\\n} // A \\\"clipping parent\\\" is an overflowable container with the characteristic of\\n// clipping (or hiding) overflowing elements with a position different from\\n// `initial`\\n\\n\\nfunction getClippingParents(element) {\\n  var clippingParents = listScrollParents(getParentNode(element));\\n  var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;\\n  var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\\n\\n  if (!isElement(clipperElement)) {\\n    return [];\\n  } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\\n\\n\\n  return clippingParents.filter(function (clippingParent) {\\n    return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\\n  });\\n} // Gets the maximum area that the element is visible in due to any number of\\n// clipping parents\\n\\n\\nexport default function getClippingRect(element, boundary, rootBoundary, strategy) {\\n  var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\\n  var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\\n  var firstClippingParent = clippingParents[0];\\n  var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\\n    var rect = getClientRectFromMixedType(element, clippingParent, strategy);\\n    accRect.top = max(rect.top, accRect.top);\\n    accRect.right = min(rect.right, accRect.right);\\n    accRect.bottom = min(rect.bottom, accRect.bottom);\\n    accRect.left = max(rect.left, accRect.left);\\n    return accRect;\\n  }, getClientRectFromMixedType(element, firstClippingParent, strategy));\\n  clippingRect.width = clippingRect.right - clippingRect.left;\\n  clippingRect.height = clippingRect.bottom - clippingRect.top;\\n  clippingRect.x = clippingRect.left;\\n  clippingRect.y = clippingRect.top;\\n  return clippingRect;\\n}\",\"import getWindow from \\\"./getWindow.js\\\";\\nimport getDocumentElement from \\\"./getDocumentElement.js\\\";\\nimport getWindowScrollBarX from \\\"./getWindowScrollBarX.js\\\";\\nimport isLayoutViewport from \\\"./isLayoutViewport.js\\\";\\nexport default function getViewportRect(element, strategy) {\\n  var win = getWindow(element);\\n  var html = getDocumentElement(element);\\n  var visualViewport = win.visualViewport;\\n  var width = html.clientWidth;\\n  var height = html.clientHeight;\\n  var x = 0;\\n  var y = 0;\\n\\n  if (visualViewport) {\\n    width = visualViewport.width;\\n    height = visualViewport.height;\\n    var layoutViewport = isLayoutViewport();\\n\\n    if (layoutViewport || !layoutViewport && strategy === 'fixed') {\\n      x = visualViewport.offsetLeft;\\n      y = visualViewport.offsetTop;\\n    }\\n  }\\n\\n  return {\\n    width: width,\\n    height: height,\\n    x: x + getWindowScrollBarX(element),\\n    y: y\\n  };\\n}\",\"import getDocumentElement from \\\"./getDocumentElement.js\\\";\\nimport getComputedStyle from \\\"./getComputedStyle.js\\\";\\nimport getWindowScrollBarX from \\\"./getWindowScrollBarX.js\\\";\\nimport getWindowScroll from \\\"./getWindowScroll.js\\\";\\nimport { max } from \\\"../utils/math.js\\\"; // Gets the entire size of the scrollable document area, even extending outside\\n// of the `<html>` and `<body>` rect bounds if horizontally scrollable\\n\\nexport default function getDocumentRect(element) {\\n  var _element$ownerDocumen;\\n\\n  var html = getDocumentElement(element);\\n  var winScroll = getWindowScroll(element);\\n  var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\\n  var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\\n  var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\\n  var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\\n  var y = -winScroll.scrollTop;\\n\\n  if (getComputedStyle(body || html).direction === 'rtl') {\\n    x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\\n  }\\n\\n  return {\\n    width: width,\\n    height: height,\\n    x: x,\\n    y: y\\n  };\\n}\",\"import getBasePlacement from \\\"./getBasePlacement.js\\\";\\nimport getVariation from \\\"./getVariation.js\\\";\\nimport getMainAxisFromPlacement from \\\"./getMainAxisFromPlacement.js\\\";\\nimport { top, right, bottom, left, start, end } from \\\"../enums.js\\\";\\nexport default function computeOffsets(_ref) {\\n  var reference = _ref.reference,\\n      element = _ref.element,\\n      placement = _ref.placement;\\n  var basePlacement = placement ? getBasePlacement(placement) : null;\\n  var variation = placement ? getVariation(placement) : null;\\n  var commonX = reference.x + reference.width / 2 - element.width / 2;\\n  var commonY = reference.y + reference.height / 2 - element.height / 2;\\n  var offsets;\\n\\n  switch (basePlacement) {\\n    case top:\\n      offsets = {\\n        x: commonX,\\n        y: reference.y - element.height\\n      };\\n      break;\\n\\n    case bottom:\\n      offsets = {\\n        x: commonX,\\n        y: reference.y + reference.height\\n      };\\n      break;\\n\\n    case right:\\n      offsets = {\\n        x: reference.x + reference.width,\\n        y: commonY\\n      };\\n      break;\\n\\n    case left:\\n      offsets = {\\n        x: reference.x - element.width,\\n        y: commonY\\n      };\\n      break;\\n\\n    default:\\n      offsets = {\\n        x: reference.x,\\n        y: reference.y\\n      };\\n  }\\n\\n  var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\\n\\n  if (mainAxis != null) {\\n    var len = mainAxis === 'y' ? 'height' : 'width';\\n\\n    switch (variation) {\\n      case start:\\n        offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\\n        break;\\n\\n      case end:\\n        offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\\n        break;\\n\\n      default:\\n    }\\n  }\\n\\n  return offsets;\\n}\",\"import getClippingRect from \\\"../dom-utils/getClippingRect.js\\\";\\nimport getDocumentElement from \\\"../dom-utils/getDocumentElement.js\\\";\\nimport getBoundingClientRect from \\\"../dom-utils/getBoundingClientRect.js\\\";\\nimport computeOffsets from \\\"./computeOffsets.js\\\";\\nimport rectToClientRect from \\\"./rectToClientRect.js\\\";\\nimport { clippingParents, reference, popper, bottom, top, right, basePlacements, viewport } from \\\"../enums.js\\\";\\nimport { isElement } from \\\"../dom-utils/instanceOf.js\\\";\\nimport mergePaddingObject from \\\"./mergePaddingObject.js\\\";\\nimport expandToHashMap from \\\"./expandToHashMap.js\\\"; // eslint-disable-next-line import/no-unused-modules\\n\\nexport default function detectOverflow(state, options) {\\n  if (options === void 0) {\\n    options = {};\\n  }\\n\\n  var _options = options,\\n      _options$placement = _options.placement,\\n      placement = _options$placement === void 0 ? state.placement : _options$placement,\\n      _options$strategy = _options.strategy,\\n      strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,\\n      _options$boundary = _options.boundary,\\n      boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\\n      _options$rootBoundary = _options.rootBoundary,\\n      rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\\n      _options$elementConte = _options.elementContext,\\n      elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\\n      _options$altBoundary = _options.altBoundary,\\n      altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\\n      _options$padding = _options.padding,\\n      padding = _options$padding === void 0 ? 0 : _options$padding;\\n  var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\\n  var altContext = elementContext === popper ? reference : popper;\\n  var popperRect = state.rects.popper;\\n  var element = state.elements[altBoundary ? altContext : elementContext];\\n  var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);\\n  var referenceClientRect = getBoundingClientRect(state.elements.reference);\\n  var popperOffsets = computeOffsets({\\n    reference: referenceClientRect,\\n    element: popperRect,\\n    strategy: 'absolute',\\n    placement: placement\\n  });\\n  var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\\n  var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\\n  // 0 or negative = within the clipping rect\\n\\n  var overflowOffsets = {\\n    top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\\n    bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\\n    left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\\n    right: elementClientRect.right - clippingClientRect.right + paddingObject.right\\n  };\\n  var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\\n\\n  if (elementContext === popper && offsetData) {\\n    var offset = offsetData[placement];\\n    Object.keys(overflowOffsets).forEach(function (key) {\\n      var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\\n      var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\\n      overflowOffsets[key] += offset[axis] * multiply;\\n    });\\n  }\\n\\n  return overflowOffsets;\\n}\",\"import getVariation from \\\"./getVariation.js\\\";\\nimport { variationPlacements, basePlacements, placements as allPlacements } from \\\"../enums.js\\\";\\nimport detectOverflow from \\\"./detectOverflow.js\\\";\\nimport getBasePlacement from \\\"./getBasePlacement.js\\\";\\nexport default function computeAutoPlacement(state, options) {\\n  if (options === void 0) {\\n    options = {};\\n  }\\n\\n  var _options = options,\\n      placement = _options.placement,\\n      boundary = _options.boundary,\\n      rootBoundary = _options.rootBoundary,\\n      padding = _options.padding,\\n      flipVariations = _options.flipVariations,\\n      _options$allowedAutoP = _options.allowedAutoPlacements,\\n      allowedAutoPlacements = _options$allowedAutoP === void 0 ? allPlacements : _options$allowedAutoP;\\n  var variation = getVariation(placement);\\n  var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\\n    return getVariation(placement) === variation;\\n  }) : basePlacements;\\n  var allowedPlacements = placements.filter(function (placement) {\\n    return allowedAutoPlacements.indexOf(placement) >= 0;\\n  });\\n\\n  if (allowedPlacements.length === 0) {\\n    allowedPlacements = placements;\\n\\n    if (process.env.NODE_ENV !== \\\"production\\\") {\\n      console.error(['Popper: The `allowedAutoPlacements` option did not allow any', 'placements. Ensure the `placement` option matches the variation', 'of the allowed placements.', 'For example, \\\"auto\\\" cannot be used to allow \\\"bottom-start\\\".', 'Use \\\"auto-start\\\" instead.'].join(' '));\\n    }\\n  } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\\n\\n\\n  var overflows = allowedPlacements.reduce(function (acc, placement) {\\n    acc[placement] = detectOverflow(state, {\\n      placement: placement,\\n      boundary: boundary,\\n      rootBoundary: rootBoundary,\\n      padding: padding\\n    })[getBasePlacement(placement)];\\n    return acc;\\n  }, {});\\n  return Object.keys(overflows).sort(function (a, b) {\\n    return overflows[a] - overflows[b];\\n  });\\n}\",\"import getOppositePlacement from \\\"../utils/getOppositePlacement.js\\\";\\nimport getBasePlacement from \\\"../utils/getBasePlacement.js\\\";\\nimport getOppositeVariationPlacement from \\\"../utils/getOppositeVariationPlacement.js\\\";\\nimport detectOverflow from \\\"../utils/detectOverflow.js\\\";\\nimport computeAutoPlacement from \\\"../utils/computeAutoPlacement.js\\\";\\nimport { bottom, top, start, right, left, auto } from \\\"../enums.js\\\";\\nimport getVariation from \\\"../utils/getVariation.js\\\"; // eslint-disable-next-line import/no-unused-modules\\n\\nfunction getExpandedFallbackPlacements(placement) {\\n  if (getBasePlacement(placement) === auto) {\\n    return [];\\n  }\\n\\n  var oppositePlacement = getOppositePlacement(placement);\\n  return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\\n}\\n\\nfunction flip(_ref) {\\n  var state = _ref.state,\\n      options = _ref.options,\\n      name = _ref.name;\\n\\n  if (state.modifiersData[name]._skip) {\\n    return;\\n  }\\n\\n  var _options$mainAxis = options.mainAxis,\\n      checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\\n      _options$altAxis = options.altAxis,\\n      checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\\n      specifiedFallbackPlacements = options.fallbackPlacements,\\n      padding = options.padding,\\n      boundary = options.boundary,\\n      rootBoundary = options.rootBoundary,\\n      altBoundary = options.altBoundary,\\n      _options$flipVariatio = options.flipVariations,\\n      flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\\n      allowedAutoPlacements = options.allowedAutoPlacements;\\n  var preferredPlacement = state.options.placement;\\n  var basePlacement = getBasePlacement(preferredPlacement);\\n  var isBasePlacement = basePlacement === preferredPlacement;\\n  var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\\n  var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\\n    return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\\n      placement: placement,\\n      boundary: boundary,\\n      rootBoundary: rootBoundary,\\n      padding: padding,\\n      flipVariations: flipVariations,\\n      allowedAutoPlacements: allowedAutoPlacements\\n    }) : placement);\\n  }, []);\\n  var referenceRect = state.rects.reference;\\n  var popperRect = state.rects.popper;\\n  var checksMap = new Map();\\n  var makeFallbackChecks = true;\\n  var firstFittingPlacement = placements[0];\\n\\n  for (var i = 0; i < placements.length; i++) {\\n    var placement = placements[i];\\n\\n    var _basePlacement = getBasePlacement(placement);\\n\\n    var isStartVariation = getVariation(placement) === start;\\n    var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\\n    var len = isVertical ? 'width' : 'height';\\n    var overflow = detectOverflow(state, {\\n      placement: placement,\\n      boundary: boundary,\\n      rootBoundary: rootBoundary,\\n      altBoundary: altBoundary,\\n      padding: padding\\n    });\\n    var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\\n\\n    if (referenceRect[len] > popperRect[len]) {\\n      mainVariationSide = getOppositePlacement(mainVariationSide);\\n    }\\n\\n    var altVariationSide = getOppositePlacement(mainVariationSide);\\n    var checks = [];\\n\\n    if (checkMainAxis) {\\n      checks.push(overflow[_basePlacement] <= 0);\\n    }\\n\\n    if (checkAltAxis) {\\n      checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\\n    }\\n\\n    if (checks.every(function (check) {\\n      return check;\\n    })) {\\n      firstFittingPlacement = placement;\\n      makeFallbackChecks = false;\\n      break;\\n    }\\n\\n    checksMap.set(placement, checks);\\n  }\\n\\n  if (makeFallbackChecks) {\\n    // `2` may be desired in some cases – research later\\n    var numberOfChecks = flipVariations ? 3 : 1;\\n\\n    var _loop = function _loop(_i) {\\n      var fittingPlacement = placements.find(function (placement) {\\n        var checks = checksMap.get(placement);\\n\\n        if (checks) {\\n          return checks.slice(0, _i).every(function (check) {\\n            return check;\\n          });\\n        }\\n      });\\n\\n      if (fittingPlacement) {\\n        firstFittingPlacement = fittingPlacement;\\n        return \\\"break\\\";\\n      }\\n    };\\n\\n    for (var _i = numberOfChecks; _i > 0; _i--) {\\n      var _ret = _loop(_i);\\n\\n      if (_ret === \\\"break\\\") break;\\n    }\\n  }\\n\\n  if (state.placement !== firstFittingPlacement) {\\n    state.modifiersData[name]._skip = true;\\n    state.placement = firstFittingPlacement;\\n    state.reset = true;\\n  }\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'flip',\\n  enabled: true,\\n  phase: 'main',\\n  fn: flip,\\n  requiresIfExists: ['offset'],\\n  data: {\\n    _skip: false\\n  }\\n};\",\"import { top, bottom, left, right } from \\\"../enums.js\\\";\\nimport detectOverflow from \\\"../utils/detectOverflow.js\\\";\\n\\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\\n  if (preventedOffsets === void 0) {\\n    preventedOffsets = {\\n      x: 0,\\n      y: 0\\n    };\\n  }\\n\\n  return {\\n    top: overflow.top - rect.height - preventedOffsets.y,\\n    right: overflow.right - rect.width + preventedOffsets.x,\\n    bottom: overflow.bottom - rect.height + preventedOffsets.y,\\n    left: overflow.left - rect.width - preventedOffsets.x\\n  };\\n}\\n\\nfunction isAnySideFullyClipped(overflow) {\\n  return [top, right, bottom, left].some(function (side) {\\n    return overflow[side] >= 0;\\n  });\\n}\\n\\nfunction hide(_ref) {\\n  var state = _ref.state,\\n      name = _ref.name;\\n  var referenceRect = state.rects.reference;\\n  var popperRect = state.rects.popper;\\n  var preventedOffsets = state.modifiersData.preventOverflow;\\n  var referenceOverflow = detectOverflow(state, {\\n    elementContext: 'reference'\\n  });\\n  var popperAltOverflow = detectOverflow(state, {\\n    altBoundary: true\\n  });\\n  var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\\n  var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\\n  var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\\n  var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\\n  state.modifiersData[name] = {\\n    referenceClippingOffsets: referenceClippingOffsets,\\n    popperEscapeOffsets: popperEscapeOffsets,\\n    isReferenceHidden: isReferenceHidden,\\n    hasPopperEscaped: hasPopperEscaped\\n  };\\n  state.attributes.popper = Object.assign({}, state.attributes.popper, {\\n    'data-popper-reference-hidden': isReferenceHidden,\\n    'data-popper-escaped': hasPopperEscaped\\n  });\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'hide',\\n  enabled: true,\\n  phase: 'main',\\n  requiresIfExists: ['preventOverflow'],\\n  fn: hide\\n};\",\"import getBasePlacement from \\\"../utils/getBasePlacement.js\\\";\\nimport { top, left, right, placements } from \\\"../enums.js\\\"; // eslint-disable-next-line import/no-unused-modules\\n\\nexport function distanceAndSkiddingToXY(placement, rects, offset) {\\n  var basePlacement = getBasePlacement(placement);\\n  var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\\n\\n  var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\\n    placement: placement\\n  })) : offset,\\n      skidding = _ref[0],\\n      distance = _ref[1];\\n\\n  skidding = skidding || 0;\\n  distance = (distance || 0) * invertDistance;\\n  return [left, right].indexOf(basePlacement) >= 0 ? {\\n    x: distance,\\n    y: skidding\\n  } : {\\n    x: skidding,\\n    y: distance\\n  };\\n}\\n\\nfunction offset(_ref2) {\\n  var state = _ref2.state,\\n      options = _ref2.options,\\n      name = _ref2.name;\\n  var _options$offset = options.offset,\\n      offset = _options$offset === void 0 ? [0, 0] : _options$offset;\\n  var data = placements.reduce(function (acc, placement) {\\n    acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\\n    return acc;\\n  }, {});\\n  var _data$state$placement = data[state.placement],\\n      x = _data$state$placement.x,\\n      y = _data$state$placement.y;\\n\\n  if (state.modifiersData.popperOffsets != null) {\\n    state.modifiersData.popperOffsets.x += x;\\n    state.modifiersData.popperOffsets.y += y;\\n  }\\n\\n  state.modifiersData[name] = data;\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'offset',\\n  enabled: true,\\n  phase: 'main',\\n  requires: ['popperOffsets'],\\n  fn: offset\\n};\",\"import computeOffsets from \\\"../utils/computeOffsets.js\\\";\\n\\nfunction popperOffsets(_ref) {\\n  var state = _ref.state,\\n      name = _ref.name;\\n  // Offsets are the actual position the popper needs to have to be\\n  // properly positioned near its reference element\\n  // This is the most basic placement, and will be adjusted by\\n  // the modifiers in the next step\\n  state.modifiersData[name] = computeOffsets({\\n    reference: state.rects.reference,\\n    element: state.rects.popper,\\n    strategy: 'absolute',\\n    placement: state.placement\\n  });\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'popperOffsets',\\n  enabled: true,\\n  phase: 'read',\\n  fn: popperOffsets,\\n  data: {}\\n};\",\"import { top, left, right, bottom, start } from \\\"../enums.js\\\";\\nimport getBasePlacement from \\\"../utils/getBasePlacement.js\\\";\\nimport getMainAxisFromPlacement from \\\"../utils/getMainAxisFromPlacement.js\\\";\\nimport getAltAxis from \\\"../utils/getAltAxis.js\\\";\\nimport { within, withinMaxClamp } from \\\"../utils/within.js\\\";\\nimport getLayoutRect from \\\"../dom-utils/getLayoutRect.js\\\";\\nimport getOffsetParent from \\\"../dom-utils/getOffsetParent.js\\\";\\nimport detectOverflow from \\\"../utils/detectOverflow.js\\\";\\nimport getVariation from \\\"../utils/getVariation.js\\\";\\nimport getFreshSideObject from \\\"../utils/getFreshSideObject.js\\\";\\nimport { min as mathMin, max as mathMax } from \\\"../utils/math.js\\\";\\n\\nfunction preventOverflow(_ref) {\\n  var state = _ref.state,\\n      options = _ref.options,\\n      name = _ref.name;\\n  var _options$mainAxis = options.mainAxis,\\n      checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\\n      _options$altAxis = options.altAxis,\\n      checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\\n      boundary = options.boundary,\\n      rootBoundary = options.rootBoundary,\\n      altBoundary = options.altBoundary,\\n      padding = options.padding,\\n      _options$tether = options.tether,\\n      tether = _options$tether === void 0 ? true : _options$tether,\\n      _options$tetherOffset = options.tetherOffset,\\n      tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\\n  var overflow = detectOverflow(state, {\\n    boundary: boundary,\\n    rootBoundary: rootBoundary,\\n    padding: padding,\\n    altBoundary: altBoundary\\n  });\\n  var basePlacement = getBasePlacement(state.placement);\\n  var variation = getVariation(state.placement);\\n  var isBasePlacement = !variation;\\n  var mainAxis = getMainAxisFromPlacement(basePlacement);\\n  var altAxis = getAltAxis(mainAxis);\\n  var popperOffsets = state.modifiersData.popperOffsets;\\n  var referenceRect = state.rects.reference;\\n  var popperRect = state.rects.popper;\\n  var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\\n    placement: state.placement\\n  })) : tetherOffset;\\n  var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {\\n    mainAxis: tetherOffsetValue,\\n    altAxis: tetherOffsetValue\\n  } : Object.assign({\\n    mainAxis: 0,\\n    altAxis: 0\\n  }, tetherOffsetValue);\\n  var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;\\n  var data = {\\n    x: 0,\\n    y: 0\\n  };\\n\\n  if (!popperOffsets) {\\n    return;\\n  }\\n\\n  if (checkMainAxis) {\\n    var _offsetModifierState$;\\n\\n    var mainSide = mainAxis === 'y' ? top : left;\\n    var altSide = mainAxis === 'y' ? bottom : right;\\n    var len = mainAxis === 'y' ? 'height' : 'width';\\n    var offset = popperOffsets[mainAxis];\\n    var min = offset + overflow[mainSide];\\n    var max = offset - overflow[altSide];\\n    var additive = tether ? -popperRect[len] / 2 : 0;\\n    var minLen = variation === start ? referenceRect[len] : popperRect[len];\\n    var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\\n    // outside the reference bounds\\n\\n    var arrowElement = state.elements.arrow;\\n    var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\\n      width: 0,\\n      height: 0\\n    };\\n    var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\\n    var arrowPaddingMin = arrowPaddingObject[mainSide];\\n    var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\\n    // to include its full size in the calculation. If the reference is small\\n    // and near the edge of a boundary, the popper can overflow even if the\\n    // reference is not overflowing as well (e.g. virtual elements with no\\n    // width or height)\\n\\n    var arrowLen = within(0, referenceRect[len], arrowRect[len]);\\n    var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;\\n    var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;\\n    var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\\n    var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\\n    var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;\\n    var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;\\n    var tetherMax = offset + maxOffset - offsetModifierValue;\\n    var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);\\n    popperOffsets[mainAxis] = preventedOffset;\\n    data[mainAxis] = preventedOffset - offset;\\n  }\\n\\n  if (checkAltAxis) {\\n    var _offsetModifierState$2;\\n\\n    var _mainSide = mainAxis === 'x' ? top : left;\\n\\n    var _altSide = mainAxis === 'x' ? bottom : right;\\n\\n    var _offset = popperOffsets[altAxis];\\n\\n    var _len = altAxis === 'y' ? 'height' : 'width';\\n\\n    var _min = _offset + overflow[_mainSide];\\n\\n    var _max = _offset - overflow[_altSide];\\n\\n    var isOriginSide = [top, left].indexOf(basePlacement) !== -1;\\n\\n    var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;\\n\\n    var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;\\n\\n    var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;\\n\\n    var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);\\n\\n    popperOffsets[altAxis] = _preventedOffset;\\n    data[altAxis] = _preventedOffset - _offset;\\n  }\\n\\n  state.modifiersData[name] = data;\\n} // eslint-disable-next-line import/no-unused-modules\\n\\n\\nexport default {\\n  name: 'preventOverflow',\\n  enabled: true,\\n  phase: 'main',\\n  fn: preventOverflow,\\n  requiresIfExists: ['offset']\\n};\",\"export default function getAltAxis(axis) {\\n  return axis === 'x' ? 'y' : 'x';\\n}\",\"import getBoundingClientRect from \\\"./getBoundingClientRect.js\\\";\\nimport getNodeScroll from \\\"./getNodeScroll.js\\\";\\nimport getNodeName from \\\"./getNodeName.js\\\";\\nimport { isHTMLElement } from \\\"./instanceOf.js\\\";\\nimport getWindowScrollBarX from \\\"./getWindowScrollBarX.js\\\";\\nimport getDocumentElement from \\\"./getDocumentElement.js\\\";\\nimport isScrollParent from \\\"./isScrollParent.js\\\";\\nimport { round } from \\\"../utils/math.js\\\";\\n\\nfunction isElementScaled(element) {\\n  var rect = element.getBoundingClientRect();\\n  var scaleX = round(rect.width) / element.offsetWidth || 1;\\n  var scaleY = round(rect.height) / element.offsetHeight || 1;\\n  return scaleX !== 1 || scaleY !== 1;\\n} // Returns the composite rect of an element relative to its offsetParent.\\n// Composite means it takes into account transforms as well as layout.\\n\\n\\nexport default function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\\n  if (isFixed === void 0) {\\n    isFixed = false;\\n  }\\n\\n  var isOffsetParentAnElement = isHTMLElement(offsetParent);\\n  var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\\n  var documentElement = getDocumentElement(offsetParent);\\n  var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);\\n  var scroll = {\\n    scrollLeft: 0,\\n    scrollTop: 0\\n  };\\n  var offsets = {\\n    x: 0,\\n    y: 0\\n  };\\n\\n  if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\\n    if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\\n    isScrollParent(documentElement)) {\\n      scroll = getNodeScroll(offsetParent);\\n    }\\n\\n    if (isHTMLElement(offsetParent)) {\\n      offsets = getBoundingClientRect(offsetParent, true);\\n      offsets.x += offsetParent.clientLeft;\\n      offsets.y += offsetParent.clientTop;\\n    } else if (documentElement) {\\n      offsets.x = getWindowScrollBarX(documentElement);\\n    }\\n  }\\n\\n  return {\\n    x: rect.left + scroll.scrollLeft - offsets.x,\\n    y: rect.top + scroll.scrollTop - offsets.y,\\n    width: rect.width,\\n    height: rect.height\\n  };\\n}\",\"import getWindowScroll from \\\"./getWindowScroll.js\\\";\\nimport getWindow from \\\"./getWindow.js\\\";\\nimport { isHTMLElement } from \\\"./instanceOf.js\\\";\\nimport getHTMLElementScroll from \\\"./getHTMLElementScroll.js\\\";\\nexport default function getNodeScroll(node) {\\n  if (node === getWindow(node) || !isHTMLElement(node)) {\\n    return getWindowScroll(node);\\n  } else {\\n    return getHTMLElementScroll(node);\\n  }\\n}\",\"export default function getHTMLElementScroll(element) {\\n  return {\\n    scrollLeft: element.scrollLeft,\\n    scrollTop: element.scrollTop\\n  };\\n}\",\"import { modifierPhases } from \\\"../enums.js\\\"; // source: https://stackoverflow.com/questions/49875255\\n\\nfunction order(modifiers) {\\n  var map = new Map();\\n  var visited = new Set();\\n  var result = [];\\n  modifiers.forEach(function (modifier) {\\n    map.set(modifier.name, modifier);\\n  }); // On visiting object, check for its dependencies and visit them recursively\\n\\n  function sort(modifier) {\\n    visited.add(modifier.name);\\n    var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\\n    requires.forEach(function (dep) {\\n      if (!visited.has(dep)) {\\n        var depModifier = map.get(dep);\\n\\n        if (depModifier) {\\n          sort(depModifier);\\n        }\\n      }\\n    });\\n    result.push(modifier);\\n  }\\n\\n  modifiers.forEach(function (modifier) {\\n    if (!visited.has(modifier.name)) {\\n      // check for visited object\\n      sort(modifier);\\n    }\\n  });\\n  return result;\\n}\\n\\nexport default function orderModifiers(modifiers) {\\n  // order based on dependencies\\n  var orderedModifiers = order(modifiers); // order based on phase\\n\\n  return modifierPhases.reduce(function (acc, phase) {\\n    return acc.concat(orderedModifiers.filter(function (modifier) {\\n      return modifier.phase === phase;\\n    }));\\n  }, []);\\n}\",\"import getCompositeRect from \\\"./dom-utils/getCompositeRect.js\\\";\\nimport getLayoutRect from \\\"./dom-utils/getLayoutRect.js\\\";\\nimport listScrollParents from \\\"./dom-utils/listScrollParents.js\\\";\\nimport getOffsetParent from \\\"./dom-utils/getOffsetParent.js\\\";\\nimport getComputedStyle from \\\"./dom-utils/getComputedStyle.js\\\";\\nimport orderModifiers from \\\"./utils/orderModifiers.js\\\";\\nimport debounce from \\\"./utils/debounce.js\\\";\\nimport validateModifiers from \\\"./utils/validateModifiers.js\\\";\\nimport uniqueBy from \\\"./utils/uniqueBy.js\\\";\\nimport getBasePlacement from \\\"./utils/getBasePlacement.js\\\";\\nimport mergeByName from \\\"./utils/mergeByName.js\\\";\\nimport detectOverflow from \\\"./utils/detectOverflow.js\\\";\\nimport { isElement } from \\\"./dom-utils/instanceOf.js\\\";\\nimport { auto } from \\\"./enums.js\\\";\\nvar INVALID_ELEMENT_ERROR = 'Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.';\\nvar INFINITE_LOOP_ERROR = 'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.';\\nvar DEFAULT_OPTIONS = {\\n  placement: 'bottom',\\n  modifiers: [],\\n  strategy: 'absolute'\\n};\\n\\nfunction areValidElements() {\\n  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\\n    args[_key] = arguments[_key];\\n  }\\n\\n  return !args.some(function (element) {\\n    return !(element && typeof element.getBoundingClientRect === 'function');\\n  });\\n}\\n\\nexport function popperGenerator(generatorOptions) {\\n  if (generatorOptions === void 0) {\\n    generatorOptions = {};\\n  }\\n\\n  var _generatorOptions = generatorOptions,\\n      _generatorOptions$def = _generatorOptions.defaultModifiers,\\n      defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\\n      _generatorOptions$def2 = _generatorOptions.defaultOptions,\\n      defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\\n  return function createPopper(reference, popper, options) {\\n    if (options === void 0) {\\n      options = defaultOptions;\\n    }\\n\\n    var state = {\\n      placement: 'bottom',\\n      orderedModifiers: [],\\n      options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\\n      modifiersData: {},\\n      elements: {\\n        reference: reference,\\n        popper: popper\\n      },\\n      attributes: {},\\n      styles: {}\\n    };\\n    var effectCleanupFns = [];\\n    var isDestroyed = false;\\n    var instance = {\\n      state: state,\\n      setOptions: function setOptions(setOptionsAction) {\\n        var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\\n        cleanupModifierEffects();\\n        state.options = Object.assign({}, defaultOptions, state.options, options);\\n        state.scrollParents = {\\n          reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\\n          popper: listScrollParents(popper)\\n        }; // Orders the modifiers based on their dependencies and `phase`\\n        // properties\\n\\n        var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\\n\\n        state.orderedModifiers = orderedModifiers.filter(function (m) {\\n          return m.enabled;\\n        }); // Validate the provided modifiers so that the consumer will get warned\\n        // if one of the modifiers is invalid for any reason\\n\\n        if (process.env.NODE_ENV !== \\\"production\\\") {\\n          var modifiers = uniqueBy([].concat(orderedModifiers, state.options.modifiers), function (_ref) {\\n            var name = _ref.name;\\n            return name;\\n          });\\n          validateModifiers(modifiers);\\n\\n          if (getBasePlacement(state.options.placement) === auto) {\\n            var flipModifier = state.orderedModifiers.find(function (_ref2) {\\n              var name = _ref2.name;\\n              return name === 'flip';\\n            });\\n\\n            if (!flipModifier) {\\n              console.error(['Popper: \\\"auto\\\" placements require the \\\"flip\\\" modifier be', 'present and enabled to work.'].join(' '));\\n            }\\n          }\\n\\n          var _getComputedStyle = getComputedStyle(popper),\\n              marginTop = _getComputedStyle.marginTop,\\n              marginRight = _getComputedStyle.marginRight,\\n              marginBottom = _getComputedStyle.marginBottom,\\n              marginLeft = _getComputedStyle.marginLeft; // We no longer take into account `margins` on the popper, and it can\\n          // cause bugs with positioning, so we'll warn the consumer\\n\\n\\n          if ([marginTop, marginRight, marginBottom, marginLeft].some(function (margin) {\\n            return parseFloat(margin);\\n          })) {\\n            console.warn(['Popper: CSS \\\"margin\\\" styles cannot be used to apply padding', 'between the popper and its reference element or boundary.', 'To replicate margin, use the `offset` modifier, as well as', 'the `padding` option in the `preventOverflow` and `flip`', 'modifiers.'].join(' '));\\n          }\\n        }\\n\\n        runModifierEffects();\\n        return instance.update();\\n      },\\n      // Sync update – it will always be executed, even if not necessary. This\\n      // is useful for low frequency updates where sync behavior simplifies the\\n      // logic.\\n      // For high frequency updates (e.g. `resize` and `scroll` events), always\\n      // prefer the async Popper#update method\\n      forceUpdate: function forceUpdate() {\\n        if (isDestroyed) {\\n          return;\\n        }\\n\\n        var _state$elements = state.elements,\\n            reference = _state$elements.reference,\\n            popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\\n        // anymore\\n\\n        if (!areValidElements(reference, popper)) {\\n          if (process.env.NODE_ENV !== \\\"production\\\") {\\n            console.error(INVALID_ELEMENT_ERROR);\\n          }\\n\\n          return;\\n        } // Store the reference and popper rects to be read by modifiers\\n\\n\\n        state.rects = {\\n          reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\\n          popper: getLayoutRect(popper)\\n        }; // Modifiers have the ability to reset the current update cycle. The\\n        // most common use case for this is the `flip` modifier changing the\\n        // placement, which then needs to re-run all the modifiers, because the\\n        // logic was previously ran for the previous placement and is therefore\\n        // stale/incorrect\\n\\n        state.reset = false;\\n        state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\\n        // is filled with the initial data specified by the modifier. This means\\n        // it doesn't persist and is fresh on each update.\\n        // To ensure persistent data, use `${name}#persistent`\\n\\n        state.orderedModifiers.forEach(function (modifier) {\\n          return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\\n        });\\n        var __debug_loops__ = 0;\\n\\n        for (var index = 0; index < state.orderedModifiers.length; index++) {\\n          if (process.env.NODE_ENV !== \\\"production\\\") {\\n            __debug_loops__ += 1;\\n\\n            if (__debug_loops__ > 100) {\\n              console.error(INFINITE_LOOP_ERROR);\\n              break;\\n            }\\n          }\\n\\n          if (state.reset === true) {\\n            state.reset = false;\\n            index = -1;\\n            continue;\\n          }\\n\\n          var _state$orderedModifie = state.orderedModifiers[index],\\n              fn = _state$orderedModifie.fn,\\n              _state$orderedModifie2 = _state$orderedModifie.options,\\n              _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\\n              name = _state$orderedModifie.name;\\n\\n          if (typeof fn === 'function') {\\n            state = fn({\\n              state: state,\\n              options: _options,\\n              name: name,\\n              instance: instance\\n            }) || state;\\n          }\\n        }\\n      },\\n      // Async and optimistically optimized update – it will not be executed if\\n      // not necessary (debounced to run at most once-per-tick)\\n      update: debounce(function () {\\n        return new Promise(function (resolve) {\\n          instance.forceUpdate();\\n          resolve(state);\\n        });\\n      }),\\n      destroy: function destroy() {\\n        cleanupModifierEffects();\\n        isDestroyed = true;\\n      }\\n    };\\n\\n    if (!areValidElements(reference, popper)) {\\n      if (process.env.NODE_ENV !== \\\"production\\\") {\\n        console.error(INVALID_ELEMENT_ERROR);\\n      }\\n\\n      return instance;\\n    }\\n\\n    instance.setOptions(options).then(function (state) {\\n      if (!isDestroyed && options.onFirstUpdate) {\\n        options.onFirstUpdate(state);\\n      }\\n    }); // Modifiers have the ability to execute arbitrary code before the first\\n    // update cycle runs. They will be executed in the same order as the update\\n    // cycle. This is useful when a modifier adds some persistent data that\\n    // other modifiers need to use, but the modifier is run after the dependent\\n    // one.\\n\\n    function runModifierEffects() {\\n      state.orderedModifiers.forEach(function (_ref3) {\\n        var name = _ref3.name,\\n            _ref3$options = _ref3.options,\\n            options = _ref3$options === void 0 ? {} : _ref3$options,\\n            effect = _ref3.effect;\\n\\n        if (typeof effect === 'function') {\\n          var cleanupFn = effect({\\n            state: state,\\n            name: name,\\n            instance: instance,\\n            options: options\\n          });\\n\\n          var noopFn = function noopFn() {};\\n\\n          effectCleanupFns.push(cleanupFn || noopFn);\\n        }\\n      });\\n    }\\n\\n    function cleanupModifierEffects() {\\n      effectCleanupFns.forEach(function (fn) {\\n        return fn();\\n      });\\n      effectCleanupFns = [];\\n    }\\n\\n    return instance;\\n  };\\n}\\nexport var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\\n\\nexport { detectOverflow };\",\"export default function debounce(fn) {\\n  var pending;\\n  return function () {\\n    if (!pending) {\\n      pending = new Promise(function (resolve) {\\n        Promise.resolve().then(function () {\\n          pending = undefined;\\n          resolve(fn());\\n        });\\n      });\\n    }\\n\\n    return pending;\\n  };\\n}\",\"export default function mergeByName(modifiers) {\\n  var merged = modifiers.reduce(function (merged, current) {\\n    var existing = merged[current.name];\\n    merged[current.name] = existing ? Object.assign({}, existing, current, {\\n      options: Object.assign({}, existing.options, current.options),\\n      data: Object.assign({}, existing.data, current.data)\\n    }) : current;\\n    return merged;\\n  }, {}); // IE11 does not support Object.values\\n\\n  return Object.keys(merged).map(function (key) {\\n    return merged[key];\\n  });\\n}\",\"import { popperGenerator, detectOverflow } from \\\"./createPopper.js\\\";\\nimport eventListeners from \\\"./modifiers/eventListeners.js\\\";\\nimport popperOffsets from \\\"./modifiers/popperOffsets.js\\\";\\nimport computeStyles from \\\"./modifiers/computeStyles.js\\\";\\nimport applyStyles from \\\"./modifiers/applyStyles.js\\\";\\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles];\\nvar createPopper = /*#__PURE__*/popperGenerator({\\n  defaultModifiers: defaultModifiers\\n}); // eslint-disable-next-line import/no-unused-modules\\n\\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow };\",\"import { popperGenerator, detectOverflow } from \\\"./createPopper.js\\\";\\nimport eventListeners from \\\"./modifiers/eventListeners.js\\\";\\nimport popperOffsets from \\\"./modifiers/popperOffsets.js\\\";\\nimport computeStyles from \\\"./modifiers/computeStyles.js\\\";\\nimport applyStyles from \\\"./modifiers/applyStyles.js\\\";\\nimport offset from \\\"./modifiers/offset.js\\\";\\nimport flip from \\\"./modifiers/flip.js\\\";\\nimport preventOverflow from \\\"./modifiers/preventOverflow.js\\\";\\nimport arrow from \\\"./modifiers/arrow.js\\\";\\nimport hide from \\\"./modifiers/hide.js\\\";\\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles, offset, flip, preventOverflow, arrow, hide];\\nvar createPopper = /*#__PURE__*/popperGenerator({\\n  defaultModifiers: defaultModifiers\\n}); // eslint-disable-next-line import/no-unused-modules\\n\\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow }; // eslint-disable-next-line import/no-unused-modules\\n\\nexport { createPopper as createPopperLite } from \\\"./popper-lite.js\\\"; // eslint-disable-next-line import/no-unused-modules\\n\\nexport * from \\\"./modifiers/index.js\\\";\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): dropdown.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport * as Popper from '@popperjs/core'\\nimport {\\n  defineJQueryPlugin,\\n  execute,\\n  getElement,\\n  getNextActiveElement,\\n  isDisabled,\\n  isElement,\\n  isRTL,\\n  isVisible,\\n  noop\\n} from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport Manipulator from './dom/manipulator.js'\\nimport SelectorEngine from './dom/selector-engine.js'\\nimport BaseComponent from './base-component.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'dropdown'\\nconst DATA_KEY = 'bs.dropdown'\\nconst EVENT_KEY = `.${DATA_KEY}`\\nconst DATA_API_KEY = '.data-api'\\n\\nconst ESCAPE_KEY = 'Escape'\\nconst TAB_KEY = 'Tab'\\nconst ARROW_UP_KEY = 'ArrowUp'\\nconst ARROW_DOWN_KEY = 'ArrowDown'\\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\\n\\nconst EVENT_HIDE = `hide${EVENT_KEY}`\\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\\nconst EVENT_SHOW = `show${EVENT_KEY}`\\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\\n\\nconst CLASS_NAME_SHOW = 'show'\\nconst CLASS_NAME_DROPUP = 'dropup'\\nconst CLASS_NAME_DROPEND = 'dropend'\\nconst CLASS_NAME_DROPSTART = 'dropstart'\\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\\n\\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\\\"dropdown\\\"]:not(.disabled):not(:disabled)'\\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\\nconst SELECTOR_MENU = '.dropdown-menu'\\nconst SELECTOR_NAVBAR = '.navbar'\\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\\n\\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\\nconst PLACEMENT_TOPCENTER = 'top'\\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\\n\\nconst Default = {\\n  autoClose: true,\\n  boundary: 'clippingParents',\\n  display: 'dynamic',\\n  offset: [0, 2],\\n  popperConfig: null,\\n  reference: 'toggle'\\n}\\n\\nconst DefaultType = {\\n  autoClose: '(boolean|string)',\\n  boundary: '(string|element)',\\n  display: 'string',\\n  offset: '(array|string|function)',\\n  popperConfig: '(null|object|function)',\\n  reference: '(string|element|object)'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Dropdown extends BaseComponent {\\n  constructor(element, config) {\\n    super(element, config)\\n\\n    this._popper = null\\n    this._parent = this._element.parentNode // dropdown wrapper\\n    // todo: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\\n    this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\\n      SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\\n      SelectorEngine.findOne(SELECTOR_MENU, this._parent)\\n    this._inNavbar = this._detectNavbar()\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  toggle() {\\n    return this._isShown() ? this.hide() : this.show()\\n  }\\n\\n  show() {\\n    if (isDisabled(this._element) || this._isShown()) {\\n      return\\n    }\\n\\n    const relatedTarget = {\\n      relatedTarget: this._element\\n    }\\n\\n    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\\n\\n    if (showEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    this._createPopper()\\n\\n    // If this is a touch-enabled device we add extra\\n    // empty mouseover listeners to the body's immediate children;\\n    // only needed because of broken event delegation on iOS\\n    // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\\n    if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\\n      for (const element of [].concat(...document.body.children)) {\\n        EventHandler.on(element, 'mouseover', noop)\\n      }\\n    }\\n\\n    this._element.focus()\\n    this._element.setAttribute('aria-expanded', true)\\n\\n    this._menu.classList.add(CLASS_NAME_SHOW)\\n    this._element.classList.add(CLASS_NAME_SHOW)\\n    EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\\n  }\\n\\n  hide() {\\n    if (isDisabled(this._element) || !this._isShown()) {\\n      return\\n    }\\n\\n    const relatedTarget = {\\n      relatedTarget: this._element\\n    }\\n\\n    this._completeHide(relatedTarget)\\n  }\\n\\n  dispose() {\\n    if (this._popper) {\\n      this._popper.destroy()\\n    }\\n\\n    super.dispose()\\n  }\\n\\n  update() {\\n    this._inNavbar = this._detectNavbar()\\n    if (this._popper) {\\n      this._popper.update()\\n    }\\n  }\\n\\n  // Private\\n  _completeHide(relatedTarget) {\\n    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\\n    if (hideEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    // If this is a touch-enabled device we remove the extra\\n    // empty mouseover listeners we added for iOS support\\n    if ('ontouchstart' in document.documentElement) {\\n      for (const element of [].concat(...document.body.children)) {\\n        EventHandler.off(element, 'mouseover', noop)\\n      }\\n    }\\n\\n    if (this._popper) {\\n      this._popper.destroy()\\n    }\\n\\n    this._menu.classList.remove(CLASS_NAME_SHOW)\\n    this._element.classList.remove(CLASS_NAME_SHOW)\\n    this._element.setAttribute('aria-expanded', 'false')\\n    Manipulator.removeDataAttribute(this._menu, 'popper')\\n    EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\\n  }\\n\\n  _getConfig(config) {\\n    config = super._getConfig(config)\\n\\n    if (typeof config.reference === 'object' && !isElement(config.reference) &&\\n      typeof config.reference.getBoundingClientRect !== 'function'\\n    ) {\\n      // Popper virtual elements require a getBoundingClientRect method\\n      throw new TypeError(`${NAME.toUpperCase()}: Option \\\"reference\\\" provided type \\\"object\\\" without a required \\\"getBoundingClientRect\\\" method.`)\\n    }\\n\\n    return config\\n  }\\n\\n  _createPopper() {\\n    if (typeof Popper === 'undefined') {\\n      throw new TypeError('Bootstrap\\\\'s dropdowns require Popper (https://popper.js.org)')\\n    }\\n\\n    let referenceElement = this._element\\n\\n    if (this._config.reference === 'parent') {\\n      referenceElement = this._parent\\n    } else if (isElement(this._config.reference)) {\\n      referenceElement = getElement(this._config.reference)\\n    } else if (typeof this._config.reference === 'object') {\\n      referenceElement = this._config.reference\\n    }\\n\\n    const popperConfig = this._getPopperConfig()\\n    this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\\n  }\\n\\n  _isShown() {\\n    return this._menu.classList.contains(CLASS_NAME_SHOW)\\n  }\\n\\n  _getPlacement() {\\n    const parentDropdown = this._parent\\n\\n    if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\\n      return PLACEMENT_RIGHT\\n    }\\n\\n    if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\\n      return PLACEMENT_LEFT\\n    }\\n\\n    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\\n      return PLACEMENT_TOPCENTER\\n    }\\n\\n    if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\\n      return PLACEMENT_BOTTOMCENTER\\n    }\\n\\n    // We need to trim the value because custom properties can also include spaces\\n    const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\\n\\n    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\\n      return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\\n    }\\n\\n    return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\\n  }\\n\\n  _detectNavbar() {\\n    return this._element.closest(SELECTOR_NAVBAR) !== null\\n  }\\n\\n  _getOffset() {\\n    const { offset } = this._config\\n\\n    if (typeof offset === 'string') {\\n      return offset.split(',').map(value => Number.parseInt(value, 10))\\n    }\\n\\n    if (typeof offset === 'function') {\\n      return popperData => offset(popperData, this._element)\\n    }\\n\\n    return offset\\n  }\\n\\n  _getPopperConfig() {\\n    const defaultBsPopperConfig = {\\n      placement: this._getPlacement(),\\n      modifiers: [{\\n        name: 'preventOverflow',\\n        options: {\\n          boundary: this._config.boundary\\n        }\\n      },\\n      {\\n        name: 'offset',\\n        options: {\\n          offset: this._getOffset()\\n        }\\n      }]\\n    }\\n\\n    // Disable Popper if we have a static display or Dropdown is in Navbar\\n    if (this._inNavbar || this._config.display === 'static') {\\n      Manipulator.setDataAttribute(this._menu, 'popper', 'static') // todo:v6 remove\\n      defaultBsPopperConfig.modifiers = [{\\n        name: 'applyStyles',\\n        enabled: false\\n      }]\\n    }\\n\\n    return {\\n      ...defaultBsPopperConfig,\\n      ...execute(this._config.popperConfig, [defaultBsPopperConfig])\\n    }\\n  }\\n\\n  _selectMenuItem({ key, target }) {\\n    const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\\n\\n    if (!items.length) {\\n      return\\n    }\\n\\n    // if target isn't included in items (e.g. when expanding the dropdown)\\n    // allow cycling to get the last item in case key equals ARROW_UP_KEY\\n    getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Dropdown.getOrCreateInstance(this, config)\\n\\n      if (typeof config !== 'string') {\\n        return\\n      }\\n\\n      if (typeof data[config] === 'undefined') {\\n        throw new TypeError(`No method named \\\"${config}\\\"`)\\n      }\\n\\n      data[config]()\\n    })\\n  }\\n\\n  static clearMenus(event) {\\n    if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\\n      return\\n    }\\n\\n    const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\\n\\n    for (const toggle of openToggles) {\\n      const context = Dropdown.getInstance(toggle)\\n      if (!context || context._config.autoClose === false) {\\n        continue\\n      }\\n\\n      const composedPath = event.composedPath()\\n      const isMenuTarget = composedPath.includes(context._menu)\\n      if (\\n        composedPath.includes(context._element) ||\\n        (context._config.autoClose === 'inside' && !isMenuTarget) ||\\n        (context._config.autoClose === 'outside' && isMenuTarget)\\n      ) {\\n        continue\\n      }\\n\\n      // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\\n      if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\\n        continue\\n      }\\n\\n      const relatedTarget = { relatedTarget: context._element }\\n\\n      if (event.type === 'click') {\\n        relatedTarget.clickEvent = event\\n      }\\n\\n      context._completeHide(relatedTarget)\\n    }\\n  }\\n\\n  static dataApiKeydownHandler(event) {\\n    // If not an UP | DOWN | ESCAPE key => not a dropdown command\\n    // If input/textarea && if key is other than ESCAPE => not a dropdown command\\n\\n    const isInput = /input|textarea/i.test(event.target.tagName)\\n    const isEscapeEvent = event.key === ESCAPE_KEY\\n    const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\\n\\n    if (!isUpOrDownEvent && !isEscapeEvent) {\\n      return\\n    }\\n\\n    if (isInput && !isEscapeEvent) {\\n      return\\n    }\\n\\n    event.preventDefault()\\n\\n    // todo: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\\n    const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\\n      this :\\n      (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\\n        SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\\n        SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\\n\\n    const instance = Dropdown.getOrCreateInstance(getToggleButton)\\n\\n    if (isUpOrDownEvent) {\\n      event.stopPropagation()\\n      instance.show()\\n      instance._selectMenuItem(event)\\n      return\\n    }\\n\\n    if (instance._isShown()) { // else is escape and we check if it is shown\\n      event.stopPropagation()\\n      instance.hide()\\n      getToggleButton.focus()\\n    }\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\\n  event.preventDefault()\\n  Dropdown.getOrCreateInstance(this).toggle()\\n})\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Dropdown)\\n\\nexport default Dropdown\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/scrollBar.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport SelectorEngine from '../dom/selector-engine.js'\\nimport Manipulator from '../dom/manipulator.js'\\nimport { isElement } from './index.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\\nconst PROPERTY_PADDING = 'padding-right'\\nconst PROPERTY_MARGIN = 'margin-right'\\n\\n/**\\n * Class definition\\n */\\n\\nclass ScrollBarHelper {\\n  constructor() {\\n    this._element = document.body\\n  }\\n\\n  // Public\\n  getWidth() {\\n    // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\\n    const documentWidth = document.documentElement.clientWidth\\n    return Math.abs(window.innerWidth - documentWidth)\\n  }\\n\\n  hide() {\\n    const width = this.getWidth()\\n    this._disableOverFlow()\\n    // give padding to element to balance the hidden scrollbar width\\n    this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\\n    // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\\n    this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\\n    this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\\n  }\\n\\n  reset() {\\n    this._resetElementAttributes(this._element, 'overflow')\\n    this._resetElementAttributes(this._element, PROPERTY_PADDING)\\n    this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\\n    this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\\n  }\\n\\n  isOverflowing() {\\n    return this.getWidth() > 0\\n  }\\n\\n  // Private\\n  _disableOverFlow() {\\n    this._saveInitialAttribute(this._element, 'overflow')\\n    this._element.style.overflow = 'hidden'\\n  }\\n\\n  _setElementAttributes(selector, styleProperty, callback) {\\n    const scrollbarWidth = this.getWidth()\\n    const manipulationCallBack = element => {\\n      if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\\n        return\\n      }\\n\\n      this._saveInitialAttribute(element, styleProperty)\\n      const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\\n      element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\\n    }\\n\\n    this._applyManipulationCallback(selector, manipulationCallBack)\\n  }\\n\\n  _saveInitialAttribute(element, styleProperty) {\\n    const actualValue = element.style.getPropertyValue(styleProperty)\\n    if (actualValue) {\\n      Manipulator.setDataAttribute(element, styleProperty, actualValue)\\n    }\\n  }\\n\\n  _resetElementAttributes(selector, styleProperty) {\\n    const manipulationCallBack = element => {\\n      const value = Manipulator.getDataAttribute(element, styleProperty)\\n      // We only want to remove the property if the value is `null`; the value can also be zero\\n      if (value === null) {\\n        element.style.removeProperty(styleProperty)\\n        return\\n      }\\n\\n      Manipulator.removeDataAttribute(element, styleProperty)\\n      element.style.setProperty(styleProperty, value)\\n    }\\n\\n    this._applyManipulationCallback(selector, manipulationCallBack)\\n  }\\n\\n  _applyManipulationCallback(selector, callBack) {\\n    if (isElement(selector)) {\\n      callBack(selector)\\n      return\\n    }\\n\\n    for (const sel of SelectorEngine.find(selector, this._element)) {\\n      callBack(sel)\\n    }\\n  }\\n}\\n\\nexport default ScrollBarHelper\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/backdrop.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport EventHandler from '../dom/event-handler.js'\\nimport { execute, executeAfterTransition, getElement, reflow } from './index.js'\\nimport Config from './config.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'backdrop'\\nconst CLASS_NAME_FADE = 'fade'\\nconst CLASS_NAME_SHOW = 'show'\\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\\n\\nconst Default = {\\n  className: 'modal-backdrop',\\n  clickCallback: null,\\n  isAnimated: false,\\n  isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\\n  rootElement: 'body' // give the choice to place backdrop under different elements\\n}\\n\\nconst DefaultType = {\\n  className: 'string',\\n  clickCallback: '(function|null)',\\n  isAnimated: 'boolean',\\n  isVisible: 'boolean',\\n  rootElement: '(element|string)'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Backdrop extends Config {\\n  constructor(config) {\\n    super()\\n    this._config = this._getConfig(config)\\n    this._isAppended = false\\n    this._element = null\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  show(callback) {\\n    if (!this._config.isVisible) {\\n      execute(callback)\\n      return\\n    }\\n\\n    this._append()\\n\\n    const element = this._getElement()\\n    if (this._config.isAnimated) {\\n      reflow(element)\\n    }\\n\\n    element.classList.add(CLASS_NAME_SHOW)\\n\\n    this._emulateAnimation(() => {\\n      execute(callback)\\n    })\\n  }\\n\\n  hide(callback) {\\n    if (!this._config.isVisible) {\\n      execute(callback)\\n      return\\n    }\\n\\n    this._getElement().classList.remove(CLASS_NAME_SHOW)\\n\\n    this._emulateAnimation(() => {\\n      this.dispose()\\n      execute(callback)\\n    })\\n  }\\n\\n  dispose() {\\n    if (!this._isAppended) {\\n      return\\n    }\\n\\n    EventHandler.off(this._element, EVENT_MOUSEDOWN)\\n\\n    this._element.remove()\\n    this._isAppended = false\\n  }\\n\\n  // Private\\n  _getElement() {\\n    if (!this._element) {\\n      const backdrop = document.createElement('div')\\n      backdrop.className = this._config.className\\n      if (this._config.isAnimated) {\\n        backdrop.classList.add(CLASS_NAME_FADE)\\n      }\\n\\n      this._element = backdrop\\n    }\\n\\n    return this._element\\n  }\\n\\n  _configAfterMerge(config) {\\n    // use getElement() with the default \\\"body\\\" to get a fresh Element on each instantiation\\n    config.rootElement = getElement(config.rootElement)\\n    return config\\n  }\\n\\n  _append() {\\n    if (this._isAppended) {\\n      return\\n    }\\n\\n    const element = this._getElement()\\n    this._config.rootElement.append(element)\\n\\n    EventHandler.on(element, EVENT_MOUSEDOWN, () => {\\n      execute(this._config.clickCallback)\\n    })\\n\\n    this._isAppended = true\\n  }\\n\\n  _emulateAnimation(callback) {\\n    executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\\n  }\\n}\\n\\nexport default Backdrop\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/focustrap.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport EventHandler from '../dom/event-handler.js'\\nimport SelectorEngine from '../dom/selector-engine.js'\\nimport Config from './config.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'focustrap'\\nconst DATA_KEY = 'bs.focustrap'\\nconst EVENT_KEY = `.${DATA_KEY}`\\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\\n\\nconst TAB_KEY = 'Tab'\\nconst TAB_NAV_FORWARD = 'forward'\\nconst TAB_NAV_BACKWARD = 'backward'\\n\\nconst Default = {\\n  autofocus: true,\\n  trapElement: null // The element to trap focus inside of\\n}\\n\\nconst DefaultType = {\\n  autofocus: 'boolean',\\n  trapElement: 'element'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass FocusTrap extends Config {\\n  constructor(config) {\\n    super()\\n    this._config = this._getConfig(config)\\n    this._isActive = false\\n    this._lastTabNavDirection = null\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  activate() {\\n    if (this._isActive) {\\n      return\\n    }\\n\\n    if (this._config.autofocus) {\\n      this._config.trapElement.focus()\\n    }\\n\\n    EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\\n    EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\\n    EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\\n\\n    this._isActive = true\\n  }\\n\\n  deactivate() {\\n    if (!this._isActive) {\\n      return\\n    }\\n\\n    this._isActive = false\\n    EventHandler.off(document, EVENT_KEY)\\n  }\\n\\n  // Private\\n  _handleFocusin(event) {\\n    const { trapElement } = this._config\\n\\n    if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\\n      return\\n    }\\n\\n    const elements = SelectorEngine.focusableChildren(trapElement)\\n\\n    if (elements.length === 0) {\\n      trapElement.focus()\\n    } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\\n      elements[elements.length - 1].focus()\\n    } else {\\n      elements[0].focus()\\n    }\\n  }\\n\\n  _handleKeydown(event) {\\n    if (event.key !== TAB_KEY) {\\n      return\\n    }\\n\\n    this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\\n  }\\n}\\n\\nexport default FocusTrap\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): modal.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { defineJQueryPlugin, isRTL, isVisible, reflow } from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport SelectorEngine from './dom/selector-engine.js'\\nimport ScrollBarHelper from './util/scrollbar.js'\\nimport BaseComponent from './base-component.js'\\nimport Backdrop from './util/backdrop.js'\\nimport FocusTrap from './util/focustrap.js'\\nimport { enableDismissTrigger } from './util/component-functions.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'modal'\\nconst DATA_KEY = 'bs.modal'\\nconst EVENT_KEY = `.${DATA_KEY}`\\nconst DATA_API_KEY = '.data-api'\\nconst ESCAPE_KEY = 'Escape'\\n\\nconst EVENT_HIDE = `hide${EVENT_KEY}`\\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\\nconst EVENT_SHOW = `show${EVENT_KEY}`\\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\\n\\nconst CLASS_NAME_OPEN = 'modal-open'\\nconst CLASS_NAME_FADE = 'fade'\\nconst CLASS_NAME_SHOW = 'show'\\nconst CLASS_NAME_STATIC = 'modal-static'\\n\\nconst OPEN_SELECTOR = '.modal.show'\\nconst SELECTOR_DIALOG = '.modal-dialog'\\nconst SELECTOR_MODAL_BODY = '.modal-body'\\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\\\"modal\\\"]'\\n\\nconst Default = {\\n  backdrop: true,\\n  focus: true,\\n  keyboard: true\\n}\\n\\nconst DefaultType = {\\n  backdrop: '(boolean|string)',\\n  focus: 'boolean',\\n  keyboard: 'boolean'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Modal extends BaseComponent {\\n  constructor(element, config) {\\n    super(element, config)\\n\\n    this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\\n    this._backdrop = this._initializeBackDrop()\\n    this._focustrap = this._initializeFocusTrap()\\n    this._isShown = false\\n    this._isTransitioning = false\\n    this._scrollBar = new ScrollBarHelper()\\n\\n    this._addEventListeners()\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  toggle(relatedTarget) {\\n    return this._isShown ? this.hide() : this.show(relatedTarget)\\n  }\\n\\n  show(relatedTarget) {\\n    if (this._isShown || this._isTransitioning) {\\n      return\\n    }\\n\\n    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\\n      relatedTarget\\n    })\\n\\n    if (showEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    this._isShown = true\\n    this._isTransitioning = true\\n\\n    this._scrollBar.hide()\\n\\n    document.body.classList.add(CLASS_NAME_OPEN)\\n\\n    this._adjustDialog()\\n\\n    this._backdrop.show(() => this._showElement(relatedTarget))\\n  }\\n\\n  hide() {\\n    if (!this._isShown || this._isTransitioning) {\\n      return\\n    }\\n\\n    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\\n\\n    if (hideEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    this._isShown = false\\n    this._isTransitioning = true\\n    this._focustrap.deactivate()\\n\\n    this._element.classList.remove(CLASS_NAME_SHOW)\\n\\n    this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\\n  }\\n\\n  dispose() {\\n    for (const htmlElement of [window, this._dialog]) {\\n      EventHandler.off(htmlElement, EVENT_KEY)\\n    }\\n\\n    this._backdrop.dispose()\\n    this._focustrap.deactivate()\\n    super.dispose()\\n  }\\n\\n  handleUpdate() {\\n    this._adjustDialog()\\n  }\\n\\n  // Private\\n  _initializeBackDrop() {\\n    return new Backdrop({\\n      isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\\n      isAnimated: this._isAnimated()\\n    })\\n  }\\n\\n  _initializeFocusTrap() {\\n    return new FocusTrap({\\n      trapElement: this._element\\n    })\\n  }\\n\\n  _showElement(relatedTarget) {\\n    // try to append dynamic modal\\n    if (!document.body.contains(this._element)) {\\n      document.body.append(this._element)\\n    }\\n\\n    this._element.style.display = 'block'\\n    this._element.removeAttribute('aria-hidden')\\n    this._element.setAttribute('aria-modal', true)\\n    this._element.setAttribute('role', 'dialog')\\n    this._element.scrollTop = 0\\n\\n    const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\\n    if (modalBody) {\\n      modalBody.scrollTop = 0\\n    }\\n\\n    reflow(this._element)\\n\\n    this._element.classList.add(CLASS_NAME_SHOW)\\n\\n    const transitionComplete = () => {\\n      if (this._config.focus) {\\n        this._focustrap.activate()\\n      }\\n\\n      this._isTransitioning = false\\n      EventHandler.trigger(this._element, EVENT_SHOWN, {\\n        relatedTarget\\n      })\\n    }\\n\\n    this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\\n  }\\n\\n  _addEventListeners() {\\n    EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\\n      if (event.key !== ESCAPE_KEY) {\\n        return\\n      }\\n\\n      if (this._config.keyboard) {\\n        event.preventDefault()\\n        this.hide()\\n        return\\n      }\\n\\n      this._triggerBackdropTransition()\\n    })\\n\\n    EventHandler.on(window, EVENT_RESIZE, () => {\\n      if (this._isShown && !this._isTransitioning) {\\n        this._adjustDialog()\\n      }\\n    })\\n\\n    EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\\n      // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\\n      EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\\n        if (this._element !== event.target || this._element !== event2.target) {\\n          return\\n        }\\n\\n        if (this._config.backdrop === 'static') {\\n          this._triggerBackdropTransition()\\n          return\\n        }\\n\\n        if (this._config.backdrop) {\\n          this.hide()\\n        }\\n      })\\n    })\\n  }\\n\\n  _hideModal() {\\n    this._element.style.display = 'none'\\n    this._element.setAttribute('aria-hidden', true)\\n    this._element.removeAttribute('aria-modal')\\n    this._element.removeAttribute('role')\\n    this._isTransitioning = false\\n\\n    this._backdrop.hide(() => {\\n      document.body.classList.remove(CLASS_NAME_OPEN)\\n      this._resetAdjustments()\\n      this._scrollBar.reset()\\n      EventHandler.trigger(this._element, EVENT_HIDDEN)\\n    })\\n  }\\n\\n  _isAnimated() {\\n    return this._element.classList.contains(CLASS_NAME_FADE)\\n  }\\n\\n  _triggerBackdropTransition() {\\n    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\\n    if (hideEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\\n    const initialOverflowY = this._element.style.overflowY\\n    // return if the following background transition hasn't yet completed\\n    if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\\n      return\\n    }\\n\\n    if (!isModalOverflowing) {\\n      this._element.style.overflowY = 'hidden'\\n    }\\n\\n    this._element.classList.add(CLASS_NAME_STATIC)\\n    this._queueCallback(() => {\\n      this._element.classList.remove(CLASS_NAME_STATIC)\\n      this._queueCallback(() => {\\n        this._element.style.overflowY = initialOverflowY\\n      }, this._dialog)\\n    }, this._dialog)\\n\\n    this._element.focus()\\n  }\\n\\n  /**\\n   * The following methods are used to handle overflowing modals\\n   */\\n\\n  _adjustDialog() {\\n    const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\\n    const scrollbarWidth = this._scrollBar.getWidth()\\n    const isBodyOverflowing = scrollbarWidth > 0\\n\\n    if (isBodyOverflowing && !isModalOverflowing) {\\n      const property = isRTL() ? 'paddingLeft' : 'paddingRight'\\n      this._element.style[property] = `${scrollbarWidth}px`\\n    }\\n\\n    if (!isBodyOverflowing && isModalOverflowing) {\\n      const property = isRTL() ? 'paddingRight' : 'paddingLeft'\\n      this._element.style[property] = `${scrollbarWidth}px`\\n    }\\n  }\\n\\n  _resetAdjustments() {\\n    this._element.style.paddingLeft = ''\\n    this._element.style.paddingRight = ''\\n  }\\n\\n  // Static\\n  static jQueryInterface(config, relatedTarget) {\\n    return this.each(function () {\\n      const data = Modal.getOrCreateInstance(this, config)\\n\\n      if (typeof config !== 'string') {\\n        return\\n      }\\n\\n      if (typeof data[config] === 'undefined') {\\n        throw new TypeError(`No method named \\\"${config}\\\"`)\\n      }\\n\\n      data[config](relatedTarget)\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\\n  const target = SelectorEngine.getElementFromSelector(this)\\n\\n  if (['A', 'AREA'].includes(this.tagName)) {\\n    event.preventDefault()\\n  }\\n\\n  EventHandler.one(target, EVENT_SHOW, showEvent => {\\n    if (showEvent.defaultPrevented) {\\n      // only register focus restorer if modal will actually get shown\\n      return\\n    }\\n\\n    EventHandler.one(target, EVENT_HIDDEN, () => {\\n      if (isVisible(this)) {\\n        this.focus()\\n      }\\n    })\\n  })\\n\\n  // avoid conflict when clicking modal toggler while another one is open\\n  const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\\n  if (alreadyOpen) {\\n    Modal.getInstance(alreadyOpen).hide()\\n  }\\n\\n  const data = Modal.getOrCreateInstance(target)\\n\\n  data.toggle(this)\\n})\\n\\nenableDismissTrigger(Modal)\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Modal)\\n\\nexport default Modal\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): offcanvas.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport {\\n  defineJQueryPlugin,\\n  isDisabled,\\n  isVisible\\n} from './util/index.js'\\nimport ScrollBarHelper from './util/scrollbar.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport BaseComponent from './base-component.js'\\nimport SelectorEngine from './dom/selector-engine.js'\\nimport Backdrop from './util/backdrop.js'\\nimport FocusTrap from './util/focustrap.js'\\nimport { enableDismissTrigger } from './util/component-functions.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'offcanvas'\\nconst DATA_KEY = 'bs.offcanvas'\\nconst EVENT_KEY = `.${DATA_KEY}`\\nconst DATA_API_KEY = '.data-api'\\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\\nconst ESCAPE_KEY = 'Escape'\\n\\nconst CLASS_NAME_SHOW = 'show'\\nconst CLASS_NAME_SHOWING = 'showing'\\nconst CLASS_NAME_HIDING = 'hiding'\\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\\nconst OPEN_SELECTOR = '.offcanvas.show'\\n\\nconst EVENT_SHOW = `show${EVENT_KEY}`\\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\\nconst EVENT_HIDE = `hide${EVENT_KEY}`\\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\\n\\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\\\"offcanvas\\\"]'\\n\\nconst Default = {\\n  backdrop: true,\\n  keyboard: true,\\n  scroll: false\\n}\\n\\nconst DefaultType = {\\n  backdrop: '(boolean|string)',\\n  keyboard: 'boolean',\\n  scroll: 'boolean'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Offcanvas extends BaseComponent {\\n  constructor(element, config) {\\n    super(element, config)\\n\\n    this._isShown = false\\n    this._backdrop = this._initializeBackDrop()\\n    this._focustrap = this._initializeFocusTrap()\\n    this._addEventListeners()\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  toggle(relatedTarget) {\\n    return this._isShown ? this.hide() : this.show(relatedTarget)\\n  }\\n\\n  show(relatedTarget) {\\n    if (this._isShown) {\\n      return\\n    }\\n\\n    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\\n\\n    if (showEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    this._isShown = true\\n    this._backdrop.show()\\n\\n    if (!this._config.scroll) {\\n      new ScrollBarHelper().hide()\\n    }\\n\\n    this._element.setAttribute('aria-modal', true)\\n    this._element.setAttribute('role', 'dialog')\\n    this._element.classList.add(CLASS_NAME_SHOWING)\\n\\n    const completeCallBack = () => {\\n      if (!this._config.scroll || this._config.backdrop) {\\n        this._focustrap.activate()\\n      }\\n\\n      this._element.classList.add(CLASS_NAME_SHOW)\\n      this._element.classList.remove(CLASS_NAME_SHOWING)\\n      EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\\n    }\\n\\n    this._queueCallback(completeCallBack, this._element, true)\\n  }\\n\\n  hide() {\\n    if (!this._isShown) {\\n      return\\n    }\\n\\n    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\\n\\n    if (hideEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    this._focustrap.deactivate()\\n    this._element.blur()\\n    this._isShown = false\\n    this._element.classList.add(CLASS_NAME_HIDING)\\n    this._backdrop.hide()\\n\\n    const completeCallback = () => {\\n      this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\\n      this._element.removeAttribute('aria-modal')\\n      this._element.removeAttribute('role')\\n\\n      if (!this._config.scroll) {\\n        new ScrollBarHelper().reset()\\n      }\\n\\n      EventHandler.trigger(this._element, EVENT_HIDDEN)\\n    }\\n\\n    this._queueCallback(completeCallback, this._element, true)\\n  }\\n\\n  dispose() {\\n    this._backdrop.dispose()\\n    this._focustrap.deactivate()\\n    super.dispose()\\n  }\\n\\n  // Private\\n  _initializeBackDrop() {\\n    const clickCallback = () => {\\n      if (this._config.backdrop === 'static') {\\n        EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\\n        return\\n      }\\n\\n      this.hide()\\n    }\\n\\n    // 'static' option will be translated to true, and booleans will keep their value\\n    const isVisible = Boolean(this._config.backdrop)\\n\\n    return new Backdrop({\\n      className: CLASS_NAME_BACKDROP,\\n      isVisible,\\n      isAnimated: true,\\n      rootElement: this._element.parentNode,\\n      clickCallback: isVisible ? clickCallback : null\\n    })\\n  }\\n\\n  _initializeFocusTrap() {\\n    return new FocusTrap({\\n      trapElement: this._element\\n    })\\n  }\\n\\n  _addEventListeners() {\\n    EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\\n      if (event.key !== ESCAPE_KEY) {\\n        return\\n      }\\n\\n      if (!this._config.keyboard) {\\n        EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\\n        return\\n      }\\n\\n      this.hide()\\n    })\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Offcanvas.getOrCreateInstance(this, config)\\n\\n      if (typeof config !== 'string') {\\n        return\\n      }\\n\\n      if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\\n        throw new TypeError(`No method named \\\"${config}\\\"`)\\n      }\\n\\n      data[config](this)\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\\n  const target = SelectorEngine.getElementFromSelector(this)\\n\\n  if (['A', 'AREA'].includes(this.tagName)) {\\n    event.preventDefault()\\n  }\\n\\n  if (isDisabled(this)) {\\n    return\\n  }\\n\\n  EventHandler.one(target, EVENT_HIDDEN, () => {\\n    // focus on trigger when it is closed\\n    if (isVisible(this)) {\\n      this.focus()\\n    }\\n  })\\n\\n  // avoid conflict when clicking a toggler of an offcanvas, while another is open\\n  const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\\n  if (alreadyOpen && alreadyOpen !== target) {\\n    Offcanvas.getInstance(alreadyOpen).hide()\\n  }\\n\\n  const data = Offcanvas.getOrCreateInstance(target)\\n  data.toggle(this)\\n})\\n\\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\\n  for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\\n    Offcanvas.getOrCreateInstance(selector).show()\\n  }\\n})\\n\\nEventHandler.on(window, EVENT_RESIZE, () => {\\n  for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\\n    if (getComputedStyle(element).position !== 'fixed') {\\n      Offcanvas.getOrCreateInstance(element).hide()\\n    }\\n  }\\n})\\n\\nenableDismissTrigger(Offcanvas)\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Offcanvas)\\n\\nexport default Offcanvas\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/sanitizer.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nconst uriAttributes = new Set([\\n  'background',\\n  'cite',\\n  'href',\\n  'itemtype',\\n  'longdesc',\\n  'poster',\\n  'src',\\n  'xlink:href'\\n])\\n\\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\\\w-]*$/i\\n\\n/**\\n * A pattern that recognizes a commonly useful subset of URLs that are safe.\\n *\\n * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\\n */\\nconst SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i\\n\\n/**\\n * A pattern that matches safe data URLs. Only matches image, video and audio types.\\n *\\n * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\\n */\\nconst DATA_URL_PATTERN = /^data:(?:image\\\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\\\/(?:mpeg|mp4|ogg|webm)|audio\\\\/(?:mp3|oga|ogg|opus));base64,[\\\\d+/a-z]+=*$/i\\n\\nconst allowedAttribute = (attribute, allowedAttributeList) => {\\n  const attributeName = attribute.nodeName.toLowerCase()\\n\\n  if (allowedAttributeList.includes(attributeName)) {\\n    if (uriAttributes.has(attributeName)) {\\n      return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue))\\n    }\\n\\n    return true\\n  }\\n\\n  // Check if a regular expression validates the attribute.\\n  return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\\n    .some(regex => regex.test(attributeName))\\n}\\n\\nexport const DefaultAllowlist = {\\n  // Global attributes allowed on any supplied element below.\\n  '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\\n  a: ['target', 'href', 'title', 'rel'],\\n  area: [],\\n  b: [],\\n  br: [],\\n  col: [],\\n  code: [],\\n  div: [],\\n  em: [],\\n  hr: [],\\n  h1: [],\\n  h2: [],\\n  h3: [],\\n  h4: [],\\n  h5: [],\\n  h6: [],\\n  i: [],\\n  img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\\n  li: [],\\n  ol: [],\\n  p: [],\\n  pre: [],\\n  s: [],\\n  small: [],\\n  span: [],\\n  sub: [],\\n  sup: [],\\n  strong: [],\\n  u: [],\\n  ul: []\\n}\\n\\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\\n  if (!unsafeHtml.length) {\\n    return unsafeHtml\\n  }\\n\\n  if (sanitizeFunction && typeof sanitizeFunction === 'function') {\\n    return sanitizeFunction(unsafeHtml)\\n  }\\n\\n  const domParser = new window.DOMParser()\\n  const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\\n  const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\\n\\n  for (const element of elements) {\\n    const elementName = element.nodeName.toLowerCase()\\n\\n    if (!Object.keys(allowList).includes(elementName)) {\\n      element.remove()\\n\\n      continue\\n    }\\n\\n    const attributeList = [].concat(...element.attributes)\\n    const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\\n\\n    for (const attribute of attributeList) {\\n      if (!allowedAttribute(attribute, allowedAttributes)) {\\n        element.removeAttribute(attribute.nodeName)\\n      }\\n    }\\n  }\\n\\n  return createdDocument.body.innerHTML\\n}\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): util/template-factory.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\\nimport { execute, getElement, isElement } from './index.js'\\nimport SelectorEngine from '../dom/selector-engine.js'\\nimport Config from './config.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'TemplateFactory'\\n\\nconst Default = {\\n  allowList: DefaultAllowlist,\\n  content: {}, // { selector : text ,  selector2 : text2 , }\\n  extraClass: '',\\n  html: false,\\n  sanitize: true,\\n  sanitizeFn: null,\\n  template: '<div></div>'\\n}\\n\\nconst DefaultType = {\\n  allowList: 'object',\\n  content: 'object',\\n  extraClass: '(string|function)',\\n  html: 'boolean',\\n  sanitize: 'boolean',\\n  sanitizeFn: '(null|function)',\\n  template: 'string'\\n}\\n\\nconst DefaultContentType = {\\n  entry: '(string|element|function|null)',\\n  selector: '(string|element)'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass TemplateFactory extends Config {\\n  constructor(config) {\\n    super()\\n    this._config = this._getConfig(config)\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  getContent() {\\n    return Object.values(this._config.content)\\n      .map(config => this._resolvePossibleFunction(config))\\n      .filter(Boolean)\\n  }\\n\\n  hasContent() {\\n    return this.getContent().length > 0\\n  }\\n\\n  changeContent(content) {\\n    this._checkContent(content)\\n    this._config.content = { ...this._config.content, ...content }\\n    return this\\n  }\\n\\n  toHtml() {\\n    const templateWrapper = document.createElement('div')\\n    templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\\n\\n    for (const [selector, text] of Object.entries(this._config.content)) {\\n      this._setContent(templateWrapper, text, selector)\\n    }\\n\\n    const template = templateWrapper.children[0]\\n    const extraClass = this._resolvePossibleFunction(this._config.extraClass)\\n\\n    if (extraClass) {\\n      template.classList.add(...extraClass.split(' '))\\n    }\\n\\n    return template\\n  }\\n\\n  // Private\\n  _typeCheckConfig(config) {\\n    super._typeCheckConfig(config)\\n    this._checkContent(config.content)\\n  }\\n\\n  _checkContent(arg) {\\n    for (const [selector, content] of Object.entries(arg)) {\\n      super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\\n    }\\n  }\\n\\n  _setContent(template, content, selector) {\\n    const templateElement = SelectorEngine.findOne(selector, template)\\n\\n    if (!templateElement) {\\n      return\\n    }\\n\\n    content = this._resolvePossibleFunction(content)\\n\\n    if (!content) {\\n      templateElement.remove()\\n      return\\n    }\\n\\n    if (isElement(content)) {\\n      this._putElementInTemplate(getElement(content), templateElement)\\n      return\\n    }\\n\\n    if (this._config.html) {\\n      templateElement.innerHTML = this._maybeSanitize(content)\\n      return\\n    }\\n\\n    templateElement.textContent = content\\n  }\\n\\n  _maybeSanitize(arg) {\\n    return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\\n  }\\n\\n  _resolvePossibleFunction(arg) {\\n    return execute(arg, [this])\\n  }\\n\\n  _putElementInTemplate(element, templateElement) {\\n    if (this._config.html) {\\n      templateElement.innerHTML = ''\\n      templateElement.append(element)\\n      return\\n    }\\n\\n    templateElement.textContent = element.textContent\\n  }\\n}\\n\\nexport default TemplateFactory\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): tooltip.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport * as Popper from '@popperjs/core'\\nimport { defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop } from './util/index.js'\\nimport { DefaultAllowlist } from './util/sanitizer.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport Manipulator from './dom/manipulator.js'\\nimport BaseComponent from './base-component.js'\\nimport TemplateFactory from './util/template-factory.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'tooltip'\\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\\n\\nconst CLASS_NAME_FADE = 'fade'\\nconst CLASS_NAME_MODAL = 'modal'\\nconst CLASS_NAME_SHOW = 'show'\\n\\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\\n\\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\\n\\nconst TRIGGER_HOVER = 'hover'\\nconst TRIGGER_FOCUS = 'focus'\\nconst TRIGGER_CLICK = 'click'\\nconst TRIGGER_MANUAL = 'manual'\\n\\nconst EVENT_HIDE = 'hide'\\nconst EVENT_HIDDEN = 'hidden'\\nconst EVENT_SHOW = 'show'\\nconst EVENT_SHOWN = 'shown'\\nconst EVENT_INSERTED = 'inserted'\\nconst EVENT_CLICK = 'click'\\nconst EVENT_FOCUSIN = 'focusin'\\nconst EVENT_FOCUSOUT = 'focusout'\\nconst EVENT_MOUSEENTER = 'mouseenter'\\nconst EVENT_MOUSELEAVE = 'mouseleave'\\n\\nconst AttachmentMap = {\\n  AUTO: 'auto',\\n  TOP: 'top',\\n  RIGHT: isRTL() ? 'left' : 'right',\\n  BOTTOM: 'bottom',\\n  LEFT: isRTL() ? 'right' : 'left'\\n}\\n\\nconst Default = {\\n  allowList: DefaultAllowlist,\\n  animation: true,\\n  boundary: 'clippingParents',\\n  container: false,\\n  customClass: '',\\n  delay: 0,\\n  fallbackPlacements: ['top', 'right', 'bottom', 'left'],\\n  html: false,\\n  offset: [0, 0],\\n  placement: 'top',\\n  popperConfig: null,\\n  sanitize: true,\\n  sanitizeFn: null,\\n  selector: false,\\n  template: '<div class=\\\"tooltip\\\" role=\\\"tooltip\\\">' +\\n            '<div class=\\\"tooltip-arrow\\\"></div>' +\\n            '<div class=\\\"tooltip-inner\\\"></div>' +\\n            '</div>',\\n  title: '',\\n  trigger: 'hover focus'\\n}\\n\\nconst DefaultType = {\\n  allowList: 'object',\\n  animation: 'boolean',\\n  boundary: '(string|element)',\\n  container: '(string|element|boolean)',\\n  customClass: '(string|function)',\\n  delay: '(number|object)',\\n  fallbackPlacements: 'array',\\n  html: 'boolean',\\n  offset: '(array|string|function)',\\n  placement: '(string|function)',\\n  popperConfig: '(null|object|function)',\\n  sanitize: 'boolean',\\n  sanitizeFn: '(null|function)',\\n  selector: '(string|boolean)',\\n  template: 'string',\\n  title: '(string|element|function)',\\n  trigger: 'string'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Tooltip extends BaseComponent {\\n  constructor(element, config) {\\n    if (typeof Popper === 'undefined') {\\n      throw new TypeError('Bootstrap\\\\'s tooltips require Popper (https://popper.js.org)')\\n    }\\n\\n    super(element, config)\\n\\n    // Private\\n    this._isEnabled = true\\n    this._timeout = 0\\n    this._isHovered = null\\n    this._activeTrigger = {}\\n    this._popper = null\\n    this._templateFactory = null\\n    this._newContent = null\\n\\n    // Protected\\n    this.tip = null\\n\\n    this._setListeners()\\n\\n    if (!this._config.selector) {\\n      this._fixTitle()\\n    }\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  enable() {\\n    this._isEnabled = true\\n  }\\n\\n  disable() {\\n    this._isEnabled = false\\n  }\\n\\n  toggleEnabled() {\\n    this._isEnabled = !this._isEnabled\\n  }\\n\\n  toggle() {\\n    if (!this._isEnabled) {\\n      return\\n    }\\n\\n    this._activeTrigger.click = !this._activeTrigger.click\\n    if (this._isShown()) {\\n      this._leave()\\n      return\\n    }\\n\\n    this._enter()\\n  }\\n\\n  dispose() {\\n    clearTimeout(this._timeout)\\n\\n    EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\\n\\n    if (this._element.getAttribute('data-bs-original-title')) {\\n      this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\\n    }\\n\\n    this._disposePopper()\\n    super.dispose()\\n  }\\n\\n  show() {\\n    if (this._element.style.display === 'none') {\\n      throw new Error('Please use show on visible elements')\\n    }\\n\\n    if (!(this._isWithContent() && this._isEnabled)) {\\n      return\\n    }\\n\\n    const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\\n    const shadowRoot = findShadowRoot(this._element)\\n    const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\\n\\n    if (showEvent.defaultPrevented || !isInTheDom) {\\n      return\\n    }\\n\\n    // todo v6 remove this OR make it optional\\n    this._disposePopper()\\n\\n    const tip = this._getTipElement()\\n\\n    this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\\n\\n    const { container } = this._config\\n\\n    if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\\n      container.append(tip)\\n      EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\\n    }\\n\\n    this._popper = this._createPopper(tip)\\n\\n    tip.classList.add(CLASS_NAME_SHOW)\\n\\n    // If this is a touch-enabled device we add extra\\n    // empty mouseover listeners to the body's immediate children;\\n    // only needed because of broken event delegation on iOS\\n    // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\\n    if ('ontouchstart' in document.documentElement) {\\n      for (const element of [].concat(...document.body.children)) {\\n        EventHandler.on(element, 'mouseover', noop)\\n      }\\n    }\\n\\n    const complete = () => {\\n      EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\\n\\n      if (this._isHovered === false) {\\n        this._leave()\\n      }\\n\\n      this._isHovered = false\\n    }\\n\\n    this._queueCallback(complete, this.tip, this._isAnimated())\\n  }\\n\\n  hide() {\\n    if (!this._isShown()) {\\n      return\\n    }\\n\\n    const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\\n    if (hideEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    const tip = this._getTipElement()\\n    tip.classList.remove(CLASS_NAME_SHOW)\\n\\n    // If this is a touch-enabled device we remove the extra\\n    // empty mouseover listeners we added for iOS support\\n    if ('ontouchstart' in document.documentElement) {\\n      for (const element of [].concat(...document.body.children)) {\\n        EventHandler.off(element, 'mouseover', noop)\\n      }\\n    }\\n\\n    this._activeTrigger[TRIGGER_CLICK] = false\\n    this._activeTrigger[TRIGGER_FOCUS] = false\\n    this._activeTrigger[TRIGGER_HOVER] = false\\n    this._isHovered = null // it is a trick to support manual triggering\\n\\n    const complete = () => {\\n      if (this._isWithActiveTrigger()) {\\n        return\\n      }\\n\\n      if (!this._isHovered) {\\n        this._disposePopper()\\n      }\\n\\n      this._element.removeAttribute('aria-describedby')\\n      EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\\n    }\\n\\n    this._queueCallback(complete, this.tip, this._isAnimated())\\n  }\\n\\n  update() {\\n    if (this._popper) {\\n      this._popper.update()\\n    }\\n  }\\n\\n  // Protected\\n  _isWithContent() {\\n    return Boolean(this._getTitle())\\n  }\\n\\n  _getTipElement() {\\n    if (!this.tip) {\\n      this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\\n    }\\n\\n    return this.tip\\n  }\\n\\n  _createTipElement(content) {\\n    const tip = this._getTemplateFactory(content).toHtml()\\n\\n    // todo: remove this check on v6\\n    if (!tip) {\\n      return null\\n    }\\n\\n    tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\\n    // todo: on v6 the following can be achieved with CSS only\\n    tip.classList.add(`bs-${this.constructor.NAME}-auto`)\\n\\n    const tipId = getUID(this.constructor.NAME).toString()\\n\\n    tip.setAttribute('id', tipId)\\n\\n    if (this._isAnimated()) {\\n      tip.classList.add(CLASS_NAME_FADE)\\n    }\\n\\n    return tip\\n  }\\n\\n  setContent(content) {\\n    this._newContent = content\\n    if (this._isShown()) {\\n      this._disposePopper()\\n      this.show()\\n    }\\n  }\\n\\n  _getTemplateFactory(content) {\\n    if (this._templateFactory) {\\n      this._templateFactory.changeContent(content)\\n    } else {\\n      this._templateFactory = new TemplateFactory({\\n        ...this._config,\\n        // the `content` var has to be after `this._config`\\n        // to override config.content in case of popover\\n        content,\\n        extraClass: this._resolvePossibleFunction(this._config.customClass)\\n      })\\n    }\\n\\n    return this._templateFactory\\n  }\\n\\n  _getContentForTemplate() {\\n    return {\\n      [SELECTOR_TOOLTIP_INNER]: this._getTitle()\\n    }\\n  }\\n\\n  _getTitle() {\\n    return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\\n  }\\n\\n  // Private\\n  _initializeOnDelegatedTarget(event) {\\n    return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\\n  }\\n\\n  _isAnimated() {\\n    return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\\n  }\\n\\n  _isShown() {\\n    return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\\n  }\\n\\n  _createPopper(tip) {\\n    const placement = execute(this._config.placement, [this, tip, this._element])\\n    const attachment = AttachmentMap[placement.toUpperCase()]\\n    return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\\n  }\\n\\n  _getOffset() {\\n    const { offset } = this._config\\n\\n    if (typeof offset === 'string') {\\n      return offset.split(',').map(value => Number.parseInt(value, 10))\\n    }\\n\\n    if (typeof offset === 'function') {\\n      return popperData => offset(popperData, this._element)\\n    }\\n\\n    return offset\\n  }\\n\\n  _resolvePossibleFunction(arg) {\\n    return execute(arg, [this._element])\\n  }\\n\\n  _getPopperConfig(attachment) {\\n    const defaultBsPopperConfig = {\\n      placement: attachment,\\n      modifiers: [\\n        {\\n          name: 'flip',\\n          options: {\\n            fallbackPlacements: this._config.fallbackPlacements\\n          }\\n        },\\n        {\\n          name: 'offset',\\n          options: {\\n            offset: this._getOffset()\\n          }\\n        },\\n        {\\n          name: 'preventOverflow',\\n          options: {\\n            boundary: this._config.boundary\\n          }\\n        },\\n        {\\n          name: 'arrow',\\n          options: {\\n            element: `.${this.constructor.NAME}-arrow`\\n          }\\n        },\\n        {\\n          name: 'preSetPlacement',\\n          enabled: true,\\n          phase: 'beforeMain',\\n          fn: data => {\\n            // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\\n            // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\\n            this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\\n          }\\n        }\\n      ]\\n    }\\n\\n    return {\\n      ...defaultBsPopperConfig,\\n      ...execute(this._config.popperConfig, [defaultBsPopperConfig])\\n    }\\n  }\\n\\n  _setListeners() {\\n    const triggers = this._config.trigger.split(' ')\\n\\n    for (const trigger of triggers) {\\n      if (trigger === 'click') {\\n        EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\\n          const context = this._initializeOnDelegatedTarget(event)\\n          context.toggle()\\n        })\\n      } else if (trigger !== TRIGGER_MANUAL) {\\n        const eventIn = trigger === TRIGGER_HOVER ?\\n          this.constructor.eventName(EVENT_MOUSEENTER) :\\n          this.constructor.eventName(EVENT_FOCUSIN)\\n        const eventOut = trigger === TRIGGER_HOVER ?\\n          this.constructor.eventName(EVENT_MOUSELEAVE) :\\n          this.constructor.eventName(EVENT_FOCUSOUT)\\n\\n        EventHandler.on(this._element, eventIn, this._config.selector, event => {\\n          const context = this._initializeOnDelegatedTarget(event)\\n          context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\\n          context._enter()\\n        })\\n        EventHandler.on(this._element, eventOut, this._config.selector, event => {\\n          const context = this._initializeOnDelegatedTarget(event)\\n          context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\\n            context._element.contains(event.relatedTarget)\\n\\n          context._leave()\\n        })\\n      }\\n    }\\n\\n    this._hideModalHandler = () => {\\n      if (this._element) {\\n        this.hide()\\n      }\\n    }\\n\\n    EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\\n  }\\n\\n  _fixTitle() {\\n    const title = this._element.getAttribute('title')\\n\\n    if (!title) {\\n      return\\n    }\\n\\n    if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\\n      this._element.setAttribute('aria-label', title)\\n    }\\n\\n    this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\\n    this._element.removeAttribute('title')\\n  }\\n\\n  _enter() {\\n    if (this._isShown() || this._isHovered) {\\n      this._isHovered = true\\n      return\\n    }\\n\\n    this._isHovered = true\\n\\n    this._setTimeout(() => {\\n      if (this._isHovered) {\\n        this.show()\\n      }\\n    }, this._config.delay.show)\\n  }\\n\\n  _leave() {\\n    if (this._isWithActiveTrigger()) {\\n      return\\n    }\\n\\n    this._isHovered = false\\n\\n    this._setTimeout(() => {\\n      if (!this._isHovered) {\\n        this.hide()\\n      }\\n    }, this._config.delay.hide)\\n  }\\n\\n  _setTimeout(handler, timeout) {\\n    clearTimeout(this._timeout)\\n    this._timeout = setTimeout(handler, timeout)\\n  }\\n\\n  _isWithActiveTrigger() {\\n    return Object.values(this._activeTrigger).includes(true)\\n  }\\n\\n  _getConfig(config) {\\n    const dataAttributes = Manipulator.getDataAttributes(this._element)\\n\\n    for (const dataAttribute of Object.keys(dataAttributes)) {\\n      if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\\n        delete dataAttributes[dataAttribute]\\n      }\\n    }\\n\\n    config = {\\n      ...dataAttributes,\\n      ...(typeof config === 'object' && config ? config : {})\\n    }\\n    config = this._mergeConfigObj(config)\\n    config = this._configAfterMerge(config)\\n    this._typeCheckConfig(config)\\n    return config\\n  }\\n\\n  _configAfterMerge(config) {\\n    config.container = config.container === false ? document.body : getElement(config.container)\\n\\n    if (typeof config.delay === 'number') {\\n      config.delay = {\\n        show: config.delay,\\n        hide: config.delay\\n      }\\n    }\\n\\n    if (typeof config.title === 'number') {\\n      config.title = config.title.toString()\\n    }\\n\\n    if (typeof config.content === 'number') {\\n      config.content = config.content.toString()\\n    }\\n\\n    return config\\n  }\\n\\n  _getDelegateConfig() {\\n    const config = {}\\n\\n    for (const [key, value] of Object.entries(this._config)) {\\n      if (this.constructor.Default[key] !== value) {\\n        config[key] = value\\n      }\\n    }\\n\\n    config.selector = false\\n    config.trigger = 'manual'\\n\\n    // In the future can be replaced with:\\n    // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\\n    // `Object.fromEntries(keysWithDifferentValues)`\\n    return config\\n  }\\n\\n  _disposePopper() {\\n    if (this._popper) {\\n      this._popper.destroy()\\n      this._popper = null\\n    }\\n\\n    if (this.tip) {\\n      this.tip.remove()\\n      this.tip = null\\n    }\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Tooltip.getOrCreateInstance(this, config)\\n\\n      if (typeof config !== 'string') {\\n        return\\n      }\\n\\n      if (typeof data[config] === 'undefined') {\\n        throw new TypeError(`No method named \\\"${config}\\\"`)\\n      }\\n\\n      data[config]()\\n    })\\n  }\\n}\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Tooltip)\\n\\nexport default Tooltip\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): popover.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { defineJQueryPlugin } from './util/index.js'\\nimport Tooltip from './tooltip.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'popover'\\n\\nconst SELECTOR_TITLE = '.popover-header'\\nconst SELECTOR_CONTENT = '.popover-body'\\n\\nconst Default = {\\n  ...Tooltip.Default,\\n  content: '',\\n  offset: [0, 8],\\n  placement: 'right',\\n  template: '<div class=\\\"popover\\\" role=\\\"tooltip\\\">' +\\n    '<div class=\\\"popover-arrow\\\"></div>' +\\n    '<h3 class=\\\"popover-header\\\"></h3>' +\\n    '<div class=\\\"popover-body\\\"></div>' +\\n    '</div>',\\n  trigger: 'click'\\n}\\n\\nconst DefaultType = {\\n  ...Tooltip.DefaultType,\\n  content: '(null|string|element|function)'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Popover extends Tooltip {\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Overrides\\n  _isWithContent() {\\n    return this._getTitle() || this._getContent()\\n  }\\n\\n  // Private\\n  _getContentForTemplate() {\\n    return {\\n      [SELECTOR_TITLE]: this._getTitle(),\\n      [SELECTOR_CONTENT]: this._getContent()\\n    }\\n  }\\n\\n  _getContent() {\\n    return this._resolvePossibleFunction(this._config.content)\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Popover.getOrCreateInstance(this, config)\\n\\n      if (typeof config !== 'string') {\\n        return\\n      }\\n\\n      if (typeof data[config] === 'undefined') {\\n        throw new TypeError(`No method named \\\"${config}\\\"`)\\n      }\\n\\n      data[config]()\\n    })\\n  }\\n}\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Popover)\\n\\nexport default Popover\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): scrollspy.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { defineJQueryPlugin, getElement, isDisabled, isVisible } from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport SelectorEngine from './dom/selector-engine.js'\\nimport BaseComponent from './base-component.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'scrollspy'\\nconst DATA_KEY = 'bs.scrollspy'\\nconst EVENT_KEY = `.${DATA_KEY}`\\nconst DATA_API_KEY = '.data-api'\\n\\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\\nconst EVENT_CLICK = `click${EVENT_KEY}`\\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\\n\\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\\nconst CLASS_NAME_ACTIVE = 'active'\\n\\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\\\"scroll\\\"]'\\nconst SELECTOR_TARGET_LINKS = '[href]'\\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\\nconst SELECTOR_NAV_LINKS = '.nav-link'\\nconst SELECTOR_NAV_ITEMS = '.nav-item'\\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\\nconst SELECTOR_DROPDOWN = '.dropdown'\\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\\n\\nconst Default = {\\n  offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\\n  rootMargin: '0px 0px -25%',\\n  smoothScroll: false,\\n  target: null,\\n  threshold: [0.1, 0.5, 1]\\n}\\n\\nconst DefaultType = {\\n  offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\\n  rootMargin: 'string',\\n  smoothScroll: 'boolean',\\n  target: 'element',\\n  threshold: 'array'\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass ScrollSpy extends BaseComponent {\\n  constructor(element, config) {\\n    super(element, config)\\n\\n    // this._element is the observablesContainer and config.target the menu links wrapper\\n    this._targetLinks = new Map()\\n    this._observableSections = new Map()\\n    this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\\n    this._activeTarget = null\\n    this._observer = null\\n    this._previousScrollData = {\\n      visibleEntryTop: 0,\\n      parentScrollTop: 0\\n    }\\n    this.refresh() // initialize\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  refresh() {\\n    this._initializeTargetsAndObservables()\\n    this._maybeEnableSmoothScroll()\\n\\n    if (this._observer) {\\n      this._observer.disconnect()\\n    } else {\\n      this._observer = this._getNewObserver()\\n    }\\n\\n    for (const section of this._observableSections.values()) {\\n      this._observer.observe(section)\\n    }\\n  }\\n\\n  dispose() {\\n    this._observer.disconnect()\\n    super.dispose()\\n  }\\n\\n  // Private\\n  _configAfterMerge(config) {\\n    // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\\n    config.target = getElement(config.target) || document.body\\n\\n    // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\\n    config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\\n\\n    if (typeof config.threshold === 'string') {\\n      config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\\n    }\\n\\n    return config\\n  }\\n\\n  _maybeEnableSmoothScroll() {\\n    if (!this._config.smoothScroll) {\\n      return\\n    }\\n\\n    // unregister any previous listeners\\n    EventHandler.off(this._config.target, EVENT_CLICK)\\n\\n    EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\\n      const observableSection = this._observableSections.get(event.target.hash)\\n      if (observableSection) {\\n        event.preventDefault()\\n        const root = this._rootElement || window\\n        const height = observableSection.offsetTop - this._element.offsetTop\\n        if (root.scrollTo) {\\n          root.scrollTo({ top: height, behavior: 'smooth' })\\n          return\\n        }\\n\\n        // Chrome 60 doesn't support `scrollTo`\\n        root.scrollTop = height\\n      }\\n    })\\n  }\\n\\n  _getNewObserver() {\\n    const options = {\\n      root: this._rootElement,\\n      threshold: this._config.threshold,\\n      rootMargin: this._config.rootMargin\\n    }\\n\\n    return new IntersectionObserver(entries => this._observerCallback(entries), options)\\n  }\\n\\n  // The logic of selection\\n  _observerCallback(entries) {\\n    const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\\n    const activate = entry => {\\n      this._previousScrollData.visibleEntryTop = entry.target.offsetTop\\n      this._process(targetElement(entry))\\n    }\\n\\n    const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\\n    const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\\n    this._previousScrollData.parentScrollTop = parentScrollTop\\n\\n    for (const entry of entries) {\\n      if (!entry.isIntersecting) {\\n        this._activeTarget = null\\n        this._clearActiveClass(targetElement(entry))\\n\\n        continue\\n      }\\n\\n      const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\\n      // if we are scrolling down, pick the bigger offsetTop\\n      if (userScrollsDown && entryIsLowerThanPrevious) {\\n        activate(entry)\\n        // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\\n        if (!parentScrollTop) {\\n          return\\n        }\\n\\n        continue\\n      }\\n\\n      // if we are scrolling up, pick the smallest offsetTop\\n      if (!userScrollsDown && !entryIsLowerThanPrevious) {\\n        activate(entry)\\n      }\\n    }\\n  }\\n\\n  _initializeTargetsAndObservables() {\\n    this._targetLinks = new Map()\\n    this._observableSections = new Map()\\n\\n    const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\\n\\n    for (const anchor of targetLinks) {\\n      // ensure that the anchor has an id and is not disabled\\n      if (!anchor.hash || isDisabled(anchor)) {\\n        continue\\n      }\\n\\n      const observableSection = SelectorEngine.findOne(anchor.hash, this._element)\\n\\n      // ensure that the observableSection exists & is visible\\n      if (isVisible(observableSection)) {\\n        this._targetLinks.set(anchor.hash, anchor)\\n        this._observableSections.set(anchor.hash, observableSection)\\n      }\\n    }\\n  }\\n\\n  _process(target) {\\n    if (this._activeTarget === target) {\\n      return\\n    }\\n\\n    this._clearActiveClass(this._config.target)\\n    this._activeTarget = target\\n    target.classList.add(CLASS_NAME_ACTIVE)\\n    this._activateParents(target)\\n\\n    EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\\n  }\\n\\n  _activateParents(target) {\\n    // Activate dropdown parents\\n    if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\\n      SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\\n        .classList.add(CLASS_NAME_ACTIVE)\\n      return\\n    }\\n\\n    for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\\n      // Set triggered links parents as active\\n      // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\\n      for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\\n        item.classList.add(CLASS_NAME_ACTIVE)\\n      }\\n    }\\n  }\\n\\n  _clearActiveClass(parent) {\\n    parent.classList.remove(CLASS_NAME_ACTIVE)\\n\\n    const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\\n    for (const node of activeNodes) {\\n      node.classList.remove(CLASS_NAME_ACTIVE)\\n    }\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = ScrollSpy.getOrCreateInstance(this, config)\\n\\n      if (typeof config !== 'string') {\\n        return\\n      }\\n\\n      if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\\n        throw new TypeError(`No method named \\\"${config}\\\"`)\\n      }\\n\\n      data[config]()\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\\n  for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\\n    ScrollSpy.getOrCreateInstance(spy)\\n  }\\n})\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(ScrollSpy)\\n\\nexport default ScrollSpy\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): tab.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport SelectorEngine from './dom/selector-engine.js'\\nimport BaseComponent from './base-component.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'tab'\\nconst DATA_KEY = 'bs.tab'\\nconst EVENT_KEY = `.${DATA_KEY}`\\n\\nconst EVENT_HIDE = `hide${EVENT_KEY}`\\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\\nconst EVENT_SHOW = `show${EVENT_KEY}`\\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\\n\\nconst ARROW_LEFT_KEY = 'ArrowLeft'\\nconst ARROW_RIGHT_KEY = 'ArrowRight'\\nconst ARROW_UP_KEY = 'ArrowUp'\\nconst ARROW_DOWN_KEY = 'ArrowDown'\\n\\nconst CLASS_NAME_ACTIVE = 'active'\\nconst CLASS_NAME_FADE = 'fade'\\nconst CLASS_NAME_SHOW = 'show'\\nconst CLASS_DROPDOWN = 'dropdown'\\n\\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = ':not(.dropdown-toggle)'\\n\\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\\\"tablist\\\"]'\\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\\\"tab\\\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\\\"tab\\\"], [data-bs-toggle=\\\"pill\\\"], [data-bs-toggle=\\\"list\\\"]' // todo:v6: could be only `tab`\\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\\n\\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\\\"tab\\\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\\\"pill\\\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\\\"list\\\"]`\\n\\n/**\\n * Class definition\\n */\\n\\nclass Tab extends BaseComponent {\\n  constructor(element) {\\n    super(element)\\n    this._parent = this._element.closest(SELECTOR_TAB_PANEL)\\n\\n    if (!this._parent) {\\n      return\\n      // todo: should Throw exception on v6\\n      // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\\n    }\\n\\n    // Set up initial aria attributes\\n    this._setInitialAttributes(this._parent, this._getChildren())\\n\\n    EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\\n  }\\n\\n  // Getters\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  show() { // Shows this elem and deactivate the active sibling if exists\\n    const innerElem = this._element\\n    if (this._elemIsActive(innerElem)) {\\n      return\\n    }\\n\\n    // Search for active tab on same parent to deactivate it\\n    const active = this._getActiveElem()\\n\\n    const hideEvent = active ?\\n      EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\\n      null\\n\\n    const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\\n\\n    if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\\n      return\\n    }\\n\\n    this._deactivate(active, innerElem)\\n    this._activate(innerElem, active)\\n  }\\n\\n  // Private\\n  _activate(element, relatedElem) {\\n    if (!element) {\\n      return\\n    }\\n\\n    element.classList.add(CLASS_NAME_ACTIVE)\\n\\n    this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\\n\\n    const complete = () => {\\n      if (element.getAttribute('role') !== 'tab') {\\n        element.classList.add(CLASS_NAME_SHOW)\\n        return\\n      }\\n\\n      element.removeAttribute('tabindex')\\n      element.setAttribute('aria-selected', true)\\n      this._toggleDropDown(element, true)\\n      EventHandler.trigger(element, EVENT_SHOWN, {\\n        relatedTarget: relatedElem\\n      })\\n    }\\n\\n    this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\\n  }\\n\\n  _deactivate(element, relatedElem) {\\n    if (!element) {\\n      return\\n    }\\n\\n    element.classList.remove(CLASS_NAME_ACTIVE)\\n    element.blur()\\n\\n    this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\\n\\n    const complete = () => {\\n      if (element.getAttribute('role') !== 'tab') {\\n        element.classList.remove(CLASS_NAME_SHOW)\\n        return\\n      }\\n\\n      element.setAttribute('aria-selected', false)\\n      element.setAttribute('tabindex', '-1')\\n      this._toggleDropDown(element, false)\\n      EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\\n    }\\n\\n    this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\\n  }\\n\\n  _keydown(event) {\\n    if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key))) {\\n      return\\n    }\\n\\n    event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\\n    event.preventDefault()\\n    const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\\n    const nextActiveElement = getNextActiveElement(this._getChildren().filter(element => !isDisabled(element)), event.target, isNext, true)\\n\\n    if (nextActiveElement) {\\n      nextActiveElement.focus({ preventScroll: true })\\n      Tab.getOrCreateInstance(nextActiveElement).show()\\n    }\\n  }\\n\\n  _getChildren() { // collection of inner elements\\n    return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\\n  }\\n\\n  _getActiveElem() {\\n    return this._getChildren().find(child => this._elemIsActive(child)) || null\\n  }\\n\\n  _setInitialAttributes(parent, children) {\\n    this._setAttributeIfNotExists(parent, 'role', 'tablist')\\n\\n    for (const child of children) {\\n      this._setInitialAttributesOnChild(child)\\n    }\\n  }\\n\\n  _setInitialAttributesOnChild(child) {\\n    child = this._getInnerElement(child)\\n    const isActive = this._elemIsActive(child)\\n    const outerElem = this._getOuterElement(child)\\n    child.setAttribute('aria-selected', isActive)\\n\\n    if (outerElem !== child) {\\n      this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\\n    }\\n\\n    if (!isActive) {\\n      child.setAttribute('tabindex', '-1')\\n    }\\n\\n    this._setAttributeIfNotExists(child, 'role', 'tab')\\n\\n    // set attributes to the related panel too\\n    this._setInitialAttributesOnTargetPanel(child)\\n  }\\n\\n  _setInitialAttributesOnTargetPanel(child) {\\n    const target = SelectorEngine.getElementFromSelector(child)\\n\\n    if (!target) {\\n      return\\n    }\\n\\n    this._setAttributeIfNotExists(target, 'role', 'tabpanel')\\n\\n    if (child.id) {\\n      this._setAttributeIfNotExists(target, 'aria-labelledby', `#${child.id}`)\\n    }\\n  }\\n\\n  _toggleDropDown(element, open) {\\n    const outerElem = this._getOuterElement(element)\\n    if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\\n      return\\n    }\\n\\n    const toggle = (selector, className) => {\\n      const element = SelectorEngine.findOne(selector, outerElem)\\n      if (element) {\\n        element.classList.toggle(className, open)\\n      }\\n    }\\n\\n    toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\\n    toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\\n    outerElem.setAttribute('aria-expanded', open)\\n  }\\n\\n  _setAttributeIfNotExists(element, attribute, value) {\\n    if (!element.hasAttribute(attribute)) {\\n      element.setAttribute(attribute, value)\\n    }\\n  }\\n\\n  _elemIsActive(elem) {\\n    return elem.classList.contains(CLASS_NAME_ACTIVE)\\n  }\\n\\n  // Try to get the inner element (usually the .nav-link)\\n  _getInnerElement(elem) {\\n    return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\\n  }\\n\\n  // Try to get the outer element (usually the .nav-item)\\n  _getOuterElement(elem) {\\n    return elem.closest(SELECTOR_OUTER) || elem\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Tab.getOrCreateInstance(this)\\n\\n      if (typeof config !== 'string') {\\n        return\\n      }\\n\\n      if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\\n        throw new TypeError(`No method named \\\"${config}\\\"`)\\n      }\\n\\n      data[config]()\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\\n  if (['A', 'AREA'].includes(this.tagName)) {\\n    event.preventDefault()\\n  }\\n\\n  if (isDisabled(this)) {\\n    return\\n  }\\n\\n  Tab.getOrCreateInstance(this).show()\\n})\\n\\n/**\\n * Initialize on focus\\n */\\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\\n  for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\\n    Tab.getOrCreateInstance(element)\\n  }\\n})\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Tab)\\n\\nexport default Tab\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): toast.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport { defineJQueryPlugin, reflow } from './util/index.js'\\nimport EventHandler from './dom/event-handler.js'\\nimport BaseComponent from './base-component.js'\\nimport { enableDismissTrigger } from './util/component-functions.js'\\n\\n/**\\n * Constants\\n */\\n\\nconst NAME = 'toast'\\nconst DATA_KEY = 'bs.toast'\\nconst EVENT_KEY = `.${DATA_KEY}`\\n\\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\\nconst EVENT_HIDE = `hide${EVENT_KEY}`\\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\\nconst EVENT_SHOW = `show${EVENT_KEY}`\\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\\n\\nconst CLASS_NAME_FADE = 'fade'\\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\\nconst CLASS_NAME_SHOW = 'show'\\nconst CLASS_NAME_SHOWING = 'showing'\\n\\nconst DefaultType = {\\n  animation: 'boolean',\\n  autohide: 'boolean',\\n  delay: 'number'\\n}\\n\\nconst Default = {\\n  animation: true,\\n  autohide: true,\\n  delay: 5000\\n}\\n\\n/**\\n * Class definition\\n */\\n\\nclass Toast extends BaseComponent {\\n  constructor(element, config) {\\n    super(element, config)\\n\\n    this._timeout = null\\n    this._hasMouseInteraction = false\\n    this._hasKeyboardInteraction = false\\n    this._setListeners()\\n  }\\n\\n  // Getters\\n  static get Default() {\\n    return Default\\n  }\\n\\n  static get DefaultType() {\\n    return DefaultType\\n  }\\n\\n  static get NAME() {\\n    return NAME\\n  }\\n\\n  // Public\\n  show() {\\n    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\\n\\n    if (showEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    this._clearTimeout()\\n\\n    if (this._config.animation) {\\n      this._element.classList.add(CLASS_NAME_FADE)\\n    }\\n\\n    const complete = () => {\\n      this._element.classList.remove(CLASS_NAME_SHOWING)\\n      EventHandler.trigger(this._element, EVENT_SHOWN)\\n\\n      this._maybeScheduleHide()\\n    }\\n\\n    this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\\n    reflow(this._element)\\n    this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\\n\\n    this._queueCallback(complete, this._element, this._config.animation)\\n  }\\n\\n  hide() {\\n    if (!this.isShown()) {\\n      return\\n    }\\n\\n    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\\n\\n    if (hideEvent.defaultPrevented) {\\n      return\\n    }\\n\\n    const complete = () => {\\n      this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\\n      this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\\n      EventHandler.trigger(this._element, EVENT_HIDDEN)\\n    }\\n\\n    this._element.classList.add(CLASS_NAME_SHOWING)\\n    this._queueCallback(complete, this._element, this._config.animation)\\n  }\\n\\n  dispose() {\\n    this._clearTimeout()\\n\\n    if (this.isShown()) {\\n      this._element.classList.remove(CLASS_NAME_SHOW)\\n    }\\n\\n    super.dispose()\\n  }\\n\\n  isShown() {\\n    return this._element.classList.contains(CLASS_NAME_SHOW)\\n  }\\n\\n  // Private\\n\\n  _maybeScheduleHide() {\\n    if (!this._config.autohide) {\\n      return\\n    }\\n\\n    if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\\n      return\\n    }\\n\\n    this._timeout = setTimeout(() => {\\n      this.hide()\\n    }, this._config.delay)\\n  }\\n\\n  _onInteraction(event, isInteracting) {\\n    switch (event.type) {\\n      case 'mouseover':\\n      case 'mouseout': {\\n        this._hasMouseInteraction = isInteracting\\n        break\\n      }\\n\\n      case 'focusin':\\n      case 'focusout': {\\n        this._hasKeyboardInteraction = isInteracting\\n        break\\n      }\\n\\n      default: {\\n        break\\n      }\\n    }\\n\\n    if (isInteracting) {\\n      this._clearTimeout()\\n      return\\n    }\\n\\n    const nextElement = event.relatedTarget\\n    if (this._element === nextElement || this._element.contains(nextElement)) {\\n      return\\n    }\\n\\n    this._maybeScheduleHide()\\n  }\\n\\n  _setListeners() {\\n    EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\\n    EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\\n    EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\\n    EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\\n  }\\n\\n  _clearTimeout() {\\n    clearTimeout(this._timeout)\\n    this._timeout = null\\n  }\\n\\n  // Static\\n  static jQueryInterface(config) {\\n    return this.each(function () {\\n      const data = Toast.getOrCreateInstance(this, config)\\n\\n      if (typeof config === 'string') {\\n        if (typeof data[config] === 'undefined') {\\n          throw new TypeError(`No method named \\\"${config}\\\"`)\\n        }\\n\\n        data[config](this)\\n      }\\n    })\\n  }\\n}\\n\\n/**\\n * Data API implementation\\n */\\n\\nenableDismissTrigger(Toast)\\n\\n/**\\n * jQuery\\n */\\n\\ndefineJQueryPlugin(Toast)\\n\\nexport default Toast\\n\",\"/**\\n * --------------------------------------------------------------------------\\n * Bootstrap (v5.3.0-alpha1): index.umd.js\\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\\n * --------------------------------------------------------------------------\\n */\\n\\nimport Alert from './src/alert.js'\\nimport Button from './src/button.js'\\nimport Carousel from './src/carousel.js'\\nimport Collapse from './src/collapse.js'\\nimport Dropdown from './src/dropdown.js'\\nimport Modal from './src/modal.js'\\nimport Offcanvas from './src/offcanvas.js'\\nimport Popover from './src/popover.js'\\nimport ScrollSpy from './src/scrollspy.js'\\nimport Tab from './src/tab.js'\\nimport Toast from './src/toast.js'\\nimport Tooltip from './src/tooltip.js'\\n\\nexport default {\\n  Alert,\\n  Button,\\n  Carousel,\\n  Collapse,\\n  Dropdown,\\n  Modal,\\n  Offcanvas,\\n  Popover,\\n  ScrollSpy,\\n  Tab,\\n  Toast,\\n  Tooltip\\n}\\n\"],\"mappings\":\"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\"}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/all.min.css",
    "content": "/*!\n * Font Awesome Free 6.0.0 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n * Copyright 2022 Fonticons, Inc.\n */\n.fa{font-family:var(--fa-style-family,\"Font Awesome 6 Free\");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-duotone,.fa-light,.fa-regular,.fa-solid,.fa-thin,.fab,.fad,.fal,.far,.fas,.fat{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.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:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;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(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);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{-webkit-animation-name:fa-beat;animation-name:fa-beat;-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{-webkit-animation-name:fa-bounce;animation-name:fa-bounce;-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{-webkit-animation-name:fa-fade;animation-name:fa-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{-webkit-animation-name:fa-beat-fade;animation-name:fa-beat-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{-webkit-animation-name:fa-flip;animation-name:fa-flip;-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{-webkit-animation-name:fa-shake;animation-name:fa-shake;-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-duration:var(--fa-animation-duration,2s);animation-duration:var(--fa-animation-duration,2s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,steps(8));animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;transition-delay:0s;transition-duration:0s}}@-webkit-keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@-webkit-keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@-webkit-keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@-webkit-keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@-webkit-keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@-webkit-keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}.fa-rotate-by{-webkit-transform:rotate(var(--fa-rotate-angle,none));transform:rotate(var(--fa-rotate-angle,none))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)}.fa-0:before{content:\"\\30\"}.fa-1:before{content:\"\\31\"}.fa-2:before{content:\"\\32\"}.fa-3:before{content:\"\\33\"}.fa-4:before{content:\"\\34\"}.fa-5:before{content:\"\\35\"}.fa-6:before{content:\"\\36\"}.fa-7:before{content:\"\\37\"}.fa-8:before{content:\"\\38\"}.fa-9:before{content:\"\\39\"}.fa-a:before{content:\"\\41\"}.fa-address-book:before,.fa-contact-book:before{content:\"\\f2b9\"}.fa-address-card:before,.fa-contact-card:before,.fa-vcard:before{content:\"\\f2bb\"}.fa-align-center:before{content:\"\\f037\"}.fa-align-justify:before{content:\"\\f039\"}.fa-align-left:before{content:\"\\f036\"}.fa-align-right:before{content:\"\\f038\"}.fa-anchor:before{content:\"\\f13d\"}.fa-angle-down:before{content:\"\\f107\"}.fa-angle-left:before{content:\"\\f104\"}.fa-angle-right:before{content:\"\\f105\"}.fa-angle-up:before{content:\"\\f106\"}.fa-angle-double-down:before,.fa-angles-down:before{content:\"\\f103\"}.fa-angle-double-left:before,.fa-angles-left:before{content:\"\\f100\"}.fa-angle-double-right:before,.fa-angles-right:before{content:\"\\f101\"}.fa-angle-double-up:before,.fa-angles-up:before{content:\"\\f102\"}.fa-ankh:before{content:\"\\f644\"}.fa-apple-alt:before,.fa-apple-whole:before{content:\"\\f5d1\"}.fa-archway:before{content:\"\\f557\"}.fa-arrow-down:before{content:\"\\f063\"}.fa-arrow-down-1-9:before,.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:\"\\f162\"}.fa-arrow-down-9-1:before,.fa-sort-numeric-desc:before,.fa-sort-numeric-down-alt:before{content:\"\\f886\"}.fa-arrow-down-a-z:before,.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:\"\\f15d\"}.fa-arrow-down-long:before,.fa-long-arrow-down:before{content:\"\\f175\"}.fa-arrow-down-short-wide:before,.fa-sort-amount-desc:before,.fa-sort-amount-down-alt:before{content:\"\\f884\"}.fa-arrow-down-wide-short:before,.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:\"\\f160\"}.fa-arrow-down-z-a:before,.fa-sort-alpha-desc:before,.fa-sort-alpha-down-alt:before{content:\"\\f881\"}.fa-arrow-left:before{content:\"\\f060\"}.fa-arrow-left-long:before,.fa-long-arrow-left:before{content:\"\\f177\"}.fa-arrow-pointer:before,.fa-mouse-pointer:before{content:\"\\f245\"}.fa-arrow-right:before{content:\"\\f061\"}.fa-arrow-right-arrow-left:before,.fa-exchange:before{content:\"\\f0ec\"}.fa-arrow-right-from-bracket:before,.fa-sign-out:before{content:\"\\f08b\"}.fa-arrow-right-long:before,.fa-long-arrow-right:before{content:\"\\f178\"}.fa-arrow-right-to-bracket:before,.fa-sign-in:before{content:\"\\f090\"}.fa-arrow-left-rotate:before,.fa-arrow-rotate-back:before,.fa-arrow-rotate-backward:before,.fa-arrow-rotate-left:before,.fa-undo:before{content:\"\\f0e2\"}.fa-arrow-right-rotate:before,.fa-arrow-rotate-forward:before,.fa-arrow-rotate-right:before,.fa-redo:before{content:\"\\f01e\"}.fa-arrow-trend-down:before{content:\"\\e097\"}.fa-arrow-trend-up:before{content:\"\\e098\"}.fa-arrow-turn-down:before,.fa-level-down:before{content:\"\\f149\"}.fa-arrow-turn-up:before,.fa-level-up:before{content:\"\\f148\"}.fa-arrow-up:before{content:\"\\f062\"}.fa-arrow-up-1-9:before,.fa-sort-numeric-up:before{content:\"\\f163\"}.fa-arrow-up-9-1:before,.fa-sort-numeric-up-alt:before{content:\"\\f887\"}.fa-arrow-up-a-z:before,.fa-sort-alpha-up:before{content:\"\\f15e\"}.fa-arrow-up-from-bracket:before{content:\"\\e09a\"}.fa-arrow-up-long:before,.fa-long-arrow-up:before{content:\"\\f176\"}.fa-arrow-up-right-from-square:before,.fa-external-link:before{content:\"\\f08e\"}.fa-arrow-up-short-wide:before,.fa-sort-amount-up-alt:before{content:\"\\f885\"}.fa-arrow-up-wide-short:before,.fa-sort-amount-up:before{content:\"\\f161\"}.fa-arrow-up-z-a:before,.fa-sort-alpha-up-alt:before{content:\"\\f882\"}.fa-arrows-h:before,.fa-arrows-left-right:before{content:\"\\f07e\"}.fa-arrows-rotate:before,.fa-refresh:before,.fa-sync:before{content:\"\\f021\"}.fa-arrows-up-down:before,.fa-arrows-v:before{content:\"\\f07d\"}.fa-arrows-up-down-left-right:before,.fa-arrows:before{content:\"\\f047\"}.fa-asterisk:before{content:\"\\2a\"}.fa-at:before{content:\"\\40\"}.fa-atom:before{content:\"\\f5d2\"}.fa-audio-description:before{content:\"\\f29e\"}.fa-austral-sign:before{content:\"\\e0a9\"}.fa-award:before{content:\"\\f559\"}.fa-b:before{content:\"\\42\"}.fa-baby:before{content:\"\\f77c\"}.fa-baby-carriage:before,.fa-carriage-baby:before{content:\"\\f77d\"}.fa-backward:before{content:\"\\f04a\"}.fa-backward-fast:before,.fa-fast-backward:before{content:\"\\f049\"}.fa-backward-step:before,.fa-step-backward:before{content:\"\\f048\"}.fa-bacon:before{content:\"\\f7e5\"}.fa-bacteria:before{content:\"\\e059\"}.fa-bacterium:before{content:\"\\e05a\"}.fa-bag-shopping:before,.fa-shopping-bag:before{content:\"\\f290\"}.fa-bahai:before{content:\"\\f666\"}.fa-baht-sign:before{content:\"\\e0ac\"}.fa-ban:before,.fa-cancel:before{content:\"\\f05e\"}.fa-ban-smoking:before,.fa-smoking-ban:before{content:\"\\f54d\"}.fa-band-aid:before,.fa-bandage:before{content:\"\\f462\"}.fa-barcode:before{content:\"\\f02a\"}.fa-bars:before,.fa-navicon:before{content:\"\\f0c9\"}.fa-bars-progress:before,.fa-tasks-alt:before{content:\"\\f828\"}.fa-bars-staggered:before,.fa-reorder:before,.fa-stream:before{content:\"\\f550\"}.fa-baseball-ball:before,.fa-baseball:before{content:\"\\f433\"}.fa-baseball-bat-ball:before{content:\"\\f432\"}.fa-basket-shopping:before,.fa-shopping-basket:before{content:\"\\f291\"}.fa-basketball-ball:before,.fa-basketball:before{content:\"\\f434\"}.fa-bath:before,.fa-bathtub:before{content:\"\\f2cd\"}.fa-battery-0:before,.fa-battery-empty:before{content:\"\\f244\"}.fa-battery-5:before,.fa-battery-full:before,.fa-battery:before{content:\"\\f240\"}.fa-battery-3:before,.fa-battery-half:before{content:\"\\f242\"}.fa-battery-2:before,.fa-battery-quarter:before{content:\"\\f243\"}.fa-battery-4:before,.fa-battery-three-quarters:before{content:\"\\f241\"}.fa-bed:before{content:\"\\f236\"}.fa-bed-pulse:before,.fa-procedures:before{content:\"\\f487\"}.fa-beer-mug-empty:before,.fa-beer:before{content:\"\\f0fc\"}.fa-bell:before{content:\"\\f0f3\"}.fa-bell-concierge:before,.fa-concierge-bell:before{content:\"\\f562\"}.fa-bell-slash:before{content:\"\\f1f6\"}.fa-bezier-curve:before{content:\"\\f55b\"}.fa-bicycle:before{content:\"\\f206\"}.fa-binoculars:before{content:\"\\f1e5\"}.fa-biohazard:before{content:\"\\f780\"}.fa-bitcoin-sign:before{content:\"\\e0b4\"}.fa-blender:before{content:\"\\f517\"}.fa-blender-phone:before{content:\"\\f6b6\"}.fa-blog:before{content:\"\\f781\"}.fa-bold:before{content:\"\\f032\"}.fa-bolt:before,.fa-zap:before{content:\"\\f0e7\"}.fa-bolt-lightning:before{content:\"\\e0b7\"}.fa-bomb:before{content:\"\\f1e2\"}.fa-bone:before{content:\"\\f5d7\"}.fa-bong:before{content:\"\\f55c\"}.fa-book:before{content:\"\\f02d\"}.fa-atlas:before,.fa-book-atlas:before{content:\"\\f558\"}.fa-bible:before,.fa-book-bible:before{content:\"\\f647\"}.fa-book-journal-whills:before,.fa-journal-whills:before{content:\"\\f66a\"}.fa-book-medical:before{content:\"\\f7e6\"}.fa-book-open:before{content:\"\\f518\"}.fa-book-open-reader:before,.fa-book-reader:before{content:\"\\f5da\"}.fa-book-quran:before,.fa-quran:before{content:\"\\f687\"}.fa-book-dead:before,.fa-book-skull:before{content:\"\\f6b7\"}.fa-bookmark:before{content:\"\\f02e\"}.fa-border-all:before{content:\"\\f84c\"}.fa-border-none:before{content:\"\\f850\"}.fa-border-style:before,.fa-border-top-left:before{content:\"\\f853\"}.fa-bowling-ball:before{content:\"\\f436\"}.fa-box:before{content:\"\\f466\"}.fa-archive:before,.fa-box-archive:before{content:\"\\f187\"}.fa-box-open:before{content:\"\\f49e\"}.fa-box-tissue:before{content:\"\\e05b\"}.fa-boxes-alt:before,.fa-boxes-stacked:before,.fa-boxes:before{content:\"\\f468\"}.fa-braille:before{content:\"\\f2a1\"}.fa-brain:before{content:\"\\f5dc\"}.fa-brazilian-real-sign:before{content:\"\\e46c\"}.fa-bread-slice:before{content:\"\\f7ec\"}.fa-briefcase:before{content:\"\\f0b1\"}.fa-briefcase-medical:before{content:\"\\f469\"}.fa-broom:before{content:\"\\f51a\"}.fa-broom-ball:before,.fa-quidditch-broom-ball:before,.fa-quidditch:before{content:\"\\f458\"}.fa-brush:before{content:\"\\f55d\"}.fa-bug:before{content:\"\\f188\"}.fa-bug-slash:before{content:\"\\e490\"}.fa-building:before{content:\"\\f1ad\"}.fa-bank:before,.fa-building-columns:before,.fa-institution:before,.fa-museum:before,.fa-university:before{content:\"\\f19c\"}.fa-bullhorn:before{content:\"\\f0a1\"}.fa-bullseye:before{content:\"\\f140\"}.fa-burger:before,.fa-hamburger:before{content:\"\\f805\"}.fa-bus:before{content:\"\\f207\"}.fa-bus-alt:before,.fa-bus-simple:before{content:\"\\f55e\"}.fa-briefcase-clock:before,.fa-business-time:before{content:\"\\f64a\"}.fa-c:before{content:\"\\43\"}.fa-birthday-cake:before,.fa-cake-candles:before,.fa-cake:before{content:\"\\f1fd\"}.fa-calculator:before{content:\"\\f1ec\"}.fa-calendar:before{content:\"\\f133\"}.fa-calendar-check:before{content:\"\\f274\"}.fa-calendar-day:before{content:\"\\f783\"}.fa-calendar-alt:before,.fa-calendar-days:before{content:\"\\f073\"}.fa-calendar-minus:before{content:\"\\f272\"}.fa-calendar-plus:before{content:\"\\f271\"}.fa-calendar-week:before{content:\"\\f784\"}.fa-calendar-times:before,.fa-calendar-xmark:before{content:\"\\f273\"}.fa-camera-alt:before,.fa-camera:before{content:\"\\f030\"}.fa-camera-retro:before{content:\"\\f083\"}.fa-camera-rotate:before{content:\"\\e0d8\"}.fa-campground:before{content:\"\\f6bb\"}.fa-candy-cane:before{content:\"\\f786\"}.fa-cannabis:before{content:\"\\f55f\"}.fa-capsules:before{content:\"\\f46b\"}.fa-automobile:before,.fa-car:before{content:\"\\f1b9\"}.fa-battery-car:before,.fa-car-battery:before{content:\"\\f5df\"}.fa-car-crash:before{content:\"\\f5e1\"}.fa-car-alt:before,.fa-car-rear:before{content:\"\\f5de\"}.fa-car-side:before{content:\"\\f5e4\"}.fa-caravan:before{content:\"\\f8ff\"}.fa-caret-down:before{content:\"\\f0d7\"}.fa-caret-left:before{content:\"\\f0d9\"}.fa-caret-right:before{content:\"\\f0da\"}.fa-caret-up:before{content:\"\\f0d8\"}.fa-carrot:before{content:\"\\f787\"}.fa-cart-arrow-down:before{content:\"\\f218\"}.fa-cart-flatbed:before,.fa-dolly-flatbed:before{content:\"\\f474\"}.fa-cart-flatbed-suitcase:before,.fa-luggage-cart:before{content:\"\\f59d\"}.fa-cart-plus:before{content:\"\\f217\"}.fa-cart-shopping:before,.fa-shopping-cart:before{content:\"\\f07a\"}.fa-cash-register:before{content:\"\\f788\"}.fa-cat:before{content:\"\\f6be\"}.fa-cedi-sign:before{content:\"\\e0df\"}.fa-cent-sign:before{content:\"\\e3f5\"}.fa-certificate:before{content:\"\\f0a3\"}.fa-chair:before{content:\"\\f6c0\"}.fa-blackboard:before,.fa-chalkboard:before{content:\"\\f51b\"}.fa-chalkboard-teacher:before,.fa-chalkboard-user:before{content:\"\\f51c\"}.fa-champagne-glasses:before,.fa-glass-cheers:before{content:\"\\f79f\"}.fa-charging-station:before{content:\"\\f5e7\"}.fa-area-chart:before,.fa-chart-area:before{content:\"\\f1fe\"}.fa-bar-chart:before,.fa-chart-bar:before{content:\"\\f080\"}.fa-chart-column:before{content:\"\\e0e3\"}.fa-chart-gantt:before{content:\"\\e0e4\"}.fa-chart-line:before,.fa-line-chart:before{content:\"\\f201\"}.fa-chart-pie:before,.fa-pie-chart:before{content:\"\\f200\"}.fa-check:before{content:\"\\f00c\"}.fa-check-double:before{content:\"\\f560\"}.fa-check-to-slot:before,.fa-vote-yea:before{content:\"\\f772\"}.fa-cheese:before{content:\"\\f7ef\"}.fa-chess:before{content:\"\\f439\"}.fa-chess-bishop:before{content:\"\\f43a\"}.fa-chess-board:before{content:\"\\f43c\"}.fa-chess-king:before{content:\"\\f43f\"}.fa-chess-knight:before{content:\"\\f441\"}.fa-chess-pawn:before{content:\"\\f443\"}.fa-chess-queen:before{content:\"\\f445\"}.fa-chess-rook:before{content:\"\\f447\"}.fa-chevron-down:before{content:\"\\f078\"}.fa-chevron-left:before{content:\"\\f053\"}.fa-chevron-right:before{content:\"\\f054\"}.fa-chevron-up:before{content:\"\\f077\"}.fa-child:before{content:\"\\f1ae\"}.fa-church:before{content:\"\\f51d\"}.fa-circle:before{content:\"\\f111\"}.fa-arrow-circle-down:before,.fa-circle-arrow-down:before{content:\"\\f0ab\"}.fa-arrow-circle-left:before,.fa-circle-arrow-left:before{content:\"\\f0a8\"}.fa-arrow-circle-right:before,.fa-circle-arrow-right:before{content:\"\\f0a9\"}.fa-arrow-circle-up:before,.fa-circle-arrow-up:before{content:\"\\f0aa\"}.fa-check-circle:before,.fa-circle-check:before{content:\"\\f058\"}.fa-chevron-circle-down:before,.fa-circle-chevron-down:before{content:\"\\f13a\"}.fa-chevron-circle-left:before,.fa-circle-chevron-left:before{content:\"\\f137\"}.fa-chevron-circle-right:before,.fa-circle-chevron-right:before{content:\"\\f138\"}.fa-chevron-circle-up:before,.fa-circle-chevron-up:before{content:\"\\f139\"}.fa-circle-dollar-to-slot:before,.fa-donate:before{content:\"\\f4b9\"}.fa-circle-dot:before,.fa-dot-circle:before{content:\"\\f192\"}.fa-arrow-alt-circle-down:before,.fa-circle-down:before{content:\"\\f358\"}.fa-circle-exclamation:before,.fa-exclamation-circle:before{content:\"\\f06a\"}.fa-circle-h:before,.fa-hospital-symbol:before{content:\"\\f47e\"}.fa-adjust:before,.fa-circle-half-stroke:before{content:\"\\f042\"}.fa-circle-info:before,.fa-info-circle:before{content:\"\\f05a\"}.fa-arrow-alt-circle-left:before,.fa-circle-left:before{content:\"\\f359\"}.fa-circle-minus:before,.fa-minus-circle:before{content:\"\\f056\"}.fa-circle-notch:before{content:\"\\f1ce\"}.fa-circle-pause:before,.fa-pause-circle:before{content:\"\\f28b\"}.fa-circle-play:before,.fa-play-circle:before{content:\"\\f144\"}.fa-circle-plus:before,.fa-plus-circle:before{content:\"\\f055\"}.fa-circle-question:before,.fa-question-circle:before{content:\"\\f059\"}.fa-circle-radiation:before,.fa-radiation-alt:before{content:\"\\f7ba\"}.fa-arrow-alt-circle-right:before,.fa-circle-right:before{content:\"\\f35a\"}.fa-circle-stop:before,.fa-stop-circle:before{content:\"\\f28d\"}.fa-arrow-alt-circle-up:before,.fa-circle-up:before{content:\"\\f35b\"}.fa-circle-user:before,.fa-user-circle:before{content:\"\\f2bd\"}.fa-circle-xmark:before,.fa-times-circle:before,.fa-xmark-circle:before{content:\"\\f057\"}.fa-city:before{content:\"\\f64f\"}.fa-clapperboard:before{content:\"\\e131\"}.fa-clipboard:before{content:\"\\f328\"}.fa-clipboard-check:before{content:\"\\f46c\"}.fa-clipboard-list:before{content:\"\\f46d\"}.fa-clock-four:before,.fa-clock:before{content:\"\\f017\"}.fa-clock-rotate-left:before,.fa-history:before{content:\"\\f1da\"}.fa-clone:before{content:\"\\f24d\"}.fa-closed-captioning:before{content:\"\\f20a\"}.fa-cloud:before{content:\"\\f0c2\"}.fa-cloud-arrow-down:before,.fa-cloud-download-alt:before,.fa-cloud-download:before{content:\"\\f0ed\"}.fa-cloud-arrow-up:before,.fa-cloud-upload-alt:before,.fa-cloud-upload:before{content:\"\\f0ee\"}.fa-cloud-meatball:before{content:\"\\f73b\"}.fa-cloud-moon:before{content:\"\\f6c3\"}.fa-cloud-moon-rain:before{content:\"\\f73c\"}.fa-cloud-rain:before{content:\"\\f73d\"}.fa-cloud-showers-heavy:before{content:\"\\f740\"}.fa-cloud-sun:before{content:\"\\f6c4\"}.fa-cloud-sun-rain:before{content:\"\\f743\"}.fa-clover:before{content:\"\\e139\"}.fa-code:before{content:\"\\f121\"}.fa-code-branch:before{content:\"\\f126\"}.fa-code-commit:before{content:\"\\f386\"}.fa-code-compare:before{content:\"\\e13a\"}.fa-code-fork:before{content:\"\\e13b\"}.fa-code-merge:before{content:\"\\f387\"}.fa-code-pull-request:before{content:\"\\e13c\"}.fa-coins:before{content:\"\\f51e\"}.fa-colon-sign:before{content:\"\\e140\"}.fa-comment:before{content:\"\\f075\"}.fa-comment-dollar:before{content:\"\\f651\"}.fa-comment-dots:before,.fa-commenting:before{content:\"\\f4ad\"}.fa-comment-medical:before{content:\"\\f7f5\"}.fa-comment-slash:before{content:\"\\f4b3\"}.fa-comment-sms:before,.fa-sms:before{content:\"\\f7cd\"}.fa-comments:before{content:\"\\f086\"}.fa-comments-dollar:before{content:\"\\f653\"}.fa-compact-disc:before{content:\"\\f51f\"}.fa-compass:before{content:\"\\f14e\"}.fa-compass-drafting:before,.fa-drafting-compass:before{content:\"\\f568\"}.fa-compress:before{content:\"\\f066\"}.fa-computer-mouse:before,.fa-mouse:before{content:\"\\f8cc\"}.fa-cookie:before{content:\"\\f563\"}.fa-cookie-bite:before{content:\"\\f564\"}.fa-copy:before{content:\"\\f0c5\"}.fa-copyright:before{content:\"\\f1f9\"}.fa-couch:before{content:\"\\f4b8\"}.fa-credit-card-alt:before,.fa-credit-card:before{content:\"\\f09d\"}.fa-crop:before{content:\"\\f125\"}.fa-crop-alt:before,.fa-crop-simple:before{content:\"\\f565\"}.fa-cross:before{content:\"\\f654\"}.fa-crosshairs:before{content:\"\\f05b\"}.fa-crow:before{content:\"\\f520\"}.fa-crown:before{content:\"\\f521\"}.fa-crutch:before{content:\"\\f7f7\"}.fa-cruzeiro-sign:before{content:\"\\e152\"}.fa-cube:before{content:\"\\f1b2\"}.fa-cubes:before{content:\"\\f1b3\"}.fa-d:before{content:\"\\44\"}.fa-database:before{content:\"\\f1c0\"}.fa-backspace:before,.fa-delete-left:before{content:\"\\f55a\"}.fa-democrat:before{content:\"\\f747\"}.fa-desktop-alt:before,.fa-desktop:before{content:\"\\f390\"}.fa-dharmachakra:before{content:\"\\f655\"}.fa-diagram-next:before{content:\"\\e476\"}.fa-diagram-predecessor:before{content:\"\\e477\"}.fa-diagram-project:before,.fa-project-diagram:before{content:\"\\f542\"}.fa-diagram-successor:before{content:\"\\e47a\"}.fa-diamond:before{content:\"\\f219\"}.fa-diamond-turn-right:before,.fa-directions:before{content:\"\\f5eb\"}.fa-dice:before{content:\"\\f522\"}.fa-dice-d20:before{content:\"\\f6cf\"}.fa-dice-d6:before{content:\"\\f6d1\"}.fa-dice-five:before{content:\"\\f523\"}.fa-dice-four:before{content:\"\\f524\"}.fa-dice-one:before{content:\"\\f525\"}.fa-dice-six:before{content:\"\\f526\"}.fa-dice-three:before{content:\"\\f527\"}.fa-dice-two:before{content:\"\\f528\"}.fa-disease:before{content:\"\\f7fa\"}.fa-divide:before{content:\"\\f529\"}.fa-dna:before{content:\"\\f471\"}.fa-dog:before{content:\"\\f6d3\"}.fa-dollar-sign:before,.fa-dollar:before,.fa-usd:before{content:\"\\24\"}.fa-dolly-box:before,.fa-dolly:before{content:\"\\f472\"}.fa-dong-sign:before{content:\"\\e169\"}.fa-door-closed:before{content:\"\\f52a\"}.fa-door-open:before{content:\"\\f52b\"}.fa-dove:before{content:\"\\f4ba\"}.fa-compress-alt:before,.fa-down-left-and-up-right-to-center:before{content:\"\\f422\"}.fa-down-long:before,.fa-long-arrow-alt-down:before{content:\"\\f309\"}.fa-download:before{content:\"\\f019\"}.fa-dragon:before{content:\"\\f6d5\"}.fa-draw-polygon:before{content:\"\\f5ee\"}.fa-droplet:before,.fa-tint:before{content:\"\\f043\"}.fa-droplet-slash:before,.fa-tint-slash:before{content:\"\\f5c7\"}.fa-drum:before{content:\"\\f569\"}.fa-drum-steelpan:before{content:\"\\f56a\"}.fa-drumstick-bite:before{content:\"\\f6d7\"}.fa-dumbbell:before{content:\"\\f44b\"}.fa-dumpster:before{content:\"\\f793\"}.fa-dumpster-fire:before{content:\"\\f794\"}.fa-dungeon:before{content:\"\\f6d9\"}.fa-e:before{content:\"\\45\"}.fa-deaf:before,.fa-deafness:before,.fa-ear-deaf:before,.fa-hard-of-hearing:before{content:\"\\f2a4\"}.fa-assistive-listening-systems:before,.fa-ear-listen:before{content:\"\\f2a2\"}.fa-earth-africa:before,.fa-globe-africa:before{content:\"\\f57c\"}.fa-earth-america:before,.fa-earth-americas:before,.fa-earth:before,.fa-globe-americas:before{content:\"\\f57d\"}.fa-earth-asia:before,.fa-globe-asia:before{content:\"\\f57e\"}.fa-earth-europe:before,.fa-globe-europe:before{content:\"\\f7a2\"}.fa-earth-oceania:before,.fa-globe-oceania:before{content:\"\\e47b\"}.fa-egg:before{content:\"\\f7fb\"}.fa-eject:before{content:\"\\f052\"}.fa-elevator:before{content:\"\\e16d\"}.fa-ellipsis-h:before,.fa-ellipsis:before{content:\"\\f141\"}.fa-ellipsis-v:before,.fa-ellipsis-vertical:before{content:\"\\f142\"}.fa-envelope:before{content:\"\\f0e0\"}.fa-envelope-open:before{content:\"\\f2b6\"}.fa-envelope-open-text:before{content:\"\\f658\"}.fa-envelopes-bulk:before,.fa-mail-bulk:before{content:\"\\f674\"}.fa-equals:before{content:\"\\3d\"}.fa-eraser:before{content:\"\\f12d\"}.fa-ethernet:before{content:\"\\f796\"}.fa-eur:before,.fa-euro-sign:before,.fa-euro:before{content:\"\\f153\"}.fa-exclamation:before{content:\"\\21\"}.fa-expand:before{content:\"\\f065\"}.fa-eye:before{content:\"\\f06e\"}.fa-eye-dropper-empty:before,.fa-eye-dropper:before,.fa-eyedropper:before{content:\"\\f1fb\"}.fa-eye-low-vision:before,.fa-low-vision:before{content:\"\\f2a8\"}.fa-eye-slash:before{content:\"\\f070\"}.fa-f:before{content:\"\\46\"}.fa-angry:before,.fa-face-angry:before{content:\"\\f556\"}.fa-dizzy:before,.fa-face-dizzy:before{content:\"\\f567\"}.fa-face-flushed:before,.fa-flushed:before{content:\"\\f579\"}.fa-face-frown:before,.fa-frown:before{content:\"\\f119\"}.fa-face-frown-open:before,.fa-frown-open:before{content:\"\\f57a\"}.fa-face-grimace:before,.fa-grimace:before{content:\"\\f57f\"}.fa-face-grin:before,.fa-grin:before{content:\"\\f580\"}.fa-face-grin-beam:before,.fa-grin-beam:before{content:\"\\f582\"}.fa-face-grin-beam-sweat:before,.fa-grin-beam-sweat:before{content:\"\\f583\"}.fa-face-grin-hearts:before,.fa-grin-hearts:before{content:\"\\f584\"}.fa-face-grin-squint:before,.fa-grin-squint:before{content:\"\\f585\"}.fa-face-grin-squint-tears:before,.fa-grin-squint-tears:before{content:\"\\f586\"}.fa-face-grin-stars:before,.fa-grin-stars:before{content:\"\\f587\"}.fa-face-grin-tears:before,.fa-grin-tears:before{content:\"\\f588\"}.fa-face-grin-tongue:before,.fa-grin-tongue:before{content:\"\\f589\"}.fa-face-grin-tongue-squint:before,.fa-grin-tongue-squint:before{content:\"\\f58a\"}.fa-face-grin-tongue-wink:before,.fa-grin-tongue-wink:before{content:\"\\f58b\"}.fa-face-grin-wide:before,.fa-grin-alt:before{content:\"\\f581\"}.fa-face-grin-wink:before,.fa-grin-wink:before{content:\"\\f58c\"}.fa-face-kiss:before,.fa-kiss:before{content:\"\\f596\"}.fa-face-kiss-beam:before,.fa-kiss-beam:before{content:\"\\f597\"}.fa-face-kiss-wink-heart:before,.fa-kiss-wink-heart:before{content:\"\\f598\"}.fa-face-laugh:before,.fa-laugh:before{content:\"\\f599\"}.fa-face-laugh-beam:before,.fa-laugh-beam:before{content:\"\\f59a\"}.fa-face-laugh-squint:before,.fa-laugh-squint:before{content:\"\\f59b\"}.fa-face-laugh-wink:before,.fa-laugh-wink:before{content:\"\\f59c\"}.fa-face-meh:before,.fa-meh:before{content:\"\\f11a\"}.fa-face-meh-blank:before,.fa-meh-blank:before{content:\"\\f5a4\"}.fa-face-rolling-eyes:before,.fa-meh-rolling-eyes:before{content:\"\\f5a5\"}.fa-face-sad-cry:before,.fa-sad-cry:before{content:\"\\f5b3\"}.fa-face-sad-tear:before,.fa-sad-tear:before{content:\"\\f5b4\"}.fa-face-smile:before,.fa-smile:before{content:\"\\f118\"}.fa-face-smile-beam:before,.fa-smile-beam:before{content:\"\\f5b8\"}.fa-face-smile-wink:before,.fa-smile-wink:before{content:\"\\f4da\"}.fa-face-surprise:before,.fa-surprise:before{content:\"\\f5c2\"}.fa-face-tired:before,.fa-tired:before{content:\"\\f5c8\"}.fa-fan:before{content:\"\\f863\"}.fa-faucet:before{content:\"\\e005\"}.fa-fax:before{content:\"\\f1ac\"}.fa-feather:before{content:\"\\f52d\"}.fa-feather-alt:before,.fa-feather-pointed:before{content:\"\\f56b\"}.fa-file:before{content:\"\\f15b\"}.fa-file-arrow-down:before,.fa-file-download:before{content:\"\\f56d\"}.fa-file-arrow-up:before,.fa-file-upload:before{content:\"\\f574\"}.fa-file-audio:before{content:\"\\f1c7\"}.fa-file-code:before{content:\"\\f1c9\"}.fa-file-contract:before{content:\"\\f56c\"}.fa-file-csv:before{content:\"\\f6dd\"}.fa-file-excel:before{content:\"\\f1c3\"}.fa-arrow-right-from-file:before,.fa-file-export:before{content:\"\\f56e\"}.fa-file-image:before{content:\"\\f1c5\"}.fa-arrow-right-to-file:before,.fa-file-import:before{content:\"\\f56f\"}.fa-file-invoice:before{content:\"\\f570\"}.fa-file-invoice-dollar:before{content:\"\\f571\"}.fa-file-alt:before,.fa-file-lines:before,.fa-file-text:before{content:\"\\f15c\"}.fa-file-medical:before{content:\"\\f477\"}.fa-file-pdf:before{content:\"\\f1c1\"}.fa-file-powerpoint:before{content:\"\\f1c4\"}.fa-file-prescription:before{content:\"\\f572\"}.fa-file-signature:before{content:\"\\f573\"}.fa-file-video:before{content:\"\\f1c8\"}.fa-file-medical-alt:before,.fa-file-waveform:before{content:\"\\f478\"}.fa-file-word:before{content:\"\\f1c2\"}.fa-file-archive:before,.fa-file-zipper:before{content:\"\\f1c6\"}.fa-fill:before{content:\"\\f575\"}.fa-fill-drip:before{content:\"\\f576\"}.fa-film:before{content:\"\\f008\"}.fa-filter:before{content:\"\\f0b0\"}.fa-filter-circle-dollar:before,.fa-funnel-dollar:before{content:\"\\f662\"}.fa-filter-circle-xmark:before{content:\"\\e17b\"}.fa-fingerprint:before{content:\"\\f577\"}.fa-fire:before{content:\"\\f06d\"}.fa-fire-extinguisher:before{content:\"\\f134\"}.fa-fire-alt:before,.fa-fire-flame-curved:before{content:\"\\f7e4\"}.fa-burn:before,.fa-fire-flame-simple:before{content:\"\\f46a\"}.fa-fish:before{content:\"\\f578\"}.fa-flag:before{content:\"\\f024\"}.fa-flag-checkered:before{content:\"\\f11e\"}.fa-flag-usa:before{content:\"\\f74d\"}.fa-flask:before{content:\"\\f0c3\"}.fa-floppy-disk:before,.fa-save:before{content:\"\\f0c7\"}.fa-florin-sign:before{content:\"\\e184\"}.fa-folder:before{content:\"\\f07b\"}.fa-folder-minus:before{content:\"\\f65d\"}.fa-folder-open:before{content:\"\\f07c\"}.fa-folder-plus:before{content:\"\\f65e\"}.fa-folder-tree:before{content:\"\\f802\"}.fa-font:before{content:\"\\f031\"}.fa-football-ball:before,.fa-football:before{content:\"\\f44e\"}.fa-forward:before{content:\"\\f04e\"}.fa-fast-forward:before,.fa-forward-fast:before{content:\"\\f050\"}.fa-forward-step:before,.fa-step-forward:before{content:\"\\f051\"}.fa-franc-sign:before{content:\"\\e18f\"}.fa-frog:before{content:\"\\f52e\"}.fa-futbol-ball:before,.fa-futbol:before,.fa-soccer-ball:before{content:\"\\f1e3\"}.fa-g:before{content:\"\\47\"}.fa-gamepad:before{content:\"\\f11b\"}.fa-gas-pump:before{content:\"\\f52f\"}.fa-dashboard:before,.fa-gauge-med:before,.fa-gauge:before,.fa-tachometer-alt-average:before{content:\"\\f624\"}.fa-gauge-high:before,.fa-tachometer-alt-fast:before,.fa-tachometer-alt:before{content:\"\\f625\"}.fa-gauge-simple-med:before,.fa-gauge-simple:before,.fa-tachometer-average:before{content:\"\\f629\"}.fa-gauge-simple-high:before,.fa-tachometer-fast:before,.fa-tachometer:before{content:\"\\f62a\"}.fa-gavel:before,.fa-legal:before{content:\"\\f0e3\"}.fa-cog:before,.fa-gear:before{content:\"\\f013\"}.fa-cogs:before,.fa-gears:before{content:\"\\f085\"}.fa-gem:before{content:\"\\f3a5\"}.fa-genderless:before{content:\"\\f22d\"}.fa-ghost:before{content:\"\\f6e2\"}.fa-gift:before{content:\"\\f06b\"}.fa-gifts:before{content:\"\\f79c\"}.fa-glasses:before{content:\"\\f530\"}.fa-globe:before{content:\"\\f0ac\"}.fa-golf-ball-tee:before,.fa-golf-ball:before{content:\"\\f450\"}.fa-gopuram:before{content:\"\\f664\"}.fa-graduation-cap:before,.fa-mortar-board:before{content:\"\\f19d\"}.fa-greater-than:before{content:\"\\3e\"}.fa-greater-than-equal:before{content:\"\\f532\"}.fa-grip-horizontal:before,.fa-grip:before{content:\"\\f58d\"}.fa-grip-lines:before{content:\"\\f7a4\"}.fa-grip-lines-vertical:before{content:\"\\f7a5\"}.fa-grip-vertical:before{content:\"\\f58e\"}.fa-guarani-sign:before{content:\"\\e19a\"}.fa-guitar:before{content:\"\\f7a6\"}.fa-gun:before{content:\"\\e19b\"}.fa-h:before{content:\"\\48\"}.fa-hammer:before{content:\"\\f6e3\"}.fa-hamsa:before{content:\"\\f665\"}.fa-hand-paper:before,.fa-hand:before{content:\"\\f256\"}.fa-hand-back-fist:before,.fa-hand-rock:before{content:\"\\f255\"}.fa-allergies:before,.fa-hand-dots:before{content:\"\\f461\"}.fa-fist-raised:before,.fa-hand-fist:before{content:\"\\f6de\"}.fa-hand-holding:before{content:\"\\f4bd\"}.fa-hand-holding-dollar:before,.fa-hand-holding-usd:before{content:\"\\f4c0\"}.fa-hand-holding-droplet:before,.fa-hand-holding-water:before{content:\"\\f4c1\"}.fa-hand-holding-heart:before{content:\"\\f4be\"}.fa-hand-holding-medical:before{content:\"\\e05c\"}.fa-hand-lizard:before{content:\"\\f258\"}.fa-hand-middle-finger:before{content:\"\\f806\"}.fa-hand-peace:before{content:\"\\f25b\"}.fa-hand-point-down:before{content:\"\\f0a7\"}.fa-hand-point-left:before{content:\"\\f0a5\"}.fa-hand-point-right:before{content:\"\\f0a4\"}.fa-hand-point-up:before{content:\"\\f0a6\"}.fa-hand-pointer:before{content:\"\\f25a\"}.fa-hand-scissors:before{content:\"\\f257\"}.fa-hand-sparkles:before{content:\"\\e05d\"}.fa-hand-spock:before{content:\"\\f259\"}.fa-hands:before,.fa-sign-language:before,.fa-signing:before{content:\"\\f2a7\"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before,.fa-hands-american-sign-language-interpreting:before,.fa-hands-asl-interpreting:before{content:\"\\f2a3\"}.fa-hands-bubbles:before,.fa-hands-wash:before{content:\"\\e05e\"}.fa-hands-clapping:before{content:\"\\e1a8\"}.fa-hands-holding:before{content:\"\\f4c2\"}.fa-hands-praying:before,.fa-praying-hands:before{content:\"\\f684\"}.fa-handshake:before{content:\"\\f2b5\"}.fa-hands-helping:before,.fa-handshake-angle:before{content:\"\\f4c4\"}.fa-handshake-alt-slash:before,.fa-handshake-simple-slash:before{content:\"\\e05f\"}.fa-handshake-slash:before{content:\"\\e060\"}.fa-hanukiah:before{content:\"\\f6e6\"}.fa-hard-drive:before,.fa-hdd:before{content:\"\\f0a0\"}.fa-hashtag:before{content:\"\\23\"}.fa-hat-cowboy:before{content:\"\\f8c0\"}.fa-hat-cowboy-side:before{content:\"\\f8c1\"}.fa-hat-wizard:before{content:\"\\f6e8\"}.fa-head-side-cough:before{content:\"\\e061\"}.fa-head-side-cough-slash:before{content:\"\\e062\"}.fa-head-side-mask:before{content:\"\\e063\"}.fa-head-side-virus:before{content:\"\\e064\"}.fa-header:before,.fa-heading:before{content:\"\\f1dc\"}.fa-headphones:before{content:\"\\f025\"}.fa-headphones-alt:before,.fa-headphones-simple:before{content:\"\\f58f\"}.fa-headset:before{content:\"\\f590\"}.fa-heart:before{content:\"\\f004\"}.fa-heart-broken:before,.fa-heart-crack:before{content:\"\\f7a9\"}.fa-heart-pulse:before,.fa-heartbeat:before{content:\"\\f21e\"}.fa-helicopter:before{content:\"\\f533\"}.fa-hard-hat:before,.fa-hat-hard:before,.fa-helmet-safety:before{content:\"\\f807\"}.fa-highlighter:before{content:\"\\f591\"}.fa-hippo:before{content:\"\\f6ed\"}.fa-hockey-puck:before{content:\"\\f453\"}.fa-holly-berry:before{content:\"\\f7aa\"}.fa-horse:before{content:\"\\f6f0\"}.fa-horse-head:before{content:\"\\f7ab\"}.fa-hospital-alt:before,.fa-hospital-wide:before,.fa-hospital:before{content:\"\\f0f8\"}.fa-hospital-user:before{content:\"\\f80d\"}.fa-hot-tub-person:before,.fa-hot-tub:before{content:\"\\f593\"}.fa-hotdog:before{content:\"\\f80f\"}.fa-hotel:before{content:\"\\f594\"}.fa-hourglass-2:before,.fa-hourglass-half:before,.fa-hourglass:before{content:\"\\f254\"}.fa-hourglass-empty:before{content:\"\\f252\"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:\"\\f253\"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:\"\\f251\"}.fa-home-alt:before,.fa-home-lg-alt:before,.fa-home:before,.fa-house:before{content:\"\\f015\"}.fa-home-lg:before,.fa-house-chimney:before{content:\"\\e3af\"}.fa-house-chimney-crack:before,.fa-house-damage:before{content:\"\\f6f1\"}.fa-clinic-medical:before,.fa-house-chimney-medical:before{content:\"\\f7f2\"}.fa-house-chimney-user:before{content:\"\\e065\"}.fa-house-chimney-window:before{content:\"\\e00d\"}.fa-house-crack:before{content:\"\\e3b1\"}.fa-house-laptop:before,.fa-laptop-house:before{content:\"\\e066\"}.fa-house-medical:before{content:\"\\e3b2\"}.fa-home-user:before,.fa-house-user:before{content:\"\\e1b0\"}.fa-hryvnia-sign:before,.fa-hryvnia:before{content:\"\\f6f2\"}.fa-i:before{content:\"\\49\"}.fa-i-cursor:before{content:\"\\f246\"}.fa-ice-cream:before{content:\"\\f810\"}.fa-icicles:before{content:\"\\f7ad\"}.fa-heart-music-camera-bolt:before,.fa-icons:before{content:\"\\f86d\"}.fa-id-badge:before{content:\"\\f2c1\"}.fa-drivers-license:before,.fa-id-card:before{content:\"\\f2c2\"}.fa-id-card-alt:before,.fa-id-card-clip:before{content:\"\\f47f\"}.fa-igloo:before{content:\"\\f7ae\"}.fa-image:before{content:\"\\f03e\"}.fa-image-portrait:before,.fa-portrait:before{content:\"\\f3e0\"}.fa-images:before{content:\"\\f302\"}.fa-inbox:before{content:\"\\f01c\"}.fa-indent:before{content:\"\\f03c\"}.fa-indian-rupee-sign:before,.fa-indian-rupee:before,.fa-inr:before{content:\"\\e1bc\"}.fa-industry:before{content:\"\\f275\"}.fa-infinity:before{content:\"\\f534\"}.fa-info:before{content:\"\\f129\"}.fa-italic:before{content:\"\\f033\"}.fa-j:before{content:\"\\4a\"}.fa-jedi:before{content:\"\\f669\"}.fa-fighter-jet:before,.fa-jet-fighter:before{content:\"\\f0fb\"}.fa-joint:before{content:\"\\f595\"}.fa-k:before{content:\"\\4b\"}.fa-kaaba:before{content:\"\\f66b\"}.fa-key:before{content:\"\\f084\"}.fa-keyboard:before{content:\"\\f11c\"}.fa-khanda:before{content:\"\\f66d\"}.fa-kip-sign:before{content:\"\\e1c4\"}.fa-first-aid:before,.fa-kit-medical:before{content:\"\\f479\"}.fa-kiwi-bird:before{content:\"\\f535\"}.fa-l:before{content:\"\\4c\"}.fa-landmark:before{content:\"\\f66f\"}.fa-language:before{content:\"\\f1ab\"}.fa-laptop:before{content:\"\\f109\"}.fa-laptop-code:before{content:\"\\f5fc\"}.fa-laptop-medical:before{content:\"\\f812\"}.fa-lari-sign:before{content:\"\\e1c8\"}.fa-layer-group:before{content:\"\\f5fd\"}.fa-leaf:before{content:\"\\f06c\"}.fa-left-long:before,.fa-long-arrow-alt-left:before{content:\"\\f30a\"}.fa-arrows-alt-h:before,.fa-left-right:before{content:\"\\f337\"}.fa-lemon:before{content:\"\\f094\"}.fa-less-than:before{content:\"\\3c\"}.fa-less-than-equal:before{content:\"\\f537\"}.fa-life-ring:before{content:\"\\f1cd\"}.fa-lightbulb:before{content:\"\\f0eb\"}.fa-chain:before,.fa-link:before{content:\"\\f0c1\"}.fa-chain-broken:before,.fa-chain-slash:before,.fa-link-slash:before,.fa-unlink:before{content:\"\\f127\"}.fa-lira-sign:before{content:\"\\f195\"}.fa-list-squares:before,.fa-list:before{content:\"\\f03a\"}.fa-list-check:before,.fa-tasks:before{content:\"\\f0ae\"}.fa-list-1-2:before,.fa-list-numeric:before,.fa-list-ol:before{content:\"\\f0cb\"}.fa-list-dots:before,.fa-list-ul:before{content:\"\\f0ca\"}.fa-litecoin-sign:before{content:\"\\e1d3\"}.fa-location-arrow:before{content:\"\\f124\"}.fa-location-crosshairs:before,.fa-location:before{content:\"\\f601\"}.fa-location-dot:before,.fa-map-marker-alt:before{content:\"\\f3c5\"}.fa-location-pin:before,.fa-map-marker:before{content:\"\\f041\"}.fa-lock:before{content:\"\\f023\"}.fa-lock-open:before{content:\"\\f3c1\"}.fa-lungs:before{content:\"\\f604\"}.fa-lungs-virus:before{content:\"\\e067\"}.fa-m:before{content:\"\\4d\"}.fa-magnet:before{content:\"\\f076\"}.fa-magnifying-glass:before,.fa-search:before{content:\"\\f002\"}.fa-magnifying-glass-dollar:before,.fa-search-dollar:before{content:\"\\f688\"}.fa-magnifying-glass-location:before,.fa-search-location:before{content:\"\\f689\"}.fa-magnifying-glass-minus:before,.fa-search-minus:before{content:\"\\f010\"}.fa-magnifying-glass-plus:before,.fa-search-plus:before{content:\"\\f00e\"}.fa-manat-sign:before{content:\"\\e1d5\"}.fa-map:before{content:\"\\f279\"}.fa-map-location:before,.fa-map-marked:before{content:\"\\f59f\"}.fa-map-location-dot:before,.fa-map-marked-alt:before{content:\"\\f5a0\"}.fa-map-pin:before{content:\"\\f276\"}.fa-marker:before{content:\"\\f5a1\"}.fa-mars:before{content:\"\\f222\"}.fa-mars-and-venus:before{content:\"\\f224\"}.fa-mars-double:before{content:\"\\f227\"}.fa-mars-stroke:before{content:\"\\f229\"}.fa-mars-stroke-h:before,.fa-mars-stroke-right:before{content:\"\\f22b\"}.fa-mars-stroke-up:before,.fa-mars-stroke-v:before{content:\"\\f22a\"}.fa-glass-martini-alt:before,.fa-martini-glass:before{content:\"\\f57b\"}.fa-cocktail:before,.fa-martini-glass-citrus:before{content:\"\\f561\"}.fa-glass-martini:before,.fa-martini-glass-empty:before{content:\"\\f000\"}.fa-mask:before{content:\"\\f6fa\"}.fa-mask-face:before{content:\"\\e1d7\"}.fa-masks-theater:before,.fa-theater-masks:before{content:\"\\f630\"}.fa-expand-arrows-alt:before,.fa-maximize:before{content:\"\\f31e\"}.fa-medal:before{content:\"\\f5a2\"}.fa-memory:before{content:\"\\f538\"}.fa-menorah:before{content:\"\\f676\"}.fa-mercury:before{content:\"\\f223\"}.fa-comment-alt:before,.fa-message:before{content:\"\\f27a\"}.fa-meteor:before{content:\"\\f753\"}.fa-microchip:before{content:\"\\f2db\"}.fa-microphone:before{content:\"\\f130\"}.fa-microphone-alt:before,.fa-microphone-lines:before{content:\"\\f3c9\"}.fa-microphone-alt-slash:before,.fa-microphone-lines-slash:before{content:\"\\f539\"}.fa-microphone-slash:before{content:\"\\f131\"}.fa-microscope:before{content:\"\\f610\"}.fa-mill-sign:before{content:\"\\e1ed\"}.fa-compress-arrows-alt:before,.fa-minimize:before{content:\"\\f78c\"}.fa-minus:before,.fa-subtract:before{content:\"\\f068\"}.fa-mitten:before{content:\"\\f7b5\"}.fa-mobile-android:before,.fa-mobile-phone:before,.fa-mobile:before{content:\"\\f3ce\"}.fa-mobile-button:before{content:\"\\f10b\"}.fa-mobile-alt:before,.fa-mobile-screen-button:before{content:\"\\f3cd\"}.fa-money-bill:before{content:\"\\f0d6\"}.fa-money-bill-1:before,.fa-money-bill-alt:before{content:\"\\f3d1\"}.fa-money-bill-1-wave:before,.fa-money-bill-wave-alt:before{content:\"\\f53b\"}.fa-money-bill-wave:before{content:\"\\f53a\"}.fa-money-check:before{content:\"\\f53c\"}.fa-money-check-alt:before,.fa-money-check-dollar:before{content:\"\\f53d\"}.fa-monument:before{content:\"\\f5a6\"}.fa-moon:before{content:\"\\f186\"}.fa-mortar-pestle:before{content:\"\\f5a7\"}.fa-mosque:before{content:\"\\f678\"}.fa-motorcycle:before{content:\"\\f21c\"}.fa-mountain:before{content:\"\\f6fc\"}.fa-mug-hot:before{content:\"\\f7b6\"}.fa-coffee:before,.fa-mug-saucer:before{content:\"\\f0f4\"}.fa-music:before{content:\"\\f001\"}.fa-n:before{content:\"\\4e\"}.fa-naira-sign:before{content:\"\\e1f6\"}.fa-network-wired:before{content:\"\\f6ff\"}.fa-neuter:before{content:\"\\f22c\"}.fa-newspaper:before{content:\"\\f1ea\"}.fa-not-equal:before{content:\"\\f53e\"}.fa-note-sticky:before,.fa-sticky-note:before{content:\"\\f249\"}.fa-notes-medical:before{content:\"\\f481\"}.fa-o:before{content:\"\\4f\"}.fa-object-group:before{content:\"\\f247\"}.fa-object-ungroup:before{content:\"\\f248\"}.fa-oil-can:before{content:\"\\f613\"}.fa-om:before{content:\"\\f679\"}.fa-otter:before{content:\"\\f700\"}.fa-dedent:before,.fa-outdent:before{content:\"\\f03b\"}.fa-p:before{content:\"\\50\"}.fa-pager:before{content:\"\\f815\"}.fa-paint-roller:before{content:\"\\f5aa\"}.fa-paint-brush:before,.fa-paintbrush:before{content:\"\\f1fc\"}.fa-palette:before{content:\"\\f53f\"}.fa-pallet:before{content:\"\\f482\"}.fa-panorama:before{content:\"\\e209\"}.fa-paper-plane:before{content:\"\\f1d8\"}.fa-paperclip:before{content:\"\\f0c6\"}.fa-parachute-box:before{content:\"\\f4cd\"}.fa-paragraph:before{content:\"\\f1dd\"}.fa-passport:before{content:\"\\f5ab\"}.fa-file-clipboard:before,.fa-paste:before{content:\"\\f0ea\"}.fa-pause:before{content:\"\\f04c\"}.fa-paw:before{content:\"\\f1b0\"}.fa-peace:before{content:\"\\f67c\"}.fa-pen:before{content:\"\\f304\"}.fa-pen-alt:before,.fa-pen-clip:before{content:\"\\f305\"}.fa-pen-fancy:before{content:\"\\f5ac\"}.fa-pen-nib:before{content:\"\\f5ad\"}.fa-pen-ruler:before,.fa-pencil-ruler:before{content:\"\\f5ae\"}.fa-edit:before,.fa-pen-to-square:before{content:\"\\f044\"}.fa-pencil-alt:before,.fa-pencil:before{content:\"\\f303\"}.fa-people-arrows-left-right:before,.fa-people-arrows:before{content:\"\\e068\"}.fa-people-carry-box:before,.fa-people-carry:before{content:\"\\f4ce\"}.fa-pepper-hot:before{content:\"\\f816\"}.fa-percent:before,.fa-percentage:before{content:\"\\25\"}.fa-male:before,.fa-person:before{content:\"\\f183\"}.fa-biking:before,.fa-person-biking:before{content:\"\\f84a\"}.fa-person-booth:before{content:\"\\f756\"}.fa-diagnoses:before,.fa-person-dots-from-line:before{content:\"\\f470\"}.fa-female:before,.fa-person-dress:before{content:\"\\f182\"}.fa-hiking:before,.fa-person-hiking:before{content:\"\\f6ec\"}.fa-person-praying:before,.fa-pray:before{content:\"\\f683\"}.fa-person-running:before,.fa-running:before{content:\"\\f70c\"}.fa-person-skating:before,.fa-skating:before{content:\"\\f7c5\"}.fa-person-skiing:before,.fa-skiing:before{content:\"\\f7c9\"}.fa-person-skiing-nordic:before,.fa-skiing-nordic:before{content:\"\\f7ca\"}.fa-person-snowboarding:before,.fa-snowboarding:before{content:\"\\f7ce\"}.fa-person-swimming:before,.fa-swimmer:before{content:\"\\f5c4\"}.fa-person-walking:before,.fa-walking:before{content:\"\\f554\"}.fa-blind:before,.fa-person-walking-with-cane:before{content:\"\\f29d\"}.fa-peseta-sign:before{content:\"\\e221\"}.fa-peso-sign:before{content:\"\\e222\"}.fa-phone:before{content:\"\\f095\"}.fa-phone-alt:before,.fa-phone-flip:before{content:\"\\f879\"}.fa-phone-slash:before{content:\"\\f3dd\"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:\"\\f2a0\"}.fa-photo-film:before,.fa-photo-video:before{content:\"\\f87c\"}.fa-piggy-bank:before{content:\"\\f4d3\"}.fa-pills:before{content:\"\\f484\"}.fa-pizza-slice:before{content:\"\\f818\"}.fa-place-of-worship:before{content:\"\\f67f\"}.fa-plane:before{content:\"\\f072\"}.fa-plane-arrival:before{content:\"\\f5af\"}.fa-plane-departure:before{content:\"\\f5b0\"}.fa-plane-slash:before{content:\"\\e069\"}.fa-play:before{content:\"\\f04b\"}.fa-plug:before{content:\"\\f1e6\"}.fa-add:before,.fa-plus:before{content:\"\\2b\"}.fa-plus-minus:before{content:\"\\e43c\"}.fa-podcast:before{content:\"\\f2ce\"}.fa-poo:before{content:\"\\f2fe\"}.fa-poo-bolt:before,.fa-poo-storm:before{content:\"\\f75a\"}.fa-poop:before{content:\"\\f619\"}.fa-power-off:before{content:\"\\f011\"}.fa-prescription:before{content:\"\\f5b1\"}.fa-prescription-bottle:before{content:\"\\f485\"}.fa-prescription-bottle-alt:before,.fa-prescription-bottle-medical:before{content:\"\\f486\"}.fa-print:before{content:\"\\f02f\"}.fa-pump-medical:before{content:\"\\e06a\"}.fa-pump-soap:before{content:\"\\e06b\"}.fa-puzzle-piece:before{content:\"\\f12e\"}.fa-q:before{content:\"\\51\"}.fa-qrcode:before{content:\"\\f029\"}.fa-question:before{content:\"\\3f\"}.fa-quote-left-alt:before,.fa-quote-left:before{content:\"\\f10d\"}.fa-quote-right-alt:before,.fa-quote-right:before{content:\"\\f10e\"}.fa-r:before{content:\"\\52\"}.fa-radiation:before{content:\"\\f7b9\"}.fa-rainbow:before{content:\"\\f75b\"}.fa-receipt:before{content:\"\\f543\"}.fa-record-vinyl:before{content:\"\\f8d9\"}.fa-ad:before,.fa-rectangle-ad:before{content:\"\\f641\"}.fa-list-alt:before,.fa-rectangle-list:before{content:\"\\f022\"}.fa-rectangle-times:before,.fa-rectangle-xmark:before,.fa-times-rectangle:before,.fa-window-close:before{content:\"\\f410\"}.fa-recycle:before{content:\"\\f1b8\"}.fa-registered:before{content:\"\\f25d\"}.fa-repeat:before{content:\"\\f363\"}.fa-mail-reply:before,.fa-reply:before{content:\"\\f3e5\"}.fa-mail-reply-all:before,.fa-reply-all:before{content:\"\\f122\"}.fa-republican:before{content:\"\\f75e\"}.fa-restroom:before{content:\"\\f7bd\"}.fa-retweet:before{content:\"\\f079\"}.fa-ribbon:before{content:\"\\f4d6\"}.fa-right-from-bracket:before,.fa-sign-out-alt:before{content:\"\\f2f5\"}.fa-exchange-alt:before,.fa-right-left:before{content:\"\\f362\"}.fa-long-arrow-alt-right:before,.fa-right-long:before{content:\"\\f30b\"}.fa-right-to-bracket:before,.fa-sign-in-alt:before{content:\"\\f2f6\"}.fa-ring:before{content:\"\\f70b\"}.fa-road:before{content:\"\\f018\"}.fa-robot:before{content:\"\\f544\"}.fa-rocket:before{content:\"\\f135\"}.fa-rotate:before,.fa-sync-alt:before{content:\"\\f2f1\"}.fa-rotate-back:before,.fa-rotate-backward:before,.fa-rotate-left:before,.fa-undo-alt:before{content:\"\\f2ea\"}.fa-redo-alt:before,.fa-rotate-forward:before,.fa-rotate-right:before{content:\"\\f2f9\"}.fa-route:before{content:\"\\f4d7\"}.fa-feed:before,.fa-rss:before{content:\"\\f09e\"}.fa-rouble:before,.fa-rub:before,.fa-ruble-sign:before,.fa-ruble:before{content:\"\\f158\"}.fa-ruler:before{content:\"\\f545\"}.fa-ruler-combined:before{content:\"\\f546\"}.fa-ruler-horizontal:before{content:\"\\f547\"}.fa-ruler-vertical:before{content:\"\\f548\"}.fa-rupee-sign:before,.fa-rupee:before{content:\"\\f156\"}.fa-rupiah-sign:before{content:\"\\e23d\"}.fa-s:before{content:\"\\53\"}.fa-sailboat:before{content:\"\\e445\"}.fa-satellite:before{content:\"\\f7bf\"}.fa-satellite-dish:before{content:\"\\f7c0\"}.fa-balance-scale:before,.fa-scale-balanced:before{content:\"\\f24e\"}.fa-balance-scale-left:before,.fa-scale-unbalanced:before{content:\"\\f515\"}.fa-balance-scale-right:before,.fa-scale-unbalanced-flip:before{content:\"\\f516\"}.fa-school:before{content:\"\\f549\"}.fa-cut:before,.fa-scissors:before{content:\"\\f0c4\"}.fa-screwdriver:before{content:\"\\f54a\"}.fa-screwdriver-wrench:before,.fa-tools:before{content:\"\\f7d9\"}.fa-scroll:before{content:\"\\f70e\"}.fa-scroll-torah:before,.fa-torah:before{content:\"\\f6a0\"}.fa-sd-card:before{content:\"\\f7c2\"}.fa-section:before{content:\"\\e447\"}.fa-seedling:before,.fa-sprout:before{content:\"\\f4d8\"}.fa-server:before{content:\"\\f233\"}.fa-shapes:before,.fa-triangle-circle-square:before{content:\"\\f61f\"}.fa-arrow-turn-right:before,.fa-mail-forward:before,.fa-share:before{content:\"\\f064\"}.fa-share-from-square:before,.fa-share-square:before{content:\"\\f14d\"}.fa-share-alt:before,.fa-share-nodes:before{content:\"\\f1e0\"}.fa-ils:before,.fa-shekel-sign:before,.fa-shekel:before,.fa-sheqel-sign:before,.fa-sheqel:before{content:\"\\f20b\"}.fa-shield:before{content:\"\\f132\"}.fa-shield-alt:before,.fa-shield-blank:before{content:\"\\f3ed\"}.fa-shield-virus:before{content:\"\\e06c\"}.fa-ship:before{content:\"\\f21a\"}.fa-shirt:before,.fa-t-shirt:before,.fa-tshirt:before{content:\"\\f553\"}.fa-shoe-prints:before{content:\"\\f54b\"}.fa-shop:before,.fa-store-alt:before{content:\"\\f54f\"}.fa-shop-slash:before,.fa-store-alt-slash:before{content:\"\\e070\"}.fa-shower:before{content:\"\\f2cc\"}.fa-shrimp:before{content:\"\\e448\"}.fa-random:before,.fa-shuffle:before{content:\"\\f074\"}.fa-shuttle-space:before,.fa-space-shuttle:before{content:\"\\f197\"}.fa-sign-hanging:before,.fa-sign:before{content:\"\\f4d9\"}.fa-signal-5:before,.fa-signal-perfect:before,.fa-signal:before{content:\"\\f012\"}.fa-signature:before{content:\"\\f5b7\"}.fa-map-signs:before,.fa-signs-post:before{content:\"\\f277\"}.fa-sim-card:before{content:\"\\f7c4\"}.fa-sink:before{content:\"\\e06d\"}.fa-sitemap:before{content:\"\\f0e8\"}.fa-skull:before{content:\"\\f54c\"}.fa-skull-crossbones:before{content:\"\\f714\"}.fa-slash:before{content:\"\\f715\"}.fa-sleigh:before{content:\"\\f7cc\"}.fa-sliders-h:before,.fa-sliders:before{content:\"\\f1de\"}.fa-smog:before{content:\"\\f75f\"}.fa-smoking:before{content:\"\\f48d\"}.fa-snowflake:before{content:\"\\f2dc\"}.fa-snowman:before{content:\"\\f7d0\"}.fa-snowplow:before{content:\"\\f7d2\"}.fa-soap:before{content:\"\\e06e\"}.fa-socks:before{content:\"\\f696\"}.fa-solar-panel:before{content:\"\\f5ba\"}.fa-sort:before,.fa-unsorted:before{content:\"\\f0dc\"}.fa-sort-desc:before,.fa-sort-down:before{content:\"\\f0dd\"}.fa-sort-asc:before,.fa-sort-up:before{content:\"\\f0de\"}.fa-spa:before{content:\"\\f5bb\"}.fa-pastafarianism:before,.fa-spaghetti-monster-flying:before{content:\"\\f67b\"}.fa-spell-check:before{content:\"\\f891\"}.fa-spider:before{content:\"\\f717\"}.fa-spinner:before{content:\"\\f110\"}.fa-splotch:before{content:\"\\f5bc\"}.fa-spoon:before,.fa-utensil-spoon:before{content:\"\\f2e5\"}.fa-spray-can:before{content:\"\\f5bd\"}.fa-air-freshener:before,.fa-spray-can-sparkles:before{content:\"\\f5d0\"}.fa-square:before{content:\"\\f0c8\"}.fa-external-link-square:before,.fa-square-arrow-up-right:before{content:\"\\f14c\"}.fa-caret-square-down:before,.fa-square-caret-down:before{content:\"\\f150\"}.fa-caret-square-left:before,.fa-square-caret-left:before{content:\"\\f191\"}.fa-caret-square-right:before,.fa-square-caret-right:before{content:\"\\f152\"}.fa-caret-square-up:before,.fa-square-caret-up:before{content:\"\\f151\"}.fa-check-square:before,.fa-square-check:before{content:\"\\f14a\"}.fa-envelope-square:before,.fa-square-envelope:before{content:\"\\f199\"}.fa-square-full:before{content:\"\\f45c\"}.fa-h-square:before,.fa-square-h:before{content:\"\\f0fd\"}.fa-minus-square:before,.fa-square-minus:before{content:\"\\f146\"}.fa-parking:before,.fa-square-parking:before{content:\"\\f540\"}.fa-pen-square:before,.fa-pencil-square:before,.fa-square-pen:before{content:\"\\f14b\"}.fa-phone-square:before,.fa-square-phone:before{content:\"\\f098\"}.fa-phone-square-alt:before,.fa-square-phone-flip:before{content:\"\\f87b\"}.fa-plus-square:before,.fa-square-plus:before{content:\"\\f0fe\"}.fa-poll-h:before,.fa-square-poll-horizontal:before{content:\"\\f682\"}.fa-poll:before,.fa-square-poll-vertical:before{content:\"\\f681\"}.fa-square-root-alt:before,.fa-square-root-variable:before{content:\"\\f698\"}.fa-rss-square:before,.fa-square-rss:before{content:\"\\f143\"}.fa-share-alt-square:before,.fa-square-share-nodes:before{content:\"\\f1e1\"}.fa-external-link-square-alt:before,.fa-square-up-right:before{content:\"\\f360\"}.fa-square-xmark:before,.fa-times-square:before,.fa-xmark-square:before{content:\"\\f2d3\"}.fa-stairs:before{content:\"\\e289\"}.fa-stamp:before{content:\"\\f5bf\"}.fa-star:before{content:\"\\f005\"}.fa-star-and-crescent:before{content:\"\\f699\"}.fa-star-half:before{content:\"\\f089\"}.fa-star-half-alt:before,.fa-star-half-stroke:before{content:\"\\f5c0\"}.fa-star-of-david:before{content:\"\\f69a\"}.fa-star-of-life:before{content:\"\\f621\"}.fa-gbp:before,.fa-pound-sign:before,.fa-sterling-sign:before{content:\"\\f154\"}.fa-stethoscope:before{content:\"\\f0f1\"}.fa-stop:before{content:\"\\f04d\"}.fa-stopwatch:before{content:\"\\f2f2\"}.fa-stopwatch-20:before{content:\"\\e06f\"}.fa-store:before{content:\"\\f54e\"}.fa-store-slash:before{content:\"\\e071\"}.fa-street-view:before{content:\"\\f21d\"}.fa-strikethrough:before{content:\"\\f0cc\"}.fa-stroopwafel:before{content:\"\\f551\"}.fa-subscript:before{content:\"\\f12c\"}.fa-suitcase:before{content:\"\\f0f2\"}.fa-medkit:before,.fa-suitcase-medical:before{content:\"\\f0fa\"}.fa-suitcase-rolling:before{content:\"\\f5c1\"}.fa-sun:before{content:\"\\f185\"}.fa-superscript:before{content:\"\\f12b\"}.fa-swatchbook:before{content:\"\\f5c3\"}.fa-synagogue:before{content:\"\\f69b\"}.fa-syringe:before{content:\"\\f48e\"}.fa-t:before{content:\"\\54\"}.fa-table:before{content:\"\\f0ce\"}.fa-table-cells:before,.fa-th:before{content:\"\\f00a\"}.fa-table-cells-large:before,.fa-th-large:before{content:\"\\f009\"}.fa-columns:before,.fa-table-columns:before{content:\"\\f0db\"}.fa-table-list:before,.fa-th-list:before{content:\"\\f00b\"}.fa-ping-pong-paddle-ball:before,.fa-table-tennis-paddle-ball:before,.fa-table-tennis:before{content:\"\\f45d\"}.fa-tablet-android:before,.fa-tablet:before{content:\"\\f3fb\"}.fa-tablet-button:before{content:\"\\f10a\"}.fa-tablet-alt:before,.fa-tablet-screen-button:before{content:\"\\f3fa\"}.fa-tablets:before{content:\"\\f490\"}.fa-digital-tachograph:before,.fa-tachograph-digital:before{content:\"\\f566\"}.fa-tag:before{content:\"\\f02b\"}.fa-tags:before{content:\"\\f02c\"}.fa-tape:before{content:\"\\f4db\"}.fa-cab:before,.fa-taxi:before{content:\"\\f1ba\"}.fa-teeth:before{content:\"\\f62e\"}.fa-teeth-open:before{content:\"\\f62f\"}.fa-temperature-0:before,.fa-temperature-empty:before,.fa-thermometer-0:before,.fa-thermometer-empty:before{content:\"\\f2cb\"}.fa-temperature-4:before,.fa-temperature-full:before,.fa-thermometer-4:before,.fa-thermometer-full:before{content:\"\\f2c7\"}.fa-temperature-2:before,.fa-temperature-half:before,.fa-thermometer-2:before,.fa-thermometer-half:before{content:\"\\f2c9\"}.fa-temperature-high:before{content:\"\\f769\"}.fa-temperature-low:before{content:\"\\f76b\"}.fa-temperature-1:before,.fa-temperature-quarter:before,.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:\"\\f2ca\"}.fa-temperature-3:before,.fa-temperature-three-quarters:before,.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:\"\\f2c8\"}.fa-tenge-sign:before,.fa-tenge:before{content:\"\\f7d7\"}.fa-terminal:before{content:\"\\f120\"}.fa-text-height:before{content:\"\\f034\"}.fa-remove-format:before,.fa-text-slash:before{content:\"\\f87d\"}.fa-text-width:before{content:\"\\f035\"}.fa-thermometer:before{content:\"\\f491\"}.fa-thumbs-down:before{content:\"\\f165\"}.fa-thumbs-up:before{content:\"\\f164\"}.fa-thumb-tack:before,.fa-thumbtack:before{content:\"\\f08d\"}.fa-ticket:before{content:\"\\f145\"}.fa-ticket-alt:before,.fa-ticket-simple:before{content:\"\\f3ff\"}.fa-timeline:before{content:\"\\e29c\"}.fa-toggle-off:before{content:\"\\f204\"}.fa-toggle-on:before{content:\"\\f205\"}.fa-toilet:before{content:\"\\f7d8\"}.fa-toilet-paper:before{content:\"\\f71e\"}.fa-toilet-paper-slash:before{content:\"\\e072\"}.fa-toolbox:before{content:\"\\f552\"}.fa-tooth:before{content:\"\\f5c9\"}.fa-torii-gate:before{content:\"\\f6a1\"}.fa-broadcast-tower:before,.fa-tower-broadcast:before{content:\"\\f519\"}.fa-tractor:before{content:\"\\f722\"}.fa-trademark:before{content:\"\\f25c\"}.fa-traffic-light:before{content:\"\\f637\"}.fa-trailer:before{content:\"\\e041\"}.fa-train:before{content:\"\\f238\"}.fa-subway:before,.fa-train-subway:before{content:\"\\f239\"}.fa-train-tram:before,.fa-tram:before{content:\"\\f7da\"}.fa-transgender-alt:before,.fa-transgender:before{content:\"\\f225\"}.fa-trash:before{content:\"\\f1f8\"}.fa-trash-arrow-up:before,.fa-trash-restore:before{content:\"\\f829\"}.fa-trash-alt:before,.fa-trash-can:before{content:\"\\f2ed\"}.fa-trash-can-arrow-up:before,.fa-trash-restore-alt:before{content:\"\\f82a\"}.fa-tree:before{content:\"\\f1bb\"}.fa-exclamation-triangle:before,.fa-triangle-exclamation:before,.fa-warning:before{content:\"\\f071\"}.fa-trophy:before{content:\"\\f091\"}.fa-truck:before{content:\"\\f0d1\"}.fa-shipping-fast:before,.fa-truck-fast:before{content:\"\\f48b\"}.fa-ambulance:before,.fa-truck-medical:before{content:\"\\f0f9\"}.fa-truck-monster:before{content:\"\\f63b\"}.fa-truck-moving:before{content:\"\\f4df\"}.fa-truck-pickup:before{content:\"\\f63c\"}.fa-truck-loading:before,.fa-truck-ramp-box:before{content:\"\\f4de\"}.fa-teletype:before,.fa-tty:before{content:\"\\f1e4\"}.fa-try:before,.fa-turkish-lira-sign:before,.fa-turkish-lira:before{content:\"\\e2bb\"}.fa-level-down-alt:before,.fa-turn-down:before{content:\"\\f3be\"}.fa-level-up-alt:before,.fa-turn-up:before{content:\"\\f3bf\"}.fa-television:before,.fa-tv-alt:before,.fa-tv:before{content:\"\\f26c\"}.fa-u:before{content:\"\\55\"}.fa-umbrella:before{content:\"\\f0e9\"}.fa-umbrella-beach:before{content:\"\\f5ca\"}.fa-underline:before{content:\"\\f0cd\"}.fa-universal-access:before{content:\"\\f29a\"}.fa-unlock:before{content:\"\\f09c\"}.fa-unlock-alt:before,.fa-unlock-keyhole:before{content:\"\\f13e\"}.fa-arrows-alt-v:before,.fa-up-down:before{content:\"\\f338\"}.fa-arrows-alt:before,.fa-up-down-left-right:before{content:\"\\f0b2\"}.fa-long-arrow-alt-up:before,.fa-up-long:before{content:\"\\f30c\"}.fa-expand-alt:before,.fa-up-right-and-down-left-from-center:before{content:\"\\f424\"}.fa-external-link-alt:before,.fa-up-right-from-square:before{content:\"\\f35d\"}.fa-upload:before{content:\"\\f093\"}.fa-user:before{content:\"\\f007\"}.fa-user-astronaut:before{content:\"\\f4fb\"}.fa-user-check:before{content:\"\\f4fc\"}.fa-user-clock:before{content:\"\\f4fd\"}.fa-user-doctor:before,.fa-user-md:before{content:\"\\f0f0\"}.fa-user-cog:before,.fa-user-gear:before{content:\"\\f4fe\"}.fa-user-graduate:before{content:\"\\f501\"}.fa-user-friends:before,.fa-user-group:before{content:\"\\f500\"}.fa-user-injured:before{content:\"\\f728\"}.fa-user-alt:before,.fa-user-large:before{content:\"\\f406\"}.fa-user-alt-slash:before,.fa-user-large-slash:before{content:\"\\f4fa\"}.fa-user-lock:before{content:\"\\f502\"}.fa-user-minus:before{content:\"\\f503\"}.fa-user-ninja:before{content:\"\\f504\"}.fa-user-nurse:before{content:\"\\f82f\"}.fa-user-edit:before,.fa-user-pen:before{content:\"\\f4ff\"}.fa-user-plus:before{content:\"\\f234\"}.fa-user-secret:before{content:\"\\f21b\"}.fa-user-shield:before{content:\"\\f505\"}.fa-user-slash:before{content:\"\\f506\"}.fa-user-tag:before{content:\"\\f507\"}.fa-user-tie:before{content:\"\\f508\"}.fa-user-times:before,.fa-user-xmark:before{content:\"\\f235\"}.fa-users:before{content:\"\\f0c0\"}.fa-users-cog:before,.fa-users-gear:before{content:\"\\f509\"}.fa-users-slash:before{content:\"\\e073\"}.fa-cutlery:before,.fa-utensils:before{content:\"\\f2e7\"}.fa-v:before{content:\"\\56\"}.fa-shuttle-van:before,.fa-van-shuttle:before{content:\"\\f5b6\"}.fa-vault:before{content:\"\\e2c5\"}.fa-vector-square:before{content:\"\\f5cb\"}.fa-venus:before{content:\"\\f221\"}.fa-venus-double:before{content:\"\\f226\"}.fa-venus-mars:before{content:\"\\f228\"}.fa-vest:before{content:\"\\e085\"}.fa-vest-patches:before{content:\"\\e086\"}.fa-vial:before{content:\"\\f492\"}.fa-vials:before{content:\"\\f493\"}.fa-video-camera:before,.fa-video:before{content:\"\\f03d\"}.fa-video-slash:before{content:\"\\f4e2\"}.fa-vihara:before{content:\"\\f6a7\"}.fa-virus:before{content:\"\\e074\"}.fa-virus-covid:before{content:\"\\e4a8\"}.fa-virus-covid-slash:before{content:\"\\e4a9\"}.fa-virus-slash:before{content:\"\\e075\"}.fa-viruses:before{content:\"\\e076\"}.fa-voicemail:before{content:\"\\f897\"}.fa-volleyball-ball:before,.fa-volleyball:before{content:\"\\f45f\"}.fa-volume-high:before,.fa-volume-up:before{content:\"\\f028\"}.fa-volume-down:before,.fa-volume-low:before{content:\"\\f027\"}.fa-volume-off:before{content:\"\\f026\"}.fa-volume-mute:before,.fa-volume-times:before,.fa-volume-xmark:before{content:\"\\f6a9\"}.fa-vr-cardboard:before{content:\"\\f729\"}.fa-w:before{content:\"\\57\"}.fa-wallet:before{content:\"\\f555\"}.fa-magic:before,.fa-wand-magic:before{content:\"\\f0d0\"}.fa-magic-wand-sparkles:before,.fa-wand-magic-sparkles:before{content:\"\\e2ca\"}.fa-wand-sparkles:before{content:\"\\f72b\"}.fa-warehouse:before{content:\"\\f494\"}.fa-water:before{content:\"\\f773\"}.fa-ladder-water:before,.fa-swimming-pool:before,.fa-water-ladder:before{content:\"\\f5c5\"}.fa-wave-square:before{content:\"\\f83e\"}.fa-weight-hanging:before{content:\"\\f5cd\"}.fa-weight-scale:before,.fa-weight:before{content:\"\\f496\"}.fa-wheelchair:before{content:\"\\f193\"}.fa-glass-whiskey:before,.fa-whiskey-glass:before{content:\"\\f7a0\"}.fa-wifi-3:before,.fa-wifi-strong:before,.fa-wifi:before{content:\"\\f1eb\"}.fa-wind:before{content:\"\\f72e\"}.fa-window-maximize:before{content:\"\\f2d0\"}.fa-window-minimize:before{content:\"\\f2d1\"}.fa-window-restore:before{content:\"\\f2d2\"}.fa-wine-bottle:before{content:\"\\f72f\"}.fa-wine-glass:before{content:\"\\f4e3\"}.fa-wine-glass-alt:before,.fa-wine-glass-empty:before{content:\"\\f5ce\"}.fa-krw:before,.fa-won-sign:before,.fa-won:before{content:\"\\f159\"}.fa-wrench:before{content:\"\\f0ad\"}.fa-x:before{content:\"\\58\"}.fa-x-ray:before{content:\"\\f497\"}.fa-close:before,.fa-multiply:before,.fa-remove:before,.fa-times:before,.fa-xmark:before{content:\"\\f00d\"}.fa-y:before{content:\"\\59\"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen-sign:before,.fa-yen:before{content:\"\\f157\"}.fa-yin-yang:before{content:\"\\f6ad\"}.fa-z:before{content:\"\\5a\"}.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.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}:host,:root{--fa-font-brands:normal 400 1em/1 \"Font Awesome 6 Brands\"}@font-face{font-family:\"Font Awesome 6 Brands\";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format(\"woff2\"),url(../webfonts/fa-brands-400.ttf) format(\"truetype\")}.fa-brands,.fab{font-family:\"Font Awesome 6 Brands\";font-weight:400}.fa-42-group:before,.fa-innosoft:before{content:\"\\e080\"}.fa-500px:before{content:\"\\f26e\"}.fa-accessible-icon:before{content:\"\\f368\"}.fa-accusoft:before{content:\"\\f369\"}.fa-adn:before{content:\"\\f170\"}.fa-adversal:before{content:\"\\f36a\"}.fa-affiliatetheme:before{content:\"\\f36b\"}.fa-airbnb:before{content:\"\\f834\"}.fa-algolia:before{content:\"\\f36c\"}.fa-alipay:before{content:\"\\f642\"}.fa-amazon:before{content:\"\\f270\"}.fa-amazon-pay:before{content:\"\\f42c\"}.fa-amilia:before{content:\"\\f36d\"}.fa-android:before{content:\"\\f17b\"}.fa-angellist:before{content:\"\\f209\"}.fa-angrycreative:before{content:\"\\f36e\"}.fa-angular:before{content:\"\\f420\"}.fa-app-store:before{content:\"\\f36f\"}.fa-app-store-ios:before{content:\"\\f370\"}.fa-apper:before{content:\"\\f371\"}.fa-apple:before{content:\"\\f179\"}.fa-apple-pay:before{content:\"\\f415\"}.fa-artstation:before{content:\"\\f77a\"}.fa-asymmetrik:before{content:\"\\f372\"}.fa-atlassian:before{content:\"\\f77b\"}.fa-audible:before{content:\"\\f373\"}.fa-autoprefixer:before{content:\"\\f41c\"}.fa-avianex:before{content:\"\\f374\"}.fa-aviato:before{content:\"\\f421\"}.fa-aws:before{content:\"\\f375\"}.fa-bandcamp:before{content:\"\\f2d5\"}.fa-battle-net:before{content:\"\\f835\"}.fa-behance:before{content:\"\\f1b4\"}.fa-behance-square:before{content:\"\\f1b5\"}.fa-bilibili:before{content:\"\\e3d9\"}.fa-bimobject:before{content:\"\\f378\"}.fa-bitbucket:before{content:\"\\f171\"}.fa-bitcoin:before{content:\"\\f379\"}.fa-bity:before{content:\"\\f37a\"}.fa-black-tie:before{content:\"\\f27e\"}.fa-blackberry:before{content:\"\\f37b\"}.fa-blogger:before{content:\"\\f37c\"}.fa-blogger-b:before{content:\"\\f37d\"}.fa-bluetooth:before{content:\"\\f293\"}.fa-bluetooth-b:before{content:\"\\f294\"}.fa-bootstrap:before{content:\"\\f836\"}.fa-bots:before{content:\"\\e340\"}.fa-btc:before{content:\"\\f15a\"}.fa-buffer:before{content:\"\\f837\"}.fa-buromobelexperte:before{content:\"\\f37f\"}.fa-buy-n-large:before{content:\"\\f8a6\"}.fa-buysellads:before{content:\"\\f20d\"}.fa-canadian-maple-leaf:before{content:\"\\f785\"}.fa-cc-amazon-pay:before{content:\"\\f42d\"}.fa-cc-amex:before{content:\"\\f1f3\"}.fa-cc-apple-pay:before{content:\"\\f416\"}.fa-cc-diners-club:before{content:\"\\f24c\"}.fa-cc-discover:before{content:\"\\f1f2\"}.fa-cc-jcb:before{content:\"\\f24b\"}.fa-cc-mastercard:before{content:\"\\f1f1\"}.fa-cc-paypal:before{content:\"\\f1f4\"}.fa-cc-stripe:before{content:\"\\f1f5\"}.fa-cc-visa:before{content:\"\\f1f0\"}.fa-centercode:before{content:\"\\f380\"}.fa-centos:before{content:\"\\f789\"}.fa-chrome:before{content:\"\\f268\"}.fa-chromecast:before{content:\"\\f838\"}.fa-cloudflare:before{content:\"\\e07d\"}.fa-cloudscale:before{content:\"\\f383\"}.fa-cloudsmith:before{content:\"\\f384\"}.fa-cloudversify:before{content:\"\\f385\"}.fa-cmplid:before{content:\"\\e360\"}.fa-codepen:before{content:\"\\f1cb\"}.fa-codiepie:before{content:\"\\f284\"}.fa-confluence:before{content:\"\\f78d\"}.fa-connectdevelop:before{content:\"\\f20e\"}.fa-contao:before{content:\"\\f26d\"}.fa-cotton-bureau:before{content:\"\\f89e\"}.fa-cpanel:before{content:\"\\f388\"}.fa-creative-commons:before{content:\"\\f25e\"}.fa-creative-commons-by:before{content:\"\\f4e7\"}.fa-creative-commons-nc:before{content:\"\\f4e8\"}.fa-creative-commons-nc-eu:before{content:\"\\f4e9\"}.fa-creative-commons-nc-jp:before{content:\"\\f4ea\"}.fa-creative-commons-nd:before{content:\"\\f4eb\"}.fa-creative-commons-pd:before{content:\"\\f4ec\"}.fa-creative-commons-pd-alt:before{content:\"\\f4ed\"}.fa-creative-commons-remix:before{content:\"\\f4ee\"}.fa-creative-commons-sa:before{content:\"\\f4ef\"}.fa-creative-commons-sampling:before{content:\"\\f4f0\"}.fa-creative-commons-sampling-plus:before{content:\"\\f4f1\"}.fa-creative-commons-share:before{content:\"\\f4f2\"}.fa-creative-commons-zero:before{content:\"\\f4f3\"}.fa-critical-role:before{content:\"\\f6c9\"}.fa-css3:before{content:\"\\f13c\"}.fa-css3-alt:before{content:\"\\f38b\"}.fa-cuttlefish:before{content:\"\\f38c\"}.fa-d-and-d:before{content:\"\\f38d\"}.fa-d-and-d-beyond:before{content:\"\\f6ca\"}.fa-dailymotion:before{content:\"\\e052\"}.fa-dashcube:before{content:\"\\f210\"}.fa-deezer:before{content:\"\\e077\"}.fa-delicious:before{content:\"\\f1a5\"}.fa-deploydog:before{content:\"\\f38e\"}.fa-deskpro:before{content:\"\\f38f\"}.fa-dev:before{content:\"\\f6cc\"}.fa-deviantart:before{content:\"\\f1bd\"}.fa-dhl:before{content:\"\\f790\"}.fa-diaspora:before{content:\"\\f791\"}.fa-digg:before{content:\"\\f1a6\"}.fa-digital-ocean:before{content:\"\\f391\"}.fa-discord:before{content:\"\\f392\"}.fa-discourse:before{content:\"\\f393\"}.fa-dochub:before{content:\"\\f394\"}.fa-docker:before{content:\"\\f395\"}.fa-draft2digital:before{content:\"\\f396\"}.fa-dribbble:before{content:\"\\f17d\"}.fa-dribbble-square:before{content:\"\\f397\"}.fa-dropbox:before{content:\"\\f16b\"}.fa-drupal:before{content:\"\\f1a9\"}.fa-dyalog:before{content:\"\\f399\"}.fa-earlybirds:before{content:\"\\f39a\"}.fa-ebay:before{content:\"\\f4f4\"}.fa-edge:before{content:\"\\f282\"}.fa-edge-legacy:before{content:\"\\e078\"}.fa-elementor:before{content:\"\\f430\"}.fa-ello:before{content:\"\\f5f1\"}.fa-ember:before{content:\"\\f423\"}.fa-empire:before{content:\"\\f1d1\"}.fa-envira:before{content:\"\\f299\"}.fa-erlang:before{content:\"\\f39d\"}.fa-ethereum:before{content:\"\\f42e\"}.fa-etsy:before{content:\"\\f2d7\"}.fa-evernote:before{content:\"\\f839\"}.fa-expeditedssl:before{content:\"\\f23e\"}.fa-facebook:before{content:\"\\f09a\"}.fa-facebook-f:before{content:\"\\f39e\"}.fa-facebook-messenger:before{content:\"\\f39f\"}.fa-facebook-square:before{content:\"\\f082\"}.fa-fantasy-flight-games:before{content:\"\\f6dc\"}.fa-fedex:before{content:\"\\f797\"}.fa-fedora:before{content:\"\\f798\"}.fa-figma:before{content:\"\\f799\"}.fa-firefox:before{content:\"\\f269\"}.fa-firefox-browser:before{content:\"\\e007\"}.fa-first-order:before{content:\"\\f2b0\"}.fa-first-order-alt:before{content:\"\\f50a\"}.fa-firstdraft:before{content:\"\\f3a1\"}.fa-flickr:before{content:\"\\f16e\"}.fa-flipboard:before{content:\"\\f44d\"}.fa-fly:before{content:\"\\f417\"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:\"\\f2b4\"}.fa-fonticons:before{content:\"\\f280\"}.fa-fonticons-fi:before{content:\"\\f3a2\"}.fa-fort-awesome:before{content:\"\\f286\"}.fa-fort-awesome-alt:before{content:\"\\f3a3\"}.fa-forumbee:before{content:\"\\f211\"}.fa-foursquare:before{content:\"\\f180\"}.fa-free-code-camp:before{content:\"\\f2c5\"}.fa-freebsd:before{content:\"\\f3a4\"}.fa-fulcrum:before{content:\"\\f50b\"}.fa-galactic-republic:before{content:\"\\f50c\"}.fa-galactic-senate:before{content:\"\\f50d\"}.fa-get-pocket:before{content:\"\\f265\"}.fa-gg:before{content:\"\\f260\"}.fa-gg-circle:before{content:\"\\f261\"}.fa-git:before{content:\"\\f1d3\"}.fa-git-alt:before{content:\"\\f841\"}.fa-git-square:before{content:\"\\f1d2\"}.fa-github:before{content:\"\\f09b\"}.fa-github-alt:before{content:\"\\f113\"}.fa-github-square:before{content:\"\\f092\"}.fa-gitkraken:before{content:\"\\f3a6\"}.fa-gitlab:before{content:\"\\f296\"}.fa-gitter:before{content:\"\\f426\"}.fa-glide:before{content:\"\\f2a5\"}.fa-glide-g:before{content:\"\\f2a6\"}.fa-gofore:before{content:\"\\f3a7\"}.fa-golang:before{content:\"\\e40f\"}.fa-goodreads:before{content:\"\\f3a8\"}.fa-goodreads-g:before{content:\"\\f3a9\"}.fa-google:before{content:\"\\f1a0\"}.fa-google-drive:before{content:\"\\f3aa\"}.fa-google-pay:before{content:\"\\e079\"}.fa-google-play:before{content:\"\\f3ab\"}.fa-google-plus:before{content:\"\\f2b3\"}.fa-google-plus-g:before{content:\"\\f0d5\"}.fa-google-plus-square:before{content:\"\\f0d4\"}.fa-google-wallet:before{content:\"\\f1ee\"}.fa-gratipay:before{content:\"\\f184\"}.fa-grav:before{content:\"\\f2d6\"}.fa-gripfire:before{content:\"\\f3ac\"}.fa-grunt:before{content:\"\\f3ad\"}.fa-guilded:before{content:\"\\e07e\"}.fa-gulp:before{content:\"\\f3ae\"}.fa-hacker-news:before{content:\"\\f1d4\"}.fa-hacker-news-square:before{content:\"\\f3af\"}.fa-hackerrank:before{content:\"\\f5f7\"}.fa-hashnode:before{content:\"\\e499\"}.fa-hips:before{content:\"\\f452\"}.fa-hire-a-helper:before{content:\"\\f3b0\"}.fa-hive:before{content:\"\\e07f\"}.fa-hooli:before{content:\"\\f427\"}.fa-hornbill:before{content:\"\\f592\"}.fa-hotjar:before{content:\"\\f3b1\"}.fa-houzz:before{content:\"\\f27c\"}.fa-html5:before{content:\"\\f13b\"}.fa-hubspot:before{content:\"\\f3b2\"}.fa-ideal:before{content:\"\\e013\"}.fa-imdb:before{content:\"\\f2d8\"}.fa-instagram:before{content:\"\\f16d\"}.fa-instagram-square:before{content:\"\\e055\"}.fa-instalod:before{content:\"\\e081\"}.fa-intercom:before{content:\"\\f7af\"}.fa-internet-explorer:before{content:\"\\f26b\"}.fa-invision:before{content:\"\\f7b0\"}.fa-ioxhost:before{content:\"\\f208\"}.fa-itch-io:before{content:\"\\f83a\"}.fa-itunes:before{content:\"\\f3b4\"}.fa-itunes-note:before{content:\"\\f3b5\"}.fa-java:before{content:\"\\f4e4\"}.fa-jedi-order:before{content:\"\\f50e\"}.fa-jenkins:before{content:\"\\f3b6\"}.fa-jira:before{content:\"\\f7b1\"}.fa-joget:before{content:\"\\f3b7\"}.fa-joomla:before{content:\"\\f1aa\"}.fa-js:before{content:\"\\f3b8\"}.fa-js-square:before{content:\"\\f3b9\"}.fa-jsfiddle:before{content:\"\\f1cc\"}.fa-kaggle:before{content:\"\\f5fa\"}.fa-keybase:before{content:\"\\f4f5\"}.fa-keycdn:before{content:\"\\f3ba\"}.fa-kickstarter:before{content:\"\\f3bb\"}.fa-kickstarter-k:before{content:\"\\f3bc\"}.fa-korvue:before{content:\"\\f42f\"}.fa-laravel:before{content:\"\\f3bd\"}.fa-lastfm:before{content:\"\\f202\"}.fa-lastfm-square:before{content:\"\\f203\"}.fa-leanpub:before{content:\"\\f212\"}.fa-less:before{content:\"\\f41d\"}.fa-line:before{content:\"\\f3c0\"}.fa-linkedin:before{content:\"\\f08c\"}.fa-linkedin-in:before{content:\"\\f0e1\"}.fa-linode:before{content:\"\\f2b8\"}.fa-linux:before{content:\"\\f17c\"}.fa-lyft:before{content:\"\\f3c3\"}.fa-magento:before{content:\"\\f3c4\"}.fa-mailchimp:before{content:\"\\f59e\"}.fa-mandalorian:before{content:\"\\f50f\"}.fa-markdown:before{content:\"\\f60f\"}.fa-mastodon:before{content:\"\\f4f6\"}.fa-maxcdn:before{content:\"\\f136\"}.fa-mdb:before{content:\"\\f8ca\"}.fa-medapps:before{content:\"\\f3c6\"}.fa-medium-m:before,.fa-medium:before{content:\"\\f23a\"}.fa-medrt:before{content:\"\\f3c8\"}.fa-meetup:before{content:\"\\f2e0\"}.fa-megaport:before{content:\"\\f5a3\"}.fa-mendeley:before{content:\"\\f7b3\"}.fa-microblog:before{content:\"\\e01a\"}.fa-microsoft:before{content:\"\\f3ca\"}.fa-mix:before{content:\"\\f3cb\"}.fa-mixcloud:before{content:\"\\f289\"}.fa-mixer:before{content:\"\\e056\"}.fa-mizuni:before{content:\"\\f3cc\"}.fa-modx:before{content:\"\\f285\"}.fa-monero:before{content:\"\\f3d0\"}.fa-napster:before{content:\"\\f3d2\"}.fa-neos:before{content:\"\\f612\"}.fa-nimblr:before{content:\"\\f5a8\"}.fa-node:before{content:\"\\f419\"}.fa-node-js:before{content:\"\\f3d3\"}.fa-npm:before{content:\"\\f3d4\"}.fa-ns8:before{content:\"\\f3d5\"}.fa-nutritionix:before{content:\"\\f3d6\"}.fa-octopus-deploy:before{content:\"\\e082\"}.fa-odnoklassniki:before{content:\"\\f263\"}.fa-odnoklassniki-square:before{content:\"\\f264\"}.fa-old-republic:before{content:\"\\f510\"}.fa-opencart:before{content:\"\\f23d\"}.fa-openid:before{content:\"\\f19b\"}.fa-opera:before{content:\"\\f26a\"}.fa-optin-monster:before{content:\"\\f23c\"}.fa-orcid:before{content:\"\\f8d2\"}.fa-osi:before{content:\"\\f41a\"}.fa-padlet:before{content:\"\\e4a0\"}.fa-page4:before{content:\"\\f3d7\"}.fa-pagelines:before{content:\"\\f18c\"}.fa-palfed:before{content:\"\\f3d8\"}.fa-patreon:before{content:\"\\f3d9\"}.fa-paypal:before{content:\"\\f1ed\"}.fa-perbyte:before{content:\"\\e083\"}.fa-periscope:before{content:\"\\f3da\"}.fa-phabricator:before{content:\"\\f3db\"}.fa-phoenix-framework:before{content:\"\\f3dc\"}.fa-phoenix-squadron:before{content:\"\\f511\"}.fa-php:before{content:\"\\f457\"}.fa-pied-piper:before{content:\"\\f2ae\"}.fa-pied-piper-alt:before{content:\"\\f1a8\"}.fa-pied-piper-hat:before{content:\"\\f4e5\"}.fa-pied-piper-pp:before{content:\"\\f1a7\"}.fa-pied-piper-square:before{content:\"\\e01e\"}.fa-pinterest:before{content:\"\\f0d2\"}.fa-pinterest-p:before{content:\"\\f231\"}.fa-pinterest-square:before{content:\"\\f0d3\"}.fa-pix:before{content:\"\\e43a\"}.fa-playstation:before{content:\"\\f3df\"}.fa-product-hunt:before{content:\"\\f288\"}.fa-pushed:before{content:\"\\f3e1\"}.fa-python:before{content:\"\\f3e2\"}.fa-qq:before{content:\"\\f1d6\"}.fa-quinscape:before{content:\"\\f459\"}.fa-quora:before{content:\"\\f2c4\"}.fa-r-project:before{content:\"\\f4f7\"}.fa-raspberry-pi:before{content:\"\\f7bb\"}.fa-ravelry:before{content:\"\\f2d9\"}.fa-react:before{content:\"\\f41b\"}.fa-reacteurope:before{content:\"\\f75d\"}.fa-readme:before{content:\"\\f4d5\"}.fa-rebel:before{content:\"\\f1d0\"}.fa-red-river:before{content:\"\\f3e3\"}.fa-reddit:before{content:\"\\f1a1\"}.fa-reddit-alien:before{content:\"\\f281\"}.fa-reddit-square:before{content:\"\\f1a2\"}.fa-redhat:before{content:\"\\f7bc\"}.fa-renren:before{content:\"\\f18b\"}.fa-replyd:before{content:\"\\f3e6\"}.fa-researchgate:before{content:\"\\f4f8\"}.fa-resolving:before{content:\"\\f3e7\"}.fa-rev:before{content:\"\\f5b2\"}.fa-rocketchat:before{content:\"\\f3e8\"}.fa-rockrms:before{content:\"\\f3e9\"}.fa-rust:before{content:\"\\e07a\"}.fa-safari:before{content:\"\\f267\"}.fa-salesforce:before{content:\"\\f83b\"}.fa-sass:before{content:\"\\f41e\"}.fa-schlix:before{content:\"\\f3ea\"}.fa-scribd:before{content:\"\\f28a\"}.fa-searchengin:before{content:\"\\f3eb\"}.fa-sellcast:before{content:\"\\f2da\"}.fa-sellsy:before{content:\"\\f213\"}.fa-servicestack:before{content:\"\\f3ec\"}.fa-shirtsinbulk:before{content:\"\\f214\"}.fa-shopify:before{content:\"\\e057\"}.fa-shopware:before{content:\"\\f5b5\"}.fa-simplybuilt:before{content:\"\\f215\"}.fa-sistrix:before{content:\"\\f3ee\"}.fa-sith:before{content:\"\\f512\"}.fa-sitrox:before{content:\"\\e44a\"}.fa-sketch:before{content:\"\\f7c6\"}.fa-skyatlas:before{content:\"\\f216\"}.fa-skype:before{content:\"\\f17e\"}.fa-slack-hash:before,.fa-slack:before{content:\"\\f198\"}.fa-slideshare:before{content:\"\\f1e7\"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:\"\\f2ab\"}.fa-snapchat-square:before{content:\"\\f2ad\"}.fa-soundcloud:before{content:\"\\f1be\"}.fa-sourcetree:before{content:\"\\f7d3\"}.fa-speakap:before{content:\"\\f3f3\"}.fa-speaker-deck:before{content:\"\\f83c\"}.fa-spotify:before{content:\"\\f1bc\"}.fa-square-font-awesome:before{content:\"\\f425\"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:\"\\f35c\"}.fa-squarespace:before{content:\"\\f5be\"}.fa-stack-exchange:before{content:\"\\f18d\"}.fa-stack-overflow:before{content:\"\\f16c\"}.fa-stackpath:before{content:\"\\f842\"}.fa-staylinked:before{content:\"\\f3f5\"}.fa-steam:before{content:\"\\f1b6\"}.fa-steam-square:before{content:\"\\f1b7\"}.fa-steam-symbol:before{content:\"\\f3f6\"}.fa-sticker-mule:before{content:\"\\f3f7\"}.fa-strava:before{content:\"\\f428\"}.fa-stripe:before{content:\"\\f429\"}.fa-stripe-s:before{content:\"\\f42a\"}.fa-studiovinari:before{content:\"\\f3f8\"}.fa-stumbleupon:before{content:\"\\f1a4\"}.fa-stumbleupon-circle:before{content:\"\\f1a3\"}.fa-superpowers:before{content:\"\\f2dd\"}.fa-supple:before{content:\"\\f3f9\"}.fa-suse:before{content:\"\\f7d6\"}.fa-swift:before{content:\"\\f8e1\"}.fa-symfony:before{content:\"\\f83d\"}.fa-teamspeak:before{content:\"\\f4f9\"}.fa-telegram-plane:before,.fa-telegram:before{content:\"\\f2c6\"}.fa-tencent-weibo:before{content:\"\\f1d5\"}.fa-the-red-yeti:before{content:\"\\f69d\"}.fa-themeco:before{content:\"\\f5c6\"}.fa-themeisle:before{content:\"\\f2b2\"}.fa-think-peaks:before{content:\"\\f731\"}.fa-tiktok:before{content:\"\\e07b\"}.fa-trade-federation:before{content:\"\\f513\"}.fa-trello:before{content:\"\\f181\"}.fa-tumblr:before{content:\"\\f173\"}.fa-tumblr-square:before{content:\"\\f174\"}.fa-twitch:before{content:\"\\f1e8\"}.fa-twitter:before{content:\"\\f099\"}.fa-twitter-square:before{content:\"\\f081\"}.fa-typo3:before{content:\"\\f42b\"}.fa-uber:before{content:\"\\f402\"}.fa-ubuntu:before{content:\"\\f7df\"}.fa-uikit:before{content:\"\\f403\"}.fa-umbraco:before{content:\"\\f8e8\"}.fa-uncharted:before{content:\"\\e084\"}.fa-uniregistry:before{content:\"\\f404\"}.fa-unity:before{content:\"\\e049\"}.fa-unsplash:before{content:\"\\e07c\"}.fa-untappd:before{content:\"\\f405\"}.fa-ups:before{content:\"\\f7e0\"}.fa-usb:before{content:\"\\f287\"}.fa-usps:before{content:\"\\f7e1\"}.fa-ussunnah:before{content:\"\\f407\"}.fa-vaadin:before{content:\"\\f408\"}.fa-viacoin:before{content:\"\\f237\"}.fa-viadeo:before{content:\"\\f2a9\"}.fa-viadeo-square:before{content:\"\\f2aa\"}.fa-viber:before{content:\"\\f409\"}.fa-vimeo:before{content:\"\\f40a\"}.fa-vimeo-square:before{content:\"\\f194\"}.fa-vimeo-v:before{content:\"\\f27d\"}.fa-vine:before{content:\"\\f1ca\"}.fa-vk:before{content:\"\\f189\"}.fa-vnv:before{content:\"\\f40b\"}.fa-vuejs:before{content:\"\\f41f\"}.fa-watchman-monitoring:before{content:\"\\e087\"}.fa-waze:before{content:\"\\f83f\"}.fa-weebly:before{content:\"\\f5cc\"}.fa-weibo:before{content:\"\\f18a\"}.fa-weixin:before{content:\"\\f1d7\"}.fa-whatsapp:before{content:\"\\f232\"}.fa-whatsapp-square:before{content:\"\\f40c\"}.fa-whmcs:before{content:\"\\f40d\"}.fa-wikipedia-w:before{content:\"\\f266\"}.fa-windows:before{content:\"\\f17a\"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:\"\\e2d0\"}.fa-wix:before{content:\"\\f5cf\"}.fa-wizards-of-the-coast:before{content:\"\\f730\"}.fa-wodu:before{content:\"\\e088\"}.fa-wolf-pack-battalion:before{content:\"\\f514\"}.fa-wordpress:before{content:\"\\f19a\"}.fa-wordpress-simple:before{content:\"\\f411\"}.fa-wpbeginner:before{content:\"\\f297\"}.fa-wpexplorer:before{content:\"\\f2de\"}.fa-wpforms:before{content:\"\\f298\"}.fa-wpressr:before{content:\"\\f3e4\"}.fa-xbox:before{content:\"\\f412\"}.fa-xing:before{content:\"\\f168\"}.fa-xing-square:before{content:\"\\f169\"}.fa-y-combinator:before{content:\"\\f23b\"}.fa-yahoo:before{content:\"\\f19e\"}.fa-yammer:before{content:\"\\f840\"}.fa-yandex:before{content:\"\\f413\"}.fa-yandex-international:before{content:\"\\f414\"}.fa-yarn:before{content:\"\\f7e3\"}.fa-yelp:before{content:\"\\f1e9\"}.fa-yoast:before{content:\"\\f2b1\"}.fa-youtube:before{content:\"\\f167\"}.fa-youtube-square:before{content:\"\\f431\"}.fa-zhihu:before{content:\"\\f63f\"}:host,:root{--fa-font-regular:normal 400 1em/1 \"Font Awesome 6 Free\"}@font-face{font-family:\"Font Awesome 6 Free\";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format(\"woff2\"),url(../webfonts/fa-regular-400.ttf) format(\"truetype\")}.fa-regular,.far{font-family:\"Font Awesome 6 Free\";font-weight:400}:host,:root{--fa-font-solid:normal 900 1em/1 \"Font Awesome 6 Free\"}@font-face{font-family:\"Font Awesome 6 Free\";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format(\"woff2\"),url(../webfonts/fa-solid-900.ttf) format(\"truetype\")}.fa-solid,.fas{font-family:\"Font Awesome 6 Free\";font-weight:900}@font-face{font-family:\"Font Awesome 5 Brands\";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format(\"woff2\"),url(../webfonts/fa-brands-400.ttf) format(\"truetype\")}@font-face{font-family:\"Font Awesome 5 Free\";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format(\"woff2\"),url(../webfonts/fa-solid-900.ttf) format(\"truetype\")}@font-face{font-family:\"Font Awesome 5 Free\";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format(\"woff2\"),url(../webfonts/fa-regular-400.ttf) format(\"truetype\")}@font-face{font-family:\"FontAwesome\";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format(\"woff2\"),url(../webfonts/fa-solid-900.ttf) format(\"truetype\")}@font-face{font-family:\"FontAwesome\";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format(\"woff2\"),url(../webfonts/fa-brands-400.ttf) format(\"truetype\")}@font-face{font-family:\"FontAwesome\";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format(\"woff2\"),url(../webfonts/fa-regular-400.ttf) format(\"truetype\");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:\"FontAwesome\";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format(\"woff2\"),url(../webfonts/fa-v4compatibility.ttf) format(\"truetype\");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f250,u+f252,u+f27a}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/common.css",
    "content": "\nbody {\n    /*background-image: linear-gradient(180deg, #eee, #fff 100px, #fff);*/\n    padding-top: 5.5rem;\n}\n\n/*.container {*/\n/*    max-width: 960px;*/\n/*}*/\n\nmain {\n    min-height: 72rem;\n}\n\n@media (min-width: 768px) {\n    .bd-toc-collapse {\n        display: block !important;\n    }\n}\n\n.bd-toc {\n    grid-area: toc\n}\n\n.bd-toc nav {\n    font-size: .875rem\n}\n\n.bd-toc nav ul {\n    padding-left: 0;\n    margin-bottom: 0;\n    list-style: none\n}\n\n.bd-toc nav ul ul {\n    padding-left: 1rem;\n    margin-top: .25rem\n}\n\n.bd-toc nav li {\n    margin-bottom: .25rem\n}\n\n.bd-toc nav a {\n    color: inherit;\n    padding: .1875rem .3rem;\n    text-decoration: none\n}\n\n.bd-toc nav a:not(:hover) {\n    text-decoration: none\n}\n\n.bd-toc nav a:hover, .bd-toc nav a:focus, .bd-toc nav a.active {\n    background-color: #dddddd;\n}\n\n.bd-toc nav a.active {\n    font-weight: 600\n}\n\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/fontawesome.min.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.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-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:\"\\f26e\"}.fa-accessible-icon:before{content:\"\\f368\"}.fa-accusoft:before{content:\"\\f369\"}.fa-acquisitions-incorporated:before{content:\"\\f6af\"}.fa-ad:before{content:\"\\f641\"}.fa-address-book:before{content:\"\\f2b9\"}.fa-address-card:before{content:\"\\f2bb\"}.fa-adjust:before{content:\"\\f042\"}.fa-adn:before{content:\"\\f170\"}.fa-adversal:before{content:\"\\f36a\"}.fa-affiliatetheme:before{content:\"\\f36b\"}.fa-air-freshener:before{content:\"\\f5d0\"}.fa-airbnb:before{content:\"\\f834\"}.fa-algolia:before{content:\"\\f36c\"}.fa-align-center:before{content:\"\\f037\"}.fa-align-justify:before{content:\"\\f039\"}.fa-align-left:before{content:\"\\f036\"}.fa-align-right:before{content:\"\\f038\"}.fa-alipay:before{content:\"\\f642\"}.fa-allergies:before{content:\"\\f461\"}.fa-amazon:before{content:\"\\f270\"}.fa-amazon-pay:before{content:\"\\f42c\"}.fa-ambulance:before{content:\"\\f0f9\"}.fa-american-sign-language-interpreting:before{content:\"\\f2a3\"}.fa-amilia:before{content:\"\\f36d\"}.fa-anchor:before{content:\"\\f13d\"}.fa-android:before{content:\"\\f17b\"}.fa-angellist:before{content:\"\\f209\"}.fa-angle-double-down:before{content:\"\\f103\"}.fa-angle-double-left:before{content:\"\\f100\"}.fa-angle-double-right:before{content:\"\\f101\"}.fa-angle-double-up:before{content:\"\\f102\"}.fa-angle-down:before{content:\"\\f107\"}.fa-angle-left:before{content:\"\\f104\"}.fa-angle-right:before{content:\"\\f105\"}.fa-angle-up:before{content:\"\\f106\"}.fa-angry:before{content:\"\\f556\"}.fa-angrycreative:before{content:\"\\f36e\"}.fa-angular:before{content:\"\\f420\"}.fa-ankh:before{content:\"\\f644\"}.fa-app-store:before{content:\"\\f36f\"}.fa-app-store-ios:before{content:\"\\f370\"}.fa-apper:before{content:\"\\f371\"}.fa-apple:before{content:\"\\f179\"}.fa-apple-alt:before{content:\"\\f5d1\"}.fa-apple-pay:before{content:\"\\f415\"}.fa-archive:before{content:\"\\f187\"}.fa-archway:before{content:\"\\f557\"}.fa-arrow-alt-circle-down:before{content:\"\\f358\"}.fa-arrow-alt-circle-left:before{content:\"\\f359\"}.fa-arrow-alt-circle-right:before{content:\"\\f35a\"}.fa-arrow-alt-circle-up:before{content:\"\\f35b\"}.fa-arrow-circle-down:before{content:\"\\f0ab\"}.fa-arrow-circle-left:before{content:\"\\f0a8\"}.fa-arrow-circle-right:before{content:\"\\f0a9\"}.fa-arrow-circle-up:before{content:\"\\f0aa\"}.fa-arrow-down:before{content:\"\\f063\"}.fa-arrow-left:before{content:\"\\f060\"}.fa-arrow-right:before{content:\"\\f061\"}.fa-arrow-up:before{content:\"\\f062\"}.fa-arrows-alt:before{content:\"\\f0b2\"}.fa-arrows-alt-h:before{content:\"\\f337\"}.fa-arrows-alt-v:before{content:\"\\f338\"}.fa-artstation:before{content:\"\\f77a\"}.fa-assistive-listening-systems:before{content:\"\\f2a2\"}.fa-asterisk:before{content:\"\\f069\"}.fa-asymmetrik:before{content:\"\\f372\"}.fa-at:before{content:\"\\f1fa\"}.fa-atlas:before{content:\"\\f558\"}.fa-atlassian:before{content:\"\\f77b\"}.fa-atom:before{content:\"\\f5d2\"}.fa-audible:before{content:\"\\f373\"}.fa-audio-description:before{content:\"\\f29e\"}.fa-autoprefixer:before{content:\"\\f41c\"}.fa-avianex:before{content:\"\\f374\"}.fa-aviato:before{content:\"\\f421\"}.fa-award:before{content:\"\\f559\"}.fa-aws:before{content:\"\\f375\"}.fa-baby:before{content:\"\\f77c\"}.fa-baby-carriage:before{content:\"\\f77d\"}.fa-backspace:before{content:\"\\f55a\"}.fa-backward:before{content:\"\\f04a\"}.fa-bacon:before{content:\"\\f7e5\"}.fa-bacteria:before{content:\"\\e059\"}.fa-bacterium:before{content:\"\\e05a\"}.fa-bahai:before{content:\"\\f666\"}.fa-balance-scale:before{content:\"\\f24e\"}.fa-balance-scale-left:before{content:\"\\f515\"}.fa-balance-scale-right:before{content:\"\\f516\"}.fa-ban:before{content:\"\\f05e\"}.fa-band-aid:before{content:\"\\f462\"}.fa-bandcamp:before{content:\"\\f2d5\"}.fa-barcode:before{content:\"\\f02a\"}.fa-bars:before{content:\"\\f0c9\"}.fa-baseball-ball:before{content:\"\\f433\"}.fa-basketball-ball:before{content:\"\\f434\"}.fa-bath:before{content:\"\\f2cd\"}.fa-battery-empty:before{content:\"\\f244\"}.fa-battery-full:before{content:\"\\f240\"}.fa-battery-half:before{content:\"\\f242\"}.fa-battery-quarter:before{content:\"\\f243\"}.fa-battery-three-quarters:before{content:\"\\f241\"}.fa-battle-net:before{content:\"\\f835\"}.fa-bed:before{content:\"\\f236\"}.fa-beer:before{content:\"\\f0fc\"}.fa-behance:before{content:\"\\f1b4\"}.fa-behance-square:before{content:\"\\f1b5\"}.fa-bell:before{content:\"\\f0f3\"}.fa-bell-slash:before{content:\"\\f1f6\"}.fa-bezier-curve:before{content:\"\\f55b\"}.fa-bible:before{content:\"\\f647\"}.fa-bicycle:before{content:\"\\f206\"}.fa-biking:before{content:\"\\f84a\"}.fa-bimobject:before{content:\"\\f378\"}.fa-binoculars:before{content:\"\\f1e5\"}.fa-biohazard:before{content:\"\\f780\"}.fa-birthday-cake:before{content:\"\\f1fd\"}.fa-bitbucket:before{content:\"\\f171\"}.fa-bitcoin:before{content:\"\\f379\"}.fa-bity:before{content:\"\\f37a\"}.fa-black-tie:before{content:\"\\f27e\"}.fa-blackberry:before{content:\"\\f37b\"}.fa-blender:before{content:\"\\f517\"}.fa-blender-phone:before{content:\"\\f6b6\"}.fa-blind:before{content:\"\\f29d\"}.fa-blog:before{content:\"\\f781\"}.fa-blogger:before{content:\"\\f37c\"}.fa-blogger-b:before{content:\"\\f37d\"}.fa-bluetooth:before{content:\"\\f293\"}.fa-bluetooth-b:before{content:\"\\f294\"}.fa-bold:before{content:\"\\f032\"}.fa-bolt:before{content:\"\\f0e7\"}.fa-bomb:before{content:\"\\f1e2\"}.fa-bone:before{content:\"\\f5d7\"}.fa-bong:before{content:\"\\f55c\"}.fa-book:before{content:\"\\f02d\"}.fa-book-dead:before{content:\"\\f6b7\"}.fa-book-medical:before{content:\"\\f7e6\"}.fa-book-open:before{content:\"\\f518\"}.fa-book-reader:before{content:\"\\f5da\"}.fa-bookmark:before{content:\"\\f02e\"}.fa-bootstrap:before{content:\"\\f836\"}.fa-border-all:before{content:\"\\f84c\"}.fa-border-none:before{content:\"\\f850\"}.fa-border-style:before{content:\"\\f853\"}.fa-bowling-ball:before{content:\"\\f436\"}.fa-box:before{content:\"\\f466\"}.fa-box-open:before{content:\"\\f49e\"}.fa-box-tissue:before{content:\"\\e05b\"}.fa-boxes:before{content:\"\\f468\"}.fa-braille:before{content:\"\\f2a1\"}.fa-brain:before{content:\"\\f5dc\"}.fa-bread-slice:before{content:\"\\f7ec\"}.fa-briefcase:before{content:\"\\f0b1\"}.fa-briefcase-medical:before{content:\"\\f469\"}.fa-broadcast-tower:before{content:\"\\f519\"}.fa-broom:before{content:\"\\f51a\"}.fa-brush:before{content:\"\\f55d\"}.fa-btc:before{content:\"\\f15a\"}.fa-buffer:before{content:\"\\f837\"}.fa-bug:before{content:\"\\f188\"}.fa-building:before{content:\"\\f1ad\"}.fa-bullhorn:before{content:\"\\f0a1\"}.fa-bullseye:before{content:\"\\f140\"}.fa-burn:before{content:\"\\f46a\"}.fa-buromobelexperte:before{content:\"\\f37f\"}.fa-bus:before{content:\"\\f207\"}.fa-bus-alt:before{content:\"\\f55e\"}.fa-business-time:before{content:\"\\f64a\"}.fa-buy-n-large:before{content:\"\\f8a6\"}.fa-buysellads:before{content:\"\\f20d\"}.fa-calculator:before{content:\"\\f1ec\"}.fa-calendar:before{content:\"\\f133\"}.fa-calendar-alt:before{content:\"\\f073\"}.fa-calendar-check:before{content:\"\\f274\"}.fa-calendar-day:before{content:\"\\f783\"}.fa-calendar-minus:before{content:\"\\f272\"}.fa-calendar-plus:before{content:\"\\f271\"}.fa-calendar-times:before{content:\"\\f273\"}.fa-calendar-week:before{content:\"\\f784\"}.fa-camera:before{content:\"\\f030\"}.fa-camera-retro:before{content:\"\\f083\"}.fa-campground:before{content:\"\\f6bb\"}.fa-canadian-maple-leaf:before{content:\"\\f785\"}.fa-candy-cane:before{content:\"\\f786\"}.fa-cannabis:before{content:\"\\f55f\"}.fa-capsules:before{content:\"\\f46b\"}.fa-car:before{content:\"\\f1b9\"}.fa-car-alt:before{content:\"\\f5de\"}.fa-car-battery:before{content:\"\\f5df\"}.fa-car-crash:before{content:\"\\f5e1\"}.fa-car-side:before{content:\"\\f5e4\"}.fa-caravan:before{content:\"\\f8ff\"}.fa-caret-down:before{content:\"\\f0d7\"}.fa-caret-left:before{content:\"\\f0d9\"}.fa-caret-right:before{content:\"\\f0da\"}.fa-caret-square-down:before{content:\"\\f150\"}.fa-caret-square-left:before{content:\"\\f191\"}.fa-caret-square-right:before{content:\"\\f152\"}.fa-caret-square-up:before{content:\"\\f151\"}.fa-caret-up:before{content:\"\\f0d8\"}.fa-carrot:before{content:\"\\f787\"}.fa-cart-arrow-down:before{content:\"\\f218\"}.fa-cart-plus:before{content:\"\\f217\"}.fa-cash-register:before{content:\"\\f788\"}.fa-cat:before{content:\"\\f6be\"}.fa-cc-amazon-pay:before{content:\"\\f42d\"}.fa-cc-amex:before{content:\"\\f1f3\"}.fa-cc-apple-pay:before{content:\"\\f416\"}.fa-cc-diners-club:before{content:\"\\f24c\"}.fa-cc-discover:before{content:\"\\f1f2\"}.fa-cc-jcb:before{content:\"\\f24b\"}.fa-cc-mastercard:before{content:\"\\f1f1\"}.fa-cc-paypal:before{content:\"\\f1f4\"}.fa-cc-stripe:before{content:\"\\f1f5\"}.fa-cc-visa:before{content:\"\\f1f0\"}.fa-centercode:before{content:\"\\f380\"}.fa-centos:before{content:\"\\f789\"}.fa-certificate:before{content:\"\\f0a3\"}.fa-chair:before{content:\"\\f6c0\"}.fa-chalkboard:before{content:\"\\f51b\"}.fa-chalkboard-teacher:before{content:\"\\f51c\"}.fa-charging-station:before{content:\"\\f5e7\"}.fa-chart-area:before{content:\"\\f1fe\"}.fa-chart-bar:before{content:\"\\f080\"}.fa-chart-line:before{content:\"\\f201\"}.fa-chart-pie:before{content:\"\\f200\"}.fa-check:before{content:\"\\f00c\"}.fa-check-circle:before{content:\"\\f058\"}.fa-check-double:before{content:\"\\f560\"}.fa-check-square:before{content:\"\\f14a\"}.fa-cheese:before{content:\"\\f7ef\"}.fa-chess:before{content:\"\\f439\"}.fa-chess-bishop:before{content:\"\\f43a\"}.fa-chess-board:before{content:\"\\f43c\"}.fa-chess-king:before{content:\"\\f43f\"}.fa-chess-knight:before{content:\"\\f441\"}.fa-chess-pawn:before{content:\"\\f443\"}.fa-chess-queen:before{content:\"\\f445\"}.fa-chess-rook:before{content:\"\\f447\"}.fa-chevron-circle-down:before{content:\"\\f13a\"}.fa-chevron-circle-left:before{content:\"\\f137\"}.fa-chevron-circle-right:before{content:\"\\f138\"}.fa-chevron-circle-up:before{content:\"\\f139\"}.fa-chevron-down:before{content:\"\\f078\"}.fa-chevron-left:before{content:\"\\f053\"}.fa-chevron-right:before{content:\"\\f054\"}.fa-chevron-up:before{content:\"\\f077\"}.fa-child:before{content:\"\\f1ae\"}.fa-chrome:before{content:\"\\f268\"}.fa-chromecast:before{content:\"\\f838\"}.fa-church:before{content:\"\\f51d\"}.fa-circle:before{content:\"\\f111\"}.fa-circle-notch:before{content:\"\\f1ce\"}.fa-city:before{content:\"\\f64f\"}.fa-clinic-medical:before{content:\"\\f7f2\"}.fa-clipboard:before{content:\"\\f328\"}.fa-clipboard-check:before{content:\"\\f46c\"}.fa-clipboard-list:before{content:\"\\f46d\"}.fa-clock:before{content:\"\\f017\"}.fa-clone:before{content:\"\\f24d\"}.fa-closed-captioning:before{content:\"\\f20a\"}.fa-cloud:before{content:\"\\f0c2\"}.fa-cloud-download-alt:before{content:\"\\f381\"}.fa-cloud-meatball:before{content:\"\\f73b\"}.fa-cloud-moon:before{content:\"\\f6c3\"}.fa-cloud-moon-rain:before{content:\"\\f73c\"}.fa-cloud-rain:before{content:\"\\f73d\"}.fa-cloud-showers-heavy:before{content:\"\\f740\"}.fa-cloud-sun:before{content:\"\\f6c4\"}.fa-cloud-sun-rain:before{content:\"\\f743\"}.fa-cloud-upload-alt:before{content:\"\\f382\"}.fa-cloudflare:before{content:\"\\e07d\"}.fa-cloudscale:before{content:\"\\f383\"}.fa-cloudsmith:before{content:\"\\f384\"}.fa-cloudversify:before{content:\"\\f385\"}.fa-cocktail:before{content:\"\\f561\"}.fa-code:before{content:\"\\f121\"}.fa-code-branch:before{content:\"\\f126\"}.fa-codepen:before{content:\"\\f1cb\"}.fa-codiepie:before{content:\"\\f284\"}.fa-coffee:before{content:\"\\f0f4\"}.fa-cog:before{content:\"\\f013\"}.fa-cogs:before{content:\"\\f085\"}.fa-coins:before{content:\"\\f51e\"}.fa-columns:before{content:\"\\f0db\"}.fa-comment:before{content:\"\\f075\"}.fa-comment-alt:before{content:\"\\f27a\"}.fa-comment-dollar:before{content:\"\\f651\"}.fa-comment-dots:before{content:\"\\f4ad\"}.fa-comment-medical:before{content:\"\\f7f5\"}.fa-comment-slash:before{content:\"\\f4b3\"}.fa-comments:before{content:\"\\f086\"}.fa-comments-dollar:before{content:\"\\f653\"}.fa-compact-disc:before{content:\"\\f51f\"}.fa-compass:before{content:\"\\f14e\"}.fa-compress:before{content:\"\\f066\"}.fa-compress-alt:before{content:\"\\f422\"}.fa-compress-arrows-alt:before{content:\"\\f78c\"}.fa-concierge-bell:before{content:\"\\f562\"}.fa-confluence:before{content:\"\\f78d\"}.fa-connectdevelop:before{content:\"\\f20e\"}.fa-contao:before{content:\"\\f26d\"}.fa-cookie:before{content:\"\\f563\"}.fa-cookie-bite:before{content:\"\\f564\"}.fa-copy:before{content:\"\\f0c5\"}.fa-copyright:before{content:\"\\f1f9\"}.fa-cotton-bureau:before{content:\"\\f89e\"}.fa-couch:before{content:\"\\f4b8\"}.fa-cpanel:before{content:\"\\f388\"}.fa-creative-commons:before{content:\"\\f25e\"}.fa-creative-commons-by:before{content:\"\\f4e7\"}.fa-creative-commons-nc:before{content:\"\\f4e8\"}.fa-creative-commons-nc-eu:before{content:\"\\f4e9\"}.fa-creative-commons-nc-jp:before{content:\"\\f4ea\"}.fa-creative-commons-nd:before{content:\"\\f4eb\"}.fa-creative-commons-pd:before{content:\"\\f4ec\"}.fa-creative-commons-pd-alt:before{content:\"\\f4ed\"}.fa-creative-commons-remix:before{content:\"\\f4ee\"}.fa-creative-commons-sa:before{content:\"\\f4ef\"}.fa-creative-commons-sampling:before{content:\"\\f4f0\"}.fa-creative-commons-sampling-plus:before{content:\"\\f4f1\"}.fa-creative-commons-share:before{content:\"\\f4f2\"}.fa-creative-commons-zero:before{content:\"\\f4f3\"}.fa-credit-card:before{content:\"\\f09d\"}.fa-critical-role:before{content:\"\\f6c9\"}.fa-crop:before{content:\"\\f125\"}.fa-crop-alt:before{content:\"\\f565\"}.fa-cross:before{content:\"\\f654\"}.fa-crosshairs:before{content:\"\\f05b\"}.fa-crow:before{content:\"\\f520\"}.fa-crown:before{content:\"\\f521\"}.fa-crutch:before{content:\"\\f7f7\"}.fa-css3:before{content:\"\\f13c\"}.fa-css3-alt:before{content:\"\\f38b\"}.fa-cube:before{content:\"\\f1b2\"}.fa-cubes:before{content:\"\\f1b3\"}.fa-cut:before{content:\"\\f0c4\"}.fa-cuttlefish:before{content:\"\\f38c\"}.fa-d-and-d:before{content:\"\\f38d\"}.fa-d-and-d-beyond:before{content:\"\\f6ca\"}.fa-dailymotion:before{content:\"\\e052\"}.fa-dashcube:before{content:\"\\f210\"}.fa-database:before{content:\"\\f1c0\"}.fa-deaf:before{content:\"\\f2a4\"}.fa-deezer:before{content:\"\\e077\"}.fa-delicious:before{content:\"\\f1a5\"}.fa-democrat:before{content:\"\\f747\"}.fa-deploydog:before{content:\"\\f38e\"}.fa-deskpro:before{content:\"\\f38f\"}.fa-desktop:before{content:\"\\f108\"}.fa-dev:before{content:\"\\f6cc\"}.fa-deviantart:before{content:\"\\f1bd\"}.fa-dharmachakra:before{content:\"\\f655\"}.fa-dhl:before{content:\"\\f790\"}.fa-diagnoses:before{content:\"\\f470\"}.fa-diaspora:before{content:\"\\f791\"}.fa-dice:before{content:\"\\f522\"}.fa-dice-d20:before{content:\"\\f6cf\"}.fa-dice-d6:before{content:\"\\f6d1\"}.fa-dice-five:before{content:\"\\f523\"}.fa-dice-four:before{content:\"\\f524\"}.fa-dice-one:before{content:\"\\f525\"}.fa-dice-six:before{content:\"\\f526\"}.fa-dice-three:before{content:\"\\f527\"}.fa-dice-two:before{content:\"\\f528\"}.fa-digg:before{content:\"\\f1a6\"}.fa-digital-ocean:before{content:\"\\f391\"}.fa-digital-tachograph:before{content:\"\\f566\"}.fa-directions:before{content:\"\\f5eb\"}.fa-discord:before{content:\"\\f392\"}.fa-discourse:before{content:\"\\f393\"}.fa-disease:before{content:\"\\f7fa\"}.fa-divide:before{content:\"\\f529\"}.fa-dizzy:before{content:\"\\f567\"}.fa-dna:before{content:\"\\f471\"}.fa-dochub:before{content:\"\\f394\"}.fa-docker:before{content:\"\\f395\"}.fa-dog:before{content:\"\\f6d3\"}.fa-dollar-sign:before{content:\"\\f155\"}.fa-dolly:before{content:\"\\f472\"}.fa-dolly-flatbed:before{content:\"\\f474\"}.fa-donate:before{content:\"\\f4b9\"}.fa-door-closed:before{content:\"\\f52a\"}.fa-door-open:before{content:\"\\f52b\"}.fa-dot-circle:before{content:\"\\f192\"}.fa-dove:before{content:\"\\f4ba\"}.fa-download:before{content:\"\\f019\"}.fa-draft2digital:before{content:\"\\f396\"}.fa-drafting-compass:before{content:\"\\f568\"}.fa-dragon:before{content:\"\\f6d5\"}.fa-draw-polygon:before{content:\"\\f5ee\"}.fa-dribbble:before{content:\"\\f17d\"}.fa-dribbble-square:before{content:\"\\f397\"}.fa-dropbox:before{content:\"\\f16b\"}.fa-drum:before{content:\"\\f569\"}.fa-drum-steelpan:before{content:\"\\f56a\"}.fa-drumstick-bite:before{content:\"\\f6d7\"}.fa-drupal:before{content:\"\\f1a9\"}.fa-dumbbell:before{content:\"\\f44b\"}.fa-dumpster:before{content:\"\\f793\"}.fa-dumpster-fire:before{content:\"\\f794\"}.fa-dungeon:before{content:\"\\f6d9\"}.fa-dyalog:before{content:\"\\f399\"}.fa-earlybirds:before{content:\"\\f39a\"}.fa-ebay:before{content:\"\\f4f4\"}.fa-edge:before{content:\"\\f282\"}.fa-edge-legacy:before{content:\"\\e078\"}.fa-edit:before{content:\"\\f044\"}.fa-egg:before{content:\"\\f7fb\"}.fa-eject:before{content:\"\\f052\"}.fa-elementor:before{content:\"\\f430\"}.fa-ellipsis-h:before{content:\"\\f141\"}.fa-ellipsis-v:before{content:\"\\f142\"}.fa-ello:before{content:\"\\f5f1\"}.fa-ember:before{content:\"\\f423\"}.fa-empire:before{content:\"\\f1d1\"}.fa-envelope:before{content:\"\\f0e0\"}.fa-envelope-open:before{content:\"\\f2b6\"}.fa-envelope-open-text:before{content:\"\\f658\"}.fa-envelope-square:before{content:\"\\f199\"}.fa-envira:before{content:\"\\f299\"}.fa-equals:before{content:\"\\f52c\"}.fa-eraser:before{content:\"\\f12d\"}.fa-erlang:before{content:\"\\f39d\"}.fa-ethereum:before{content:\"\\f42e\"}.fa-ethernet:before{content:\"\\f796\"}.fa-etsy:before{content:\"\\f2d7\"}.fa-euro-sign:before{content:\"\\f153\"}.fa-evernote:before{content:\"\\f839\"}.fa-exchange-alt:before{content:\"\\f362\"}.fa-exclamation:before{content:\"\\f12a\"}.fa-exclamation-circle:before{content:\"\\f06a\"}.fa-exclamation-triangle:before{content:\"\\f071\"}.fa-expand:before{content:\"\\f065\"}.fa-expand-alt:before{content:\"\\f424\"}.fa-expand-arrows-alt:before{content:\"\\f31e\"}.fa-expeditedssl:before{content:\"\\f23e\"}.fa-external-link-alt:before{content:\"\\f35d\"}.fa-external-link-square-alt:before{content:\"\\f360\"}.fa-eye:before{content:\"\\f06e\"}.fa-eye-dropper:before{content:\"\\f1fb\"}.fa-eye-slash:before{content:\"\\f070\"}.fa-facebook:before{content:\"\\f09a\"}.fa-facebook-f:before{content:\"\\f39e\"}.fa-facebook-messenger:before{content:\"\\f39f\"}.fa-facebook-square:before{content:\"\\f082\"}.fa-fan:before{content:\"\\f863\"}.fa-fantasy-flight-games:before{content:\"\\f6dc\"}.fa-fast-backward:before{content:\"\\f049\"}.fa-fast-forward:before{content:\"\\f050\"}.fa-faucet:before{content:\"\\e005\"}.fa-fax:before{content:\"\\f1ac\"}.fa-feather:before{content:\"\\f52d\"}.fa-feather-alt:before{content:\"\\f56b\"}.fa-fedex:before{content:\"\\f797\"}.fa-fedora:before{content:\"\\f798\"}.fa-female:before{content:\"\\f182\"}.fa-fighter-jet:before{content:\"\\f0fb\"}.fa-figma:before{content:\"\\f799\"}.fa-file:before{content:\"\\f15b\"}.fa-file-alt:before{content:\"\\f15c\"}.fa-file-archive:before{content:\"\\f1c6\"}.fa-file-audio:before{content:\"\\f1c7\"}.fa-file-code:before{content:\"\\f1c9\"}.fa-file-contract:before{content:\"\\f56c\"}.fa-file-csv:before{content:\"\\f6dd\"}.fa-file-download:before{content:\"\\f56d\"}.fa-file-excel:before{content:\"\\f1c3\"}.fa-file-export:before{content:\"\\f56e\"}.fa-file-image:before{content:\"\\f1c5\"}.fa-file-import:before{content:\"\\f56f\"}.fa-file-invoice:before{content:\"\\f570\"}.fa-file-invoice-dollar:before{content:\"\\f571\"}.fa-file-medical:before{content:\"\\f477\"}.fa-file-medical-alt:before{content:\"\\f478\"}.fa-file-pdf:before{content:\"\\f1c1\"}.fa-file-powerpoint:before{content:\"\\f1c4\"}.fa-file-prescription:before{content:\"\\f572\"}.fa-file-signature:before{content:\"\\f573\"}.fa-file-upload:before{content:\"\\f574\"}.fa-file-video:before{content:\"\\f1c8\"}.fa-file-word:before{content:\"\\f1c2\"}.fa-fill:before{content:\"\\f575\"}.fa-fill-drip:before{content:\"\\f576\"}.fa-film:before{content:\"\\f008\"}.fa-filter:before{content:\"\\f0b0\"}.fa-fingerprint:before{content:\"\\f577\"}.fa-fire:before{content:\"\\f06d\"}.fa-fire-alt:before{content:\"\\f7e4\"}.fa-fire-extinguisher:before{content:\"\\f134\"}.fa-firefox:before{content:\"\\f269\"}.fa-firefox-browser:before{content:\"\\e007\"}.fa-first-aid:before{content:\"\\f479\"}.fa-first-order:before{content:\"\\f2b0\"}.fa-first-order-alt:before{content:\"\\f50a\"}.fa-firstdraft:before{content:\"\\f3a1\"}.fa-fish:before{content:\"\\f578\"}.fa-fist-raised:before{content:\"\\f6de\"}.fa-flag:before{content:\"\\f024\"}.fa-flag-checkered:before{content:\"\\f11e\"}.fa-flag-usa:before{content:\"\\f74d\"}.fa-flask:before{content:\"\\f0c3\"}.fa-flickr:before{content:\"\\f16e\"}.fa-flipboard:before{content:\"\\f44d\"}.fa-flushed:before{content:\"\\f579\"}.fa-fly:before{content:\"\\f417\"}.fa-folder:before{content:\"\\f07b\"}.fa-folder-minus:before{content:\"\\f65d\"}.fa-folder-open:before{content:\"\\f07c\"}.fa-folder-plus:before{content:\"\\f65e\"}.fa-font:before{content:\"\\f031\"}.fa-font-awesome:before{content:\"\\f2b4\"}.fa-font-awesome-alt:before{content:\"\\f35c\"}.fa-font-awesome-flag:before{content:\"\\f425\"}.fa-font-awesome-logo-full:before{content:\"\\f4e6\"}.fa-fonticons:before{content:\"\\f280\"}.fa-fonticons-fi:before{content:\"\\f3a2\"}.fa-football-ball:before{content:\"\\f44e\"}.fa-fort-awesome:before{content:\"\\f286\"}.fa-fort-awesome-alt:before{content:\"\\f3a3\"}.fa-forumbee:before{content:\"\\f211\"}.fa-forward:before{content:\"\\f04e\"}.fa-foursquare:before{content:\"\\f180\"}.fa-free-code-camp:before{content:\"\\f2c5\"}.fa-freebsd:before{content:\"\\f3a4\"}.fa-frog:before{content:\"\\f52e\"}.fa-frown:before{content:\"\\f119\"}.fa-frown-open:before{content:\"\\f57a\"}.fa-fulcrum:before{content:\"\\f50b\"}.fa-funnel-dollar:before{content:\"\\f662\"}.fa-futbol:before{content:\"\\f1e3\"}.fa-galactic-republic:before{content:\"\\f50c\"}.fa-galactic-senate:before{content:\"\\f50d\"}.fa-gamepad:before{content:\"\\f11b\"}.fa-gas-pump:before{content:\"\\f52f\"}.fa-gavel:before{content:\"\\f0e3\"}.fa-gem:before{content:\"\\f3a5\"}.fa-genderless:before{content:\"\\f22d\"}.fa-get-pocket:before{content:\"\\f265\"}.fa-gg:before{content:\"\\f260\"}.fa-gg-circle:before{content:\"\\f261\"}.fa-ghost:before{content:\"\\f6e2\"}.fa-gift:before{content:\"\\f06b\"}.fa-gifts:before{content:\"\\f79c\"}.fa-git:before{content:\"\\f1d3\"}.fa-git-alt:before{content:\"\\f841\"}.fa-git-square:before{content:\"\\f1d2\"}.fa-github:before{content:\"\\f09b\"}.fa-github-alt:before{content:\"\\f113\"}.fa-github-square:before{content:\"\\f092\"}.fa-gitkraken:before{content:\"\\f3a6\"}.fa-gitlab:before{content:\"\\f296\"}.fa-gitter:before{content:\"\\f426\"}.fa-glass-cheers:before{content:\"\\f79f\"}.fa-glass-martini:before{content:\"\\f000\"}.fa-glass-martini-alt:before{content:\"\\f57b\"}.fa-glass-whiskey:before{content:\"\\f7a0\"}.fa-glasses:before{content:\"\\f530\"}.fa-glide:before{content:\"\\f2a5\"}.fa-glide-g:before{content:\"\\f2a6\"}.fa-globe:before{content:\"\\f0ac\"}.fa-globe-africa:before{content:\"\\f57c\"}.fa-globe-americas:before{content:\"\\f57d\"}.fa-globe-asia:before{content:\"\\f57e\"}.fa-globe-europe:before{content:\"\\f7a2\"}.fa-gofore:before{content:\"\\f3a7\"}.fa-golf-ball:before{content:\"\\f450\"}.fa-goodreads:before{content:\"\\f3a8\"}.fa-goodreads-g:before{content:\"\\f3a9\"}.fa-google:before{content:\"\\f1a0\"}.fa-google-drive:before{content:\"\\f3aa\"}.fa-google-pay:before{content:\"\\e079\"}.fa-google-play:before{content:\"\\f3ab\"}.fa-google-plus:before{content:\"\\f2b3\"}.fa-google-plus-g:before{content:\"\\f0d5\"}.fa-google-plus-square:before{content:\"\\f0d4\"}.fa-google-wallet:before{content:\"\\f1ee\"}.fa-gopuram:before{content:\"\\f664\"}.fa-graduation-cap:before{content:\"\\f19d\"}.fa-gratipay:before{content:\"\\f184\"}.fa-grav:before{content:\"\\f2d6\"}.fa-greater-than:before{content:\"\\f531\"}.fa-greater-than-equal:before{content:\"\\f532\"}.fa-grimace:before{content:\"\\f57f\"}.fa-grin:before{content:\"\\f580\"}.fa-grin-alt:before{content:\"\\f581\"}.fa-grin-beam:before{content:\"\\f582\"}.fa-grin-beam-sweat:before{content:\"\\f583\"}.fa-grin-hearts:before{content:\"\\f584\"}.fa-grin-squint:before{content:\"\\f585\"}.fa-grin-squint-tears:before{content:\"\\f586\"}.fa-grin-stars:before{content:\"\\f587\"}.fa-grin-tears:before{content:\"\\f588\"}.fa-grin-tongue:before{content:\"\\f589\"}.fa-grin-tongue-squint:before{content:\"\\f58a\"}.fa-grin-tongue-wink:before{content:\"\\f58b\"}.fa-grin-wink:before{content:\"\\f58c\"}.fa-grip-horizontal:before{content:\"\\f58d\"}.fa-grip-lines:before{content:\"\\f7a4\"}.fa-grip-lines-vertical:before{content:\"\\f7a5\"}.fa-grip-vertical:before{content:\"\\f58e\"}.fa-gripfire:before{content:\"\\f3ac\"}.fa-grunt:before{content:\"\\f3ad\"}.fa-guilded:before{content:\"\\e07e\"}.fa-guitar:before{content:\"\\f7a6\"}.fa-gulp:before{content:\"\\f3ae\"}.fa-h-square:before{content:\"\\f0fd\"}.fa-hacker-news:before{content:\"\\f1d4\"}.fa-hacker-news-square:before{content:\"\\f3af\"}.fa-hackerrank:before{content:\"\\f5f7\"}.fa-hamburger:before{content:\"\\f805\"}.fa-hammer:before{content:\"\\f6e3\"}.fa-hamsa:before{content:\"\\f665\"}.fa-hand-holding:before{content:\"\\f4bd\"}.fa-hand-holding-heart:before{content:\"\\f4be\"}.fa-hand-holding-medical:before{content:\"\\e05c\"}.fa-hand-holding-usd:before{content:\"\\f4c0\"}.fa-hand-holding-water:before{content:\"\\f4c1\"}.fa-hand-lizard:before{content:\"\\f258\"}.fa-hand-middle-finger:before{content:\"\\f806\"}.fa-hand-paper:before{content:\"\\f256\"}.fa-hand-peace:before{content:\"\\f25b\"}.fa-hand-point-down:before{content:\"\\f0a7\"}.fa-hand-point-left:before{content:\"\\f0a5\"}.fa-hand-point-right:before{content:\"\\f0a4\"}.fa-hand-point-up:before{content:\"\\f0a6\"}.fa-hand-pointer:before{content:\"\\f25a\"}.fa-hand-rock:before{content:\"\\f255\"}.fa-hand-scissors:before{content:\"\\f257\"}.fa-hand-sparkles:before{content:\"\\e05d\"}.fa-hand-spock:before{content:\"\\f259\"}.fa-hands:before{content:\"\\f4c2\"}.fa-hands-helping:before{content:\"\\f4c4\"}.fa-hands-wash:before{content:\"\\e05e\"}.fa-handshake:before{content:\"\\f2b5\"}.fa-handshake-alt-slash:before{content:\"\\e05f\"}.fa-handshake-slash:before{content:\"\\e060\"}.fa-hanukiah:before{content:\"\\f6e6\"}.fa-hard-hat:before{content:\"\\f807\"}.fa-hashtag:before{content:\"\\f292\"}.fa-hat-cowboy:before{content:\"\\f8c0\"}.fa-hat-cowboy-side:before{content:\"\\f8c1\"}.fa-hat-wizard:before{content:\"\\f6e8\"}.fa-hdd:before{content:\"\\f0a0\"}.fa-head-side-cough:before{content:\"\\e061\"}.fa-head-side-cough-slash:before{content:\"\\e062\"}.fa-head-side-mask:before{content:\"\\e063\"}.fa-head-side-virus:before{content:\"\\e064\"}.fa-heading:before{content:\"\\f1dc\"}.fa-headphones:before{content:\"\\f025\"}.fa-headphones-alt:before{content:\"\\f58f\"}.fa-headset:before{content:\"\\f590\"}.fa-heart:before{content:\"\\f004\"}.fa-heart-broken:before{content:\"\\f7a9\"}.fa-heartbeat:before{content:\"\\f21e\"}.fa-helicopter:before{content:\"\\f533\"}.fa-highlighter:before{content:\"\\f591\"}.fa-hiking:before{content:\"\\f6ec\"}.fa-hippo:before{content:\"\\f6ed\"}.fa-hips:before{content:\"\\f452\"}.fa-hire-a-helper:before{content:\"\\f3b0\"}.fa-history:before{content:\"\\f1da\"}.fa-hive:before{content:\"\\e07f\"}.fa-hockey-puck:before{content:\"\\f453\"}.fa-holly-berry:before{content:\"\\f7aa\"}.fa-home:before{content:\"\\f015\"}.fa-hooli:before{content:\"\\f427\"}.fa-hornbill:before{content:\"\\f592\"}.fa-horse:before{content:\"\\f6f0\"}.fa-horse-head:before{content:\"\\f7ab\"}.fa-hospital:before{content:\"\\f0f8\"}.fa-hospital-alt:before{content:\"\\f47d\"}.fa-hospital-symbol:before{content:\"\\f47e\"}.fa-hospital-user:before{content:\"\\f80d\"}.fa-hot-tub:before{content:\"\\f593\"}.fa-hotdog:before{content:\"\\f80f\"}.fa-hotel:before{content:\"\\f594\"}.fa-hotjar:before{content:\"\\f3b1\"}.fa-hourglass:before{content:\"\\f254\"}.fa-hourglass-end:before{content:\"\\f253\"}.fa-hourglass-half:before{content:\"\\f252\"}.fa-hourglass-start:before{content:\"\\f251\"}.fa-house-damage:before{content:\"\\f6f1\"}.fa-house-user:before{content:\"\\e065\"}.fa-houzz:before{content:\"\\f27c\"}.fa-hryvnia:before{content:\"\\f6f2\"}.fa-html5:before{content:\"\\f13b\"}.fa-hubspot:before{content:\"\\f3b2\"}.fa-i-cursor:before{content:\"\\f246\"}.fa-ice-cream:before{content:\"\\f810\"}.fa-icicles:before{content:\"\\f7ad\"}.fa-icons:before{content:\"\\f86d\"}.fa-id-badge:before{content:\"\\f2c1\"}.fa-id-card:before{content:\"\\f2c2\"}.fa-id-card-alt:before{content:\"\\f47f\"}.fa-ideal:before{content:\"\\e013\"}.fa-igloo:before{content:\"\\f7ae\"}.fa-image:before{content:\"\\f03e\"}.fa-images:before{content:\"\\f302\"}.fa-imdb:before{content:\"\\f2d8\"}.fa-inbox:before{content:\"\\f01c\"}.fa-indent:before{content:\"\\f03c\"}.fa-industry:before{content:\"\\f275\"}.fa-infinity:before{content:\"\\f534\"}.fa-info:before{content:\"\\f129\"}.fa-info-circle:before{content:\"\\f05a\"}.fa-innosoft:before{content:\"\\e080\"}.fa-instagram:before{content:\"\\f16d\"}.fa-instagram-square:before{content:\"\\e055\"}.fa-instalod:before{content:\"\\e081\"}.fa-intercom:before{content:\"\\f7af\"}.fa-internet-explorer:before{content:\"\\f26b\"}.fa-invision:before{content:\"\\f7b0\"}.fa-ioxhost:before{content:\"\\f208\"}.fa-italic:before{content:\"\\f033\"}.fa-itch-io:before{content:\"\\f83a\"}.fa-itunes:before{content:\"\\f3b4\"}.fa-itunes-note:before{content:\"\\f3b5\"}.fa-java:before{content:\"\\f4e4\"}.fa-jedi:before{content:\"\\f669\"}.fa-jedi-order:before{content:\"\\f50e\"}.fa-jenkins:before{content:\"\\f3b6\"}.fa-jira:before{content:\"\\f7b1\"}.fa-joget:before{content:\"\\f3b7\"}.fa-joint:before{content:\"\\f595\"}.fa-joomla:before{content:\"\\f1aa\"}.fa-journal-whills:before{content:\"\\f66a\"}.fa-js:before{content:\"\\f3b8\"}.fa-js-square:before{content:\"\\f3b9\"}.fa-jsfiddle:before{content:\"\\f1cc\"}.fa-kaaba:before{content:\"\\f66b\"}.fa-kaggle:before{content:\"\\f5fa\"}.fa-key:before{content:\"\\f084\"}.fa-keybase:before{content:\"\\f4f5\"}.fa-keyboard:before{content:\"\\f11c\"}.fa-keycdn:before{content:\"\\f3ba\"}.fa-khanda:before{content:\"\\f66d\"}.fa-kickstarter:before{content:\"\\f3bb\"}.fa-kickstarter-k:before{content:\"\\f3bc\"}.fa-kiss:before{content:\"\\f596\"}.fa-kiss-beam:before{content:\"\\f597\"}.fa-kiss-wink-heart:before{content:\"\\f598\"}.fa-kiwi-bird:before{content:\"\\f535\"}.fa-korvue:before{content:\"\\f42f\"}.fa-landmark:before{content:\"\\f66f\"}.fa-language:before{content:\"\\f1ab\"}.fa-laptop:before{content:\"\\f109\"}.fa-laptop-code:before{content:\"\\f5fc\"}.fa-laptop-house:before{content:\"\\e066\"}.fa-laptop-medical:before{content:\"\\f812\"}.fa-laravel:before{content:\"\\f3bd\"}.fa-lastfm:before{content:\"\\f202\"}.fa-lastfm-square:before{content:\"\\f203\"}.fa-laugh:before{content:\"\\f599\"}.fa-laugh-beam:before{content:\"\\f59a\"}.fa-laugh-squint:before{content:\"\\f59b\"}.fa-laugh-wink:before{content:\"\\f59c\"}.fa-layer-group:before{content:\"\\f5fd\"}.fa-leaf:before{content:\"\\f06c\"}.fa-leanpub:before{content:\"\\f212\"}.fa-lemon:before{content:\"\\f094\"}.fa-less:before{content:\"\\f41d\"}.fa-less-than:before{content:\"\\f536\"}.fa-less-than-equal:before{content:\"\\f537\"}.fa-level-down-alt:before{content:\"\\f3be\"}.fa-level-up-alt:before{content:\"\\f3bf\"}.fa-life-ring:before{content:\"\\f1cd\"}.fa-lightbulb:before{content:\"\\f0eb\"}.fa-line:before{content:\"\\f3c0\"}.fa-link:before{content:\"\\f0c1\"}.fa-linkedin:before{content:\"\\f08c\"}.fa-linkedin-in:before{content:\"\\f0e1\"}.fa-linode:before{content:\"\\f2b8\"}.fa-linux:before{content:\"\\f17c\"}.fa-lira-sign:before{content:\"\\f195\"}.fa-list:before{content:\"\\f03a\"}.fa-list-alt:before{content:\"\\f022\"}.fa-list-ol:before{content:\"\\f0cb\"}.fa-list-ul:before{content:\"\\f0ca\"}.fa-location-arrow:before{content:\"\\f124\"}.fa-lock:before{content:\"\\f023\"}.fa-lock-open:before{content:\"\\f3c1\"}.fa-long-arrow-alt-down:before{content:\"\\f309\"}.fa-long-arrow-alt-left:before{content:\"\\f30a\"}.fa-long-arrow-alt-right:before{content:\"\\f30b\"}.fa-long-arrow-alt-up:before{content:\"\\f30c\"}.fa-low-vision:before{content:\"\\f2a8\"}.fa-luggage-cart:before{content:\"\\f59d\"}.fa-lungs:before{content:\"\\f604\"}.fa-lungs-virus:before{content:\"\\e067\"}.fa-lyft:before{content:\"\\f3c3\"}.fa-magento:before{content:\"\\f3c4\"}.fa-magic:before{content:\"\\f0d0\"}.fa-magnet:before{content:\"\\f076\"}.fa-mail-bulk:before{content:\"\\f674\"}.fa-mailchimp:before{content:\"\\f59e\"}.fa-male:before{content:\"\\f183\"}.fa-mandalorian:before{content:\"\\f50f\"}.fa-map:before{content:\"\\f279\"}.fa-map-marked:before{content:\"\\f59f\"}.fa-map-marked-alt:before{content:\"\\f5a0\"}.fa-map-marker:before{content:\"\\f041\"}.fa-map-marker-alt:before{content:\"\\f3c5\"}.fa-map-pin:before{content:\"\\f276\"}.fa-map-signs:before{content:\"\\f277\"}.fa-markdown:before{content:\"\\f60f\"}.fa-marker:before{content:\"\\f5a1\"}.fa-mars:before{content:\"\\f222\"}.fa-mars-double:before{content:\"\\f227\"}.fa-mars-stroke:before{content:\"\\f229\"}.fa-mars-stroke-h:before{content:\"\\f22b\"}.fa-mars-stroke-v:before{content:\"\\f22a\"}.fa-mask:before{content:\"\\f6fa\"}.fa-mastodon:before{content:\"\\f4f6\"}.fa-maxcdn:before{content:\"\\f136\"}.fa-mdb:before{content:\"\\f8ca\"}.fa-medal:before{content:\"\\f5a2\"}.fa-medapps:before{content:\"\\f3c6\"}.fa-medium:before{content:\"\\f23a\"}.fa-medium-m:before{content:\"\\f3c7\"}.fa-medkit:before{content:\"\\f0fa\"}.fa-medrt:before{content:\"\\f3c8\"}.fa-meetup:before{content:\"\\f2e0\"}.fa-megaport:before{content:\"\\f5a3\"}.fa-meh:before{content:\"\\f11a\"}.fa-meh-blank:before{content:\"\\f5a4\"}.fa-meh-rolling-eyes:before{content:\"\\f5a5\"}.fa-memory:before{content:\"\\f538\"}.fa-mendeley:before{content:\"\\f7b3\"}.fa-menorah:before{content:\"\\f676\"}.fa-mercury:before{content:\"\\f223\"}.fa-meteor:before{content:\"\\f753\"}.fa-microblog:before{content:\"\\e01a\"}.fa-microchip:before{content:\"\\f2db\"}.fa-microphone:before{content:\"\\f130\"}.fa-microphone-alt:before{content:\"\\f3c9\"}.fa-microphone-alt-slash:before{content:\"\\f539\"}.fa-microphone-slash:before{content:\"\\f131\"}.fa-microscope:before{content:\"\\f610\"}.fa-microsoft:before{content:\"\\f3ca\"}.fa-minus:before{content:\"\\f068\"}.fa-minus-circle:before{content:\"\\f056\"}.fa-minus-square:before{content:\"\\f146\"}.fa-mitten:before{content:\"\\f7b5\"}.fa-mix:before{content:\"\\f3cb\"}.fa-mixcloud:before{content:\"\\f289\"}.fa-mixer:before{content:\"\\e056\"}.fa-mizuni:before{content:\"\\f3cc\"}.fa-mobile:before{content:\"\\f10b\"}.fa-mobile-alt:before{content:\"\\f3cd\"}.fa-modx:before{content:\"\\f285\"}.fa-monero:before{content:\"\\f3d0\"}.fa-money-bill:before{content:\"\\f0d6\"}.fa-money-bill-alt:before{content:\"\\f3d1\"}.fa-money-bill-wave:before{content:\"\\f53a\"}.fa-money-bill-wave-alt:before{content:\"\\f53b\"}.fa-money-check:before{content:\"\\f53c\"}.fa-money-check-alt:before{content:\"\\f53d\"}.fa-monument:before{content:\"\\f5a6\"}.fa-moon:before{content:\"\\f186\"}.fa-mortar-pestle:before{content:\"\\f5a7\"}.fa-mosque:before{content:\"\\f678\"}.fa-motorcycle:before{content:\"\\f21c\"}.fa-mountain:before{content:\"\\f6fc\"}.fa-mouse:before{content:\"\\f8cc\"}.fa-mouse-pointer:before{content:\"\\f245\"}.fa-mug-hot:before{content:\"\\f7b6\"}.fa-music:before{content:\"\\f001\"}.fa-napster:before{content:\"\\f3d2\"}.fa-neos:before{content:\"\\f612\"}.fa-network-wired:before{content:\"\\f6ff\"}.fa-neuter:before{content:\"\\f22c\"}.fa-newspaper:before{content:\"\\f1ea\"}.fa-nimblr:before{content:\"\\f5a8\"}.fa-node:before{content:\"\\f419\"}.fa-node-js:before{content:\"\\f3d3\"}.fa-not-equal:before{content:\"\\f53e\"}.fa-notes-medical:before{content:\"\\f481\"}.fa-npm:before{content:\"\\f3d4\"}.fa-ns8:before{content:\"\\f3d5\"}.fa-nutritionix:before{content:\"\\f3d6\"}.fa-object-group:before{content:\"\\f247\"}.fa-object-ungroup:before{content:\"\\f248\"}.fa-octopus-deploy:before{content:\"\\e082\"}.fa-odnoklassniki:before{content:\"\\f263\"}.fa-odnoklassniki-square:before{content:\"\\f264\"}.fa-oil-can:before{content:\"\\f613\"}.fa-old-republic:before{content:\"\\f510\"}.fa-om:before{content:\"\\f679\"}.fa-opencart:before{content:\"\\f23d\"}.fa-openid:before{content:\"\\f19b\"}.fa-opera:before{content:\"\\f26a\"}.fa-optin-monster:before{content:\"\\f23c\"}.fa-orcid:before{content:\"\\f8d2\"}.fa-osi:before{content:\"\\f41a\"}.fa-otter:before{content:\"\\f700\"}.fa-outdent:before{content:\"\\f03b\"}.fa-page4:before{content:\"\\f3d7\"}.fa-pagelines:before{content:\"\\f18c\"}.fa-pager:before{content:\"\\f815\"}.fa-paint-brush:before{content:\"\\f1fc\"}.fa-paint-roller:before{content:\"\\f5aa\"}.fa-palette:before{content:\"\\f53f\"}.fa-palfed:before{content:\"\\f3d8\"}.fa-pallet:before{content:\"\\f482\"}.fa-paper-plane:before{content:\"\\f1d8\"}.fa-paperclip:before{content:\"\\f0c6\"}.fa-parachute-box:before{content:\"\\f4cd\"}.fa-paragraph:before{content:\"\\f1dd\"}.fa-parking:before{content:\"\\f540\"}.fa-passport:before{content:\"\\f5ab\"}.fa-pastafarianism:before{content:\"\\f67b\"}.fa-paste:before{content:\"\\f0ea\"}.fa-patreon:before{content:\"\\f3d9\"}.fa-pause:before{content:\"\\f04c\"}.fa-pause-circle:before{content:\"\\f28b\"}.fa-paw:before{content:\"\\f1b0\"}.fa-paypal:before{content:\"\\f1ed\"}.fa-peace:before{content:\"\\f67c\"}.fa-pen:before{content:\"\\f304\"}.fa-pen-alt:before{content:\"\\f305\"}.fa-pen-fancy:before{content:\"\\f5ac\"}.fa-pen-nib:before{content:\"\\f5ad\"}.fa-pen-square:before{content:\"\\f14b\"}.fa-pencil-alt:before{content:\"\\f303\"}.fa-pencil-ruler:before{content:\"\\f5ae\"}.fa-penny-arcade:before{content:\"\\f704\"}.fa-people-arrows:before{content:\"\\e068\"}.fa-people-carry:before{content:\"\\f4ce\"}.fa-pepper-hot:before{content:\"\\f816\"}.fa-perbyte:before{content:\"\\e083\"}.fa-percent:before{content:\"\\f295\"}.fa-percentage:before{content:\"\\f541\"}.fa-periscope:before{content:\"\\f3da\"}.fa-person-booth:before{content:\"\\f756\"}.fa-phabricator:before{content:\"\\f3db\"}.fa-phoenix-framework:before{content:\"\\f3dc\"}.fa-phoenix-squadron:before{content:\"\\f511\"}.fa-phone:before{content:\"\\f095\"}.fa-phone-alt:before{content:\"\\f879\"}.fa-phone-slash:before{content:\"\\f3dd\"}.fa-phone-square:before{content:\"\\f098\"}.fa-phone-square-alt:before{content:\"\\f87b\"}.fa-phone-volume:before{content:\"\\f2a0\"}.fa-photo-video:before{content:\"\\f87c\"}.fa-php:before{content:\"\\f457\"}.fa-pied-piper:before{content:\"\\f2ae\"}.fa-pied-piper-alt:before{content:\"\\f1a8\"}.fa-pied-piper-hat:before{content:\"\\f4e5\"}.fa-pied-piper-pp:before{content:\"\\f1a7\"}.fa-pied-piper-square:before{content:\"\\e01e\"}.fa-piggy-bank:before{content:\"\\f4d3\"}.fa-pills:before{content:\"\\f484\"}.fa-pinterest:before{content:\"\\f0d2\"}.fa-pinterest-p:before{content:\"\\f231\"}.fa-pinterest-square:before{content:\"\\f0d3\"}.fa-pizza-slice:before{content:\"\\f818\"}.fa-place-of-worship:before{content:\"\\f67f\"}.fa-plane:before{content:\"\\f072\"}.fa-plane-arrival:before{content:\"\\f5af\"}.fa-plane-departure:before{content:\"\\f5b0\"}.fa-plane-slash:before{content:\"\\e069\"}.fa-play:before{content:\"\\f04b\"}.fa-play-circle:before{content:\"\\f144\"}.fa-playstation:before{content:\"\\f3df\"}.fa-plug:before{content:\"\\f1e6\"}.fa-plus:before{content:\"\\f067\"}.fa-plus-circle:before{content:\"\\f055\"}.fa-plus-square:before{content:\"\\f0fe\"}.fa-podcast:before{content:\"\\f2ce\"}.fa-poll:before{content:\"\\f681\"}.fa-poll-h:before{content:\"\\f682\"}.fa-poo:before{content:\"\\f2fe\"}.fa-poo-storm:before{content:\"\\f75a\"}.fa-poop:before{content:\"\\f619\"}.fa-portrait:before{content:\"\\f3e0\"}.fa-pound-sign:before{content:\"\\f154\"}.fa-power-off:before{content:\"\\f011\"}.fa-pray:before{content:\"\\f683\"}.fa-praying-hands:before{content:\"\\f684\"}.fa-prescription:before{content:\"\\f5b1\"}.fa-prescription-bottle:before{content:\"\\f485\"}.fa-prescription-bottle-alt:before{content:\"\\f486\"}.fa-print:before{content:\"\\f02f\"}.fa-procedures:before{content:\"\\f487\"}.fa-product-hunt:before{content:\"\\f288\"}.fa-project-diagram:before{content:\"\\f542\"}.fa-pump-medical:before{content:\"\\e06a\"}.fa-pump-soap:before{content:\"\\e06b\"}.fa-pushed:before{content:\"\\f3e1\"}.fa-puzzle-piece:before{content:\"\\f12e\"}.fa-python:before{content:\"\\f3e2\"}.fa-qq:before{content:\"\\f1d6\"}.fa-qrcode:before{content:\"\\f029\"}.fa-question:before{content:\"\\f128\"}.fa-question-circle:before{content:\"\\f059\"}.fa-quidditch:before{content:\"\\f458\"}.fa-quinscape:before{content:\"\\f459\"}.fa-quora:before{content:\"\\f2c4\"}.fa-quote-left:before{content:\"\\f10d\"}.fa-quote-right:before{content:\"\\f10e\"}.fa-quran:before{content:\"\\f687\"}.fa-r-project:before{content:\"\\f4f7\"}.fa-radiation:before{content:\"\\f7b9\"}.fa-radiation-alt:before{content:\"\\f7ba\"}.fa-rainbow:before{content:\"\\f75b\"}.fa-random:before{content:\"\\f074\"}.fa-raspberry-pi:before{content:\"\\f7bb\"}.fa-ravelry:before{content:\"\\f2d9\"}.fa-react:before{content:\"\\f41b\"}.fa-reacteurope:before{content:\"\\f75d\"}.fa-readme:before{content:\"\\f4d5\"}.fa-rebel:before{content:\"\\f1d0\"}.fa-receipt:before{content:\"\\f543\"}.fa-record-vinyl:before{content:\"\\f8d9\"}.fa-recycle:before{content:\"\\f1b8\"}.fa-red-river:before{content:\"\\f3e3\"}.fa-reddit:before{content:\"\\f1a1\"}.fa-reddit-alien:before{content:\"\\f281\"}.fa-reddit-square:before{content:\"\\f1a2\"}.fa-redhat:before{content:\"\\f7bc\"}.fa-redo:before{content:\"\\f01e\"}.fa-redo-alt:before{content:\"\\f2f9\"}.fa-registered:before{content:\"\\f25d\"}.fa-remove-format:before{content:\"\\f87d\"}.fa-renren:before{content:\"\\f18b\"}.fa-reply:before{content:\"\\f3e5\"}.fa-reply-all:before{content:\"\\f122\"}.fa-replyd:before{content:\"\\f3e6\"}.fa-republican:before{content:\"\\f75e\"}.fa-researchgate:before{content:\"\\f4f8\"}.fa-resolving:before{content:\"\\f3e7\"}.fa-restroom:before{content:\"\\f7bd\"}.fa-retweet:before{content:\"\\f079\"}.fa-rev:before{content:\"\\f5b2\"}.fa-ribbon:before{content:\"\\f4d6\"}.fa-ring:before{content:\"\\f70b\"}.fa-road:before{content:\"\\f018\"}.fa-robot:before{content:\"\\f544\"}.fa-rocket:before{content:\"\\f135\"}.fa-rocketchat:before{content:\"\\f3e8\"}.fa-rockrms:before{content:\"\\f3e9\"}.fa-route:before{content:\"\\f4d7\"}.fa-rss:before{content:\"\\f09e\"}.fa-rss-square:before{content:\"\\f143\"}.fa-ruble-sign:before{content:\"\\f158\"}.fa-ruler:before{content:\"\\f545\"}.fa-ruler-combined:before{content:\"\\f546\"}.fa-ruler-horizontal:before{content:\"\\f547\"}.fa-ruler-vertical:before{content:\"\\f548\"}.fa-running:before{content:\"\\f70c\"}.fa-rupee-sign:before{content:\"\\f156\"}.fa-rust:before{content:\"\\e07a\"}.fa-sad-cry:before{content:\"\\f5b3\"}.fa-sad-tear:before{content:\"\\f5b4\"}.fa-safari:before{content:\"\\f267\"}.fa-salesforce:before{content:\"\\f83b\"}.fa-sass:before{content:\"\\f41e\"}.fa-satellite:before{content:\"\\f7bf\"}.fa-satellite-dish:before{content:\"\\f7c0\"}.fa-save:before{content:\"\\f0c7\"}.fa-schlix:before{content:\"\\f3ea\"}.fa-school:before{content:\"\\f549\"}.fa-screwdriver:before{content:\"\\f54a\"}.fa-scribd:before{content:\"\\f28a\"}.fa-scroll:before{content:\"\\f70e\"}.fa-sd-card:before{content:\"\\f7c2\"}.fa-search:before{content:\"\\f002\"}.fa-search-dollar:before{content:\"\\f688\"}.fa-search-location:before{content:\"\\f689\"}.fa-search-minus:before{content:\"\\f010\"}.fa-search-plus:before{content:\"\\f00e\"}.fa-searchengin:before{content:\"\\f3eb\"}.fa-seedling:before{content:\"\\f4d8\"}.fa-sellcast:before{content:\"\\f2da\"}.fa-sellsy:before{content:\"\\f213\"}.fa-server:before{content:\"\\f233\"}.fa-servicestack:before{content:\"\\f3ec\"}.fa-shapes:before{content:\"\\f61f\"}.fa-share:before{content:\"\\f064\"}.fa-share-alt:before{content:\"\\f1e0\"}.fa-share-alt-square:before{content:\"\\f1e1\"}.fa-share-square:before{content:\"\\f14d\"}.fa-shekel-sign:before{content:\"\\f20b\"}.fa-shield-alt:before{content:\"\\f3ed\"}.fa-shield-virus:before{content:\"\\e06c\"}.fa-ship:before{content:\"\\f21a\"}.fa-shipping-fast:before{content:\"\\f48b\"}.fa-shirtsinbulk:before{content:\"\\f214\"}.fa-shoe-prints:before{content:\"\\f54b\"}.fa-shopify:before{content:\"\\e057\"}.fa-shopping-bag:before{content:\"\\f290\"}.fa-shopping-basket:before{content:\"\\f291\"}.fa-shopping-cart:before{content:\"\\f07a\"}.fa-shopware:before{content:\"\\f5b5\"}.fa-shower:before{content:\"\\f2cc\"}.fa-shuttle-van:before{content:\"\\f5b6\"}.fa-sign:before{content:\"\\f4d9\"}.fa-sign-in-alt:before{content:\"\\f2f6\"}.fa-sign-language:before{content:\"\\f2a7\"}.fa-sign-out-alt:before{content:\"\\f2f5\"}.fa-signal:before{content:\"\\f012\"}.fa-signature:before{content:\"\\f5b7\"}.fa-sim-card:before{content:\"\\f7c4\"}.fa-simplybuilt:before{content:\"\\f215\"}.fa-sink:before{content:\"\\e06d\"}.fa-sistrix:before{content:\"\\f3ee\"}.fa-sitemap:before{content:\"\\f0e8\"}.fa-sith:before{content:\"\\f512\"}.fa-skating:before{content:\"\\f7c5\"}.fa-sketch:before{content:\"\\f7c6\"}.fa-skiing:before{content:\"\\f7c9\"}.fa-skiing-nordic:before{content:\"\\f7ca\"}.fa-skull:before{content:\"\\f54c\"}.fa-skull-crossbones:before{content:\"\\f714\"}.fa-skyatlas:before{content:\"\\f216\"}.fa-skype:before{content:\"\\f17e\"}.fa-slack:before{content:\"\\f198\"}.fa-slack-hash:before{content:\"\\f3ef\"}.fa-slash:before{content:\"\\f715\"}.fa-sleigh:before{content:\"\\f7cc\"}.fa-sliders-h:before{content:\"\\f1de\"}.fa-slideshare:before{content:\"\\f1e7\"}.fa-smile:before{content:\"\\f118\"}.fa-smile-beam:before{content:\"\\f5b8\"}.fa-smile-wink:before{content:\"\\f4da\"}.fa-smog:before{content:\"\\f75f\"}.fa-smoking:before{content:\"\\f48d\"}.fa-smoking-ban:before{content:\"\\f54d\"}.fa-sms:before{content:\"\\f7cd\"}.fa-snapchat:before{content:\"\\f2ab\"}.fa-snapchat-ghost:before{content:\"\\f2ac\"}.fa-snapchat-square:before{content:\"\\f2ad\"}.fa-snowboarding:before{content:\"\\f7ce\"}.fa-snowflake:before{content:\"\\f2dc\"}.fa-snowman:before{content:\"\\f7d0\"}.fa-snowplow:before{content:\"\\f7d2\"}.fa-soap:before{content:\"\\e06e\"}.fa-socks:before{content:\"\\f696\"}.fa-solar-panel:before{content:\"\\f5ba\"}.fa-sort:before{content:\"\\f0dc\"}.fa-sort-alpha-down:before{content:\"\\f15d\"}.fa-sort-alpha-down-alt:before{content:\"\\f881\"}.fa-sort-alpha-up:before{content:\"\\f15e\"}.fa-sort-alpha-up-alt:before{content:\"\\f882\"}.fa-sort-amount-down:before{content:\"\\f160\"}.fa-sort-amount-down-alt:before{content:\"\\f884\"}.fa-sort-amount-up:before{content:\"\\f161\"}.fa-sort-amount-up-alt:before{content:\"\\f885\"}.fa-sort-down:before{content:\"\\f0dd\"}.fa-sort-numeric-down:before{content:\"\\f162\"}.fa-sort-numeric-down-alt:before{content:\"\\f886\"}.fa-sort-numeric-up:before{content:\"\\f163\"}.fa-sort-numeric-up-alt:before{content:\"\\f887\"}.fa-sort-up:before{content:\"\\f0de\"}.fa-soundcloud:before{content:\"\\f1be\"}.fa-sourcetree:before{content:\"\\f7d3\"}.fa-spa:before{content:\"\\f5bb\"}.fa-space-shuttle:before{content:\"\\f197\"}.fa-speakap:before{content:\"\\f3f3\"}.fa-speaker-deck:before{content:\"\\f83c\"}.fa-spell-check:before{content:\"\\f891\"}.fa-spider:before{content:\"\\f717\"}.fa-spinner:before{content:\"\\f110\"}.fa-splotch:before{content:\"\\f5bc\"}.fa-spotify:before{content:\"\\f1bc\"}.fa-spray-can:before{content:\"\\f5bd\"}.fa-square:before{content:\"\\f0c8\"}.fa-square-full:before{content:\"\\f45c\"}.fa-square-root-alt:before{content:\"\\f698\"}.fa-squarespace:before{content:\"\\f5be\"}.fa-stack-exchange:before{content:\"\\f18d\"}.fa-stack-overflow:before{content:\"\\f16c\"}.fa-stackpath:before{content:\"\\f842\"}.fa-stamp:before{content:\"\\f5bf\"}.fa-star:before{content:\"\\f005\"}.fa-star-and-crescent:before{content:\"\\f699\"}.fa-star-half:before{content:\"\\f089\"}.fa-star-half-alt:before{content:\"\\f5c0\"}.fa-star-of-david:before{content:\"\\f69a\"}.fa-star-of-life:before{content:\"\\f621\"}.fa-staylinked:before{content:\"\\f3f5\"}.fa-steam:before{content:\"\\f1b6\"}.fa-steam-square:before{content:\"\\f1b7\"}.fa-steam-symbol:before{content:\"\\f3f6\"}.fa-step-backward:before{content:\"\\f048\"}.fa-step-forward:before{content:\"\\f051\"}.fa-stethoscope:before{content:\"\\f0f1\"}.fa-sticker-mule:before{content:\"\\f3f7\"}.fa-sticky-note:before{content:\"\\f249\"}.fa-stop:before{content:\"\\f04d\"}.fa-stop-circle:before{content:\"\\f28d\"}.fa-stopwatch:before{content:\"\\f2f2\"}.fa-stopwatch-20:before{content:\"\\e06f\"}.fa-store:before{content:\"\\f54e\"}.fa-store-alt:before{content:\"\\f54f\"}.fa-store-alt-slash:before{content:\"\\e070\"}.fa-store-slash:before{content:\"\\e071\"}.fa-strava:before{content:\"\\f428\"}.fa-stream:before{content:\"\\f550\"}.fa-street-view:before{content:\"\\f21d\"}.fa-strikethrough:before{content:\"\\f0cc\"}.fa-stripe:before{content:\"\\f429\"}.fa-stripe-s:before{content:\"\\f42a\"}.fa-stroopwafel:before{content:\"\\f551\"}.fa-studiovinari:before{content:\"\\f3f8\"}.fa-stumbleupon:before{content:\"\\f1a4\"}.fa-stumbleupon-circle:before{content:\"\\f1a3\"}.fa-subscript:before{content:\"\\f12c\"}.fa-subway:before{content:\"\\f239\"}.fa-suitcase:before{content:\"\\f0f2\"}.fa-suitcase-rolling:before{content:\"\\f5c1\"}.fa-sun:before{content:\"\\f185\"}.fa-superpowers:before{content:\"\\f2dd\"}.fa-superscript:before{content:\"\\f12b\"}.fa-supple:before{content:\"\\f3f9\"}.fa-surprise:before{content:\"\\f5c2\"}.fa-suse:before{content:\"\\f7d6\"}.fa-swatchbook:before{content:\"\\f5c3\"}.fa-swift:before{content:\"\\f8e1\"}.fa-swimmer:before{content:\"\\f5c4\"}.fa-swimming-pool:before{content:\"\\f5c5\"}.fa-symfony:before{content:\"\\f83d\"}.fa-synagogue:before{content:\"\\f69b\"}.fa-sync:before{content:\"\\f021\"}.fa-sync-alt:before{content:\"\\f2f1\"}.fa-syringe:before{content:\"\\f48e\"}.fa-table:before{content:\"\\f0ce\"}.fa-table-tennis:before{content:\"\\f45d\"}.fa-tablet:before{content:\"\\f10a\"}.fa-tablet-alt:before{content:\"\\f3fa\"}.fa-tablets:before{content:\"\\f490\"}.fa-tachometer-alt:before{content:\"\\f3fd\"}.fa-tag:before{content:\"\\f02b\"}.fa-tags:before{content:\"\\f02c\"}.fa-tape:before{content:\"\\f4db\"}.fa-tasks:before{content:\"\\f0ae\"}.fa-taxi:before{content:\"\\f1ba\"}.fa-teamspeak:before{content:\"\\f4f9\"}.fa-teeth:before{content:\"\\f62e\"}.fa-teeth-open:before{content:\"\\f62f\"}.fa-telegram:before{content:\"\\f2c6\"}.fa-telegram-plane:before{content:\"\\f3fe\"}.fa-temperature-high:before{content:\"\\f769\"}.fa-temperature-low:before{content:\"\\f76b\"}.fa-tencent-weibo:before{content:\"\\f1d5\"}.fa-tenge:before{content:\"\\f7d7\"}.fa-terminal:before{content:\"\\f120\"}.fa-text-height:before{content:\"\\f034\"}.fa-text-width:before{content:\"\\f035\"}.fa-th:before{content:\"\\f00a\"}.fa-th-large:before{content:\"\\f009\"}.fa-th-list:before{content:\"\\f00b\"}.fa-the-red-yeti:before{content:\"\\f69d\"}.fa-theater-masks:before{content:\"\\f630\"}.fa-themeco:before{content:\"\\f5c6\"}.fa-themeisle:before{content:\"\\f2b2\"}.fa-thermometer:before{content:\"\\f491\"}.fa-thermometer-empty:before{content:\"\\f2cb\"}.fa-thermometer-full:before{content:\"\\f2c7\"}.fa-thermometer-half:before{content:\"\\f2c9\"}.fa-thermometer-quarter:before{content:\"\\f2ca\"}.fa-thermometer-three-quarters:before{content:\"\\f2c8\"}.fa-think-peaks:before{content:\"\\f731\"}.fa-thumbs-down:before{content:\"\\f165\"}.fa-thumbs-up:before{content:\"\\f164\"}.fa-thumbtack:before{content:\"\\f08d\"}.fa-ticket-alt:before{content:\"\\f3ff\"}.fa-tiktok:before{content:\"\\e07b\"}.fa-times:before{content:\"\\f00d\"}.fa-times-circle:before{content:\"\\f057\"}.fa-tint:before{content:\"\\f043\"}.fa-tint-slash:before{content:\"\\f5c7\"}.fa-tired:before{content:\"\\f5c8\"}.fa-toggle-off:before{content:\"\\f204\"}.fa-toggle-on:before{content:\"\\f205\"}.fa-toilet:before{content:\"\\f7d8\"}.fa-toilet-paper:before{content:\"\\f71e\"}.fa-toilet-paper-slash:before{content:\"\\e072\"}.fa-toolbox:before{content:\"\\f552\"}.fa-tools:before{content:\"\\f7d9\"}.fa-tooth:before{content:\"\\f5c9\"}.fa-torah:before{content:\"\\f6a0\"}.fa-torii-gate:before{content:\"\\f6a1\"}.fa-tractor:before{content:\"\\f722\"}.fa-trade-federation:before{content:\"\\f513\"}.fa-trademark:before{content:\"\\f25c\"}.fa-traffic-light:before{content:\"\\f637\"}.fa-trailer:before{content:\"\\e041\"}.fa-train:before{content:\"\\f238\"}.fa-tram:before{content:\"\\f7da\"}.fa-transgender:before{content:\"\\f224\"}.fa-transgender-alt:before{content:\"\\f225\"}.fa-trash:before{content:\"\\f1f8\"}.fa-trash-alt:before{content:\"\\f2ed\"}.fa-trash-restore:before{content:\"\\f829\"}.fa-trash-restore-alt:before{content:\"\\f82a\"}.fa-tree:before{content:\"\\f1bb\"}.fa-trello:before{content:\"\\f181\"}.fa-trophy:before{content:\"\\f091\"}.fa-truck:before{content:\"\\f0d1\"}.fa-truck-loading:before{content:\"\\f4de\"}.fa-truck-monster:before{content:\"\\f63b\"}.fa-truck-moving:before{content:\"\\f4df\"}.fa-truck-pickup:before{content:\"\\f63c\"}.fa-tshirt:before{content:\"\\f553\"}.fa-tty:before{content:\"\\f1e4\"}.fa-tumblr:before{content:\"\\f173\"}.fa-tumblr-square:before{content:\"\\f174\"}.fa-tv:before{content:\"\\f26c\"}.fa-twitch:before{content:\"\\f1e8\"}.fa-twitter:before{content:\"\\f099\"}.fa-twitter-square:before{content:\"\\f081\"}.fa-typo3:before{content:\"\\f42b\"}.fa-uber:before{content:\"\\f402\"}.fa-ubuntu:before{content:\"\\f7df\"}.fa-uikit:before{content:\"\\f403\"}.fa-umbraco:before{content:\"\\f8e8\"}.fa-umbrella:before{content:\"\\f0e9\"}.fa-umbrella-beach:before{content:\"\\f5ca\"}.fa-uncharted:before{content:\"\\e084\"}.fa-underline:before{content:\"\\f0cd\"}.fa-undo:before{content:\"\\f0e2\"}.fa-undo-alt:before{content:\"\\f2ea\"}.fa-uniregistry:before{content:\"\\f404\"}.fa-unity:before{content:\"\\e049\"}.fa-universal-access:before{content:\"\\f29a\"}.fa-university:before{content:\"\\f19c\"}.fa-unlink:before{content:\"\\f127\"}.fa-unlock:before{content:\"\\f09c\"}.fa-unlock-alt:before{content:\"\\f13e\"}.fa-unsplash:before{content:\"\\e07c\"}.fa-untappd:before{content:\"\\f405\"}.fa-upload:before{content:\"\\f093\"}.fa-ups:before{content:\"\\f7e0\"}.fa-usb:before{content:\"\\f287\"}.fa-user:before{content:\"\\f007\"}.fa-user-alt:before{content:\"\\f406\"}.fa-user-alt-slash:before{content:\"\\f4fa\"}.fa-user-astronaut:before{content:\"\\f4fb\"}.fa-user-check:before{content:\"\\f4fc\"}.fa-user-circle:before{content:\"\\f2bd\"}.fa-user-clock:before{content:\"\\f4fd\"}.fa-user-cog:before{content:\"\\f4fe\"}.fa-user-edit:before{content:\"\\f4ff\"}.fa-user-friends:before{content:\"\\f500\"}.fa-user-graduate:before{content:\"\\f501\"}.fa-user-injured:before{content:\"\\f728\"}.fa-user-lock:before{content:\"\\f502\"}.fa-user-md:before{content:\"\\f0f0\"}.fa-user-minus:before{content:\"\\f503\"}.fa-user-ninja:before{content:\"\\f504\"}.fa-user-nurse:before{content:\"\\f82f\"}.fa-user-plus:before{content:\"\\f234\"}.fa-user-secret:before{content:\"\\f21b\"}.fa-user-shield:before{content:\"\\f505\"}.fa-user-slash:before{content:\"\\f506\"}.fa-user-tag:before{content:\"\\f507\"}.fa-user-tie:before{content:\"\\f508\"}.fa-user-times:before{content:\"\\f235\"}.fa-users:before{content:\"\\f0c0\"}.fa-users-cog:before{content:\"\\f509\"}.fa-users-slash:before{content:\"\\e073\"}.fa-usps:before{content:\"\\f7e1\"}.fa-ussunnah:before{content:\"\\f407\"}.fa-utensil-spoon:before{content:\"\\f2e5\"}.fa-utensils:before{content:\"\\f2e7\"}.fa-vaadin:before{content:\"\\f408\"}.fa-vector-square:before{content:\"\\f5cb\"}.fa-venus:before{content:\"\\f221\"}.fa-venus-double:before{content:\"\\f226\"}.fa-venus-mars:before{content:\"\\f228\"}.fa-vest:before{content:\"\\e085\"}.fa-vest-patches:before{content:\"\\e086\"}.fa-viacoin:before{content:\"\\f237\"}.fa-viadeo:before{content:\"\\f2a9\"}.fa-viadeo-square:before{content:\"\\f2aa\"}.fa-vial:before{content:\"\\f492\"}.fa-vials:before{content:\"\\f493\"}.fa-viber:before{content:\"\\f409\"}.fa-video:before{content:\"\\f03d\"}.fa-video-slash:before{content:\"\\f4e2\"}.fa-vihara:before{content:\"\\f6a7\"}.fa-vimeo:before{content:\"\\f40a\"}.fa-vimeo-square:before{content:\"\\f194\"}.fa-vimeo-v:before{content:\"\\f27d\"}.fa-vine:before{content:\"\\f1ca\"}.fa-virus:before{content:\"\\e074\"}.fa-virus-slash:before{content:\"\\e075\"}.fa-viruses:before{content:\"\\e076\"}.fa-vk:before{content:\"\\f189\"}.fa-vnv:before{content:\"\\f40b\"}.fa-voicemail:before{content:\"\\f897\"}.fa-volleyball-ball:before{content:\"\\f45f\"}.fa-volume-down:before{content:\"\\f027\"}.fa-volume-mute:before{content:\"\\f6a9\"}.fa-volume-off:before{content:\"\\f026\"}.fa-volume-up:before{content:\"\\f028\"}.fa-vote-yea:before{content:\"\\f772\"}.fa-vr-cardboard:before{content:\"\\f729\"}.fa-vuejs:before{content:\"\\f41f\"}.fa-walking:before{content:\"\\f554\"}.fa-wallet:before{content:\"\\f555\"}.fa-warehouse:before{content:\"\\f494\"}.fa-watchman-monitoring:before{content:\"\\e087\"}.fa-water:before{content:\"\\f773\"}.fa-wave-square:before{content:\"\\f83e\"}.fa-waze:before{content:\"\\f83f\"}.fa-weebly:before{content:\"\\f5cc\"}.fa-weibo:before{content:\"\\f18a\"}.fa-weight:before{content:\"\\f496\"}.fa-weight-hanging:before{content:\"\\f5cd\"}.fa-weixin:before{content:\"\\f1d7\"}.fa-whatsapp:before{content:\"\\f232\"}.fa-whatsapp-square:before{content:\"\\f40c\"}.fa-wheelchair:before{content:\"\\f193\"}.fa-whmcs:before{content:\"\\f40d\"}.fa-wifi:before{content:\"\\f1eb\"}.fa-wikipedia-w:before{content:\"\\f266\"}.fa-wind:before{content:\"\\f72e\"}.fa-window-close:before{content:\"\\f410\"}.fa-window-maximize:before{content:\"\\f2d0\"}.fa-window-minimize:before{content:\"\\f2d1\"}.fa-window-restore:before{content:\"\\f2d2\"}.fa-windows:before{content:\"\\f17a\"}.fa-wine-bottle:before{content:\"\\f72f\"}.fa-wine-glass:before{content:\"\\f4e3\"}.fa-wine-glass-alt:before{content:\"\\f5ce\"}.fa-wix:before{content:\"\\f5cf\"}.fa-wizards-of-the-coast:before{content:\"\\f730\"}.fa-wodu:before{content:\"\\e088\"}.fa-wolf-pack-battalion:before{content:\"\\f514\"}.fa-won-sign:before{content:\"\\f159\"}.fa-wordpress:before{content:\"\\f19a\"}.fa-wordpress-simple:before{content:\"\\f411\"}.fa-wpbeginner:before{content:\"\\f297\"}.fa-wpexplorer:before{content:\"\\f2de\"}.fa-wpforms:before{content:\"\\f298\"}.fa-wpressr:before{content:\"\\f3e4\"}.fa-wrench:before{content:\"\\f0ad\"}.fa-x-ray:before{content:\"\\f497\"}.fa-xbox:before{content:\"\\f412\"}.fa-xing:before{content:\"\\f168\"}.fa-xing-square:before{content:\"\\f169\"}.fa-y-combinator:before{content:\"\\f23b\"}.fa-yahoo:before{content:\"\\f19e\"}.fa-yammer:before{content:\"\\f840\"}.fa-yandex:before{content:\"\\f413\"}.fa-yandex-international:before{content:\"\\f414\"}.fa-yarn:before{content:\"\\f7e3\"}.fa-yelp:before{content:\"\\f1e9\"}.fa-yen-sign:before{content:\"\\f157\"}.fa-yin-yang:before{content:\"\\f6ad\"}.fa-yoast:before{content:\"\\f2b1\"}.fa-youtube:before{content:\"\\f167\"}.fa-youtube-square:before{content:\"\\f431\"}.fa-zhihu:before{content:\"\\f63f\"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/index.css",
    "content": "\na,\na:focus,\na:hover {\n    color: #fff;\n}\n\n.btn-default,\n.btn-default:hover,\n.btn-default:focus {\n    color: #333;\n    text-shadow: none;\n    background-color: #fff;\n    border: 1px solid #fff;\n}\n\nhtml,\nbody {\n    height: 100%;\n    background-color: #454545;\n    /*background-image: url(../img/bg1.jpg);*/\n    background-size: cover;\n}\n\nbody {\n    color: #fff;\n    text-align: center;\n    text-shadow: 0 1px 3px rgba(0, 0, 0, .5);\n}\n\n.site-wrapper {\n    display: table;\n    width: 100%;\n    height: 100%;\n    min-height: 100%;\n    -webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .5);\n    box-shadow: inset 0 0 100px rgba(0, 0, 0, .5);\n}\n\n.site-wrapper-inner {\n    display: table-cell;\n    vertical-align: top;\n}\n\n.cover-container {\n    margin-right: auto;\n    margin-left: auto;\n}\n\n.inner {\n    padding: 30px;\n}\n\n.masthead-brand {\n    margin-top: 10px;\n    margin-bottom: 10px;\n}\n\n.masthead-nav > li {\n    display: inline-block;\n}\n\n.masthead-nav > li + li {\n    margin-left: 20px;\n}\n\n.masthead-nav > li > a {\n    padding-right: 0;\n    padding-left: 0;\n    font-size: 16px;\n    font-weight: bold;\n    color: #fff;\n    color: rgba(255, 255, 255, .75);\n    border-bottom: 2px solid transparent;\n}\n\n.masthead-nav > li > a:hover,\n.masthead-nav > li > a:focus {\n    background-color: transparent;\n    border-bottom-color: #a9a9a9;\n    border-bottom-color: rgba(255, 255, 255, .25);\n}\n\n.masthead-nav > .active > a,\n.masthead-nav > .active > a:hover,\n.masthead-nav > .active > a:focus {\n    color: #fff;\n    border-bottom-color: #fff;\n}\n\n@media (min-width: 768px) {\n    .masthead-brand {\n        float: left;\n    }\n\n    .masthead-nav {\n        float: right;\n    }\n}\n\n.cover {\n    padding: 0 20px;\n}\n\n.cover .btn-lg {\n    padding: 10px 20px;\n    font-weight: bold;\n}\n\n.mastfoot {\n    color: #999;\n    color: rgba(255, 255, 255, .5);\n}\n\n@media (min-width: 768px) {\n    .masthead {\n        position: fixed;\n        top: 0;\n    }\n\n    .mastfoot {\n        position: fixed;\n        bottom: 0;\n    }\n\n    .site-wrapper-inner {\n        vertical-align: middle;\n    }\n\n    .masthead,\n    .mastfoot,\n    .cover-container {\n        width: 100%;\n    }\n}\n\n@media (min-width: 992px) {\n    .masthead,\n    .mastfoot,\n    .cover-container {\n        width: 700px;\n    }\n}\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/jquery.treetable.css",
    "content": "table.treetable span.indenter {\n  display: inline-block;\n  margin: 0;\n  padding: 0;\n  text-align: right;\n\n  /* Disable text selection of nodes (for better D&D UX) */\n  user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -o-user-select: none;\n  -webkit-user-select: none;\n\n  /* Force content-box box model for indenter (Bootstrap compatibility) */\n  -webkit-box-sizing: content-box;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n\n  width: 19px;\n}\n\ntable.treetable span.indenter a {\n  background-position: left center;\n  background-repeat: no-repeat;\n  display: inline-block;\n  text-decoration: none;\n  width: 19px;\n}\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/jquery.treetable.theme.default.css",
    "content": "table.treetable {\n  /*border: 1px solid #888;*/\n  /*border-collapse: collapse;*/\n  /*font-size: .8em;*/\n  /*line-height: 1;*/\n  /*margin: .6em 0 1.8em 0;*/\n  /*width: 100%;*/\n}\n\ntable.treetable caption {\n  /*font-size: .9em;*/\n  /*font-weight: bold;*/\n  /*margin-bottom: .2em;*/\n}\n\ntable.treetable thead {\n  background-color: #fcfcfc;\n}\n\ntable.treetable thead tr th {\n  /*border: 1px solid #888;*/\n  /*font-weight: normal;*/\n  /*padding: .3em 1em .1em 1em;*/\n  /*text-align: left;*/\n}\n\ntable.treetable tbody tr td {\n  /*cursor: default;*/\n  /*padding: .3em 1em;*/\n}\n\ntable.treetable span {\n  /*background-position: center left;*/\n  /*background-repeat: no-repeat;*/\n  /*padding: .2em 0 .2em 1.5em;*/\n}\n\ntable.treetable span.file {\n  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADoSURBVBgZBcExblNBGAbA2ceegTRBuIKOgiihSZNTcC5LUHAihNJR0kGKCDcYJY6D3/77MdOinTvzAgCw8ysThIvn/VojIyMjIyPP+bS1sUQIV2s95pBDDvmbP/mdkft83tpYguZq5Jh/OeaYh+yzy8hTHvNlaxNNczm+la9OTlar1UdA/+C2A4trRCnD3jS8BB1obq2Gk6GU6QbQAS4BUaYSQAf4bhhKKTFdAzrAOwAxEUAH+KEM01SY3gM6wBsEAQB0gJ+maZoC3gI6iPYaAIBJsiRmHU0AALOeFC3aK2cWAACUXe7+AwO0lc9eTHYTAAAAAElFTkSuQmCC);\n}\n\ntable.treetable span.folder {\n  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGrSURBVDjLxZO7ihRBFIa/6u0ZW7GHBUV0UQQTZzd3QdhMQxOfwMRXEANBMNQX0MzAzFAwEzHwARbNFDdwEd31Mj3X7a6uOr9BtzNjYjKBJ6nicP7v3KqcJFaxhBVtZUAK8OHlld2st7Xl3DJPVONP+zEUV4HqL5UDYHr5xvuQAjgl/Qs7TzvOOVAjxjlC+ePSwe6DfbVegLVuT4r14eTr6zvA8xSAoBLzx6pvj4l+DZIezuVkG9fY2H7YRQIMZIBwycmzH1/s3F8AapfIPNF3kQk7+kw9PWBy+IZOdg5Ug3mkAATy/t0usovzGeCUWTjCz0B+Sj0ekfdvkZ3abBv+U4GaCtJ1iEm6ANQJ6fEzrG/engcKw/wXQvEKxSEKQxRGKE7Izt+DSiwBJMUSm71rguMYhQKrBygOIRStf4TiFFRBvbRGKiQLWP29yRSHKBTtfdBmHs0BUpgvtgF4yRFR+NUKi0XZcYjCeCG2smkzLAHkbRBmP0/Uk26O5YnUActBp1GsAI+S5nRJJJal5K1aAMrq0d6Tm9uI6zjyf75dAe6tx/SsWeD//o2/Ab6IH3/h25pOAAAAAElFTkSuQmCC);\n}\n\ntable.treetable tr.collapsed span.indenter a {\n  background-image: url(data:image/png;base64,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);\n}\n\ntable.treetable tr.expanded span.indenter a {\n  background-image: url(data:image/png;base64,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);\n}\n\ntable.treetable tr.branch {\n  /*background-color: #f9f9f9;*/\n}\n\ntable.treetable tr.selected {\n  background-color: #8DADE2FF;\n  color: #fff;\n}\n\ntable.treetable tr span.indenter a {\n  outline: none; /* Expander shows outline after upgrading to 3.0 (#141) */\n}\n\ntable.treetable tr.collapsed.selected span.indenter a {\n  background-image: url(data:image/png;base64,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);\n}\n\ntable.treetable tr.expanded.selected span.indenter a {\n  background-image: url(data:image/png;base64,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);\n}\n\ntable.treetable tr.accept {\n  background-color: #a3bce4;\n  color: #fff\n}\n\ntable.treetable tr.collapsed.accept td span.indenter a {\n  background-image: url(data:image/x-png;base64,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);\n}\n\ntable.treetable tr.expanded.accept td span.indenter a {\n  background-image: url(data:image/x-png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAFtJREFUeNpi/P//PwMlgImBQsA44C6giQENDAwM//HgBmLCAF/AMBLjBUeixf///48L7/+PCvZjU4fPAAc0AxywqcMXCwegGJ1NckL6jx5wpKYDxqGXEkkCgAEAmrqBIejdgngAAAAASUVORK5CYII=);\n}\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/login.css",
    "content": "/*html, body {*/\n/*  height: 100%;*/\n/*}*/\n\n/*body {*/\n/*  display: flex;*/\n/*  align-items: center;*/\n/*  padding-top: 40px;*/\n/*  padding-bottom: 40px;*/\n/*  background-color: #f5f5f5;*/\n/*}*/\n\n/*.form-signin {*/\n/*  max-width: 330px;*/\n/*  padding: 15px;*/\n/*}*/\n\n/*#signinTab > li > a.active {*/\n/*  margin-bottom: 10px;*/\n/*  border-bottom: 2px solid cornflowerblue;*/\n/*}*/\n\n/*.form-signin .input-group > * {*/\n/*  font-size: 14px;*/\n/*  margin-top: -1px;*/\n/*  border-radius: 0;*/\n/*}*/\n\n/*.form-signin input[type=\"text\"], .form-signin input[type=\"password\"] {*/\n/*  height: 44px;*/\n/*}*/\n\n/*.form-signin .checkbox {*/\n/*  margin-top: 5px;*/\n/*}*/\n\n/*.wt-100{*/\n/*  width: 100px;*/\n/*  padding: 2px;*/\n/*}*/\n\n/*.sms-code-btu {*/\n/*  font-size: 12px;*/\n/*  border: 0;*/\n/*  height: 100%;*/\n/*  color: #3c3c3c;*/\n/*  width: 100%;*/\n/*}*/\n\n/*.form-signin .input-invalid {*/\n/*  font-size: 12px;*/\n/*  padding: 2px;*/\n/*  text-align: left;*/\n/*  color: #dc3545;*/\n/*}*/\n\n/*.form-signin .input-group-invalid > .input-group-text {*/\n/*  border: 1px solid #dc3545;*/\n/*  color: #dc3545;*/\n/*}*/\n\n/*.form-signin .input-group-valid > .input-group-text {*/\n/*  border: 1px solid #198754;*/\n/*  color: #198754;*/\n/*}*/\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/login1.css",
    "content": ":root {\n    --primary-color: #2174FF;\n    --error-color: #ff4d4f;\n    --text-black-color: rgba(0, 0, 0, 0.9);\n    --text-gray-color: rgba(0, 0, 0, 0.5);\n    --text-primary-color: #478DFF;\n    --code-bgcolor: #FFFFFF;\n    --code-border-color: #DDDDDD;\n    --input-bgcolor: #FFFFFF;\n    --input-border-color: #DDDDDD;\n    --slider-color: rgba(255, 255, 255, 0.5);\n    --slider-captcha-bg: rgba(255, 255, 255, 1);\n    --slider-thumb-color: #0b0b0b;\n    --slider-track-bg: #eee;\n    --code-text-color: rgba(71, 141, 255, 1);\n    --disabled-color: rgba(255, 255, 255, 1);\n    --disabled-submit-bg: rgba(181, 199, 255, 1);\n    --code-disabled-color: rgba(71, 141, 255, 0.4);\n    --code-disabled-bg: #eee;\n}\n\nbody {\n    margin: 0;\n    min-height: 100vh;\n    font-family: 'Orbitron', sans-serif;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n}\n\n.login-container {\n    padding-bottom: 100px;\n    border-radius: 8px;\n    width: 100%;\n    max-width: 420px;\n}\n\n.login-title {\n    font-size: 36px;\n    font-weight: normal;\n    margin: 0;\n    margin-bottom: 40px;\n    color: var(--text-black-color);\n}\n\n.tabs {\n    display: flex;\n    margin-bottom: 24px;\n    /* border-bottom: 1px solid #eee; */\n}\n\n.tab {\n    padding: 12px 20px;\n    cursor: pointer;\n    color: var(--text-gray-color);\n    /* border-bottom: 3px solid transparent; */\n    transition: all 0.3s;\n    position: relative;\n}\n\n.tab::after {\n    content: \"\";\n    position: absolute;\n    bottom: 0;\n    left: 0;\n    width: 100%;\n    height: 3px;\n    border-radius: 100px 100px 0px 0px;\n    background-color: transparent;\n}\n\n.tab.active {\n    color: var(--text-black-color);\n    border-bottom-color: var(--primary-color);\n}\n\n.tab.active::after {\n    background-color: var(--primary-color);\n}\n\n.form-group label {\n    display: block;\n    margin-bottom: 8px;\n    color: var(--text-black-color);\n    font-weight: 500;\n}\n\n.input {\n    width: calc(100% - 18px);\n    padding: 14px 0px 14px 16px;\n    /* 增加左侧padding */\n    border: 1px solid var(--input-border-color);\n    /* border-color: var(--input-border-color); */\n    background-color: var(--input-bgcolor) !important;\n    border-radius: 4px;\n    font-size: 14px;\n    transition: border-color 0.3s;\n    font-size: 14px;\n    line-height: 22px;\n    color: var(--text-black-color);\n}\n\n.dark-box .input:autofill {\n    box-shadow: 0 0 0 1000px rgb(17 17 17) inset !important;\n    border-color: rgb(64 64 64);\n}\n\n.light-box .input:autofill {\n    box-shadow: 0 0 0 1000px var(--input-bgcolor) inset !important;\n    border-color: var(--input-border-color);\n}\n\n.input:-internal-autofill-previewed,\n.input:-internal-autofill-selected {\n    -webkit-text-fill-color: var(--text-black-color) !important;\n    transition: background-color 5000s ease-in-out 0s !important;\n}\n\n.input:focus {\n    outline: none;\n    border-color: var(--primary-color) !important;\n    background-color: var(--input-bgcolor) !important;\n    color: var(--text-black-color) !important;\n}\n\n\n.password {\n    width: calc(100% - 52px);\n}\n\n/* 新增图标容器样式 */\n.input-wrapper {\n    position: relative;\n    margin-bottom: 4px;\n}\n\n.input-sub-wrapper {\n    width: 300px;\n}\n\n/* 修改错误提示定位方式 */\n.form-group > .error {\n    color: #ff4d4f;\n    font-size: 10px;\n}\n\n/* 增加表单组最小高度 */\n.form-group {\n    position: relative;\n    min-height: 74px;\n    /* 保持固定高度避免跳动 */\n}\n\n.input-icon {\n    position: absolute;\n    left: 15px;\n    top: 50%;\n    transform: translateY(-50%);\n    color: var(--primary-color);\n    width: 16px;\n    height: 16px;\n}\n\n.captcha-row {\n    display: flex;\n    gap: 10px;\n}\n\n.captcha-img {\n    border: 1px solid var(--code-border-color);\n    border-radius: 4px;\n    cursor: pointer;\n    width: 110px;\n    height: 50px;\n    color: var(--text-gray-color);\n}\n\n.sms-code-row {\n    display: flex;\n    gap: 10px;\n}\n\n.get-code-btn {\n    color: var(--code-text-color);\n    border: 1px solid var(--code-border-color);\n    padding: 0 15px;\n    border-radius: 4px;\n    cursor: pointer;\n    transition: opacity 0.3s;\n    width: 110px;\n    height: 52px;\n    background-color: var(--code-bgcolor);\n}\n\n.get-code-btn:disabled {\n    color: var(--code-disabled-color);\n    background-color: var(--code-disabled-bg);\n    cursor: not-allowed;\n}\n\n.submit-btn {\n    width: 100%;\n    background: var(--primary-color);\n    color: white;\n    padding: 8px;\n    margin-bottom: 20px;\n    border: none;\n    border-radius: 4px;\n    font-size: 16px;\n    line-height: 36px;\n    cursor: pointer;\n    transition: opacity 0.3s;\n}\n\n.submit-btn:disabled {\n    color: var(--disabled-color);\n    background-color: var(--disabled-submit-bg);\n    cursor: not-allowed;\n\n    &:hover {\n        opacity: 1;\n    }\n}\n\n.submit-btn:hover {\n    opacity: 0.9;\n}\n\n.error-message {\n    color: var(--error-color);\n    font-size: 12px;\n    margin-top: 2px;\n    display: none;\n    height: 20px;\n    /* 固定错误信息高度 */\n}\n\ninput.invalid {\n    border-color: var(--error-color);\n}\n\ninput.invalid + .error-message {\n    display: block;\n}\n\n/* 新增错误提示样式 */\n.error-alert {\n    position: fixed;\n    top: 20px;\n    background: #ff4444;\n    color: white;\n    padding: 12px 20px;\n    border-radius: 6px;\n    display: flex;\n    align-items: center;\n    gap: 10px;\n    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n    cursor: pointer;\n    transition: 0.3s all;\n    z-index: 1000;\n}\n\n.error-alert:hover {\n    transform: translateY(-2px);\n    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n}\n\n.close-icon {\n    width: 18px;\n    height: 18px;\n    opacity: 0.8;\n}\n\n.close-icon:hover {\n    opacity: 1;\n}\n\n#wechat_qrcode {\n    text-align: center;\n    height: 272px;\n}\n\n.login-page-container {\n    width: 100vw;\n    height: 100vh;\n    display: flex;\n}\n\n.lft-container {\n    width: 35%;\n    height: 100%;\n    position: relative;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.lft-container .gb {\n    width: 100%;\n    height: 100%;\n    position: absolute;\n    left: 0;\n    top: 0;\n    z-index: 4;\n}\n\n.lft-container .logo {\n    position: relative;\n    z-index: 5;\n}\n\n.lft-container p {\n    position: absolute;\n    width: 100%;\n    font-size: 16px;\n    line-height: 24px;\n    font-weight: 400;\n    color: rgba(255, 255, 255, 0.9);\n    bottom: 40px;\n    z-index: 5;\n    text-align: center;\n    margin: 0;\n}\n\n.rgt-container {\n    height: 100%;\n    width: 65%;\n    position: relative;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.dark-box {\n    background: #181818;\n}\n\n.light-box {\n    background: #FFFFFF;\n}\n\n.switch-container {\n    width: 60px;\n    height: 32px;\n    position: absolute;\n    right: 24px;\n    top: 24px;\n    border-radius: 4px;\n    box-sizing: border-box;\n    user-select: none;\n}\n\n.switch-container > .switch-inner {\n    width: 100%;\n    height: 100%;\n    border-radius: 4px;\n}\n\n.switch-inner > .inner-box {\n    width: 100%;\n    height: 100%;\n    border-radius: 4px;\n    display: flex;\n    align-items: center;\n    padding: 2px;\n    box-sizing: border-box;\n}\n\n.switch-container > .switch-inner .switch-item {\n    flex: 1;\n    height: 100%;\n    border-radius: 4px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    cursor: pointer;\n}\n\n.switch-inner > .inner-box img {\n    width: 16px;\n    height: 16px;\n}\n\n.light-inner .switch-item:first-child {\n    background: #FFFFFF;\n    box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1);\n}\n\n.light-switch {\n    background: #EEEEEE;\n}\n\n.light-switch > .light-inner {\n    display: block;\n}\n\n.light-switch > .dark-inner {\n    display: none;\n}\n\n.dark-switch {\n    background: #383838;\n}\n\n.dark-switch > .light-inner {\n    display: none;\n}\n\n.dark-switch > .dark-inner {\n    display: block;\n}\n\n.dark-inner .switch-item:last-child {\n    background: #4B4B4B;\n    box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1);\n}\n\n.record-text {\n    width: 100%;\n    position: absolute;\n    bottom: 40px;\n    left: 0;\n    font-size: 16px;\n    font-weight: normal;\n    line-height: 24px;\n    text-align: center;\n    letter-spacing: normal;\n    color: var(--text-gray-color);\n    margin: 0;\n}\n\n.record-text > span {\n    color: var(--text-primary-color);\n}\n\n.slider-captcha {\n    height: 50px;\n    display: flex;\n    align-items: center;\n    border: 1px solid var(--code-border-color);\n    background-color: var(--slider-captcha-bg) !important;\n    border-radius: 4px;\n    font-size: 14px;\n    transition: border-color 0.3s;\n    font-size: 14px;\n    line-height: 22px;\n    color: var(--text-black-color);\n    position: relative;\n    overflow: hidden;\n}\n\n.slider-track {\n    height: 100%;\n    width: 0;\n    background-color: var(--slider-track-bg);\n    z-index: 1;\n}\n\n.slider-captcha.success {\n    background-color: var(--input-bgcolor) !important;\n}\n\n.slider-thumb {\n    width: 58px;\n    height: 50px;\n    border: 1px solid var(--input-border-color);\n    border-radius: 4px;\n    position: absolute;\n    left: 0;\n    cursor: move;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    /* transition: left 0.3s; */\n    z-index: 2;\n    background-color: var(--input-bgcolor);\n}\n\n.slider-thumb.success {\n    color: rgba(70, 182, 91, 1);\n}\n\n.slider-title {\n    position: absolute;\n    left: 0;\n    width: 100%;\n    text-align: center;\n    z-index: 1;\n    transition: opacity 0.3s;\n    color: var(--slider-color);\n}\n\n.slider-title.success {\n    /*opacity: 0;*/\n    z-index: 1;\n    background-color: transparent;\n    color: rgba(70, 182, 91, 1);\n}\n\n/* 深色模式 */\n.dark-box {\n    --text-black-color: rgba(255, 255, 255, 0.9);\n    --text-gray-color: rgba(255, 255, 255, 0.5);\n    --input-bgcolor: rgba(32 35 43);\n    --input-border-color: rgba(50, 56, 67, 1);\n    --code-bgcolor: rgba(50, 56, 67, 1);\n    --code-border-color: rgba(255, 255, 255, 0.1);\n    --slider-color: rgba(255, 255, 255, 0.5);\n    --slider-captcha-bg: rgba(50, 56, 67, 1);\n    --slider-track-bg: rgba(32 35 43);\n    --code-text-color: rgba(255, 255, 255, 0.9);\n    --code-disabled-color: rgba(255, 255, 255, 0.2);\n    --code-disabled-bg: rgba(50, 56, 67, 1);\n    --disabled-submit-bg: #2174FF;\n    --disabled-color: rgba(255, 255, 255, 0.2);\n}\n\n/* 白色模式模式 */\n.light-box {\n    --text-black-color: rgba(0, 0, 0, 0.9);\n    --text-gray-color: rgba(0, 0, 0, 0.5);\n    --input-bgcolor: #FFFFFF;\n    --input-border-color: #DDDDDD;\n    --code-bgcolor: #FFFFFF;\n    --code-border-color: #DDDDDD;\n    --slider-color: rgba(0, 0, 0, 0.5);\n    --slider-captcha-bg: rgba(255, 255, 255, 1);\n    --slider-track-bg: #eee;\n    --code-text-color: rgba(71, 141, 255, 1);\n    --code-disabled-color: rgba(71, 141, 255, 0.4);\n    --code-disabled-bg: #eee;\n    --disabled-submit-bg: rgba(181, 199, 255, 1);\n    --disabled-color: rgba(255, 255, 255, 1);\n}\n\n\n\n "
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/login2.css",
    "content": "body {\n    background-size: cover;\n}\n\n/*.bg1 {*/\n/*    background-image: url(../img/bg1.jpg);*/\n/*}*/\n\n/*.bg2 {*/\n/*    background-image: url(../img/bg2.jpg);*/\n/*}*/\n\n.form-login .checkbox {\n    font-weight: normal;\n}\n\n.form-login .form-control:focus {\n    z-index: 2;\n}\n\n.form-login button[type=\"submit\"] {\n    margin-top: 5px;\n}\n\n.nav-pills > li.active > a, .nav-pills > li.active > a:focus, .nav-pills > li.active > a:hover {\n    background-color: #f5f5f5;\n    color: #3c3c3c;\n    border-color: #8c8c8c;\n}\n\n.nav-pills > li > a {\n    color: #ccc;\n    border-radius: 0px;\n    border-style: solid;\n    border-width: 0 0 2px 0;\n    border-color: #f5f5f5;\n}\n\n.input-lg, .btn-lg, .btn-group-lg > .btn {\n    font-size: 14px;\n}\n\n.input-group-btn > .sms-code-btu {\n    height: 46px;\n    background-color: #eee;\n    color: #3c3c3c;\n    width: 120px;\n}\n\n.form-control-feedback {\n    width: 44px;\n    height: 44px;\n    line-height: 44px;\n}\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/login3.css",
    "content": ":root {\n    --primary-color: #2174FF;\n    --error-color: #ff4d4f;\n    --text-black-color: rgba(0, 0, 0, 0.9);\n    --text-gray-color: rgba(0, 0, 0, 0.5);\n    --text-primary-color: #478DFF;\n    --code-bgcolor: #FFFFFF;\n    --code-border-color: #DDDDDD;\n    --input-bgcolor: #FFFFFF;\n    --input-border-color: #DDDDDD;\n    --slider-color: rgba(255, 255, 255, 0.5);\n    --slider-captcha-bg: rgba(255, 255, 255, 1);\n    --slider-thumb-color: #0b0b0b;\n    --slider-track-bg: #eee;\n    --code-text-color: rgba(71, 141, 255, 1);\n    --disabled-color: rgba(255, 255, 255, 1);\n    --disabled-submit-bg: rgba(181, 199, 255, 1);\n    --code-disabled-color: rgba(71, 141, 255, 0.4);\n    --code-disabled-bg: #eee;\n}\n\nbody {\n    margin: 0;\n    min-height: 100vh;\n    font-family: 'Orbitron', sans-serif;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n}\n\n.login-container {\n    padding-bottom: 100px;\n    border-radius: 8px;\n    width: 100%;\n    max-width: 420px;\n}\n\n.login-title {\n    font-size: 36px;\n    font-weight: normal;\n    margin: 0;\n    margin-bottom: 40px;\n    color: var(--text-black-color);\n}\n\n.tabs {\n    display: flex;\n    margin-bottom: 24px;\n    /* border-bottom: 1px solid #eee; */\n}\n\n.tab {\n    padding: 12px 20px;\n    cursor: pointer;\n    color: var(--text-gray-color);\n    /* border-bottom: 3px solid transparent; */\n    transition: all 0.3s;\n    position: relative;\n}\n\n.tab::after {\n    content: \"\";\n    position: absolute;\n    bottom: 0;\n    left: 0;\n    width: 100%;\n    height: 3px;\n    border-radius: 100px 100px 0px 0px;\n    background-color: transparent;\n}\n\n.tab.active {\n    color: var(--text-black-color);\n    border-bottom-color: var(--primary-color);\n}\n\n.tab.active::after {\n    background-color: var(--primary-color);\n}\n\n.form-group label {\n    display: block;\n    margin-bottom: 8px;\n    color: var(--text-black-color);\n    font-weight: 500;\n}\n\n.input {\n    width: calc(100% - 18px);\n    padding: 14px 0px 14px 16px;\n    /* 增加左侧padding */\n    border: 1px solid var(--input-border-color);\n    /* border-color: var(--input-border-color); */\n    background-color: var(--input-bgcolor) !important;\n    border-radius: 4px;\n    font-size: 14px;\n    transition: border-color 0.3s;\n    font-size: 14px;\n    line-height: 22px;\n    color: var(--text-black-color);\n}\n\n.dark-box .input:autofill {\n    box-shadow: 0 0 0 1000px rgb(17 17 17) inset !important;\n    border-color: rgb(64 64 64);\n}\n\n.light-box .input:autofill {\n    box-shadow: 0 0 0 1000px var(--input-bgcolor) inset !important;\n    border-color: var(--input-border-color);\n}\n\n.input:-internal-autofill-previewed,\n.input:-internal-autofill-selected {\n    -webkit-text-fill-color: var(--text-black-color) !important;\n    transition: background-color 5000s ease-in-out 0s !important;\n}\n\n.input:focus {\n    outline: none;\n    border-color: var(--primary-color) !important;\n    background-color: var(--input-bgcolor) !important;\n    color: var(--text-black-color) !important;\n}\n\n\n.password {\n    width: calc(100% - 52px);\n}\n\n/* 新增图标容器样式 */\n.input-wrapper {\n    position: relative;\n    margin-bottom: 4px;\n}\n\n.input-sub-wrapper {\n    width: 300px;\n}\n\n/* 修改错误提示定位方式 */\n.form-group > .error {\n    color: #ff4d4f;\n    font-size: 10px;\n}\n\n/* 增加表单组最小高度 */\n.form-group {\n    position: relative;\n    min-height: 74px;\n    /* 保持固定高度避免跳动 */\n}\n\n.input-icon {\n    position: absolute;\n    left: 15px;\n    top: 50%;\n    transform: translateY(-50%);\n    color: var(--primary-color);\n    width: 16px;\n    height: 16px;\n}\n\n.captcha-row {\n    display: flex;\n    gap: 10px;\n}\n\n.captcha-img {\n    border: 1px solid var(--code-border-color);\n    border-radius: 4px;\n    cursor: pointer;\n    width: 110px;\n    height: 50px;\n    color: var(--text-gray-color);\n}\n\n.sms-code-row {\n    display: flex;\n    gap: 10px;\n}\n\n.get-code-btn {\n    color: var(--code-text-color);\n    border: 1px solid var(--code-border-color);\n    padding: 0 15px;\n    border-radius: 4px;\n    cursor: pointer;\n    transition: opacity 0.3s;\n    width: 110px;\n    height: 52px;\n    background-color: var(--code-bgcolor);\n}\n\n.get-code-btn:disabled {\n    color: var(--code-disabled-color);\n    background-color: var(--code-disabled-bg);\n    cursor: not-allowed;\n}\n\n.submit-btn {\n    width: 100%;\n    background: var(--primary-color);\n    color: white;\n    padding: 8px;\n    margin-bottom: 20px;\n    border: none;\n    border-radius: 4px;\n    font-size: 16px;\n    line-height: 36px;\n    cursor: pointer;\n    transition: opacity 0.3s;\n}\n\n.submit-btn:disabled {\n    color: var(--disabled-color);\n    background-color: var(--disabled-submit-bg);\n    cursor: not-allowed;\n\n    &:hover {\n        opacity: 1;\n    }\n}\n\n.submit-btn:hover {\n    opacity: 0.9;\n}\n\n.error-message {\n    color: var(--error-color);\n    font-size: 12px;\n    margin-top: 2px;\n    display: none;\n    height: 20px;\n    /* 固定错误信息高度 */\n}\n\ninput.invalid {\n    border-color: var(--error-color);\n}\n\ninput.invalid + .error-message {\n    display: block;\n}\n\n/* 新增错误提示样式 */\n.error-alert {\n    position: fixed;\n    top: 20px;\n    background: #ff4444;\n    color: white;\n    padding: 12px 20px;\n    border-radius: 6px;\n    display: flex;\n    align-items: center;\n    gap: 10px;\n    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n    cursor: pointer;\n    transition: 0.3s all;\n    z-index: 1000;\n}\n\n.error-alert:hover {\n    transform: translateY(-2px);\n    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n}\n\n.close-icon {\n    width: 18px;\n    height: 18px;\n    opacity: 0.8;\n}\n\n.close-icon:hover {\n    opacity: 1;\n}\n\n#wechat_qrcode {\n    text-align: center;\n    height: 272px;\n}\n\n.login-page-container {\n    width: 100vw;\n    height: 100vh;\n    display: flex;\n}\n\n.lft-container {\n    width: 35%;\n    height: 100%;\n    position: relative;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.lft-container .gb {\n    width: 100%;\n    height: 100%;\n    position: absolute;\n    left: 0;\n    top: 0;\n    z-index: 4;\n}\n\n.lft-container .logo {\n    position: relative;\n    z-index: 5;\n}\n\n.lft-container p {\n    position: absolute;\n    width: 100%;\n    font-size: 16px;\n    line-height: 24px;\n    font-weight: 400;\n    color: rgba(255, 255, 255, 0.9);\n    bottom: 40px;\n    z-index: 5;\n    text-align: center;\n    margin: 0;\n}\n\n.rgt-container {\n    height: 100%;\n    width: 65%;\n    position: relative;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n}\n\n.dark-box {\n    background: #181818;\n}\n\n.light-box {\n    background: #FFFFFF;\n}\n\n.switch-container {\n    width: 60px;\n    height: 32px;\n    position: absolute;\n    right: 24px;\n    top: 24px;\n    border-radius: 4px;\n    box-sizing: border-box;\n    user-select: none;\n}\n\n.switch-container > .switch-inner {\n    width: 100%;\n    height: 100%;\n    border-radius: 4px;\n}\n\n.switch-inner > .inner-box {\n    width: 100%;\n    height: 100%;\n    border-radius: 4px;\n    display: flex;\n    align-items: center;\n    padding: 2px;\n    box-sizing: border-box;\n}\n\n.switch-container > .switch-inner .switch-item {\n    flex: 1;\n    height: 100%;\n    border-radius: 4px;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    cursor: pointer;\n}\n\n.switch-inner > .inner-box img {\n    width: 16px;\n    height: 16px;\n}\n\n.light-inner .switch-item:first-child {\n    background: #FFFFFF;\n    box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1);\n}\n\n.light-switch {\n    background: #EEEEEE;\n}\n\n.light-switch > .light-inner {\n    display: block;\n}\n\n.light-switch > .dark-inner {\n    display: none;\n}\n\n.dark-switch {\n    background: #383838;\n}\n\n.dark-switch > .light-inner {\n    display: none;\n}\n\n.dark-switch > .dark-inner {\n    display: block;\n}\n\n.dark-inner .switch-item:last-child {\n    background: #4B4B4B;\n    box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1);\n}\n\n.record-text {\n    width: 100%;\n    position: absolute;\n    bottom: 40px;\n    left: 0;\n    font-size: 16px;\n    font-weight: normal;\n    line-height: 24px;\n    text-align: center;\n    letter-spacing: normal;\n    color: var(--text-gray-color);\n    margin: 0;\n}\n\n.record-text > span {\n    color: var(--text-primary-color);\n}\n\n.slider-captcha {\n    height: 50px;\n    display: flex;\n    align-items: center;\n    border: 1px solid var(--code-border-color);\n    background-color: var(--slider-captcha-bg) !important;\n    border-radius: 4px;\n    font-size: 14px;\n    transition: border-color 0.3s;\n    font-size: 14px;\n    line-height: 22px;\n    color: var(--text-black-color);\n    position: relative;\n    overflow: hidden;\n}\n\n.slider-track {\n    height: 100%;\n    width: 0;\n    background-color: var(--slider-track-bg);\n    z-index: 1;\n}\n\n.slider-captcha.success {\n    background-color: var(--input-bgcolor) !important;\n}\n\n.slider-thumb {\n    width: 58px;\n    height: 50px;\n    border: 1px solid var(--input-border-color);\n    border-radius: 4px;\n    position: absolute;\n    left: 0;\n    cursor: move;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    /* transition: left 0.3s; */\n    z-index: 2;\n    background-color: var(--input-bgcolor);\n}\n\n.slider-thumb.success {\n    color: rgba(70, 182, 91, 1);\n}\n\n.slider-title {\n    position: absolute;\n    left: 0;\n    width: 100%;\n    text-align: center;\n    z-index: 1;\n    transition: opacity 0.3s;\n    color: var(--slider-color);\n}\n\n.slider-title.success {\n    /*opacity: 0;*/\n    z-index: 1;\n    background-color: transparent;\n    color: rgba(70, 182, 91, 1);\n}\n\n/* 深色模式 */\n.dark-box {\n    --text-black-color: rgba(255, 255, 255, 0.9);\n    --text-gray-color: rgba(255, 255, 255, 0.5);\n    --input-bgcolor: rgba(32 35 43);\n    --input-border-color: rgba(50, 56, 67, 1);\n    --code-bgcolor: rgba(50, 56, 67, 1);\n    --code-border-color: rgba(255, 255, 255, 0.1);\n    --slider-color: rgba(255, 255, 255, 0.5);\n    --slider-captcha-bg: rgba(50, 56, 67, 1);\n    --slider-track-bg: rgba(32 35 43);\n    --code-text-color: rgba(255, 255, 255, 0.9);\n    --code-disabled-color: rgba(255, 255, 255, 0.2);\n    --code-disabled-bg: rgba(50, 56, 67, 1);\n    --disabled-submit-bg: #2174FF;\n    --disabled-color: rgba(255, 255, 255, 0.2);\n}\n\n/* 白色模式模式 */\n.light-box {\n    --text-black-color: rgba(0, 0, 0, 0.9);\n    --text-gray-color: rgba(0, 0, 0, 0.5);\n    --input-bgcolor: #FFFFFF;\n    --input-border-color: #DDDDDD;\n    --code-bgcolor: #FFFFFF;\n    --code-border-color: #DDDDDD;\n    --slider-color: rgba(0, 0, 0, 0.5);\n    --slider-captcha-bg: rgba(255, 255, 255, 1);\n    --slider-track-bg: #eee;\n    --code-text-color: rgba(71, 141, 255, 1);\n    --code-disabled-color: rgba(71, 141, 255, 0.4);\n    --code-disabled-bg: #eee;\n    --disabled-submit-bg: rgba(181, 199, 255, 1);\n    --disabled-color: rgba(255, 255, 255, 1);\n}\n\n#wechat_qrcode {\n    text-align: center;\n    height: 100%;\n}\n\n#wechat_qrcode iframe {\n    width: 300px !important;\n    height: 400px !important;\n}\n\n.wechat_register {\n    text-align: center;\n    color: var(--text-gray-color);\n    cursor: pointer;\n    position: absolute;\n    left: 50%;\n    transform: translateX(-50%);\n}\n\n.wechat_register > .link {\n    color: var(--text-primary-color);\n}\n\n.wechat_modal {\n    position: fixed;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    background-color: rgba(0, 0, 0, 0.9);\n    z-index: 9;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    flex-direction: column;\n    display: none;\n}\n\n.wechat_modal .box {\n    padding: 20px;\n    padding-bottom: 30px;\n    border-radius: 5px;\n    background-color: #fff;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    flex-direction: column;\n}\n\n.wechat_modal .box .QRcode {\n    width: 200px;\n    height: 200px;\n    /* background-color: #2174FF; */\n    margin-top: 20px;\n}\n\n.wechat_modal .close {\n    width: 40px;\n    height: 40px;\n    margin-top: 20px;\n    cursor: pointer;\n}\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/navbar.css",
    "content": "body {\n    padding-top: 20px;\n    padding-bottom: 20px;\n}\n\n.navbar {\n    margin-bottom: 20px;\n}\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/css/user_me.css",
    "content": "\n.user-info {\n    padding: 0px 20px;\n    font-size: 18px;\n}\n\n.user-info {\n    text-align: left;\n}\n\n/*.user-info div.text{*/\n/*text-align: left;*/\n/*}*/"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/all.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n.fa,\n.fas,\n.far,\n.fal,\n.fad,\n.fab {\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-font-smoothing: antialiased;\n  display: inline-block;\n  font-style: normal;\n  font-variant: normal;\n  text-rendering: auto;\n  line-height: 1; }\n\n.fa-lg {\n  font-size: 1.33333em;\n  line-height: 0.75em;\n  vertical-align: -.0667em; }\n\n.fa-xs {\n  font-size: .75em; }\n\n.fa-sm {\n  font-size: .875em; }\n\n.fa-1x {\n  font-size: 1em; }\n\n.fa-2x {\n  font-size: 2em; }\n\n.fa-3x {\n  font-size: 3em; }\n\n.fa-4x {\n  font-size: 4em; }\n\n.fa-5x {\n  font-size: 5em; }\n\n.fa-6x {\n  font-size: 6em; }\n\n.fa-7x {\n  font-size: 7em; }\n\n.fa-8x {\n  font-size: 8em; }\n\n.fa-9x {\n  font-size: 9em; }\n\n.fa-10x {\n  font-size: 10em; }\n\n.fa-fw {\n  text-align: center;\n  width: 1.25em; }\n\n.fa-ul {\n  list-style-type: none;\n  margin-left: 2.5em;\n  padding-left: 0; }\n  .fa-ul > li {\n    position: relative; }\n\n.fa-li {\n  left: -2em;\n  position: absolute;\n  text-align: center;\n  width: 2em;\n  line-height: inherit; }\n\n.fa-border {\n  border: solid 0.08em #eee;\n  border-radius: .1em;\n  padding: .2em .25em .15em; }\n\n.fa-pull-left {\n  float: left; }\n\n.fa-pull-right {\n  float: right; }\n\n.fa.fa-pull-left,\n.fas.fa-pull-left,\n.far.fa-pull-left,\n.fal.fa-pull-left,\n.fab.fa-pull-left {\n  margin-right: .3em; }\n\n.fa.fa-pull-right,\n.fas.fa-pull-right,\n.far.fa-pull-right,\n.fal.fa-pull-right,\n.fab.fa-pull-right {\n  margin-left: .3em; }\n\n.fa-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n          animation: fa-spin 2s infinite linear; }\n\n.fa-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n          animation: fa-spin 1s infinite steps(8); }\n\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg); }\n  100% {\n    -webkit-transform: rotate(360deg);\n            transform: rotate(360deg); } }\n\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg); }\n  100% {\n    -webkit-transform: rotate(360deg);\n            transform: rotate(360deg); } }\n\n.fa-rotate-90 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";\n  -webkit-transform: rotate(90deg);\n          transform: rotate(90deg); }\n\n.fa-rotate-180 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";\n  -webkit-transform: rotate(180deg);\n          transform: rotate(180deg); }\n\n.fa-rotate-270 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";\n  -webkit-transform: rotate(270deg);\n          transform: rotate(270deg); }\n\n.fa-flip-horizontal {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";\n  -webkit-transform: scale(-1, 1);\n          transform: scale(-1, 1); }\n\n.fa-flip-vertical {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";\n  -webkit-transform: scale(1, -1);\n          transform: scale(1, -1); }\n\n.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";\n  -webkit-transform: scale(-1, -1);\n          transform: scale(-1, -1); }\n\n:root .fa-rotate-90,\n:root .fa-rotate-180,\n:root .fa-rotate-270,\n:root .fa-flip-horizontal,\n:root .fa-flip-vertical,\n:root .fa-flip-both {\n  -webkit-filter: none;\n          filter: none; }\n\n.fa-stack {\n  display: inline-block;\n  height: 2em;\n  line-height: 2em;\n  position: relative;\n  vertical-align: middle;\n  width: 2.5em; }\n\n.fa-stack-1x,\n.fa-stack-2x {\n  left: 0;\n  position: absolute;\n  text-align: center;\n  width: 100%; }\n\n.fa-stack-1x {\n  line-height: inherit; }\n\n.fa-stack-2x {\n  font-size: 2em; }\n\n.fa-inverse {\n  color: #fff; }\n\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\nreaders do not read off random characters that represent icons */\n.fa-500px:before {\n  content: \"\\f26e\"; }\n\n.fa-accessible-icon:before {\n  content: \"\\f368\"; }\n\n.fa-accusoft:before {\n  content: \"\\f369\"; }\n\n.fa-acquisitions-incorporated:before {\n  content: \"\\f6af\"; }\n\n.fa-ad:before {\n  content: \"\\f641\"; }\n\n.fa-address-book:before {\n  content: \"\\f2b9\"; }\n\n.fa-address-card:before {\n  content: \"\\f2bb\"; }\n\n.fa-adjust:before {\n  content: \"\\f042\"; }\n\n.fa-adn:before {\n  content: \"\\f170\"; }\n\n.fa-adversal:before {\n  content: \"\\f36a\"; }\n\n.fa-affiliatetheme:before {\n  content: \"\\f36b\"; }\n\n.fa-air-freshener:before {\n  content: \"\\f5d0\"; }\n\n.fa-airbnb:before {\n  content: \"\\f834\"; }\n\n.fa-algolia:before {\n  content: \"\\f36c\"; }\n\n.fa-align-center:before {\n  content: \"\\f037\"; }\n\n.fa-align-justify:before {\n  content: \"\\f039\"; }\n\n.fa-align-left:before {\n  content: \"\\f036\"; }\n\n.fa-align-right:before {\n  content: \"\\f038\"; }\n\n.fa-alipay:before {\n  content: \"\\f642\"; }\n\n.fa-allergies:before {\n  content: \"\\f461\"; }\n\n.fa-amazon:before {\n  content: \"\\f270\"; }\n\n.fa-amazon-pay:before {\n  content: \"\\f42c\"; }\n\n.fa-ambulance:before {\n  content: \"\\f0f9\"; }\n\n.fa-american-sign-language-interpreting:before {\n  content: \"\\f2a3\"; }\n\n.fa-amilia:before {\n  content: \"\\f36d\"; }\n\n.fa-anchor:before {\n  content: \"\\f13d\"; }\n\n.fa-android:before {\n  content: \"\\f17b\"; }\n\n.fa-angellist:before {\n  content: \"\\f209\"; }\n\n.fa-angle-double-down:before {\n  content: \"\\f103\"; }\n\n.fa-angle-double-left:before {\n  content: \"\\f100\"; }\n\n.fa-angle-double-right:before {\n  content: \"\\f101\"; }\n\n.fa-angle-double-up:before {\n  content: \"\\f102\"; }\n\n.fa-angle-down:before {\n  content: \"\\f107\"; }\n\n.fa-angle-left:before {\n  content: \"\\f104\"; }\n\n.fa-angle-right:before {\n  content: \"\\f105\"; }\n\n.fa-angle-up:before {\n  content: \"\\f106\"; }\n\n.fa-angry:before {\n  content: \"\\f556\"; }\n\n.fa-angrycreative:before {\n  content: \"\\f36e\"; }\n\n.fa-angular:before {\n  content: \"\\f420\"; }\n\n.fa-ankh:before {\n  content: \"\\f644\"; }\n\n.fa-app-store:before {\n  content: \"\\f36f\"; }\n\n.fa-app-store-ios:before {\n  content: \"\\f370\"; }\n\n.fa-apper:before {\n  content: \"\\f371\"; }\n\n.fa-apple:before {\n  content: \"\\f179\"; }\n\n.fa-apple-alt:before {\n  content: \"\\f5d1\"; }\n\n.fa-apple-pay:before {\n  content: \"\\f415\"; }\n\n.fa-archive:before {\n  content: \"\\f187\"; }\n\n.fa-archway:before {\n  content: \"\\f557\"; }\n\n.fa-arrow-alt-circle-down:before {\n  content: \"\\f358\"; }\n\n.fa-arrow-alt-circle-left:before {\n  content: \"\\f359\"; }\n\n.fa-arrow-alt-circle-right:before {\n  content: \"\\f35a\"; }\n\n.fa-arrow-alt-circle-up:before {\n  content: \"\\f35b\"; }\n\n.fa-arrow-circle-down:before {\n  content: \"\\f0ab\"; }\n\n.fa-arrow-circle-left:before {\n  content: \"\\f0a8\"; }\n\n.fa-arrow-circle-right:before {\n  content: \"\\f0a9\"; }\n\n.fa-arrow-circle-up:before {\n  content: \"\\f0aa\"; }\n\n.fa-arrow-down:before {\n  content: \"\\f063\"; }\n\n.fa-arrow-left:before {\n  content: \"\\f060\"; }\n\n.fa-arrow-right:before {\n  content: \"\\f061\"; }\n\n.fa-arrow-up:before {\n  content: \"\\f062\"; }\n\n.fa-arrows-alt:before {\n  content: \"\\f0b2\"; }\n\n.fa-arrows-alt-h:before {\n  content: \"\\f337\"; }\n\n.fa-arrows-alt-v:before {\n  content: \"\\f338\"; }\n\n.fa-artstation:before {\n  content: \"\\f77a\"; }\n\n.fa-assistive-listening-systems:before {\n  content: \"\\f2a2\"; }\n\n.fa-asterisk:before {\n  content: \"\\f069\"; }\n\n.fa-asymmetrik:before {\n  content: \"\\f372\"; }\n\n.fa-at:before {\n  content: \"\\f1fa\"; }\n\n.fa-atlas:before {\n  content: \"\\f558\"; }\n\n.fa-atlassian:before {\n  content: \"\\f77b\"; }\n\n.fa-atom:before {\n  content: \"\\f5d2\"; }\n\n.fa-audible:before {\n  content: \"\\f373\"; }\n\n.fa-audio-description:before {\n  content: \"\\f29e\"; }\n\n.fa-autoprefixer:before {\n  content: \"\\f41c\"; }\n\n.fa-avianex:before {\n  content: \"\\f374\"; }\n\n.fa-aviato:before {\n  content: \"\\f421\"; }\n\n.fa-award:before {\n  content: \"\\f559\"; }\n\n.fa-aws:before {\n  content: \"\\f375\"; }\n\n.fa-baby:before {\n  content: \"\\f77c\"; }\n\n.fa-baby-carriage:before {\n  content: \"\\f77d\"; }\n\n.fa-backspace:before {\n  content: \"\\f55a\"; }\n\n.fa-backward:before {\n  content: \"\\f04a\"; }\n\n.fa-bacon:before {\n  content: \"\\f7e5\"; }\n\n.fa-bacteria:before {\n  content: \"\\e059\"; }\n\n.fa-bacterium:before {\n  content: \"\\e05a\"; }\n\n.fa-bahai:before {\n  content: \"\\f666\"; }\n\n.fa-balance-scale:before {\n  content: \"\\f24e\"; }\n\n.fa-balance-scale-left:before {\n  content: \"\\f515\"; }\n\n.fa-balance-scale-right:before {\n  content: \"\\f516\"; }\n\n.fa-ban:before {\n  content: \"\\f05e\"; }\n\n.fa-band-aid:before {\n  content: \"\\f462\"; }\n\n.fa-bandcamp:before {\n  content: \"\\f2d5\"; }\n\n.fa-barcode:before {\n  content: \"\\f02a\"; }\n\n.fa-bars:before {\n  content: \"\\f0c9\"; }\n\n.fa-baseball-ball:before {\n  content: \"\\f433\"; }\n\n.fa-basketball-ball:before {\n  content: \"\\f434\"; }\n\n.fa-bath:before {\n  content: \"\\f2cd\"; }\n\n.fa-battery-empty:before {\n  content: \"\\f244\"; }\n\n.fa-battery-full:before {\n  content: \"\\f240\"; }\n\n.fa-battery-half:before {\n  content: \"\\f242\"; }\n\n.fa-battery-quarter:before {\n  content: \"\\f243\"; }\n\n.fa-battery-three-quarters:before {\n  content: \"\\f241\"; }\n\n.fa-battle-net:before {\n  content: \"\\f835\"; }\n\n.fa-bed:before {\n  content: \"\\f236\"; }\n\n.fa-beer:before {\n  content: \"\\f0fc\"; }\n\n.fa-behance:before {\n  content: \"\\f1b4\"; }\n\n.fa-behance-square:before {\n  content: \"\\f1b5\"; }\n\n.fa-bell:before {\n  content: \"\\f0f3\"; }\n\n.fa-bell-slash:before {\n  content: \"\\f1f6\"; }\n\n.fa-bezier-curve:before {\n  content: \"\\f55b\"; }\n\n.fa-bible:before {\n  content: \"\\f647\"; }\n\n.fa-bicycle:before {\n  content: \"\\f206\"; }\n\n.fa-biking:before {\n  content: \"\\f84a\"; }\n\n.fa-bimobject:before {\n  content: \"\\f378\"; }\n\n.fa-binoculars:before {\n  content: \"\\f1e5\"; }\n\n.fa-biohazard:before {\n  content: \"\\f780\"; }\n\n.fa-birthday-cake:before {\n  content: \"\\f1fd\"; }\n\n.fa-bitbucket:before {\n  content: \"\\f171\"; }\n\n.fa-bitcoin:before {\n  content: \"\\f379\"; }\n\n.fa-bity:before {\n  content: \"\\f37a\"; }\n\n.fa-black-tie:before {\n  content: \"\\f27e\"; }\n\n.fa-blackberry:before {\n  content: \"\\f37b\"; }\n\n.fa-blender:before {\n  content: \"\\f517\"; }\n\n.fa-blender-phone:before {\n  content: \"\\f6b6\"; }\n\n.fa-blind:before {\n  content: \"\\f29d\"; }\n\n.fa-blog:before {\n  content: \"\\f781\"; }\n\n.fa-blogger:before {\n  content: \"\\f37c\"; }\n\n.fa-blogger-b:before {\n  content: \"\\f37d\"; }\n\n.fa-bluetooth:before {\n  content: \"\\f293\"; }\n\n.fa-bluetooth-b:before {\n  content: \"\\f294\"; }\n\n.fa-bold:before {\n  content: \"\\f032\"; }\n\n.fa-bolt:before {\n  content: \"\\f0e7\"; }\n\n.fa-bomb:before {\n  content: \"\\f1e2\"; }\n\n.fa-bone:before {\n  content: \"\\f5d7\"; }\n\n.fa-bong:before {\n  content: \"\\f55c\"; }\n\n.fa-book:before {\n  content: \"\\f02d\"; }\n\n.fa-book-dead:before {\n  content: \"\\f6b7\"; }\n\n.fa-book-medical:before {\n  content: \"\\f7e6\"; }\n\n.fa-book-open:before {\n  content: \"\\f518\"; }\n\n.fa-book-reader:before {\n  content: \"\\f5da\"; }\n\n.fa-bookmark:before {\n  content: \"\\f02e\"; }\n\n.fa-bootstrap:before {\n  content: \"\\f836\"; }\n\n.fa-border-all:before {\n  content: \"\\f84c\"; }\n\n.fa-border-none:before {\n  content: \"\\f850\"; }\n\n.fa-border-style:before {\n  content: \"\\f853\"; }\n\n.fa-bowling-ball:before {\n  content: \"\\f436\"; }\n\n.fa-box:before {\n  content: \"\\f466\"; }\n\n.fa-box-open:before {\n  content: \"\\f49e\"; }\n\n.fa-box-tissue:before {\n  content: \"\\e05b\"; }\n\n.fa-boxes:before {\n  content: \"\\f468\"; }\n\n.fa-braille:before {\n  content: \"\\f2a1\"; }\n\n.fa-brain:before {\n  content: \"\\f5dc\"; }\n\n.fa-bread-slice:before {\n  content: \"\\f7ec\"; }\n\n.fa-briefcase:before {\n  content: \"\\f0b1\"; }\n\n.fa-briefcase-medical:before {\n  content: \"\\f469\"; }\n\n.fa-broadcast-tower:before {\n  content: \"\\f519\"; }\n\n.fa-broom:before {\n  content: \"\\f51a\"; }\n\n.fa-brush:before {\n  content: \"\\f55d\"; }\n\n.fa-btc:before {\n  content: \"\\f15a\"; }\n\n.fa-buffer:before {\n  content: \"\\f837\"; }\n\n.fa-bug:before {\n  content: \"\\f188\"; }\n\n.fa-building:before {\n  content: \"\\f1ad\"; }\n\n.fa-bullhorn:before {\n  content: \"\\f0a1\"; }\n\n.fa-bullseye:before {\n  content: \"\\f140\"; }\n\n.fa-burn:before {\n  content: \"\\f46a\"; }\n\n.fa-buromobelexperte:before {\n  content: \"\\f37f\"; }\n\n.fa-bus:before {\n  content: \"\\f207\"; }\n\n.fa-bus-alt:before {\n  content: \"\\f55e\"; }\n\n.fa-business-time:before {\n  content: \"\\f64a\"; }\n\n.fa-buy-n-large:before {\n  content: \"\\f8a6\"; }\n\n.fa-buysellads:before {\n  content: \"\\f20d\"; }\n\n.fa-calculator:before {\n  content: \"\\f1ec\"; }\n\n.fa-calendar:before {\n  content: \"\\f133\"; }\n\n.fa-calendar-alt:before {\n  content: \"\\f073\"; }\n\n.fa-calendar-check:before {\n  content: \"\\f274\"; }\n\n.fa-calendar-day:before {\n  content: \"\\f783\"; }\n\n.fa-calendar-minus:before {\n  content: \"\\f272\"; }\n\n.fa-calendar-plus:before {\n  content: \"\\f271\"; }\n\n.fa-calendar-times:before {\n  content: \"\\f273\"; }\n\n.fa-calendar-week:before {\n  content: \"\\f784\"; }\n\n.fa-camera:before {\n  content: \"\\f030\"; }\n\n.fa-camera-retro:before {\n  content: \"\\f083\"; }\n\n.fa-campground:before {\n  content: \"\\f6bb\"; }\n\n.fa-canadian-maple-leaf:before {\n  content: \"\\f785\"; }\n\n.fa-candy-cane:before {\n  content: \"\\f786\"; }\n\n.fa-cannabis:before {\n  content: \"\\f55f\"; }\n\n.fa-capsules:before {\n  content: \"\\f46b\"; }\n\n.fa-car:before {\n  content: \"\\f1b9\"; }\n\n.fa-car-alt:before {\n  content: \"\\f5de\"; }\n\n.fa-car-battery:before {\n  content: \"\\f5df\"; }\n\n.fa-car-crash:before {\n  content: \"\\f5e1\"; }\n\n.fa-car-side:before {\n  content: \"\\f5e4\"; }\n\n.fa-caravan:before {\n  content: \"\\f8ff\"; }\n\n.fa-caret-down:before {\n  content: \"\\f0d7\"; }\n\n.fa-caret-left:before {\n  content: \"\\f0d9\"; }\n\n.fa-caret-right:before {\n  content: \"\\f0da\"; }\n\n.fa-caret-square-down:before {\n  content: \"\\f150\"; }\n\n.fa-caret-square-left:before {\n  content: \"\\f191\"; }\n\n.fa-caret-square-right:before {\n  content: \"\\f152\"; }\n\n.fa-caret-square-up:before {\n  content: \"\\f151\"; }\n\n.fa-caret-up:before {\n  content: \"\\f0d8\"; }\n\n.fa-carrot:before {\n  content: \"\\f787\"; }\n\n.fa-cart-arrow-down:before {\n  content: \"\\f218\"; }\n\n.fa-cart-plus:before {\n  content: \"\\f217\"; }\n\n.fa-cash-register:before {\n  content: \"\\f788\"; }\n\n.fa-cat:before {\n  content: \"\\f6be\"; }\n\n.fa-cc-amazon-pay:before {\n  content: \"\\f42d\"; }\n\n.fa-cc-amex:before {\n  content: \"\\f1f3\"; }\n\n.fa-cc-apple-pay:before {\n  content: \"\\f416\"; }\n\n.fa-cc-diners-club:before {\n  content: \"\\f24c\"; }\n\n.fa-cc-discover:before {\n  content: \"\\f1f2\"; }\n\n.fa-cc-jcb:before {\n  content: \"\\f24b\"; }\n\n.fa-cc-mastercard:before {\n  content: \"\\f1f1\"; }\n\n.fa-cc-paypal:before {\n  content: \"\\f1f4\"; }\n\n.fa-cc-stripe:before {\n  content: \"\\f1f5\"; }\n\n.fa-cc-visa:before {\n  content: \"\\f1f0\"; }\n\n.fa-centercode:before {\n  content: \"\\f380\"; }\n\n.fa-centos:before {\n  content: \"\\f789\"; }\n\n.fa-certificate:before {\n  content: \"\\f0a3\"; }\n\n.fa-chair:before {\n  content: \"\\f6c0\"; }\n\n.fa-chalkboard:before {\n  content: \"\\f51b\"; }\n\n.fa-chalkboard-teacher:before {\n  content: \"\\f51c\"; }\n\n.fa-charging-station:before {\n  content: \"\\f5e7\"; }\n\n.fa-chart-area:before {\n  content: \"\\f1fe\"; }\n\n.fa-chart-bar:before {\n  content: \"\\f080\"; }\n\n.fa-chart-line:before {\n  content: \"\\f201\"; }\n\n.fa-chart-pie:before {\n  content: \"\\f200\"; }\n\n.fa-check:before {\n  content: \"\\f00c\"; }\n\n.fa-check-circle:before {\n  content: \"\\f058\"; }\n\n.fa-check-double:before {\n  content: \"\\f560\"; }\n\n.fa-check-square:before {\n  content: \"\\f14a\"; }\n\n.fa-cheese:before {\n  content: \"\\f7ef\"; }\n\n.fa-chess:before {\n  content: \"\\f439\"; }\n\n.fa-chess-bishop:before {\n  content: \"\\f43a\"; }\n\n.fa-chess-board:before {\n  content: \"\\f43c\"; }\n\n.fa-chess-king:before {\n  content: \"\\f43f\"; }\n\n.fa-chess-knight:before {\n  content: \"\\f441\"; }\n\n.fa-chess-pawn:before {\n  content: \"\\f443\"; }\n\n.fa-chess-queen:before {\n  content: \"\\f445\"; }\n\n.fa-chess-rook:before {\n  content: \"\\f447\"; }\n\n.fa-chevron-circle-down:before {\n  content: \"\\f13a\"; }\n\n.fa-chevron-circle-left:before {\n  content: \"\\f137\"; }\n\n.fa-chevron-circle-right:before {\n  content: \"\\f138\"; }\n\n.fa-chevron-circle-up:before {\n  content: \"\\f139\"; }\n\n.fa-chevron-down:before {\n  content: \"\\f078\"; }\n\n.fa-chevron-left:before {\n  content: \"\\f053\"; }\n\n.fa-chevron-right:before {\n  content: \"\\f054\"; }\n\n.fa-chevron-up:before {\n  content: \"\\f077\"; }\n\n.fa-child:before {\n  content: \"\\f1ae\"; }\n\n.fa-chrome:before {\n  content: \"\\f268\"; }\n\n.fa-chromecast:before {\n  content: \"\\f838\"; }\n\n.fa-church:before {\n  content: \"\\f51d\"; }\n\n.fa-circle:before {\n  content: \"\\f111\"; }\n\n.fa-circle-notch:before {\n  content: \"\\f1ce\"; }\n\n.fa-city:before {\n  content: \"\\f64f\"; }\n\n.fa-clinic-medical:before {\n  content: \"\\f7f2\"; }\n\n.fa-clipboard:before {\n  content: \"\\f328\"; }\n\n.fa-clipboard-check:before {\n  content: \"\\f46c\"; }\n\n.fa-clipboard-list:before {\n  content: \"\\f46d\"; }\n\n.fa-clock:before {\n  content: \"\\f017\"; }\n\n.fa-clone:before {\n  content: \"\\f24d\"; }\n\n.fa-closed-captioning:before {\n  content: \"\\f20a\"; }\n\n.fa-cloud:before {\n  content: \"\\f0c2\"; }\n\n.fa-cloud-download-alt:before {\n  content: \"\\f381\"; }\n\n.fa-cloud-meatball:before {\n  content: \"\\f73b\"; }\n\n.fa-cloud-moon:before {\n  content: \"\\f6c3\"; }\n\n.fa-cloud-moon-rain:before {\n  content: \"\\f73c\"; }\n\n.fa-cloud-rain:before {\n  content: \"\\f73d\"; }\n\n.fa-cloud-showers-heavy:before {\n  content: \"\\f740\"; }\n\n.fa-cloud-sun:before {\n  content: \"\\f6c4\"; }\n\n.fa-cloud-sun-rain:before {\n  content: \"\\f743\"; }\n\n.fa-cloud-upload-alt:before {\n  content: \"\\f382\"; }\n\n.fa-cloudflare:before {\n  content: \"\\e07d\"; }\n\n.fa-cloudscale:before {\n  content: \"\\f383\"; }\n\n.fa-cloudsmith:before {\n  content: \"\\f384\"; }\n\n.fa-cloudversify:before {\n  content: \"\\f385\"; }\n\n.fa-cocktail:before {\n  content: \"\\f561\"; }\n\n.fa-code:before {\n  content: \"\\f121\"; }\n\n.fa-code-branch:before {\n  content: \"\\f126\"; }\n\n.fa-codepen:before {\n  content: \"\\f1cb\"; }\n\n.fa-codiepie:before {\n  content: \"\\f284\"; }\n\n.fa-coffee:before {\n  content: \"\\f0f4\"; }\n\n.fa-cog:before {\n  content: \"\\f013\"; }\n\n.fa-cogs:before {\n  content: \"\\f085\"; }\n\n.fa-coins:before {\n  content: \"\\f51e\"; }\n\n.fa-columns:before {\n  content: \"\\f0db\"; }\n\n.fa-comment:before {\n  content: \"\\f075\"; }\n\n.fa-comment-alt:before {\n  content: \"\\f27a\"; }\n\n.fa-comment-dollar:before {\n  content: \"\\f651\"; }\n\n.fa-comment-dots:before {\n  content: \"\\f4ad\"; }\n\n.fa-comment-medical:before {\n  content: \"\\f7f5\"; }\n\n.fa-comment-slash:before {\n  content: \"\\f4b3\"; }\n\n.fa-comments:before {\n  content: \"\\f086\"; }\n\n.fa-comments-dollar:before {\n  content: \"\\f653\"; }\n\n.fa-compact-disc:before {\n  content: \"\\f51f\"; }\n\n.fa-compass:before {\n  content: \"\\f14e\"; }\n\n.fa-compress:before {\n  content: \"\\f066\"; }\n\n.fa-compress-alt:before {\n  content: \"\\f422\"; }\n\n.fa-compress-arrows-alt:before {\n  content: \"\\f78c\"; }\n\n.fa-concierge-bell:before {\n  content: \"\\f562\"; }\n\n.fa-confluence:before {\n  content: \"\\f78d\"; }\n\n.fa-connectdevelop:before {\n  content: \"\\f20e\"; }\n\n.fa-contao:before {\n  content: \"\\f26d\"; }\n\n.fa-cookie:before {\n  content: \"\\f563\"; }\n\n.fa-cookie-bite:before {\n  content: \"\\f564\"; }\n\n.fa-copy:before {\n  content: \"\\f0c5\"; }\n\n.fa-copyright:before {\n  content: \"\\f1f9\"; }\n\n.fa-cotton-bureau:before {\n  content: \"\\f89e\"; }\n\n.fa-couch:before {\n  content: \"\\f4b8\"; }\n\n.fa-cpanel:before {\n  content: \"\\f388\"; }\n\n.fa-creative-commons:before {\n  content: \"\\f25e\"; }\n\n.fa-creative-commons-by:before {\n  content: \"\\f4e7\"; }\n\n.fa-creative-commons-nc:before {\n  content: \"\\f4e8\"; }\n\n.fa-creative-commons-nc-eu:before {\n  content: \"\\f4e9\"; }\n\n.fa-creative-commons-nc-jp:before {\n  content: \"\\f4ea\"; }\n\n.fa-creative-commons-nd:before {\n  content: \"\\f4eb\"; }\n\n.fa-creative-commons-pd:before {\n  content: \"\\f4ec\"; }\n\n.fa-creative-commons-pd-alt:before {\n  content: \"\\f4ed\"; }\n\n.fa-creative-commons-remix:before {\n  content: \"\\f4ee\"; }\n\n.fa-creative-commons-sa:before {\n  content: \"\\f4ef\"; }\n\n.fa-creative-commons-sampling:before {\n  content: \"\\f4f0\"; }\n\n.fa-creative-commons-sampling-plus:before {\n  content: \"\\f4f1\"; }\n\n.fa-creative-commons-share:before {\n  content: \"\\f4f2\"; }\n\n.fa-creative-commons-zero:before {\n  content: \"\\f4f3\"; }\n\n.fa-credit-card:before {\n  content: \"\\f09d\"; }\n\n.fa-critical-role:before {\n  content: \"\\f6c9\"; }\n\n.fa-crop:before {\n  content: \"\\f125\"; }\n\n.fa-crop-alt:before {\n  content: \"\\f565\"; }\n\n.fa-cross:before {\n  content: \"\\f654\"; }\n\n.fa-crosshairs:before {\n  content: \"\\f05b\"; }\n\n.fa-crow:before {\n  content: \"\\f520\"; }\n\n.fa-crown:before {\n  content: \"\\f521\"; }\n\n.fa-crutch:before {\n  content: \"\\f7f7\"; }\n\n.fa-css3:before {\n  content: \"\\f13c\"; }\n\n.fa-css3-alt:before {\n  content: \"\\f38b\"; }\n\n.fa-cube:before {\n  content: \"\\f1b2\"; }\n\n.fa-cubes:before {\n  content: \"\\f1b3\"; }\n\n.fa-cut:before {\n  content: \"\\f0c4\"; }\n\n.fa-cuttlefish:before {\n  content: \"\\f38c\"; }\n\n.fa-d-and-d:before {\n  content: \"\\f38d\"; }\n\n.fa-d-and-d-beyond:before {\n  content: \"\\f6ca\"; }\n\n.fa-dailymotion:before {\n  content: \"\\e052\"; }\n\n.fa-dashcube:before {\n  content: \"\\f210\"; }\n\n.fa-database:before {\n  content: \"\\f1c0\"; }\n\n.fa-deaf:before {\n  content: \"\\f2a4\"; }\n\n.fa-deezer:before {\n  content: \"\\e077\"; }\n\n.fa-delicious:before {\n  content: \"\\f1a5\"; }\n\n.fa-democrat:before {\n  content: \"\\f747\"; }\n\n.fa-deploydog:before {\n  content: \"\\f38e\"; }\n\n.fa-deskpro:before {\n  content: \"\\f38f\"; }\n\n.fa-desktop:before {\n  content: \"\\f108\"; }\n\n.fa-dev:before {\n  content: \"\\f6cc\"; }\n\n.fa-deviantart:before {\n  content: \"\\f1bd\"; }\n\n.fa-dharmachakra:before {\n  content: \"\\f655\"; }\n\n.fa-dhl:before {\n  content: \"\\f790\"; }\n\n.fa-diagnoses:before {\n  content: \"\\f470\"; }\n\n.fa-diaspora:before {\n  content: \"\\f791\"; }\n\n.fa-dice:before {\n  content: \"\\f522\"; }\n\n.fa-dice-d20:before {\n  content: \"\\f6cf\"; }\n\n.fa-dice-d6:before {\n  content: \"\\f6d1\"; }\n\n.fa-dice-five:before {\n  content: \"\\f523\"; }\n\n.fa-dice-four:before {\n  content: \"\\f524\"; }\n\n.fa-dice-one:before {\n  content: \"\\f525\"; }\n\n.fa-dice-six:before {\n  content: \"\\f526\"; }\n\n.fa-dice-three:before {\n  content: \"\\f527\"; }\n\n.fa-dice-two:before {\n  content: \"\\f528\"; }\n\n.fa-digg:before {\n  content: \"\\f1a6\"; }\n\n.fa-digital-ocean:before {\n  content: \"\\f391\"; }\n\n.fa-digital-tachograph:before {\n  content: \"\\f566\"; }\n\n.fa-directions:before {\n  content: \"\\f5eb\"; }\n\n.fa-discord:before {\n  content: \"\\f392\"; }\n\n.fa-discourse:before {\n  content: \"\\f393\"; }\n\n.fa-disease:before {\n  content: \"\\f7fa\"; }\n\n.fa-divide:before {\n  content: \"\\f529\"; }\n\n.fa-dizzy:before {\n  content: \"\\f567\"; }\n\n.fa-dna:before {\n  content: \"\\f471\"; }\n\n.fa-dochub:before {\n  content: \"\\f394\"; }\n\n.fa-docker:before {\n  content: \"\\f395\"; }\n\n.fa-dog:before {\n  content: \"\\f6d3\"; }\n\n.fa-dollar-sign:before {\n  content: \"\\f155\"; }\n\n.fa-dolly:before {\n  content: \"\\f472\"; }\n\n.fa-dolly-flatbed:before {\n  content: \"\\f474\"; }\n\n.fa-donate:before {\n  content: \"\\f4b9\"; }\n\n.fa-door-closed:before {\n  content: \"\\f52a\"; }\n\n.fa-door-open:before {\n  content: \"\\f52b\"; }\n\n.fa-dot-circle:before {\n  content: \"\\f192\"; }\n\n.fa-dove:before {\n  content: \"\\f4ba\"; }\n\n.fa-download:before {\n  content: \"\\f019\"; }\n\n.fa-draft2digital:before {\n  content: \"\\f396\"; }\n\n.fa-drafting-compass:before {\n  content: \"\\f568\"; }\n\n.fa-dragon:before {\n  content: \"\\f6d5\"; }\n\n.fa-draw-polygon:before {\n  content: \"\\f5ee\"; }\n\n.fa-dribbble:before {\n  content: \"\\f17d\"; }\n\n.fa-dribbble-square:before {\n  content: \"\\f397\"; }\n\n.fa-dropbox:before {\n  content: \"\\f16b\"; }\n\n.fa-drum:before {\n  content: \"\\f569\"; }\n\n.fa-drum-steelpan:before {\n  content: \"\\f56a\"; }\n\n.fa-drumstick-bite:before {\n  content: \"\\f6d7\"; }\n\n.fa-drupal:before {\n  content: \"\\f1a9\"; }\n\n.fa-dumbbell:before {\n  content: \"\\f44b\"; }\n\n.fa-dumpster:before {\n  content: \"\\f793\"; }\n\n.fa-dumpster-fire:before {\n  content: \"\\f794\"; }\n\n.fa-dungeon:before {\n  content: \"\\f6d9\"; }\n\n.fa-dyalog:before {\n  content: \"\\f399\"; }\n\n.fa-earlybirds:before {\n  content: \"\\f39a\"; }\n\n.fa-ebay:before {\n  content: \"\\f4f4\"; }\n\n.fa-edge:before {\n  content: \"\\f282\"; }\n\n.fa-edge-legacy:before {\n  content: \"\\e078\"; }\n\n.fa-edit:before {\n  content: \"\\f044\"; }\n\n.fa-egg:before {\n  content: \"\\f7fb\"; }\n\n.fa-eject:before {\n  content: \"\\f052\"; }\n\n.fa-elementor:before {\n  content: \"\\f430\"; }\n\n.fa-ellipsis-h:before {\n  content: \"\\f141\"; }\n\n.fa-ellipsis-v:before {\n  content: \"\\f142\"; }\n\n.fa-ello:before {\n  content: \"\\f5f1\"; }\n\n.fa-ember:before {\n  content: \"\\f423\"; }\n\n.fa-empire:before {\n  content: \"\\f1d1\"; }\n\n.fa-envelope:before {\n  content: \"\\f0e0\"; }\n\n.fa-envelope-open:before {\n  content: \"\\f2b6\"; }\n\n.fa-envelope-open-text:before {\n  content: \"\\f658\"; }\n\n.fa-envelope-square:before {\n  content: \"\\f199\"; }\n\n.fa-envira:before {\n  content: \"\\f299\"; }\n\n.fa-equals:before {\n  content: \"\\f52c\"; }\n\n.fa-eraser:before {\n  content: \"\\f12d\"; }\n\n.fa-erlang:before {\n  content: \"\\f39d\"; }\n\n.fa-ethereum:before {\n  content: \"\\f42e\"; }\n\n.fa-ethernet:before {\n  content: \"\\f796\"; }\n\n.fa-etsy:before {\n  content: \"\\f2d7\"; }\n\n.fa-euro-sign:before {\n  content: \"\\f153\"; }\n\n.fa-evernote:before {\n  content: \"\\f839\"; }\n\n.fa-exchange-alt:before {\n  content: \"\\f362\"; }\n\n.fa-exclamation:before {\n  content: \"\\f12a\"; }\n\n.fa-exclamation-circle:before {\n  content: \"\\f06a\"; }\n\n.fa-exclamation-triangle:before {\n  content: \"\\f071\"; }\n\n.fa-expand:before {\n  content: \"\\f065\"; }\n\n.fa-expand-alt:before {\n  content: \"\\f424\"; }\n\n.fa-expand-arrows-alt:before {\n  content: \"\\f31e\"; }\n\n.fa-expeditedssl:before {\n  content: \"\\f23e\"; }\n\n.fa-external-link-alt:before {\n  content: \"\\f35d\"; }\n\n.fa-external-link-square-alt:before {\n  content: \"\\f360\"; }\n\n.fa-eye:before {\n  content: \"\\f06e\"; }\n\n.fa-eye-dropper:before {\n  content: \"\\f1fb\"; }\n\n.fa-eye-slash:before {\n  content: \"\\f070\"; }\n\n.fa-facebook:before {\n  content: \"\\f09a\"; }\n\n.fa-facebook-f:before {\n  content: \"\\f39e\"; }\n\n.fa-facebook-messenger:before {\n  content: \"\\f39f\"; }\n\n.fa-facebook-square:before {\n  content: \"\\f082\"; }\n\n.fa-fan:before {\n  content: \"\\f863\"; }\n\n.fa-fantasy-flight-games:before {\n  content: \"\\f6dc\"; }\n\n.fa-fast-backward:before {\n  content: \"\\f049\"; }\n\n.fa-fast-forward:before {\n  content: \"\\f050\"; }\n\n.fa-faucet:before {\n  content: \"\\e005\"; }\n\n.fa-fax:before {\n  content: \"\\f1ac\"; }\n\n.fa-feather:before {\n  content: \"\\f52d\"; }\n\n.fa-feather-alt:before {\n  content: \"\\f56b\"; }\n\n.fa-fedex:before {\n  content: \"\\f797\"; }\n\n.fa-fedora:before {\n  content: \"\\f798\"; }\n\n.fa-female:before {\n  content: \"\\f182\"; }\n\n.fa-fighter-jet:before {\n  content: \"\\f0fb\"; }\n\n.fa-figma:before {\n  content: \"\\f799\"; }\n\n.fa-file:before {\n  content: \"\\f15b\"; }\n\n.fa-file-alt:before {\n  content: \"\\f15c\"; }\n\n.fa-file-archive:before {\n  content: \"\\f1c6\"; }\n\n.fa-file-audio:before {\n  content: \"\\f1c7\"; }\n\n.fa-file-code:before {\n  content: \"\\f1c9\"; }\n\n.fa-file-contract:before {\n  content: \"\\f56c\"; }\n\n.fa-file-csv:before {\n  content: \"\\f6dd\"; }\n\n.fa-file-download:before {\n  content: \"\\f56d\"; }\n\n.fa-file-excel:before {\n  content: \"\\f1c3\"; }\n\n.fa-file-export:before {\n  content: \"\\f56e\"; }\n\n.fa-file-image:before {\n  content: \"\\f1c5\"; }\n\n.fa-file-import:before {\n  content: \"\\f56f\"; }\n\n.fa-file-invoice:before {\n  content: \"\\f570\"; }\n\n.fa-file-invoice-dollar:before {\n  content: \"\\f571\"; }\n\n.fa-file-medical:before {\n  content: \"\\f477\"; }\n\n.fa-file-medical-alt:before {\n  content: \"\\f478\"; }\n\n.fa-file-pdf:before {\n  content: \"\\f1c1\"; }\n\n.fa-file-powerpoint:before {\n  content: \"\\f1c4\"; }\n\n.fa-file-prescription:before {\n  content: \"\\f572\"; }\n\n.fa-file-signature:before {\n  content: \"\\f573\"; }\n\n.fa-file-upload:before {\n  content: \"\\f574\"; }\n\n.fa-file-video:before {\n  content: \"\\f1c8\"; }\n\n.fa-file-word:before {\n  content: \"\\f1c2\"; }\n\n.fa-fill:before {\n  content: \"\\f575\"; }\n\n.fa-fill-drip:before {\n  content: \"\\f576\"; }\n\n.fa-film:before {\n  content: \"\\f008\"; }\n\n.fa-filter:before {\n  content: \"\\f0b0\"; }\n\n.fa-fingerprint:before {\n  content: \"\\f577\"; }\n\n.fa-fire:before {\n  content: \"\\f06d\"; }\n\n.fa-fire-alt:before {\n  content: \"\\f7e4\"; }\n\n.fa-fire-extinguisher:before {\n  content: \"\\f134\"; }\n\n.fa-firefox:before {\n  content: \"\\f269\"; }\n\n.fa-firefox-browser:before {\n  content: \"\\e007\"; }\n\n.fa-first-aid:before {\n  content: \"\\f479\"; }\n\n.fa-first-order:before {\n  content: \"\\f2b0\"; }\n\n.fa-first-order-alt:before {\n  content: \"\\f50a\"; }\n\n.fa-firstdraft:before {\n  content: \"\\f3a1\"; }\n\n.fa-fish:before {\n  content: \"\\f578\"; }\n\n.fa-fist-raised:before {\n  content: \"\\f6de\"; }\n\n.fa-flag:before {\n  content: \"\\f024\"; }\n\n.fa-flag-checkered:before {\n  content: \"\\f11e\"; }\n\n.fa-flag-usa:before {\n  content: \"\\f74d\"; }\n\n.fa-flask:before {\n  content: \"\\f0c3\"; }\n\n.fa-flickr:before {\n  content: \"\\f16e\"; }\n\n.fa-flipboard:before {\n  content: \"\\f44d\"; }\n\n.fa-flushed:before {\n  content: \"\\f579\"; }\n\n.fa-fly:before {\n  content: \"\\f417\"; }\n\n.fa-folder:before {\n  content: \"\\f07b\"; }\n\n.fa-folder-minus:before {\n  content: \"\\f65d\"; }\n\n.fa-folder-open:before {\n  content: \"\\f07c\"; }\n\n.fa-folder-plus:before {\n  content: \"\\f65e\"; }\n\n.fa-font:before {\n  content: \"\\f031\"; }\n\n.fa-font-awesome:before {\n  content: \"\\f2b4\"; }\n\n.fa-font-awesome-alt:before {\n  content: \"\\f35c\"; }\n\n.fa-font-awesome-flag:before {\n  content: \"\\f425\"; }\n\n.fa-font-awesome-logo-full:before {\n  content: \"\\f4e6\"; }\n\n.fa-fonticons:before {\n  content: \"\\f280\"; }\n\n.fa-fonticons-fi:before {\n  content: \"\\f3a2\"; }\n\n.fa-football-ball:before {\n  content: \"\\f44e\"; }\n\n.fa-fort-awesome:before {\n  content: \"\\f286\"; }\n\n.fa-fort-awesome-alt:before {\n  content: \"\\f3a3\"; }\n\n.fa-forumbee:before {\n  content: \"\\f211\"; }\n\n.fa-forward:before {\n  content: \"\\f04e\"; }\n\n.fa-foursquare:before {\n  content: \"\\f180\"; }\n\n.fa-free-code-camp:before {\n  content: \"\\f2c5\"; }\n\n.fa-freebsd:before {\n  content: \"\\f3a4\"; }\n\n.fa-frog:before {\n  content: \"\\f52e\"; }\n\n.fa-frown:before {\n  content: \"\\f119\"; }\n\n.fa-frown-open:before {\n  content: \"\\f57a\"; }\n\n.fa-fulcrum:before {\n  content: \"\\f50b\"; }\n\n.fa-funnel-dollar:before {\n  content: \"\\f662\"; }\n\n.fa-futbol:before {\n  content: \"\\f1e3\"; }\n\n.fa-galactic-republic:before {\n  content: \"\\f50c\"; }\n\n.fa-galactic-senate:before {\n  content: \"\\f50d\"; }\n\n.fa-gamepad:before {\n  content: \"\\f11b\"; }\n\n.fa-gas-pump:before {\n  content: \"\\f52f\"; }\n\n.fa-gavel:before {\n  content: \"\\f0e3\"; }\n\n.fa-gem:before {\n  content: \"\\f3a5\"; }\n\n.fa-genderless:before {\n  content: \"\\f22d\"; }\n\n.fa-get-pocket:before {\n  content: \"\\f265\"; }\n\n.fa-gg:before {\n  content: \"\\f260\"; }\n\n.fa-gg-circle:before {\n  content: \"\\f261\"; }\n\n.fa-ghost:before {\n  content: \"\\f6e2\"; }\n\n.fa-gift:before {\n  content: \"\\f06b\"; }\n\n.fa-gifts:before {\n  content: \"\\f79c\"; }\n\n.fa-git:before {\n  content: \"\\f1d3\"; }\n\n.fa-git-alt:before {\n  content: \"\\f841\"; }\n\n.fa-git-square:before {\n  content: \"\\f1d2\"; }\n\n.fa-github:before {\n  content: \"\\f09b\"; }\n\n.fa-github-alt:before {\n  content: \"\\f113\"; }\n\n.fa-github-square:before {\n  content: \"\\f092\"; }\n\n.fa-gitkraken:before {\n  content: \"\\f3a6\"; }\n\n.fa-gitlab:before {\n  content: \"\\f296\"; }\n\n.fa-gitter:before {\n  content: \"\\f426\"; }\n\n.fa-glass-cheers:before {\n  content: \"\\f79f\"; }\n\n.fa-glass-martini:before {\n  content: \"\\f000\"; }\n\n.fa-glass-martini-alt:before {\n  content: \"\\f57b\"; }\n\n.fa-glass-whiskey:before {\n  content: \"\\f7a0\"; }\n\n.fa-glasses:before {\n  content: \"\\f530\"; }\n\n.fa-glide:before {\n  content: \"\\f2a5\"; }\n\n.fa-glide-g:before {\n  content: \"\\f2a6\"; }\n\n.fa-globe:before {\n  content: \"\\f0ac\"; }\n\n.fa-globe-africa:before {\n  content: \"\\f57c\"; }\n\n.fa-globe-americas:before {\n  content: \"\\f57d\"; }\n\n.fa-globe-asia:before {\n  content: \"\\f57e\"; }\n\n.fa-globe-europe:before {\n  content: \"\\f7a2\"; }\n\n.fa-gofore:before {\n  content: \"\\f3a7\"; }\n\n.fa-golf-ball:before {\n  content: \"\\f450\"; }\n\n.fa-goodreads:before {\n  content: \"\\f3a8\"; }\n\n.fa-goodreads-g:before {\n  content: \"\\f3a9\"; }\n\n.fa-google:before {\n  content: \"\\f1a0\"; }\n\n.fa-google-drive:before {\n  content: \"\\f3aa\"; }\n\n.fa-google-pay:before {\n  content: \"\\e079\"; }\n\n.fa-google-play:before {\n  content: \"\\f3ab\"; }\n\n.fa-google-plus:before {\n  content: \"\\f2b3\"; }\n\n.fa-google-plus-g:before {\n  content: \"\\f0d5\"; }\n\n.fa-google-plus-square:before {\n  content: \"\\f0d4\"; }\n\n.fa-google-wallet:before {\n  content: \"\\f1ee\"; }\n\n.fa-gopuram:before {\n  content: \"\\f664\"; }\n\n.fa-graduation-cap:before {\n  content: \"\\f19d\"; }\n\n.fa-gratipay:before {\n  content: \"\\f184\"; }\n\n.fa-grav:before {\n  content: \"\\f2d6\"; }\n\n.fa-greater-than:before {\n  content: \"\\f531\"; }\n\n.fa-greater-than-equal:before {\n  content: \"\\f532\"; }\n\n.fa-grimace:before {\n  content: \"\\f57f\"; }\n\n.fa-grin:before {\n  content: \"\\f580\"; }\n\n.fa-grin-alt:before {\n  content: \"\\f581\"; }\n\n.fa-grin-beam:before {\n  content: \"\\f582\"; }\n\n.fa-grin-beam-sweat:before {\n  content: \"\\f583\"; }\n\n.fa-grin-hearts:before {\n  content: \"\\f584\"; }\n\n.fa-grin-squint:before {\n  content: \"\\f585\"; }\n\n.fa-grin-squint-tears:before {\n  content: \"\\f586\"; }\n\n.fa-grin-stars:before {\n  content: \"\\f587\"; }\n\n.fa-grin-tears:before {\n  content: \"\\f588\"; }\n\n.fa-grin-tongue:before {\n  content: \"\\f589\"; }\n\n.fa-grin-tongue-squint:before {\n  content: \"\\f58a\"; }\n\n.fa-grin-tongue-wink:before {\n  content: \"\\f58b\"; }\n\n.fa-grin-wink:before {\n  content: \"\\f58c\"; }\n\n.fa-grip-horizontal:before {\n  content: \"\\f58d\"; }\n\n.fa-grip-lines:before {\n  content: \"\\f7a4\"; }\n\n.fa-grip-lines-vertical:before {\n  content: \"\\f7a5\"; }\n\n.fa-grip-vertical:before {\n  content: \"\\f58e\"; }\n\n.fa-gripfire:before {\n  content: \"\\f3ac\"; }\n\n.fa-grunt:before {\n  content: \"\\f3ad\"; }\n\n.fa-guilded:before {\n  content: \"\\e07e\"; }\n\n.fa-guitar:before {\n  content: \"\\f7a6\"; }\n\n.fa-gulp:before {\n  content: \"\\f3ae\"; }\n\n.fa-h-square:before {\n  content: \"\\f0fd\"; }\n\n.fa-hacker-news:before {\n  content: \"\\f1d4\"; }\n\n.fa-hacker-news-square:before {\n  content: \"\\f3af\"; }\n\n.fa-hackerrank:before {\n  content: \"\\f5f7\"; }\n\n.fa-hamburger:before {\n  content: \"\\f805\"; }\n\n.fa-hammer:before {\n  content: \"\\f6e3\"; }\n\n.fa-hamsa:before {\n  content: \"\\f665\"; }\n\n.fa-hand-holding:before {\n  content: \"\\f4bd\"; }\n\n.fa-hand-holding-heart:before {\n  content: \"\\f4be\"; }\n\n.fa-hand-holding-medical:before {\n  content: \"\\e05c\"; }\n\n.fa-hand-holding-usd:before {\n  content: \"\\f4c0\"; }\n\n.fa-hand-holding-water:before {\n  content: \"\\f4c1\"; }\n\n.fa-hand-lizard:before {\n  content: \"\\f258\"; }\n\n.fa-hand-middle-finger:before {\n  content: \"\\f806\"; }\n\n.fa-hand-paper:before {\n  content: \"\\f256\"; }\n\n.fa-hand-peace:before {\n  content: \"\\f25b\"; }\n\n.fa-hand-point-down:before {\n  content: \"\\f0a7\"; }\n\n.fa-hand-point-left:before {\n  content: \"\\f0a5\"; }\n\n.fa-hand-point-right:before {\n  content: \"\\f0a4\"; }\n\n.fa-hand-point-up:before {\n  content: \"\\f0a6\"; }\n\n.fa-hand-pointer:before {\n  content: \"\\f25a\"; }\n\n.fa-hand-rock:before {\n  content: \"\\f255\"; }\n\n.fa-hand-scissors:before {\n  content: \"\\f257\"; }\n\n.fa-hand-sparkles:before {\n  content: \"\\e05d\"; }\n\n.fa-hand-spock:before {\n  content: \"\\f259\"; }\n\n.fa-hands:before {\n  content: \"\\f4c2\"; }\n\n.fa-hands-helping:before {\n  content: \"\\f4c4\"; }\n\n.fa-hands-wash:before {\n  content: \"\\e05e\"; }\n\n.fa-handshake:before {\n  content: \"\\f2b5\"; }\n\n.fa-handshake-alt-slash:before {\n  content: \"\\e05f\"; }\n\n.fa-handshake-slash:before {\n  content: \"\\e060\"; }\n\n.fa-hanukiah:before {\n  content: \"\\f6e6\"; }\n\n.fa-hard-hat:before {\n  content: \"\\f807\"; }\n\n.fa-hashtag:before {\n  content: \"\\f292\"; }\n\n.fa-hat-cowboy:before {\n  content: \"\\f8c0\"; }\n\n.fa-hat-cowboy-side:before {\n  content: \"\\f8c1\"; }\n\n.fa-hat-wizard:before {\n  content: \"\\f6e8\"; }\n\n.fa-hdd:before {\n  content: \"\\f0a0\"; }\n\n.fa-head-side-cough:before {\n  content: \"\\e061\"; }\n\n.fa-head-side-cough-slash:before {\n  content: \"\\e062\"; }\n\n.fa-head-side-mask:before {\n  content: \"\\e063\"; }\n\n.fa-head-side-virus:before {\n  content: \"\\e064\"; }\n\n.fa-heading:before {\n  content: \"\\f1dc\"; }\n\n.fa-headphones:before {\n  content: \"\\f025\"; }\n\n.fa-headphones-alt:before {\n  content: \"\\f58f\"; }\n\n.fa-headset:before {\n  content: \"\\f590\"; }\n\n.fa-heart:before {\n  content: \"\\f004\"; }\n\n.fa-heart-broken:before {\n  content: \"\\f7a9\"; }\n\n.fa-heartbeat:before {\n  content: \"\\f21e\"; }\n\n.fa-helicopter:before {\n  content: \"\\f533\"; }\n\n.fa-highlighter:before {\n  content: \"\\f591\"; }\n\n.fa-hiking:before {\n  content: \"\\f6ec\"; }\n\n.fa-hippo:before {\n  content: \"\\f6ed\"; }\n\n.fa-hips:before {\n  content: \"\\f452\"; }\n\n.fa-hire-a-helper:before {\n  content: \"\\f3b0\"; }\n\n.fa-history:before {\n  content: \"\\f1da\"; }\n\n.fa-hive:before {\n  content: \"\\e07f\"; }\n\n.fa-hockey-puck:before {\n  content: \"\\f453\"; }\n\n.fa-holly-berry:before {\n  content: \"\\f7aa\"; }\n\n.fa-home:before {\n  content: \"\\f015\"; }\n\n.fa-hooli:before {\n  content: \"\\f427\"; }\n\n.fa-hornbill:before {\n  content: \"\\f592\"; }\n\n.fa-horse:before {\n  content: \"\\f6f0\"; }\n\n.fa-horse-head:before {\n  content: \"\\f7ab\"; }\n\n.fa-hospital:before {\n  content: \"\\f0f8\"; }\n\n.fa-hospital-alt:before {\n  content: \"\\f47d\"; }\n\n.fa-hospital-symbol:before {\n  content: \"\\f47e\"; }\n\n.fa-hospital-user:before {\n  content: \"\\f80d\"; }\n\n.fa-hot-tub:before {\n  content: \"\\f593\"; }\n\n.fa-hotdog:before {\n  content: \"\\f80f\"; }\n\n.fa-hotel:before {\n  content: \"\\f594\"; }\n\n.fa-hotjar:before {\n  content: \"\\f3b1\"; }\n\n.fa-hourglass:before {\n  content: \"\\f254\"; }\n\n.fa-hourglass-end:before {\n  content: \"\\f253\"; }\n\n.fa-hourglass-half:before {\n  content: \"\\f252\"; }\n\n.fa-hourglass-start:before {\n  content: \"\\f251\"; }\n\n.fa-house-damage:before {\n  content: \"\\f6f1\"; }\n\n.fa-house-user:before {\n  content: \"\\e065\"; }\n\n.fa-houzz:before {\n  content: \"\\f27c\"; }\n\n.fa-hryvnia:before {\n  content: \"\\f6f2\"; }\n\n.fa-html5:before {\n  content: \"\\f13b\"; }\n\n.fa-hubspot:before {\n  content: \"\\f3b2\"; }\n\n.fa-i-cursor:before {\n  content: \"\\f246\"; }\n\n.fa-ice-cream:before {\n  content: \"\\f810\"; }\n\n.fa-icicles:before {\n  content: \"\\f7ad\"; }\n\n.fa-icons:before {\n  content: \"\\f86d\"; }\n\n.fa-id-badge:before {\n  content: \"\\f2c1\"; }\n\n.fa-id-card:before {\n  content: \"\\f2c2\"; }\n\n.fa-id-card-alt:before {\n  content: \"\\f47f\"; }\n\n.fa-ideal:before {\n  content: \"\\e013\"; }\n\n.fa-igloo:before {\n  content: \"\\f7ae\"; }\n\n.fa-image:before {\n  content: \"\\f03e\"; }\n\n.fa-images:before {\n  content: \"\\f302\"; }\n\n.fa-imdb:before {\n  content: \"\\f2d8\"; }\n\n.fa-inbox:before {\n  content: \"\\f01c\"; }\n\n.fa-indent:before {\n  content: \"\\f03c\"; }\n\n.fa-industry:before {\n  content: \"\\f275\"; }\n\n.fa-infinity:before {\n  content: \"\\f534\"; }\n\n.fa-info:before {\n  content: \"\\f129\"; }\n\n.fa-info-circle:before {\n  content: \"\\f05a\"; }\n\n.fa-innosoft:before {\n  content: \"\\e080\"; }\n\n.fa-instagram:before {\n  content: \"\\f16d\"; }\n\n.fa-instagram-square:before {\n  content: \"\\e055\"; }\n\n.fa-instalod:before {\n  content: \"\\e081\"; }\n\n.fa-intercom:before {\n  content: \"\\f7af\"; }\n\n.fa-internet-explorer:before {\n  content: \"\\f26b\"; }\n\n.fa-invision:before {\n  content: \"\\f7b0\"; }\n\n.fa-ioxhost:before {\n  content: \"\\f208\"; }\n\n.fa-italic:before {\n  content: \"\\f033\"; }\n\n.fa-itch-io:before {\n  content: \"\\f83a\"; }\n\n.fa-itunes:before {\n  content: \"\\f3b4\"; }\n\n.fa-itunes-note:before {\n  content: \"\\f3b5\"; }\n\n.fa-java:before {\n  content: \"\\f4e4\"; }\n\n.fa-jedi:before {\n  content: \"\\f669\"; }\n\n.fa-jedi-order:before {\n  content: \"\\f50e\"; }\n\n.fa-jenkins:before {\n  content: \"\\f3b6\"; }\n\n.fa-jira:before {\n  content: \"\\f7b1\"; }\n\n.fa-joget:before {\n  content: \"\\f3b7\"; }\n\n.fa-joint:before {\n  content: \"\\f595\"; }\n\n.fa-joomla:before {\n  content: \"\\f1aa\"; }\n\n.fa-journal-whills:before {\n  content: \"\\f66a\"; }\n\n.fa-js:before {\n  content: \"\\f3b8\"; }\n\n.fa-js-square:before {\n  content: \"\\f3b9\"; }\n\n.fa-jsfiddle:before {\n  content: \"\\f1cc\"; }\n\n.fa-kaaba:before {\n  content: \"\\f66b\"; }\n\n.fa-kaggle:before {\n  content: \"\\f5fa\"; }\n\n.fa-key:before {\n  content: \"\\f084\"; }\n\n.fa-keybase:before {\n  content: \"\\f4f5\"; }\n\n.fa-keyboard:before {\n  content: \"\\f11c\"; }\n\n.fa-keycdn:before {\n  content: \"\\f3ba\"; }\n\n.fa-khanda:before {\n  content: \"\\f66d\"; }\n\n.fa-kickstarter:before {\n  content: \"\\f3bb\"; }\n\n.fa-kickstarter-k:before {\n  content: \"\\f3bc\"; }\n\n.fa-kiss:before {\n  content: \"\\f596\"; }\n\n.fa-kiss-beam:before {\n  content: \"\\f597\"; }\n\n.fa-kiss-wink-heart:before {\n  content: \"\\f598\"; }\n\n.fa-kiwi-bird:before {\n  content: \"\\f535\"; }\n\n.fa-korvue:before {\n  content: \"\\f42f\"; }\n\n.fa-landmark:before {\n  content: \"\\f66f\"; }\n\n.fa-language:before {\n  content: \"\\f1ab\"; }\n\n.fa-laptop:before {\n  content: \"\\f109\"; }\n\n.fa-laptop-code:before {\n  content: \"\\f5fc\"; }\n\n.fa-laptop-house:before {\n  content: \"\\e066\"; }\n\n.fa-laptop-medical:before {\n  content: \"\\f812\"; }\n\n.fa-laravel:before {\n  content: \"\\f3bd\"; }\n\n.fa-lastfm:before {\n  content: \"\\f202\"; }\n\n.fa-lastfm-square:before {\n  content: \"\\f203\"; }\n\n.fa-laugh:before {\n  content: \"\\f599\"; }\n\n.fa-laugh-beam:before {\n  content: \"\\f59a\"; }\n\n.fa-laugh-squint:before {\n  content: \"\\f59b\"; }\n\n.fa-laugh-wink:before {\n  content: \"\\f59c\"; }\n\n.fa-layer-group:before {\n  content: \"\\f5fd\"; }\n\n.fa-leaf:before {\n  content: \"\\f06c\"; }\n\n.fa-leanpub:before {\n  content: \"\\f212\"; }\n\n.fa-lemon:before {\n  content: \"\\f094\"; }\n\n.fa-less:before {\n  content: \"\\f41d\"; }\n\n.fa-less-than:before {\n  content: \"\\f536\"; }\n\n.fa-less-than-equal:before {\n  content: \"\\f537\"; }\n\n.fa-level-down-alt:before {\n  content: \"\\f3be\"; }\n\n.fa-level-up-alt:before {\n  content: \"\\f3bf\"; }\n\n.fa-life-ring:before {\n  content: \"\\f1cd\"; }\n\n.fa-lightbulb:before {\n  content: \"\\f0eb\"; }\n\n.fa-line:before {\n  content: \"\\f3c0\"; }\n\n.fa-link:before {\n  content: \"\\f0c1\"; }\n\n.fa-linkedin:before {\n  content: \"\\f08c\"; }\n\n.fa-linkedin-in:before {\n  content: \"\\f0e1\"; }\n\n.fa-linode:before {\n  content: \"\\f2b8\"; }\n\n.fa-linux:before {\n  content: \"\\f17c\"; }\n\n.fa-lira-sign:before {\n  content: \"\\f195\"; }\n\n.fa-list:before {\n  content: \"\\f03a\"; }\n\n.fa-list-alt:before {\n  content: \"\\f022\"; }\n\n.fa-list-ol:before {\n  content: \"\\f0cb\"; }\n\n.fa-list-ul:before {\n  content: \"\\f0ca\"; }\n\n.fa-location-arrow:before {\n  content: \"\\f124\"; }\n\n.fa-lock:before {\n  content: \"\\f023\"; }\n\n.fa-lock-open:before {\n  content: \"\\f3c1\"; }\n\n.fa-long-arrow-alt-down:before {\n  content: \"\\f309\"; }\n\n.fa-long-arrow-alt-left:before {\n  content: \"\\f30a\"; }\n\n.fa-long-arrow-alt-right:before {\n  content: \"\\f30b\"; }\n\n.fa-long-arrow-alt-up:before {\n  content: \"\\f30c\"; }\n\n.fa-low-vision:before {\n  content: \"\\f2a8\"; }\n\n.fa-luggage-cart:before {\n  content: \"\\f59d\"; }\n\n.fa-lungs:before {\n  content: \"\\f604\"; }\n\n.fa-lungs-virus:before {\n  content: \"\\e067\"; }\n\n.fa-lyft:before {\n  content: \"\\f3c3\"; }\n\n.fa-magento:before {\n  content: \"\\f3c4\"; }\n\n.fa-magic:before {\n  content: \"\\f0d0\"; }\n\n.fa-magnet:before {\n  content: \"\\f076\"; }\n\n.fa-mail-bulk:before {\n  content: \"\\f674\"; }\n\n.fa-mailchimp:before {\n  content: \"\\f59e\"; }\n\n.fa-male:before {\n  content: \"\\f183\"; }\n\n.fa-mandalorian:before {\n  content: \"\\f50f\"; }\n\n.fa-map:before {\n  content: \"\\f279\"; }\n\n.fa-map-marked:before {\n  content: \"\\f59f\"; }\n\n.fa-map-marked-alt:before {\n  content: \"\\f5a0\"; }\n\n.fa-map-marker:before {\n  content: \"\\f041\"; }\n\n.fa-map-marker-alt:before {\n  content: \"\\f3c5\"; }\n\n.fa-map-pin:before {\n  content: \"\\f276\"; }\n\n.fa-map-signs:before {\n  content: \"\\f277\"; }\n\n.fa-markdown:before {\n  content: \"\\f60f\"; }\n\n.fa-marker:before {\n  content: \"\\f5a1\"; }\n\n.fa-mars:before {\n  content: \"\\f222\"; }\n\n.fa-mars-double:before {\n  content: \"\\f227\"; }\n\n.fa-mars-stroke:before {\n  content: \"\\f229\"; }\n\n.fa-mars-stroke-h:before {\n  content: \"\\f22b\"; }\n\n.fa-mars-stroke-v:before {\n  content: \"\\f22a\"; }\n\n.fa-mask:before {\n  content: \"\\f6fa\"; }\n\n.fa-mastodon:before {\n  content: \"\\f4f6\"; }\n\n.fa-maxcdn:before {\n  content: \"\\f136\"; }\n\n.fa-mdb:before {\n  content: \"\\f8ca\"; }\n\n.fa-medal:before {\n  content: \"\\f5a2\"; }\n\n.fa-medapps:before {\n  content: \"\\f3c6\"; }\n\n.fa-medium:before {\n  content: \"\\f23a\"; }\n\n.fa-medium-m:before {\n  content: \"\\f3c7\"; }\n\n.fa-medkit:before {\n  content: \"\\f0fa\"; }\n\n.fa-medrt:before {\n  content: \"\\f3c8\"; }\n\n.fa-meetup:before {\n  content: \"\\f2e0\"; }\n\n.fa-megaport:before {\n  content: \"\\f5a3\"; }\n\n.fa-meh:before {\n  content: \"\\f11a\"; }\n\n.fa-meh-blank:before {\n  content: \"\\f5a4\"; }\n\n.fa-meh-rolling-eyes:before {\n  content: \"\\f5a5\"; }\n\n.fa-memory:before {\n  content: \"\\f538\"; }\n\n.fa-mendeley:before {\n  content: \"\\f7b3\"; }\n\n.fa-menorah:before {\n  content: \"\\f676\"; }\n\n.fa-mercury:before {\n  content: \"\\f223\"; }\n\n.fa-meteor:before {\n  content: \"\\f753\"; }\n\n.fa-microblog:before {\n  content: \"\\e01a\"; }\n\n.fa-microchip:before {\n  content: \"\\f2db\"; }\n\n.fa-microphone:before {\n  content: \"\\f130\"; }\n\n.fa-microphone-alt:before {\n  content: \"\\f3c9\"; }\n\n.fa-microphone-alt-slash:before {\n  content: \"\\f539\"; }\n\n.fa-microphone-slash:before {\n  content: \"\\f131\"; }\n\n.fa-microscope:before {\n  content: \"\\f610\"; }\n\n.fa-microsoft:before {\n  content: \"\\f3ca\"; }\n\n.fa-minus:before {\n  content: \"\\f068\"; }\n\n.fa-minus-circle:before {\n  content: \"\\f056\"; }\n\n.fa-minus-square:before {\n  content: \"\\f146\"; }\n\n.fa-mitten:before {\n  content: \"\\f7b5\"; }\n\n.fa-mix:before {\n  content: \"\\f3cb\"; }\n\n.fa-mixcloud:before {\n  content: \"\\f289\"; }\n\n.fa-mixer:before {\n  content: \"\\e056\"; }\n\n.fa-mizuni:before {\n  content: \"\\f3cc\"; }\n\n.fa-mobile:before {\n  content: \"\\f10b\"; }\n\n.fa-mobile-alt:before {\n  content: \"\\f3cd\"; }\n\n.fa-modx:before {\n  content: \"\\f285\"; }\n\n.fa-monero:before {\n  content: \"\\f3d0\"; }\n\n.fa-money-bill:before {\n  content: \"\\f0d6\"; }\n\n.fa-money-bill-alt:before {\n  content: \"\\f3d1\"; }\n\n.fa-money-bill-wave:before {\n  content: \"\\f53a\"; }\n\n.fa-money-bill-wave-alt:before {\n  content: \"\\f53b\"; }\n\n.fa-money-check:before {\n  content: \"\\f53c\"; }\n\n.fa-money-check-alt:before {\n  content: \"\\f53d\"; }\n\n.fa-monument:before {\n  content: \"\\f5a6\"; }\n\n.fa-moon:before {\n  content: \"\\f186\"; }\n\n.fa-mortar-pestle:before {\n  content: \"\\f5a7\"; }\n\n.fa-mosque:before {\n  content: \"\\f678\"; }\n\n.fa-motorcycle:before {\n  content: \"\\f21c\"; }\n\n.fa-mountain:before {\n  content: \"\\f6fc\"; }\n\n.fa-mouse:before {\n  content: \"\\f8cc\"; }\n\n.fa-mouse-pointer:before {\n  content: \"\\f245\"; }\n\n.fa-mug-hot:before {\n  content: \"\\f7b6\"; }\n\n.fa-music:before {\n  content: \"\\f001\"; }\n\n.fa-napster:before {\n  content: \"\\f3d2\"; }\n\n.fa-neos:before {\n  content: \"\\f612\"; }\n\n.fa-network-wired:before {\n  content: \"\\f6ff\"; }\n\n.fa-neuter:before {\n  content: \"\\f22c\"; }\n\n.fa-newspaper:before {\n  content: \"\\f1ea\"; }\n\n.fa-nimblr:before {\n  content: \"\\f5a8\"; }\n\n.fa-node:before {\n  content: \"\\f419\"; }\n\n.fa-node-js:before {\n  content: \"\\f3d3\"; }\n\n.fa-not-equal:before {\n  content: \"\\f53e\"; }\n\n.fa-notes-medical:before {\n  content: \"\\f481\"; }\n\n.fa-npm:before {\n  content: \"\\f3d4\"; }\n\n.fa-ns8:before {\n  content: \"\\f3d5\"; }\n\n.fa-nutritionix:before {\n  content: \"\\f3d6\"; }\n\n.fa-object-group:before {\n  content: \"\\f247\"; }\n\n.fa-object-ungroup:before {\n  content: \"\\f248\"; }\n\n.fa-octopus-deploy:before {\n  content: \"\\e082\"; }\n\n.fa-odnoklassniki:before {\n  content: \"\\f263\"; }\n\n.fa-odnoklassniki-square:before {\n  content: \"\\f264\"; }\n\n.fa-oil-can:before {\n  content: \"\\f613\"; }\n\n.fa-old-republic:before {\n  content: \"\\f510\"; }\n\n.fa-om:before {\n  content: \"\\f679\"; }\n\n.fa-opencart:before {\n  content: \"\\f23d\"; }\n\n.fa-openid:before {\n  content: \"\\f19b\"; }\n\n.fa-opera:before {\n  content: \"\\f26a\"; }\n\n.fa-optin-monster:before {\n  content: \"\\f23c\"; }\n\n.fa-orcid:before {\n  content: \"\\f8d2\"; }\n\n.fa-osi:before {\n  content: \"\\f41a\"; }\n\n.fa-otter:before {\n  content: \"\\f700\"; }\n\n.fa-outdent:before {\n  content: \"\\f03b\"; }\n\n.fa-page4:before {\n  content: \"\\f3d7\"; }\n\n.fa-pagelines:before {\n  content: \"\\f18c\"; }\n\n.fa-pager:before {\n  content: \"\\f815\"; }\n\n.fa-paint-brush:before {\n  content: \"\\f1fc\"; }\n\n.fa-paint-roller:before {\n  content: \"\\f5aa\"; }\n\n.fa-palette:before {\n  content: \"\\f53f\"; }\n\n.fa-palfed:before {\n  content: \"\\f3d8\"; }\n\n.fa-pallet:before {\n  content: \"\\f482\"; }\n\n.fa-paper-plane:before {\n  content: \"\\f1d8\"; }\n\n.fa-paperclip:before {\n  content: \"\\f0c6\"; }\n\n.fa-parachute-box:before {\n  content: \"\\f4cd\"; }\n\n.fa-paragraph:before {\n  content: \"\\f1dd\"; }\n\n.fa-parking:before {\n  content: \"\\f540\"; }\n\n.fa-passport:before {\n  content: \"\\f5ab\"; }\n\n.fa-pastafarianism:before {\n  content: \"\\f67b\"; }\n\n.fa-paste:before {\n  content: \"\\f0ea\"; }\n\n.fa-patreon:before {\n  content: \"\\f3d9\"; }\n\n.fa-pause:before {\n  content: \"\\f04c\"; }\n\n.fa-pause-circle:before {\n  content: \"\\f28b\"; }\n\n.fa-paw:before {\n  content: \"\\f1b0\"; }\n\n.fa-paypal:before {\n  content: \"\\f1ed\"; }\n\n.fa-peace:before {\n  content: \"\\f67c\"; }\n\n.fa-pen:before {\n  content: \"\\f304\"; }\n\n.fa-pen-alt:before {\n  content: \"\\f305\"; }\n\n.fa-pen-fancy:before {\n  content: \"\\f5ac\"; }\n\n.fa-pen-nib:before {\n  content: \"\\f5ad\"; }\n\n.fa-pen-square:before {\n  content: \"\\f14b\"; }\n\n.fa-pencil-alt:before {\n  content: \"\\f303\"; }\n\n.fa-pencil-ruler:before {\n  content: \"\\f5ae\"; }\n\n.fa-penny-arcade:before {\n  content: \"\\f704\"; }\n\n.fa-people-arrows:before {\n  content: \"\\e068\"; }\n\n.fa-people-carry:before {\n  content: \"\\f4ce\"; }\n\n.fa-pepper-hot:before {\n  content: \"\\f816\"; }\n\n.fa-perbyte:before {\n  content: \"\\e083\"; }\n\n.fa-percent:before {\n  content: \"\\f295\"; }\n\n.fa-percentage:before {\n  content: \"\\f541\"; }\n\n.fa-periscope:before {\n  content: \"\\f3da\"; }\n\n.fa-person-booth:before {\n  content: \"\\f756\"; }\n\n.fa-phabricator:before {\n  content: \"\\f3db\"; }\n\n.fa-phoenix-framework:before {\n  content: \"\\f3dc\"; }\n\n.fa-phoenix-squadron:before {\n  content: \"\\f511\"; }\n\n.fa-phone:before {\n  content: \"\\f095\"; }\n\n.fa-phone-alt:before {\n  content: \"\\f879\"; }\n\n.fa-phone-slash:before {\n  content: \"\\f3dd\"; }\n\n.fa-phone-square:before {\n  content: \"\\f098\"; }\n\n.fa-phone-square-alt:before {\n  content: \"\\f87b\"; }\n\n.fa-phone-volume:before {\n  content: \"\\f2a0\"; }\n\n.fa-photo-video:before {\n  content: \"\\f87c\"; }\n\n.fa-php:before {\n  content: \"\\f457\"; }\n\n.fa-pied-piper:before {\n  content: \"\\f2ae\"; }\n\n.fa-pied-piper-alt:before {\n  content: \"\\f1a8\"; }\n\n.fa-pied-piper-hat:before {\n  content: \"\\f4e5\"; }\n\n.fa-pied-piper-pp:before {\n  content: \"\\f1a7\"; }\n\n.fa-pied-piper-square:before {\n  content: \"\\e01e\"; }\n\n.fa-piggy-bank:before {\n  content: \"\\f4d3\"; }\n\n.fa-pills:before {\n  content: \"\\f484\"; }\n\n.fa-pinterest:before {\n  content: \"\\f0d2\"; }\n\n.fa-pinterest-p:before {\n  content: \"\\f231\"; }\n\n.fa-pinterest-square:before {\n  content: \"\\f0d3\"; }\n\n.fa-pizza-slice:before {\n  content: \"\\f818\"; }\n\n.fa-place-of-worship:before {\n  content: \"\\f67f\"; }\n\n.fa-plane:before {\n  content: \"\\f072\"; }\n\n.fa-plane-arrival:before {\n  content: \"\\f5af\"; }\n\n.fa-plane-departure:before {\n  content: \"\\f5b0\"; }\n\n.fa-plane-slash:before {\n  content: \"\\e069\"; }\n\n.fa-play:before {\n  content: \"\\f04b\"; }\n\n.fa-play-circle:before {\n  content: \"\\f144\"; }\n\n.fa-playstation:before {\n  content: \"\\f3df\"; }\n\n.fa-plug:before {\n  content: \"\\f1e6\"; }\n\n.fa-plus:before {\n  content: \"\\f067\"; }\n\n.fa-plus-circle:before {\n  content: \"\\f055\"; }\n\n.fa-plus-square:before {\n  content: \"\\f0fe\"; }\n\n.fa-podcast:before {\n  content: \"\\f2ce\"; }\n\n.fa-poll:before {\n  content: \"\\f681\"; }\n\n.fa-poll-h:before {\n  content: \"\\f682\"; }\n\n.fa-poo:before {\n  content: \"\\f2fe\"; }\n\n.fa-poo-storm:before {\n  content: \"\\f75a\"; }\n\n.fa-poop:before {\n  content: \"\\f619\"; }\n\n.fa-portrait:before {\n  content: \"\\f3e0\"; }\n\n.fa-pound-sign:before {\n  content: \"\\f154\"; }\n\n.fa-power-off:before {\n  content: \"\\f011\"; }\n\n.fa-pray:before {\n  content: \"\\f683\"; }\n\n.fa-praying-hands:before {\n  content: \"\\f684\"; }\n\n.fa-prescription:before {\n  content: \"\\f5b1\"; }\n\n.fa-prescription-bottle:before {\n  content: \"\\f485\"; }\n\n.fa-prescription-bottle-alt:before {\n  content: \"\\f486\"; }\n\n.fa-print:before {\n  content: \"\\f02f\"; }\n\n.fa-procedures:before {\n  content: \"\\f487\"; }\n\n.fa-product-hunt:before {\n  content: \"\\f288\"; }\n\n.fa-project-diagram:before {\n  content: \"\\f542\"; }\n\n.fa-pump-medical:before {\n  content: \"\\e06a\"; }\n\n.fa-pump-soap:before {\n  content: \"\\e06b\"; }\n\n.fa-pushed:before {\n  content: \"\\f3e1\"; }\n\n.fa-puzzle-piece:before {\n  content: \"\\f12e\"; }\n\n.fa-python:before {\n  content: \"\\f3e2\"; }\n\n.fa-qq:before {\n  content: \"\\f1d6\"; }\n\n.fa-qrcode:before {\n  content: \"\\f029\"; }\n\n.fa-question:before {\n  content: \"\\f128\"; }\n\n.fa-question-circle:before {\n  content: \"\\f059\"; }\n\n.fa-quidditch:before {\n  content: \"\\f458\"; }\n\n.fa-quinscape:before {\n  content: \"\\f459\"; }\n\n.fa-quora:before {\n  content: \"\\f2c4\"; }\n\n.fa-quote-left:before {\n  content: \"\\f10d\"; }\n\n.fa-quote-right:before {\n  content: \"\\f10e\"; }\n\n.fa-quran:before {\n  content: \"\\f687\"; }\n\n.fa-r-project:before {\n  content: \"\\f4f7\"; }\n\n.fa-radiation:before {\n  content: \"\\f7b9\"; }\n\n.fa-radiation-alt:before {\n  content: \"\\f7ba\"; }\n\n.fa-rainbow:before {\n  content: \"\\f75b\"; }\n\n.fa-random:before {\n  content: \"\\f074\"; }\n\n.fa-raspberry-pi:before {\n  content: \"\\f7bb\"; }\n\n.fa-ravelry:before {\n  content: \"\\f2d9\"; }\n\n.fa-react:before {\n  content: \"\\f41b\"; }\n\n.fa-reacteurope:before {\n  content: \"\\f75d\"; }\n\n.fa-readme:before {\n  content: \"\\f4d5\"; }\n\n.fa-rebel:before {\n  content: \"\\f1d0\"; }\n\n.fa-receipt:before {\n  content: \"\\f543\"; }\n\n.fa-record-vinyl:before {\n  content: \"\\f8d9\"; }\n\n.fa-recycle:before {\n  content: \"\\f1b8\"; }\n\n.fa-red-river:before {\n  content: \"\\f3e3\"; }\n\n.fa-reddit:before {\n  content: \"\\f1a1\"; }\n\n.fa-reddit-alien:before {\n  content: \"\\f281\"; }\n\n.fa-reddit-square:before {\n  content: \"\\f1a2\"; }\n\n.fa-redhat:before {\n  content: \"\\f7bc\"; }\n\n.fa-redo:before {\n  content: \"\\f01e\"; }\n\n.fa-redo-alt:before {\n  content: \"\\f2f9\"; }\n\n.fa-registered:before {\n  content: \"\\f25d\"; }\n\n.fa-remove-format:before {\n  content: \"\\f87d\"; }\n\n.fa-renren:before {\n  content: \"\\f18b\"; }\n\n.fa-reply:before {\n  content: \"\\f3e5\"; }\n\n.fa-reply-all:before {\n  content: \"\\f122\"; }\n\n.fa-replyd:before {\n  content: \"\\f3e6\"; }\n\n.fa-republican:before {\n  content: \"\\f75e\"; }\n\n.fa-researchgate:before {\n  content: \"\\f4f8\"; }\n\n.fa-resolving:before {\n  content: \"\\f3e7\"; }\n\n.fa-restroom:before {\n  content: \"\\f7bd\"; }\n\n.fa-retweet:before {\n  content: \"\\f079\"; }\n\n.fa-rev:before {\n  content: \"\\f5b2\"; }\n\n.fa-ribbon:before {\n  content: \"\\f4d6\"; }\n\n.fa-ring:before {\n  content: \"\\f70b\"; }\n\n.fa-road:before {\n  content: \"\\f018\"; }\n\n.fa-robot:before {\n  content: \"\\f544\"; }\n\n.fa-rocket:before {\n  content: \"\\f135\"; }\n\n.fa-rocketchat:before {\n  content: \"\\f3e8\"; }\n\n.fa-rockrms:before {\n  content: \"\\f3e9\"; }\n\n.fa-route:before {\n  content: \"\\f4d7\"; }\n\n.fa-rss:before {\n  content: \"\\f09e\"; }\n\n.fa-rss-square:before {\n  content: \"\\f143\"; }\n\n.fa-ruble-sign:before {\n  content: \"\\f158\"; }\n\n.fa-ruler:before {\n  content: \"\\f545\"; }\n\n.fa-ruler-combined:before {\n  content: \"\\f546\"; }\n\n.fa-ruler-horizontal:before {\n  content: \"\\f547\"; }\n\n.fa-ruler-vertical:before {\n  content: \"\\f548\"; }\n\n.fa-running:before {\n  content: \"\\f70c\"; }\n\n.fa-rupee-sign:before {\n  content: \"\\f156\"; }\n\n.fa-rust:before {\n  content: \"\\e07a\"; }\n\n.fa-sad-cry:before {\n  content: \"\\f5b3\"; }\n\n.fa-sad-tear:before {\n  content: \"\\f5b4\"; }\n\n.fa-safari:before {\n  content: \"\\f267\"; }\n\n.fa-salesforce:before {\n  content: \"\\f83b\"; }\n\n.fa-sass:before {\n  content: \"\\f41e\"; }\n\n.fa-satellite:before {\n  content: \"\\f7bf\"; }\n\n.fa-satellite-dish:before {\n  content: \"\\f7c0\"; }\n\n.fa-save:before {\n  content: \"\\f0c7\"; }\n\n.fa-schlix:before {\n  content: \"\\f3ea\"; }\n\n.fa-school:before {\n  content: \"\\f549\"; }\n\n.fa-screwdriver:before {\n  content: \"\\f54a\"; }\n\n.fa-scribd:before {\n  content: \"\\f28a\"; }\n\n.fa-scroll:before {\n  content: \"\\f70e\"; }\n\n.fa-sd-card:before {\n  content: \"\\f7c2\"; }\n\n.fa-search:before {\n  content: \"\\f002\"; }\n\n.fa-search-dollar:before {\n  content: \"\\f688\"; }\n\n.fa-search-location:before {\n  content: \"\\f689\"; }\n\n.fa-search-minus:before {\n  content: \"\\f010\"; }\n\n.fa-search-plus:before {\n  content: \"\\f00e\"; }\n\n.fa-searchengin:before {\n  content: \"\\f3eb\"; }\n\n.fa-seedling:before {\n  content: \"\\f4d8\"; }\n\n.fa-sellcast:before {\n  content: \"\\f2da\"; }\n\n.fa-sellsy:before {\n  content: \"\\f213\"; }\n\n.fa-server:before {\n  content: \"\\f233\"; }\n\n.fa-servicestack:before {\n  content: \"\\f3ec\"; }\n\n.fa-shapes:before {\n  content: \"\\f61f\"; }\n\n.fa-share:before {\n  content: \"\\f064\"; }\n\n.fa-share-alt:before {\n  content: \"\\f1e0\"; }\n\n.fa-share-alt-square:before {\n  content: \"\\f1e1\"; }\n\n.fa-share-square:before {\n  content: \"\\f14d\"; }\n\n.fa-shekel-sign:before {\n  content: \"\\f20b\"; }\n\n.fa-shield-alt:before {\n  content: \"\\f3ed\"; }\n\n.fa-shield-virus:before {\n  content: \"\\e06c\"; }\n\n.fa-ship:before {\n  content: \"\\f21a\"; }\n\n.fa-shipping-fast:before {\n  content: \"\\f48b\"; }\n\n.fa-shirtsinbulk:before {\n  content: \"\\f214\"; }\n\n.fa-shoe-prints:before {\n  content: \"\\f54b\"; }\n\n.fa-shopify:before {\n  content: \"\\e057\"; }\n\n.fa-shopping-bag:before {\n  content: \"\\f290\"; }\n\n.fa-shopping-basket:before {\n  content: \"\\f291\"; }\n\n.fa-shopping-cart:before {\n  content: \"\\f07a\"; }\n\n.fa-shopware:before {\n  content: \"\\f5b5\"; }\n\n.fa-shower:before {\n  content: \"\\f2cc\"; }\n\n.fa-shuttle-van:before {\n  content: \"\\f5b6\"; }\n\n.fa-sign:before {\n  content: \"\\f4d9\"; }\n\n.fa-sign-in-alt:before {\n  content: \"\\f2f6\"; }\n\n.fa-sign-language:before {\n  content: \"\\f2a7\"; }\n\n.fa-sign-out-alt:before {\n  content: \"\\f2f5\"; }\n\n.fa-signal:before {\n  content: \"\\f012\"; }\n\n.fa-signature:before {\n  content: \"\\f5b7\"; }\n\n.fa-sim-card:before {\n  content: \"\\f7c4\"; }\n\n.fa-simplybuilt:before {\n  content: \"\\f215\"; }\n\n.fa-sink:before {\n  content: \"\\e06d\"; }\n\n.fa-sistrix:before {\n  content: \"\\f3ee\"; }\n\n.fa-sitemap:before {\n  content: \"\\f0e8\"; }\n\n.fa-sith:before {\n  content: \"\\f512\"; }\n\n.fa-skating:before {\n  content: \"\\f7c5\"; }\n\n.fa-sketch:before {\n  content: \"\\f7c6\"; }\n\n.fa-skiing:before {\n  content: \"\\f7c9\"; }\n\n.fa-skiing-nordic:before {\n  content: \"\\f7ca\"; }\n\n.fa-skull:before {\n  content: \"\\f54c\"; }\n\n.fa-skull-crossbones:before {\n  content: \"\\f714\"; }\n\n.fa-skyatlas:before {\n  content: \"\\f216\"; }\n\n.fa-skype:before {\n  content: \"\\f17e\"; }\n\n.fa-slack:before {\n  content: \"\\f198\"; }\n\n.fa-slack-hash:before {\n  content: \"\\f3ef\"; }\n\n.fa-slash:before {\n  content: \"\\f715\"; }\n\n.fa-sleigh:before {\n  content: \"\\f7cc\"; }\n\n.fa-sliders-h:before {\n  content: \"\\f1de\"; }\n\n.fa-slideshare:before {\n  content: \"\\f1e7\"; }\n\n.fa-smile:before {\n  content: \"\\f118\"; }\n\n.fa-smile-beam:before {\n  content: \"\\f5b8\"; }\n\n.fa-smile-wink:before {\n  content: \"\\f4da\"; }\n\n.fa-smog:before {\n  content: \"\\f75f\"; }\n\n.fa-smoking:before {\n  content: \"\\f48d\"; }\n\n.fa-smoking-ban:before {\n  content: \"\\f54d\"; }\n\n.fa-sms:before {\n  content: \"\\f7cd\"; }\n\n.fa-snapchat:before {\n  content: \"\\f2ab\"; }\n\n.fa-snapchat-ghost:before {\n  content: \"\\f2ac\"; }\n\n.fa-snapchat-square:before {\n  content: \"\\f2ad\"; }\n\n.fa-snowboarding:before {\n  content: \"\\f7ce\"; }\n\n.fa-snowflake:before {\n  content: \"\\f2dc\"; }\n\n.fa-snowman:before {\n  content: \"\\f7d0\"; }\n\n.fa-snowplow:before {\n  content: \"\\f7d2\"; }\n\n.fa-soap:before {\n  content: \"\\e06e\"; }\n\n.fa-socks:before {\n  content: \"\\f696\"; }\n\n.fa-solar-panel:before {\n  content: \"\\f5ba\"; }\n\n.fa-sort:before {\n  content: \"\\f0dc\"; }\n\n.fa-sort-alpha-down:before {\n  content: \"\\f15d\"; }\n\n.fa-sort-alpha-down-alt:before {\n  content: \"\\f881\"; }\n\n.fa-sort-alpha-up:before {\n  content: \"\\f15e\"; }\n\n.fa-sort-alpha-up-alt:before {\n  content: \"\\f882\"; }\n\n.fa-sort-amount-down:before {\n  content: \"\\f160\"; }\n\n.fa-sort-amount-down-alt:before {\n  content: \"\\f884\"; }\n\n.fa-sort-amount-up:before {\n  content: \"\\f161\"; }\n\n.fa-sort-amount-up-alt:before {\n  content: \"\\f885\"; }\n\n.fa-sort-down:before {\n  content: \"\\f0dd\"; }\n\n.fa-sort-numeric-down:before {\n  content: \"\\f162\"; }\n\n.fa-sort-numeric-down-alt:before {\n  content: \"\\f886\"; }\n\n.fa-sort-numeric-up:before {\n  content: \"\\f163\"; }\n\n.fa-sort-numeric-up-alt:before {\n  content: \"\\f887\"; }\n\n.fa-sort-up:before {\n  content: \"\\f0de\"; }\n\n.fa-soundcloud:before {\n  content: \"\\f1be\"; }\n\n.fa-sourcetree:before {\n  content: \"\\f7d3\"; }\n\n.fa-spa:before {\n  content: \"\\f5bb\"; }\n\n.fa-space-shuttle:before {\n  content: \"\\f197\"; }\n\n.fa-speakap:before {\n  content: \"\\f3f3\"; }\n\n.fa-speaker-deck:before {\n  content: \"\\f83c\"; }\n\n.fa-spell-check:before {\n  content: \"\\f891\"; }\n\n.fa-spider:before {\n  content: \"\\f717\"; }\n\n.fa-spinner:before {\n  content: \"\\f110\"; }\n\n.fa-splotch:before {\n  content: \"\\f5bc\"; }\n\n.fa-spotify:before {\n  content: \"\\f1bc\"; }\n\n.fa-spray-can:before {\n  content: \"\\f5bd\"; }\n\n.fa-square:before {\n  content: \"\\f0c8\"; }\n\n.fa-square-full:before {\n  content: \"\\f45c\"; }\n\n.fa-square-root-alt:before {\n  content: \"\\f698\"; }\n\n.fa-squarespace:before {\n  content: \"\\f5be\"; }\n\n.fa-stack-exchange:before {\n  content: \"\\f18d\"; }\n\n.fa-stack-overflow:before {\n  content: \"\\f16c\"; }\n\n.fa-stackpath:before {\n  content: \"\\f842\"; }\n\n.fa-stamp:before {\n  content: \"\\f5bf\"; }\n\n.fa-star:before {\n  content: \"\\f005\"; }\n\n.fa-star-and-crescent:before {\n  content: \"\\f699\"; }\n\n.fa-star-half:before {\n  content: \"\\f089\"; }\n\n.fa-star-half-alt:before {\n  content: \"\\f5c0\"; }\n\n.fa-star-of-david:before {\n  content: \"\\f69a\"; }\n\n.fa-star-of-life:before {\n  content: \"\\f621\"; }\n\n.fa-staylinked:before {\n  content: \"\\f3f5\"; }\n\n.fa-steam:before {\n  content: \"\\f1b6\"; }\n\n.fa-steam-square:before {\n  content: \"\\f1b7\"; }\n\n.fa-steam-symbol:before {\n  content: \"\\f3f6\"; }\n\n.fa-step-backward:before {\n  content: \"\\f048\"; }\n\n.fa-step-forward:before {\n  content: \"\\f051\"; }\n\n.fa-stethoscope:before {\n  content: \"\\f0f1\"; }\n\n.fa-sticker-mule:before {\n  content: \"\\f3f7\"; }\n\n.fa-sticky-note:before {\n  content: \"\\f249\"; }\n\n.fa-stop:before {\n  content: \"\\f04d\"; }\n\n.fa-stop-circle:before {\n  content: \"\\f28d\"; }\n\n.fa-stopwatch:before {\n  content: \"\\f2f2\"; }\n\n.fa-stopwatch-20:before {\n  content: \"\\e06f\"; }\n\n.fa-store:before {\n  content: \"\\f54e\"; }\n\n.fa-store-alt:before {\n  content: \"\\f54f\"; }\n\n.fa-store-alt-slash:before {\n  content: \"\\e070\"; }\n\n.fa-store-slash:before {\n  content: \"\\e071\"; }\n\n.fa-strava:before {\n  content: \"\\f428\"; }\n\n.fa-stream:before {\n  content: \"\\f550\"; }\n\n.fa-street-view:before {\n  content: \"\\f21d\"; }\n\n.fa-strikethrough:before {\n  content: \"\\f0cc\"; }\n\n.fa-stripe:before {\n  content: \"\\f429\"; }\n\n.fa-stripe-s:before {\n  content: \"\\f42a\"; }\n\n.fa-stroopwafel:before {\n  content: \"\\f551\"; }\n\n.fa-studiovinari:before {\n  content: \"\\f3f8\"; }\n\n.fa-stumbleupon:before {\n  content: \"\\f1a4\"; }\n\n.fa-stumbleupon-circle:before {\n  content: \"\\f1a3\"; }\n\n.fa-subscript:before {\n  content: \"\\f12c\"; }\n\n.fa-subway:before {\n  content: \"\\f239\"; }\n\n.fa-suitcase:before {\n  content: \"\\f0f2\"; }\n\n.fa-suitcase-rolling:before {\n  content: \"\\f5c1\"; }\n\n.fa-sun:before {\n  content: \"\\f185\"; }\n\n.fa-superpowers:before {\n  content: \"\\f2dd\"; }\n\n.fa-superscript:before {\n  content: \"\\f12b\"; }\n\n.fa-supple:before {\n  content: \"\\f3f9\"; }\n\n.fa-surprise:before {\n  content: \"\\f5c2\"; }\n\n.fa-suse:before {\n  content: \"\\f7d6\"; }\n\n.fa-swatchbook:before {\n  content: \"\\f5c3\"; }\n\n.fa-swift:before {\n  content: \"\\f8e1\"; }\n\n.fa-swimmer:before {\n  content: \"\\f5c4\"; }\n\n.fa-swimming-pool:before {\n  content: \"\\f5c5\"; }\n\n.fa-symfony:before {\n  content: \"\\f83d\"; }\n\n.fa-synagogue:before {\n  content: \"\\f69b\"; }\n\n.fa-sync:before {\n  content: \"\\f021\"; }\n\n.fa-sync-alt:before {\n  content: \"\\f2f1\"; }\n\n.fa-syringe:before {\n  content: \"\\f48e\"; }\n\n.fa-table:before {\n  content: \"\\f0ce\"; }\n\n.fa-table-tennis:before {\n  content: \"\\f45d\"; }\n\n.fa-tablet:before {\n  content: \"\\f10a\"; }\n\n.fa-tablet-alt:before {\n  content: \"\\f3fa\"; }\n\n.fa-tablets:before {\n  content: \"\\f490\"; }\n\n.fa-tachometer-alt:before {\n  content: \"\\f3fd\"; }\n\n.fa-tag:before {\n  content: \"\\f02b\"; }\n\n.fa-tags:before {\n  content: \"\\f02c\"; }\n\n.fa-tape:before {\n  content: \"\\f4db\"; }\n\n.fa-tasks:before {\n  content: \"\\f0ae\"; }\n\n.fa-taxi:before {\n  content: \"\\f1ba\"; }\n\n.fa-teamspeak:before {\n  content: \"\\f4f9\"; }\n\n.fa-teeth:before {\n  content: \"\\f62e\"; }\n\n.fa-teeth-open:before {\n  content: \"\\f62f\"; }\n\n.fa-telegram:before {\n  content: \"\\f2c6\"; }\n\n.fa-telegram-plane:before {\n  content: \"\\f3fe\"; }\n\n.fa-temperature-high:before {\n  content: \"\\f769\"; }\n\n.fa-temperature-low:before {\n  content: \"\\f76b\"; }\n\n.fa-tencent-weibo:before {\n  content: \"\\f1d5\"; }\n\n.fa-tenge:before {\n  content: \"\\f7d7\"; }\n\n.fa-terminal:before {\n  content: \"\\f120\"; }\n\n.fa-text-height:before {\n  content: \"\\f034\"; }\n\n.fa-text-width:before {\n  content: \"\\f035\"; }\n\n.fa-th:before {\n  content: \"\\f00a\"; }\n\n.fa-th-large:before {\n  content: \"\\f009\"; }\n\n.fa-th-list:before {\n  content: \"\\f00b\"; }\n\n.fa-the-red-yeti:before {\n  content: \"\\f69d\"; }\n\n.fa-theater-masks:before {\n  content: \"\\f630\"; }\n\n.fa-themeco:before {\n  content: \"\\f5c6\"; }\n\n.fa-themeisle:before {\n  content: \"\\f2b2\"; }\n\n.fa-thermometer:before {\n  content: \"\\f491\"; }\n\n.fa-thermometer-empty:before {\n  content: \"\\f2cb\"; }\n\n.fa-thermometer-full:before {\n  content: \"\\f2c7\"; }\n\n.fa-thermometer-half:before {\n  content: \"\\f2c9\"; }\n\n.fa-thermometer-quarter:before {\n  content: \"\\f2ca\"; }\n\n.fa-thermometer-three-quarters:before {\n  content: \"\\f2c8\"; }\n\n.fa-think-peaks:before {\n  content: \"\\f731\"; }\n\n.fa-thumbs-down:before {\n  content: \"\\f165\"; }\n\n.fa-thumbs-up:before {\n  content: \"\\f164\"; }\n\n.fa-thumbtack:before {\n  content: \"\\f08d\"; }\n\n.fa-ticket-alt:before {\n  content: \"\\f3ff\"; }\n\n.fa-tiktok:before {\n  content: \"\\e07b\"; }\n\n.fa-times:before {\n  content: \"\\f00d\"; }\n\n.fa-times-circle:before {\n  content: \"\\f057\"; }\n\n.fa-tint:before {\n  content: \"\\f043\"; }\n\n.fa-tint-slash:before {\n  content: \"\\f5c7\"; }\n\n.fa-tired:before {\n  content: \"\\f5c8\"; }\n\n.fa-toggle-off:before {\n  content: \"\\f204\"; }\n\n.fa-toggle-on:before {\n  content: \"\\f205\"; }\n\n.fa-toilet:before {\n  content: \"\\f7d8\"; }\n\n.fa-toilet-paper:before {\n  content: \"\\f71e\"; }\n\n.fa-toilet-paper-slash:before {\n  content: \"\\e072\"; }\n\n.fa-toolbox:before {\n  content: \"\\f552\"; }\n\n.fa-tools:before {\n  content: \"\\f7d9\"; }\n\n.fa-tooth:before {\n  content: \"\\f5c9\"; }\n\n.fa-torah:before {\n  content: \"\\f6a0\"; }\n\n.fa-torii-gate:before {\n  content: \"\\f6a1\"; }\n\n.fa-tractor:before {\n  content: \"\\f722\"; }\n\n.fa-trade-federation:before {\n  content: \"\\f513\"; }\n\n.fa-trademark:before {\n  content: \"\\f25c\"; }\n\n.fa-traffic-light:before {\n  content: \"\\f637\"; }\n\n.fa-trailer:before {\n  content: \"\\e041\"; }\n\n.fa-train:before {\n  content: \"\\f238\"; }\n\n.fa-tram:before {\n  content: \"\\f7da\"; }\n\n.fa-transgender:before {\n  content: \"\\f224\"; }\n\n.fa-transgender-alt:before {\n  content: \"\\f225\"; }\n\n.fa-trash:before {\n  content: \"\\f1f8\"; }\n\n.fa-trash-alt:before {\n  content: \"\\f2ed\"; }\n\n.fa-trash-restore:before {\n  content: \"\\f829\"; }\n\n.fa-trash-restore-alt:before {\n  content: \"\\f82a\"; }\n\n.fa-tree:before {\n  content: \"\\f1bb\"; }\n\n.fa-trello:before {\n  content: \"\\f181\"; }\n\n.fa-trophy:before {\n  content: \"\\f091\"; }\n\n.fa-truck:before {\n  content: \"\\f0d1\"; }\n\n.fa-truck-loading:before {\n  content: \"\\f4de\"; }\n\n.fa-truck-monster:before {\n  content: \"\\f63b\"; }\n\n.fa-truck-moving:before {\n  content: \"\\f4df\"; }\n\n.fa-truck-pickup:before {\n  content: \"\\f63c\"; }\n\n.fa-tshirt:before {\n  content: \"\\f553\"; }\n\n.fa-tty:before {\n  content: \"\\f1e4\"; }\n\n.fa-tumblr:before {\n  content: \"\\f173\"; }\n\n.fa-tumblr-square:before {\n  content: \"\\f174\"; }\n\n.fa-tv:before {\n  content: \"\\f26c\"; }\n\n.fa-twitch:before {\n  content: \"\\f1e8\"; }\n\n.fa-twitter:before {\n  content: \"\\f099\"; }\n\n.fa-twitter-square:before {\n  content: \"\\f081\"; }\n\n.fa-typo3:before {\n  content: \"\\f42b\"; }\n\n.fa-uber:before {\n  content: \"\\f402\"; }\n\n.fa-ubuntu:before {\n  content: \"\\f7df\"; }\n\n.fa-uikit:before {\n  content: \"\\f403\"; }\n\n.fa-umbraco:before {\n  content: \"\\f8e8\"; }\n\n.fa-umbrella:before {\n  content: \"\\f0e9\"; }\n\n.fa-umbrella-beach:before {\n  content: \"\\f5ca\"; }\n\n.fa-uncharted:before {\n  content: \"\\e084\"; }\n\n.fa-underline:before {\n  content: \"\\f0cd\"; }\n\n.fa-undo:before {\n  content: \"\\f0e2\"; }\n\n.fa-undo-alt:before {\n  content: \"\\f2ea\"; }\n\n.fa-uniregistry:before {\n  content: \"\\f404\"; }\n\n.fa-unity:before {\n  content: \"\\e049\"; }\n\n.fa-universal-access:before {\n  content: \"\\f29a\"; }\n\n.fa-university:before {\n  content: \"\\f19c\"; }\n\n.fa-unlink:before {\n  content: \"\\f127\"; }\n\n.fa-unlock:before {\n  content: \"\\f09c\"; }\n\n.fa-unlock-alt:before {\n  content: \"\\f13e\"; }\n\n.fa-unsplash:before {\n  content: \"\\e07c\"; }\n\n.fa-untappd:before {\n  content: \"\\f405\"; }\n\n.fa-upload:before {\n  content: \"\\f093\"; }\n\n.fa-ups:before {\n  content: \"\\f7e0\"; }\n\n.fa-usb:before {\n  content: \"\\f287\"; }\n\n.fa-user:before {\n  content: \"\\f007\"; }\n\n.fa-user-alt:before {\n  content: \"\\f406\"; }\n\n.fa-user-alt-slash:before {\n  content: \"\\f4fa\"; }\n\n.fa-user-astronaut:before {\n  content: \"\\f4fb\"; }\n\n.fa-user-check:before {\n  content: \"\\f4fc\"; }\n\n.fa-user-circle:before {\n  content: \"\\f2bd\"; }\n\n.fa-user-clock:before {\n  content: \"\\f4fd\"; }\n\n.fa-user-cog:before {\n  content: \"\\f4fe\"; }\n\n.fa-user-edit:before {\n  content: \"\\f4ff\"; }\n\n.fa-user-friends:before {\n  content: \"\\f500\"; }\n\n.fa-user-graduate:before {\n  content: \"\\f501\"; }\n\n.fa-user-injured:before {\n  content: \"\\f728\"; }\n\n.fa-user-lock:before {\n  content: \"\\f502\"; }\n\n.fa-user-md:before {\n  content: \"\\f0f0\"; }\n\n.fa-user-minus:before {\n  content: \"\\f503\"; }\n\n.fa-user-ninja:before {\n  content: \"\\f504\"; }\n\n.fa-user-nurse:before {\n  content: \"\\f82f\"; }\n\n.fa-user-plus:before {\n  content: \"\\f234\"; }\n\n.fa-user-secret:before {\n  content: \"\\f21b\"; }\n\n.fa-user-shield:before {\n  content: \"\\f505\"; }\n\n.fa-user-slash:before {\n  content: \"\\f506\"; }\n\n.fa-user-tag:before {\n  content: \"\\f507\"; }\n\n.fa-user-tie:before {\n  content: \"\\f508\"; }\n\n.fa-user-times:before {\n  content: \"\\f235\"; }\n\n.fa-users:before {\n  content: \"\\f0c0\"; }\n\n.fa-users-cog:before {\n  content: \"\\f509\"; }\n\n.fa-users-slash:before {\n  content: \"\\e073\"; }\n\n.fa-usps:before {\n  content: \"\\f7e1\"; }\n\n.fa-ussunnah:before {\n  content: \"\\f407\"; }\n\n.fa-utensil-spoon:before {\n  content: \"\\f2e5\"; }\n\n.fa-utensils:before {\n  content: \"\\f2e7\"; }\n\n.fa-vaadin:before {\n  content: \"\\f408\"; }\n\n.fa-vector-square:before {\n  content: \"\\f5cb\"; }\n\n.fa-venus:before {\n  content: \"\\f221\"; }\n\n.fa-venus-double:before {\n  content: \"\\f226\"; }\n\n.fa-venus-mars:before {\n  content: \"\\f228\"; }\n\n.fa-vest:before {\n  content: \"\\e085\"; }\n\n.fa-vest-patches:before {\n  content: \"\\e086\"; }\n\n.fa-viacoin:before {\n  content: \"\\f237\"; }\n\n.fa-viadeo:before {\n  content: \"\\f2a9\"; }\n\n.fa-viadeo-square:before {\n  content: \"\\f2aa\"; }\n\n.fa-vial:before {\n  content: \"\\f492\"; }\n\n.fa-vials:before {\n  content: \"\\f493\"; }\n\n.fa-viber:before {\n  content: \"\\f409\"; }\n\n.fa-video:before {\n  content: \"\\f03d\"; }\n\n.fa-video-slash:before {\n  content: \"\\f4e2\"; }\n\n.fa-vihara:before {\n  content: \"\\f6a7\"; }\n\n.fa-vimeo:before {\n  content: \"\\f40a\"; }\n\n.fa-vimeo-square:before {\n  content: \"\\f194\"; }\n\n.fa-vimeo-v:before {\n  content: \"\\f27d\"; }\n\n.fa-vine:before {\n  content: \"\\f1ca\"; }\n\n.fa-virus:before {\n  content: \"\\e074\"; }\n\n.fa-virus-slash:before {\n  content: \"\\e075\"; }\n\n.fa-viruses:before {\n  content: \"\\e076\"; }\n\n.fa-vk:before {\n  content: \"\\f189\"; }\n\n.fa-vnv:before {\n  content: \"\\f40b\"; }\n\n.fa-voicemail:before {\n  content: \"\\f897\"; }\n\n.fa-volleyball-ball:before {\n  content: \"\\f45f\"; }\n\n.fa-volume-down:before {\n  content: \"\\f027\"; }\n\n.fa-volume-mute:before {\n  content: \"\\f6a9\"; }\n\n.fa-volume-off:before {\n  content: \"\\f026\"; }\n\n.fa-volume-up:before {\n  content: \"\\f028\"; }\n\n.fa-vote-yea:before {\n  content: \"\\f772\"; }\n\n.fa-vr-cardboard:before {\n  content: \"\\f729\"; }\n\n.fa-vuejs:before {\n  content: \"\\f41f\"; }\n\n.fa-walking:before {\n  content: \"\\f554\"; }\n\n.fa-wallet:before {\n  content: \"\\f555\"; }\n\n.fa-warehouse:before {\n  content: \"\\f494\"; }\n\n.fa-watchman-monitoring:before {\n  content: \"\\e087\"; }\n\n.fa-water:before {\n  content: \"\\f773\"; }\n\n.fa-wave-square:before {\n  content: \"\\f83e\"; }\n\n.fa-waze:before {\n  content: \"\\f83f\"; }\n\n.fa-weebly:before {\n  content: \"\\f5cc\"; }\n\n.fa-weibo:before {\n  content: \"\\f18a\"; }\n\n.fa-weight:before {\n  content: \"\\f496\"; }\n\n.fa-weight-hanging:before {\n  content: \"\\f5cd\"; }\n\n.fa-weixin:before {\n  content: \"\\f1d7\"; }\n\n.fa-whatsapp:before {\n  content: \"\\f232\"; }\n\n.fa-whatsapp-square:before {\n  content: \"\\f40c\"; }\n\n.fa-wheelchair:before {\n  content: \"\\f193\"; }\n\n.fa-whmcs:before {\n  content: \"\\f40d\"; }\n\n.fa-wifi:before {\n  content: \"\\f1eb\"; }\n\n.fa-wikipedia-w:before {\n  content: \"\\f266\"; }\n\n.fa-wind:before {\n  content: \"\\f72e\"; }\n\n.fa-window-close:before {\n  content: \"\\f410\"; }\n\n.fa-window-maximize:before {\n  content: \"\\f2d0\"; }\n\n.fa-window-minimize:before {\n  content: \"\\f2d1\"; }\n\n.fa-window-restore:before {\n  content: \"\\f2d2\"; }\n\n.fa-windows:before {\n  content: \"\\f17a\"; }\n\n.fa-wine-bottle:before {\n  content: \"\\f72f\"; }\n\n.fa-wine-glass:before {\n  content: \"\\f4e3\"; }\n\n.fa-wine-glass-alt:before {\n  content: \"\\f5ce\"; }\n\n.fa-wix:before {\n  content: \"\\f5cf\"; }\n\n.fa-wizards-of-the-coast:before {\n  content: \"\\f730\"; }\n\n.fa-wodu:before {\n  content: \"\\e088\"; }\n\n.fa-wolf-pack-battalion:before {\n  content: \"\\f514\"; }\n\n.fa-won-sign:before {\n  content: \"\\f159\"; }\n\n.fa-wordpress:before {\n  content: \"\\f19a\"; }\n\n.fa-wordpress-simple:before {\n  content: \"\\f411\"; }\n\n.fa-wpbeginner:before {\n  content: \"\\f297\"; }\n\n.fa-wpexplorer:before {\n  content: \"\\f2de\"; }\n\n.fa-wpforms:before {\n  content: \"\\f298\"; }\n\n.fa-wpressr:before {\n  content: \"\\f3e4\"; }\n\n.fa-wrench:before {\n  content: \"\\f0ad\"; }\n\n.fa-x-ray:before {\n  content: \"\\f497\"; }\n\n.fa-xbox:before {\n  content: \"\\f412\"; }\n\n.fa-xing:before {\n  content: \"\\f168\"; }\n\n.fa-xing-square:before {\n  content: \"\\f169\"; }\n\n.fa-y-combinator:before {\n  content: \"\\f23b\"; }\n\n.fa-yahoo:before {\n  content: \"\\f19e\"; }\n\n.fa-yammer:before {\n  content: \"\\f840\"; }\n\n.fa-yandex:before {\n  content: \"\\f413\"; }\n\n.fa-yandex-international:before {\n  content: \"\\f414\"; }\n\n.fa-yarn:before {\n  content: \"\\f7e3\"; }\n\n.fa-yelp:before {\n  content: \"\\f1e9\"; }\n\n.fa-yen-sign:before {\n  content: \"\\f157\"; }\n\n.fa-yin-yang:before {\n  content: \"\\f6ad\"; }\n\n.fa-yoast:before {\n  content: \"\\f2b1\"; }\n\n.fa-youtube:before {\n  content: \"\\f167\"; }\n\n.fa-youtube-square:before {\n  content: \"\\f431\"; }\n\n.fa-zhihu:before {\n  content: \"\\f63f\"; }\n\n.sr-only {\n  border: 0;\n  clip: rect(0, 0, 0, 0);\n  height: 1px;\n  margin: -1px;\n  overflow: hidden;\n  padding: 0;\n  position: absolute;\n  width: 1px; }\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n  clip: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  position: static;\n  width: auto; }\n@font-face {\n  font-family: 'Font Awesome 5 Brands';\n  font-style: normal;\n  font-weight: 400;\n  font-display: block;\n  src: url(\"../webfonts/fa-brands-400.eot\");\n  src: url(\"../webfonts/fa-brands-400.eot?#iefix\") format(\"embedded-opentype\"), url(\"../webfonts/fa-brands-400.woff2\") format(\"woff2\"), url(\"../webfonts/fa-brands-400.woff\") format(\"woff\"), url(\"../webfonts/fa-brands-400.ttf\") format(\"truetype\"), url(\"../webfonts/fa-brands-400.svg#fontawesome\") format(\"svg\"); }\n\n.fab {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n@font-face {\n  font-family: 'Font Awesome 5 Free';\n  font-style: normal;\n  font-weight: 400;\n  font-display: block;\n  src: url(\"../webfonts/fa-regular-400.eot\");\n  src: url(\"../webfonts/fa-regular-400.eot?#iefix\") format(\"embedded-opentype\"), url(\"../webfonts/fa-regular-400.woff2\") format(\"woff2\"), url(\"../webfonts/fa-regular-400.woff\") format(\"woff\"), url(\"../webfonts/fa-regular-400.ttf\") format(\"truetype\"), url(\"../webfonts/fa-regular-400.svg#fontawesome\") format(\"svg\"); }\n\n.far {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n@font-face {\n  font-family: 'Font Awesome 5 Free';\n  font-style: normal;\n  font-weight: 900;\n  font-display: block;\n  src: url(\"../webfonts/fa-solid-900.eot\");\n  src: url(\"../webfonts/fa-solid-900.eot?#iefix\") format(\"embedded-opentype\"), url(\"../webfonts/fa-solid-900.woff2\") format(\"woff2\"), url(\"../webfonts/fa-solid-900.woff\") format(\"woff\"), url(\"../webfonts/fa-solid-900.ttf\") format(\"truetype\"), url(\"../webfonts/fa-solid-900.svg#fontawesome\") format(\"svg\"); }\n\n.fa,\n.fas {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 900; }\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/all.min.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.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-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:\"\\f26e\"}.fa-accessible-icon:before{content:\"\\f368\"}.fa-accusoft:before{content:\"\\f369\"}.fa-acquisitions-incorporated:before{content:\"\\f6af\"}.fa-ad:before{content:\"\\f641\"}.fa-address-book:before{content:\"\\f2b9\"}.fa-address-card:before{content:\"\\f2bb\"}.fa-adjust:before{content:\"\\f042\"}.fa-adn:before{content:\"\\f170\"}.fa-adversal:before{content:\"\\f36a\"}.fa-affiliatetheme:before{content:\"\\f36b\"}.fa-air-freshener:before{content:\"\\f5d0\"}.fa-airbnb:before{content:\"\\f834\"}.fa-algolia:before{content:\"\\f36c\"}.fa-align-center:before{content:\"\\f037\"}.fa-align-justify:before{content:\"\\f039\"}.fa-align-left:before{content:\"\\f036\"}.fa-align-right:before{content:\"\\f038\"}.fa-alipay:before{content:\"\\f642\"}.fa-allergies:before{content:\"\\f461\"}.fa-amazon:before{content:\"\\f270\"}.fa-amazon-pay:before{content:\"\\f42c\"}.fa-ambulance:before{content:\"\\f0f9\"}.fa-american-sign-language-interpreting:before{content:\"\\f2a3\"}.fa-amilia:before{content:\"\\f36d\"}.fa-anchor:before{content:\"\\f13d\"}.fa-android:before{content:\"\\f17b\"}.fa-angellist:before{content:\"\\f209\"}.fa-angle-double-down:before{content:\"\\f103\"}.fa-angle-double-left:before{content:\"\\f100\"}.fa-angle-double-right:before{content:\"\\f101\"}.fa-angle-double-up:before{content:\"\\f102\"}.fa-angle-down:before{content:\"\\f107\"}.fa-angle-left:before{content:\"\\f104\"}.fa-angle-right:before{content:\"\\f105\"}.fa-angle-up:before{content:\"\\f106\"}.fa-angry:before{content:\"\\f556\"}.fa-angrycreative:before{content:\"\\f36e\"}.fa-angular:before{content:\"\\f420\"}.fa-ankh:before{content:\"\\f644\"}.fa-app-store:before{content:\"\\f36f\"}.fa-app-store-ios:before{content:\"\\f370\"}.fa-apper:before{content:\"\\f371\"}.fa-apple:before{content:\"\\f179\"}.fa-apple-alt:before{content:\"\\f5d1\"}.fa-apple-pay:before{content:\"\\f415\"}.fa-archive:before{content:\"\\f187\"}.fa-archway:before{content:\"\\f557\"}.fa-arrow-alt-circle-down:before{content:\"\\f358\"}.fa-arrow-alt-circle-left:before{content:\"\\f359\"}.fa-arrow-alt-circle-right:before{content:\"\\f35a\"}.fa-arrow-alt-circle-up:before{content:\"\\f35b\"}.fa-arrow-circle-down:before{content:\"\\f0ab\"}.fa-arrow-circle-left:before{content:\"\\f0a8\"}.fa-arrow-circle-right:before{content:\"\\f0a9\"}.fa-arrow-circle-up:before{content:\"\\f0aa\"}.fa-arrow-down:before{content:\"\\f063\"}.fa-arrow-left:before{content:\"\\f060\"}.fa-arrow-right:before{content:\"\\f061\"}.fa-arrow-up:before{content:\"\\f062\"}.fa-arrows-alt:before{content:\"\\f0b2\"}.fa-arrows-alt-h:before{content:\"\\f337\"}.fa-arrows-alt-v:before{content:\"\\f338\"}.fa-artstation:before{content:\"\\f77a\"}.fa-assistive-listening-systems:before{content:\"\\f2a2\"}.fa-asterisk:before{content:\"\\f069\"}.fa-asymmetrik:before{content:\"\\f372\"}.fa-at:before{content:\"\\f1fa\"}.fa-atlas:before{content:\"\\f558\"}.fa-atlassian:before{content:\"\\f77b\"}.fa-atom:before{content:\"\\f5d2\"}.fa-audible:before{content:\"\\f373\"}.fa-audio-description:before{content:\"\\f29e\"}.fa-autoprefixer:before{content:\"\\f41c\"}.fa-avianex:before{content:\"\\f374\"}.fa-aviato:before{content:\"\\f421\"}.fa-award:before{content:\"\\f559\"}.fa-aws:before{content:\"\\f375\"}.fa-baby:before{content:\"\\f77c\"}.fa-baby-carriage:before{content:\"\\f77d\"}.fa-backspace:before{content:\"\\f55a\"}.fa-backward:before{content:\"\\f04a\"}.fa-bacon:before{content:\"\\f7e5\"}.fa-bacteria:before{content:\"\\e059\"}.fa-bacterium:before{content:\"\\e05a\"}.fa-bahai:before{content:\"\\f666\"}.fa-balance-scale:before{content:\"\\f24e\"}.fa-balance-scale-left:before{content:\"\\f515\"}.fa-balance-scale-right:before{content:\"\\f516\"}.fa-ban:before{content:\"\\f05e\"}.fa-band-aid:before{content:\"\\f462\"}.fa-bandcamp:before{content:\"\\f2d5\"}.fa-barcode:before{content:\"\\f02a\"}.fa-bars:before{content:\"\\f0c9\"}.fa-baseball-ball:before{content:\"\\f433\"}.fa-basketball-ball:before{content:\"\\f434\"}.fa-bath:before{content:\"\\f2cd\"}.fa-battery-empty:before{content:\"\\f244\"}.fa-battery-full:before{content:\"\\f240\"}.fa-battery-half:before{content:\"\\f242\"}.fa-battery-quarter:before{content:\"\\f243\"}.fa-battery-three-quarters:before{content:\"\\f241\"}.fa-battle-net:before{content:\"\\f835\"}.fa-bed:before{content:\"\\f236\"}.fa-beer:before{content:\"\\f0fc\"}.fa-behance:before{content:\"\\f1b4\"}.fa-behance-square:before{content:\"\\f1b5\"}.fa-bell:before{content:\"\\f0f3\"}.fa-bell-slash:before{content:\"\\f1f6\"}.fa-bezier-curve:before{content:\"\\f55b\"}.fa-bible:before{content:\"\\f647\"}.fa-bicycle:before{content:\"\\f206\"}.fa-biking:before{content:\"\\f84a\"}.fa-bimobject:before{content:\"\\f378\"}.fa-binoculars:before{content:\"\\f1e5\"}.fa-biohazard:before{content:\"\\f780\"}.fa-birthday-cake:before{content:\"\\f1fd\"}.fa-bitbucket:before{content:\"\\f171\"}.fa-bitcoin:before{content:\"\\f379\"}.fa-bity:before{content:\"\\f37a\"}.fa-black-tie:before{content:\"\\f27e\"}.fa-blackberry:before{content:\"\\f37b\"}.fa-blender:before{content:\"\\f517\"}.fa-blender-phone:before{content:\"\\f6b6\"}.fa-blind:before{content:\"\\f29d\"}.fa-blog:before{content:\"\\f781\"}.fa-blogger:before{content:\"\\f37c\"}.fa-blogger-b:before{content:\"\\f37d\"}.fa-bluetooth:before{content:\"\\f293\"}.fa-bluetooth-b:before{content:\"\\f294\"}.fa-bold:before{content:\"\\f032\"}.fa-bolt:before{content:\"\\f0e7\"}.fa-bomb:before{content:\"\\f1e2\"}.fa-bone:before{content:\"\\f5d7\"}.fa-bong:before{content:\"\\f55c\"}.fa-book:before{content:\"\\f02d\"}.fa-book-dead:before{content:\"\\f6b7\"}.fa-book-medical:before{content:\"\\f7e6\"}.fa-book-open:before{content:\"\\f518\"}.fa-book-reader:before{content:\"\\f5da\"}.fa-bookmark:before{content:\"\\f02e\"}.fa-bootstrap:before{content:\"\\f836\"}.fa-border-all:before{content:\"\\f84c\"}.fa-border-none:before{content:\"\\f850\"}.fa-border-style:before{content:\"\\f853\"}.fa-bowling-ball:before{content:\"\\f436\"}.fa-box:before{content:\"\\f466\"}.fa-box-open:before{content:\"\\f49e\"}.fa-box-tissue:before{content:\"\\e05b\"}.fa-boxes:before{content:\"\\f468\"}.fa-braille:before{content:\"\\f2a1\"}.fa-brain:before{content:\"\\f5dc\"}.fa-bread-slice:before{content:\"\\f7ec\"}.fa-briefcase:before{content:\"\\f0b1\"}.fa-briefcase-medical:before{content:\"\\f469\"}.fa-broadcast-tower:before{content:\"\\f519\"}.fa-broom:before{content:\"\\f51a\"}.fa-brush:before{content:\"\\f55d\"}.fa-btc:before{content:\"\\f15a\"}.fa-buffer:before{content:\"\\f837\"}.fa-bug:before{content:\"\\f188\"}.fa-building:before{content:\"\\f1ad\"}.fa-bullhorn:before{content:\"\\f0a1\"}.fa-bullseye:before{content:\"\\f140\"}.fa-burn:before{content:\"\\f46a\"}.fa-buromobelexperte:before{content:\"\\f37f\"}.fa-bus:before{content:\"\\f207\"}.fa-bus-alt:before{content:\"\\f55e\"}.fa-business-time:before{content:\"\\f64a\"}.fa-buy-n-large:before{content:\"\\f8a6\"}.fa-buysellads:before{content:\"\\f20d\"}.fa-calculator:before{content:\"\\f1ec\"}.fa-calendar:before{content:\"\\f133\"}.fa-calendar-alt:before{content:\"\\f073\"}.fa-calendar-check:before{content:\"\\f274\"}.fa-calendar-day:before{content:\"\\f783\"}.fa-calendar-minus:before{content:\"\\f272\"}.fa-calendar-plus:before{content:\"\\f271\"}.fa-calendar-times:before{content:\"\\f273\"}.fa-calendar-week:before{content:\"\\f784\"}.fa-camera:before{content:\"\\f030\"}.fa-camera-retro:before{content:\"\\f083\"}.fa-campground:before{content:\"\\f6bb\"}.fa-canadian-maple-leaf:before{content:\"\\f785\"}.fa-candy-cane:before{content:\"\\f786\"}.fa-cannabis:before{content:\"\\f55f\"}.fa-capsules:before{content:\"\\f46b\"}.fa-car:before{content:\"\\f1b9\"}.fa-car-alt:before{content:\"\\f5de\"}.fa-car-battery:before{content:\"\\f5df\"}.fa-car-crash:before{content:\"\\f5e1\"}.fa-car-side:before{content:\"\\f5e4\"}.fa-caravan:before{content:\"\\f8ff\"}.fa-caret-down:before{content:\"\\f0d7\"}.fa-caret-left:before{content:\"\\f0d9\"}.fa-caret-right:before{content:\"\\f0da\"}.fa-caret-square-down:before{content:\"\\f150\"}.fa-caret-square-left:before{content:\"\\f191\"}.fa-caret-square-right:before{content:\"\\f152\"}.fa-caret-square-up:before{content:\"\\f151\"}.fa-caret-up:before{content:\"\\f0d8\"}.fa-carrot:before{content:\"\\f787\"}.fa-cart-arrow-down:before{content:\"\\f218\"}.fa-cart-plus:before{content:\"\\f217\"}.fa-cash-register:before{content:\"\\f788\"}.fa-cat:before{content:\"\\f6be\"}.fa-cc-amazon-pay:before{content:\"\\f42d\"}.fa-cc-amex:before{content:\"\\f1f3\"}.fa-cc-apple-pay:before{content:\"\\f416\"}.fa-cc-diners-club:before{content:\"\\f24c\"}.fa-cc-discover:before{content:\"\\f1f2\"}.fa-cc-jcb:before{content:\"\\f24b\"}.fa-cc-mastercard:before{content:\"\\f1f1\"}.fa-cc-paypal:before{content:\"\\f1f4\"}.fa-cc-stripe:before{content:\"\\f1f5\"}.fa-cc-visa:before{content:\"\\f1f0\"}.fa-centercode:before{content:\"\\f380\"}.fa-centos:before{content:\"\\f789\"}.fa-certificate:before{content:\"\\f0a3\"}.fa-chair:before{content:\"\\f6c0\"}.fa-chalkboard:before{content:\"\\f51b\"}.fa-chalkboard-teacher:before{content:\"\\f51c\"}.fa-charging-station:before{content:\"\\f5e7\"}.fa-chart-area:before{content:\"\\f1fe\"}.fa-chart-bar:before{content:\"\\f080\"}.fa-chart-line:before{content:\"\\f201\"}.fa-chart-pie:before{content:\"\\f200\"}.fa-check:before{content:\"\\f00c\"}.fa-check-circle:before{content:\"\\f058\"}.fa-check-double:before{content:\"\\f560\"}.fa-check-square:before{content:\"\\f14a\"}.fa-cheese:before{content:\"\\f7ef\"}.fa-chess:before{content:\"\\f439\"}.fa-chess-bishop:before{content:\"\\f43a\"}.fa-chess-board:before{content:\"\\f43c\"}.fa-chess-king:before{content:\"\\f43f\"}.fa-chess-knight:before{content:\"\\f441\"}.fa-chess-pawn:before{content:\"\\f443\"}.fa-chess-queen:before{content:\"\\f445\"}.fa-chess-rook:before{content:\"\\f447\"}.fa-chevron-circle-down:before{content:\"\\f13a\"}.fa-chevron-circle-left:before{content:\"\\f137\"}.fa-chevron-circle-right:before{content:\"\\f138\"}.fa-chevron-circle-up:before{content:\"\\f139\"}.fa-chevron-down:before{content:\"\\f078\"}.fa-chevron-left:before{content:\"\\f053\"}.fa-chevron-right:before{content:\"\\f054\"}.fa-chevron-up:before{content:\"\\f077\"}.fa-child:before{content:\"\\f1ae\"}.fa-chrome:before{content:\"\\f268\"}.fa-chromecast:before{content:\"\\f838\"}.fa-church:before{content:\"\\f51d\"}.fa-circle:before{content:\"\\f111\"}.fa-circle-notch:before{content:\"\\f1ce\"}.fa-city:before{content:\"\\f64f\"}.fa-clinic-medical:before{content:\"\\f7f2\"}.fa-clipboard:before{content:\"\\f328\"}.fa-clipboard-check:before{content:\"\\f46c\"}.fa-clipboard-list:before{content:\"\\f46d\"}.fa-clock:before{content:\"\\f017\"}.fa-clone:before{content:\"\\f24d\"}.fa-closed-captioning:before{content:\"\\f20a\"}.fa-cloud:before{content:\"\\f0c2\"}.fa-cloud-download-alt:before{content:\"\\f381\"}.fa-cloud-meatball:before{content:\"\\f73b\"}.fa-cloud-moon:before{content:\"\\f6c3\"}.fa-cloud-moon-rain:before{content:\"\\f73c\"}.fa-cloud-rain:before{content:\"\\f73d\"}.fa-cloud-showers-heavy:before{content:\"\\f740\"}.fa-cloud-sun:before{content:\"\\f6c4\"}.fa-cloud-sun-rain:before{content:\"\\f743\"}.fa-cloud-upload-alt:before{content:\"\\f382\"}.fa-cloudflare:before{content:\"\\e07d\"}.fa-cloudscale:before{content:\"\\f383\"}.fa-cloudsmith:before{content:\"\\f384\"}.fa-cloudversify:before{content:\"\\f385\"}.fa-cocktail:before{content:\"\\f561\"}.fa-code:before{content:\"\\f121\"}.fa-code-branch:before{content:\"\\f126\"}.fa-codepen:before{content:\"\\f1cb\"}.fa-codiepie:before{content:\"\\f284\"}.fa-coffee:before{content:\"\\f0f4\"}.fa-cog:before{content:\"\\f013\"}.fa-cogs:before{content:\"\\f085\"}.fa-coins:before{content:\"\\f51e\"}.fa-columns:before{content:\"\\f0db\"}.fa-comment:before{content:\"\\f075\"}.fa-comment-alt:before{content:\"\\f27a\"}.fa-comment-dollar:before{content:\"\\f651\"}.fa-comment-dots:before{content:\"\\f4ad\"}.fa-comment-medical:before{content:\"\\f7f5\"}.fa-comment-slash:before{content:\"\\f4b3\"}.fa-comments:before{content:\"\\f086\"}.fa-comments-dollar:before{content:\"\\f653\"}.fa-compact-disc:before{content:\"\\f51f\"}.fa-compass:before{content:\"\\f14e\"}.fa-compress:before{content:\"\\f066\"}.fa-compress-alt:before{content:\"\\f422\"}.fa-compress-arrows-alt:before{content:\"\\f78c\"}.fa-concierge-bell:before{content:\"\\f562\"}.fa-confluence:before{content:\"\\f78d\"}.fa-connectdevelop:before{content:\"\\f20e\"}.fa-contao:before{content:\"\\f26d\"}.fa-cookie:before{content:\"\\f563\"}.fa-cookie-bite:before{content:\"\\f564\"}.fa-copy:before{content:\"\\f0c5\"}.fa-copyright:before{content:\"\\f1f9\"}.fa-cotton-bureau:before{content:\"\\f89e\"}.fa-couch:before{content:\"\\f4b8\"}.fa-cpanel:before{content:\"\\f388\"}.fa-creative-commons:before{content:\"\\f25e\"}.fa-creative-commons-by:before{content:\"\\f4e7\"}.fa-creative-commons-nc:before{content:\"\\f4e8\"}.fa-creative-commons-nc-eu:before{content:\"\\f4e9\"}.fa-creative-commons-nc-jp:before{content:\"\\f4ea\"}.fa-creative-commons-nd:before{content:\"\\f4eb\"}.fa-creative-commons-pd:before{content:\"\\f4ec\"}.fa-creative-commons-pd-alt:before{content:\"\\f4ed\"}.fa-creative-commons-remix:before{content:\"\\f4ee\"}.fa-creative-commons-sa:before{content:\"\\f4ef\"}.fa-creative-commons-sampling:before{content:\"\\f4f0\"}.fa-creative-commons-sampling-plus:before{content:\"\\f4f1\"}.fa-creative-commons-share:before{content:\"\\f4f2\"}.fa-creative-commons-zero:before{content:\"\\f4f3\"}.fa-credit-card:before{content:\"\\f09d\"}.fa-critical-role:before{content:\"\\f6c9\"}.fa-crop:before{content:\"\\f125\"}.fa-crop-alt:before{content:\"\\f565\"}.fa-cross:before{content:\"\\f654\"}.fa-crosshairs:before{content:\"\\f05b\"}.fa-crow:before{content:\"\\f520\"}.fa-crown:before{content:\"\\f521\"}.fa-crutch:before{content:\"\\f7f7\"}.fa-css3:before{content:\"\\f13c\"}.fa-css3-alt:before{content:\"\\f38b\"}.fa-cube:before{content:\"\\f1b2\"}.fa-cubes:before{content:\"\\f1b3\"}.fa-cut:before{content:\"\\f0c4\"}.fa-cuttlefish:before{content:\"\\f38c\"}.fa-d-and-d:before{content:\"\\f38d\"}.fa-d-and-d-beyond:before{content:\"\\f6ca\"}.fa-dailymotion:before{content:\"\\e052\"}.fa-dashcube:before{content:\"\\f210\"}.fa-database:before{content:\"\\f1c0\"}.fa-deaf:before{content:\"\\f2a4\"}.fa-deezer:before{content:\"\\e077\"}.fa-delicious:before{content:\"\\f1a5\"}.fa-democrat:before{content:\"\\f747\"}.fa-deploydog:before{content:\"\\f38e\"}.fa-deskpro:before{content:\"\\f38f\"}.fa-desktop:before{content:\"\\f108\"}.fa-dev:before{content:\"\\f6cc\"}.fa-deviantart:before{content:\"\\f1bd\"}.fa-dharmachakra:before{content:\"\\f655\"}.fa-dhl:before{content:\"\\f790\"}.fa-diagnoses:before{content:\"\\f470\"}.fa-diaspora:before{content:\"\\f791\"}.fa-dice:before{content:\"\\f522\"}.fa-dice-d20:before{content:\"\\f6cf\"}.fa-dice-d6:before{content:\"\\f6d1\"}.fa-dice-five:before{content:\"\\f523\"}.fa-dice-four:before{content:\"\\f524\"}.fa-dice-one:before{content:\"\\f525\"}.fa-dice-six:before{content:\"\\f526\"}.fa-dice-three:before{content:\"\\f527\"}.fa-dice-two:before{content:\"\\f528\"}.fa-digg:before{content:\"\\f1a6\"}.fa-digital-ocean:before{content:\"\\f391\"}.fa-digital-tachograph:before{content:\"\\f566\"}.fa-directions:before{content:\"\\f5eb\"}.fa-discord:before{content:\"\\f392\"}.fa-discourse:before{content:\"\\f393\"}.fa-disease:before{content:\"\\f7fa\"}.fa-divide:before{content:\"\\f529\"}.fa-dizzy:before{content:\"\\f567\"}.fa-dna:before{content:\"\\f471\"}.fa-dochub:before{content:\"\\f394\"}.fa-docker:before{content:\"\\f395\"}.fa-dog:before{content:\"\\f6d3\"}.fa-dollar-sign:before{content:\"\\f155\"}.fa-dolly:before{content:\"\\f472\"}.fa-dolly-flatbed:before{content:\"\\f474\"}.fa-donate:before{content:\"\\f4b9\"}.fa-door-closed:before{content:\"\\f52a\"}.fa-door-open:before{content:\"\\f52b\"}.fa-dot-circle:before{content:\"\\f192\"}.fa-dove:before{content:\"\\f4ba\"}.fa-download:before{content:\"\\f019\"}.fa-draft2digital:before{content:\"\\f396\"}.fa-drafting-compass:before{content:\"\\f568\"}.fa-dragon:before{content:\"\\f6d5\"}.fa-draw-polygon:before{content:\"\\f5ee\"}.fa-dribbble:before{content:\"\\f17d\"}.fa-dribbble-square:before{content:\"\\f397\"}.fa-dropbox:before{content:\"\\f16b\"}.fa-drum:before{content:\"\\f569\"}.fa-drum-steelpan:before{content:\"\\f56a\"}.fa-drumstick-bite:before{content:\"\\f6d7\"}.fa-drupal:before{content:\"\\f1a9\"}.fa-dumbbell:before{content:\"\\f44b\"}.fa-dumpster:before{content:\"\\f793\"}.fa-dumpster-fire:before{content:\"\\f794\"}.fa-dungeon:before{content:\"\\f6d9\"}.fa-dyalog:before{content:\"\\f399\"}.fa-earlybirds:before{content:\"\\f39a\"}.fa-ebay:before{content:\"\\f4f4\"}.fa-edge:before{content:\"\\f282\"}.fa-edge-legacy:before{content:\"\\e078\"}.fa-edit:before{content:\"\\f044\"}.fa-egg:before{content:\"\\f7fb\"}.fa-eject:before{content:\"\\f052\"}.fa-elementor:before{content:\"\\f430\"}.fa-ellipsis-h:before{content:\"\\f141\"}.fa-ellipsis-v:before{content:\"\\f142\"}.fa-ello:before{content:\"\\f5f1\"}.fa-ember:before{content:\"\\f423\"}.fa-empire:before{content:\"\\f1d1\"}.fa-envelope:before{content:\"\\f0e0\"}.fa-envelope-open:before{content:\"\\f2b6\"}.fa-envelope-open-text:before{content:\"\\f658\"}.fa-envelope-square:before{content:\"\\f199\"}.fa-envira:before{content:\"\\f299\"}.fa-equals:before{content:\"\\f52c\"}.fa-eraser:before{content:\"\\f12d\"}.fa-erlang:before{content:\"\\f39d\"}.fa-ethereum:before{content:\"\\f42e\"}.fa-ethernet:before{content:\"\\f796\"}.fa-etsy:before{content:\"\\f2d7\"}.fa-euro-sign:before{content:\"\\f153\"}.fa-evernote:before{content:\"\\f839\"}.fa-exchange-alt:before{content:\"\\f362\"}.fa-exclamation:before{content:\"\\f12a\"}.fa-exclamation-circle:before{content:\"\\f06a\"}.fa-exclamation-triangle:before{content:\"\\f071\"}.fa-expand:before{content:\"\\f065\"}.fa-expand-alt:before{content:\"\\f424\"}.fa-expand-arrows-alt:before{content:\"\\f31e\"}.fa-expeditedssl:before{content:\"\\f23e\"}.fa-external-link-alt:before{content:\"\\f35d\"}.fa-external-link-square-alt:before{content:\"\\f360\"}.fa-eye:before{content:\"\\f06e\"}.fa-eye-dropper:before{content:\"\\f1fb\"}.fa-eye-slash:before{content:\"\\f070\"}.fa-facebook:before{content:\"\\f09a\"}.fa-facebook-f:before{content:\"\\f39e\"}.fa-facebook-messenger:before{content:\"\\f39f\"}.fa-facebook-square:before{content:\"\\f082\"}.fa-fan:before{content:\"\\f863\"}.fa-fantasy-flight-games:before{content:\"\\f6dc\"}.fa-fast-backward:before{content:\"\\f049\"}.fa-fast-forward:before{content:\"\\f050\"}.fa-faucet:before{content:\"\\e005\"}.fa-fax:before{content:\"\\f1ac\"}.fa-feather:before{content:\"\\f52d\"}.fa-feather-alt:before{content:\"\\f56b\"}.fa-fedex:before{content:\"\\f797\"}.fa-fedora:before{content:\"\\f798\"}.fa-female:before{content:\"\\f182\"}.fa-fighter-jet:before{content:\"\\f0fb\"}.fa-figma:before{content:\"\\f799\"}.fa-file:before{content:\"\\f15b\"}.fa-file-alt:before{content:\"\\f15c\"}.fa-file-archive:before{content:\"\\f1c6\"}.fa-file-audio:before{content:\"\\f1c7\"}.fa-file-code:before{content:\"\\f1c9\"}.fa-file-contract:before{content:\"\\f56c\"}.fa-file-csv:before{content:\"\\f6dd\"}.fa-file-download:before{content:\"\\f56d\"}.fa-file-excel:before{content:\"\\f1c3\"}.fa-file-export:before{content:\"\\f56e\"}.fa-file-image:before{content:\"\\f1c5\"}.fa-file-import:before{content:\"\\f56f\"}.fa-file-invoice:before{content:\"\\f570\"}.fa-file-invoice-dollar:before{content:\"\\f571\"}.fa-file-medical:before{content:\"\\f477\"}.fa-file-medical-alt:before{content:\"\\f478\"}.fa-file-pdf:before{content:\"\\f1c1\"}.fa-file-powerpoint:before{content:\"\\f1c4\"}.fa-file-prescription:before{content:\"\\f572\"}.fa-file-signature:before{content:\"\\f573\"}.fa-file-upload:before{content:\"\\f574\"}.fa-file-video:before{content:\"\\f1c8\"}.fa-file-word:before{content:\"\\f1c2\"}.fa-fill:before{content:\"\\f575\"}.fa-fill-drip:before{content:\"\\f576\"}.fa-film:before{content:\"\\f008\"}.fa-filter:before{content:\"\\f0b0\"}.fa-fingerprint:before{content:\"\\f577\"}.fa-fire:before{content:\"\\f06d\"}.fa-fire-alt:before{content:\"\\f7e4\"}.fa-fire-extinguisher:before{content:\"\\f134\"}.fa-firefox:before{content:\"\\f269\"}.fa-firefox-browser:before{content:\"\\e007\"}.fa-first-aid:before{content:\"\\f479\"}.fa-first-order:before{content:\"\\f2b0\"}.fa-first-order-alt:before{content:\"\\f50a\"}.fa-firstdraft:before{content:\"\\f3a1\"}.fa-fish:before{content:\"\\f578\"}.fa-fist-raised:before{content:\"\\f6de\"}.fa-flag:before{content:\"\\f024\"}.fa-flag-checkered:before{content:\"\\f11e\"}.fa-flag-usa:before{content:\"\\f74d\"}.fa-flask:before{content:\"\\f0c3\"}.fa-flickr:before{content:\"\\f16e\"}.fa-flipboard:before{content:\"\\f44d\"}.fa-flushed:before{content:\"\\f579\"}.fa-fly:before{content:\"\\f417\"}.fa-folder:before{content:\"\\f07b\"}.fa-folder-minus:before{content:\"\\f65d\"}.fa-folder-open:before{content:\"\\f07c\"}.fa-folder-plus:before{content:\"\\f65e\"}.fa-font:before{content:\"\\f031\"}.fa-font-awesome:before{content:\"\\f2b4\"}.fa-font-awesome-alt:before{content:\"\\f35c\"}.fa-font-awesome-flag:before{content:\"\\f425\"}.fa-font-awesome-logo-full:before{content:\"\\f4e6\"}.fa-fonticons:before{content:\"\\f280\"}.fa-fonticons-fi:before{content:\"\\f3a2\"}.fa-football-ball:before{content:\"\\f44e\"}.fa-fort-awesome:before{content:\"\\f286\"}.fa-fort-awesome-alt:before{content:\"\\f3a3\"}.fa-forumbee:before{content:\"\\f211\"}.fa-forward:before{content:\"\\f04e\"}.fa-foursquare:before{content:\"\\f180\"}.fa-free-code-camp:before{content:\"\\f2c5\"}.fa-freebsd:before{content:\"\\f3a4\"}.fa-frog:before{content:\"\\f52e\"}.fa-frown:before{content:\"\\f119\"}.fa-frown-open:before{content:\"\\f57a\"}.fa-fulcrum:before{content:\"\\f50b\"}.fa-funnel-dollar:before{content:\"\\f662\"}.fa-futbol:before{content:\"\\f1e3\"}.fa-galactic-republic:before{content:\"\\f50c\"}.fa-galactic-senate:before{content:\"\\f50d\"}.fa-gamepad:before{content:\"\\f11b\"}.fa-gas-pump:before{content:\"\\f52f\"}.fa-gavel:before{content:\"\\f0e3\"}.fa-gem:before{content:\"\\f3a5\"}.fa-genderless:before{content:\"\\f22d\"}.fa-get-pocket:before{content:\"\\f265\"}.fa-gg:before{content:\"\\f260\"}.fa-gg-circle:before{content:\"\\f261\"}.fa-ghost:before{content:\"\\f6e2\"}.fa-gift:before{content:\"\\f06b\"}.fa-gifts:before{content:\"\\f79c\"}.fa-git:before{content:\"\\f1d3\"}.fa-git-alt:before{content:\"\\f841\"}.fa-git-square:before{content:\"\\f1d2\"}.fa-github:before{content:\"\\f09b\"}.fa-github-alt:before{content:\"\\f113\"}.fa-github-square:before{content:\"\\f092\"}.fa-gitkraken:before{content:\"\\f3a6\"}.fa-gitlab:before{content:\"\\f296\"}.fa-gitter:before{content:\"\\f426\"}.fa-glass-cheers:before{content:\"\\f79f\"}.fa-glass-martini:before{content:\"\\f000\"}.fa-glass-martini-alt:before{content:\"\\f57b\"}.fa-glass-whiskey:before{content:\"\\f7a0\"}.fa-glasses:before{content:\"\\f530\"}.fa-glide:before{content:\"\\f2a5\"}.fa-glide-g:before{content:\"\\f2a6\"}.fa-globe:before{content:\"\\f0ac\"}.fa-globe-africa:before{content:\"\\f57c\"}.fa-globe-americas:before{content:\"\\f57d\"}.fa-globe-asia:before{content:\"\\f57e\"}.fa-globe-europe:before{content:\"\\f7a2\"}.fa-gofore:before{content:\"\\f3a7\"}.fa-golf-ball:before{content:\"\\f450\"}.fa-goodreads:before{content:\"\\f3a8\"}.fa-goodreads-g:before{content:\"\\f3a9\"}.fa-google:before{content:\"\\f1a0\"}.fa-google-drive:before{content:\"\\f3aa\"}.fa-google-pay:before{content:\"\\e079\"}.fa-google-play:before{content:\"\\f3ab\"}.fa-google-plus:before{content:\"\\f2b3\"}.fa-google-plus-g:before{content:\"\\f0d5\"}.fa-google-plus-square:before{content:\"\\f0d4\"}.fa-google-wallet:before{content:\"\\f1ee\"}.fa-gopuram:before{content:\"\\f664\"}.fa-graduation-cap:before{content:\"\\f19d\"}.fa-gratipay:before{content:\"\\f184\"}.fa-grav:before{content:\"\\f2d6\"}.fa-greater-than:before{content:\"\\f531\"}.fa-greater-than-equal:before{content:\"\\f532\"}.fa-grimace:before{content:\"\\f57f\"}.fa-grin:before{content:\"\\f580\"}.fa-grin-alt:before{content:\"\\f581\"}.fa-grin-beam:before{content:\"\\f582\"}.fa-grin-beam-sweat:before{content:\"\\f583\"}.fa-grin-hearts:before{content:\"\\f584\"}.fa-grin-squint:before{content:\"\\f585\"}.fa-grin-squint-tears:before{content:\"\\f586\"}.fa-grin-stars:before{content:\"\\f587\"}.fa-grin-tears:before{content:\"\\f588\"}.fa-grin-tongue:before{content:\"\\f589\"}.fa-grin-tongue-squint:before{content:\"\\f58a\"}.fa-grin-tongue-wink:before{content:\"\\f58b\"}.fa-grin-wink:before{content:\"\\f58c\"}.fa-grip-horizontal:before{content:\"\\f58d\"}.fa-grip-lines:before{content:\"\\f7a4\"}.fa-grip-lines-vertical:before{content:\"\\f7a5\"}.fa-grip-vertical:before{content:\"\\f58e\"}.fa-gripfire:before{content:\"\\f3ac\"}.fa-grunt:before{content:\"\\f3ad\"}.fa-guilded:before{content:\"\\e07e\"}.fa-guitar:before{content:\"\\f7a6\"}.fa-gulp:before{content:\"\\f3ae\"}.fa-h-square:before{content:\"\\f0fd\"}.fa-hacker-news:before{content:\"\\f1d4\"}.fa-hacker-news-square:before{content:\"\\f3af\"}.fa-hackerrank:before{content:\"\\f5f7\"}.fa-hamburger:before{content:\"\\f805\"}.fa-hammer:before{content:\"\\f6e3\"}.fa-hamsa:before{content:\"\\f665\"}.fa-hand-holding:before{content:\"\\f4bd\"}.fa-hand-holding-heart:before{content:\"\\f4be\"}.fa-hand-holding-medical:before{content:\"\\e05c\"}.fa-hand-holding-usd:before{content:\"\\f4c0\"}.fa-hand-holding-water:before{content:\"\\f4c1\"}.fa-hand-lizard:before{content:\"\\f258\"}.fa-hand-middle-finger:before{content:\"\\f806\"}.fa-hand-paper:before{content:\"\\f256\"}.fa-hand-peace:before{content:\"\\f25b\"}.fa-hand-point-down:before{content:\"\\f0a7\"}.fa-hand-point-left:before{content:\"\\f0a5\"}.fa-hand-point-right:before{content:\"\\f0a4\"}.fa-hand-point-up:before{content:\"\\f0a6\"}.fa-hand-pointer:before{content:\"\\f25a\"}.fa-hand-rock:before{content:\"\\f255\"}.fa-hand-scissors:before{content:\"\\f257\"}.fa-hand-sparkles:before{content:\"\\e05d\"}.fa-hand-spock:before{content:\"\\f259\"}.fa-hands:before{content:\"\\f4c2\"}.fa-hands-helping:before{content:\"\\f4c4\"}.fa-hands-wash:before{content:\"\\e05e\"}.fa-handshake:before{content:\"\\f2b5\"}.fa-handshake-alt-slash:before{content:\"\\e05f\"}.fa-handshake-slash:before{content:\"\\e060\"}.fa-hanukiah:before{content:\"\\f6e6\"}.fa-hard-hat:before{content:\"\\f807\"}.fa-hashtag:before{content:\"\\f292\"}.fa-hat-cowboy:before{content:\"\\f8c0\"}.fa-hat-cowboy-side:before{content:\"\\f8c1\"}.fa-hat-wizard:before{content:\"\\f6e8\"}.fa-hdd:before{content:\"\\f0a0\"}.fa-head-side-cough:before{content:\"\\e061\"}.fa-head-side-cough-slash:before{content:\"\\e062\"}.fa-head-side-mask:before{content:\"\\e063\"}.fa-head-side-virus:before{content:\"\\e064\"}.fa-heading:before{content:\"\\f1dc\"}.fa-headphones:before{content:\"\\f025\"}.fa-headphones-alt:before{content:\"\\f58f\"}.fa-headset:before{content:\"\\f590\"}.fa-heart:before{content:\"\\f004\"}.fa-heart-broken:before{content:\"\\f7a9\"}.fa-heartbeat:before{content:\"\\f21e\"}.fa-helicopter:before{content:\"\\f533\"}.fa-highlighter:before{content:\"\\f591\"}.fa-hiking:before{content:\"\\f6ec\"}.fa-hippo:before{content:\"\\f6ed\"}.fa-hips:before{content:\"\\f452\"}.fa-hire-a-helper:before{content:\"\\f3b0\"}.fa-history:before{content:\"\\f1da\"}.fa-hive:before{content:\"\\e07f\"}.fa-hockey-puck:before{content:\"\\f453\"}.fa-holly-berry:before{content:\"\\f7aa\"}.fa-home:before{content:\"\\f015\"}.fa-hooli:before{content:\"\\f427\"}.fa-hornbill:before{content:\"\\f592\"}.fa-horse:before{content:\"\\f6f0\"}.fa-horse-head:before{content:\"\\f7ab\"}.fa-hospital:before{content:\"\\f0f8\"}.fa-hospital-alt:before{content:\"\\f47d\"}.fa-hospital-symbol:before{content:\"\\f47e\"}.fa-hospital-user:before{content:\"\\f80d\"}.fa-hot-tub:before{content:\"\\f593\"}.fa-hotdog:before{content:\"\\f80f\"}.fa-hotel:before{content:\"\\f594\"}.fa-hotjar:before{content:\"\\f3b1\"}.fa-hourglass:before{content:\"\\f254\"}.fa-hourglass-end:before{content:\"\\f253\"}.fa-hourglass-half:before{content:\"\\f252\"}.fa-hourglass-start:before{content:\"\\f251\"}.fa-house-damage:before{content:\"\\f6f1\"}.fa-house-user:before{content:\"\\e065\"}.fa-houzz:before{content:\"\\f27c\"}.fa-hryvnia:before{content:\"\\f6f2\"}.fa-html5:before{content:\"\\f13b\"}.fa-hubspot:before{content:\"\\f3b2\"}.fa-i-cursor:before{content:\"\\f246\"}.fa-ice-cream:before{content:\"\\f810\"}.fa-icicles:before{content:\"\\f7ad\"}.fa-icons:before{content:\"\\f86d\"}.fa-id-badge:before{content:\"\\f2c1\"}.fa-id-card:before{content:\"\\f2c2\"}.fa-id-card-alt:before{content:\"\\f47f\"}.fa-ideal:before{content:\"\\e013\"}.fa-igloo:before{content:\"\\f7ae\"}.fa-image:before{content:\"\\f03e\"}.fa-images:before{content:\"\\f302\"}.fa-imdb:before{content:\"\\f2d8\"}.fa-inbox:before{content:\"\\f01c\"}.fa-indent:before{content:\"\\f03c\"}.fa-industry:before{content:\"\\f275\"}.fa-infinity:before{content:\"\\f534\"}.fa-info:before{content:\"\\f129\"}.fa-info-circle:before{content:\"\\f05a\"}.fa-innosoft:before{content:\"\\e080\"}.fa-instagram:before{content:\"\\f16d\"}.fa-instagram-square:before{content:\"\\e055\"}.fa-instalod:before{content:\"\\e081\"}.fa-intercom:before{content:\"\\f7af\"}.fa-internet-explorer:before{content:\"\\f26b\"}.fa-invision:before{content:\"\\f7b0\"}.fa-ioxhost:before{content:\"\\f208\"}.fa-italic:before{content:\"\\f033\"}.fa-itch-io:before{content:\"\\f83a\"}.fa-itunes:before{content:\"\\f3b4\"}.fa-itunes-note:before{content:\"\\f3b5\"}.fa-java:before{content:\"\\f4e4\"}.fa-jedi:before{content:\"\\f669\"}.fa-jedi-order:before{content:\"\\f50e\"}.fa-jenkins:before{content:\"\\f3b6\"}.fa-jira:before{content:\"\\f7b1\"}.fa-joget:before{content:\"\\f3b7\"}.fa-joint:before{content:\"\\f595\"}.fa-joomla:before{content:\"\\f1aa\"}.fa-journal-whills:before{content:\"\\f66a\"}.fa-js:before{content:\"\\f3b8\"}.fa-js-square:before{content:\"\\f3b9\"}.fa-jsfiddle:before{content:\"\\f1cc\"}.fa-kaaba:before{content:\"\\f66b\"}.fa-kaggle:before{content:\"\\f5fa\"}.fa-key:before{content:\"\\f084\"}.fa-keybase:before{content:\"\\f4f5\"}.fa-keyboard:before{content:\"\\f11c\"}.fa-keycdn:before{content:\"\\f3ba\"}.fa-khanda:before{content:\"\\f66d\"}.fa-kickstarter:before{content:\"\\f3bb\"}.fa-kickstarter-k:before{content:\"\\f3bc\"}.fa-kiss:before{content:\"\\f596\"}.fa-kiss-beam:before{content:\"\\f597\"}.fa-kiss-wink-heart:before{content:\"\\f598\"}.fa-kiwi-bird:before{content:\"\\f535\"}.fa-korvue:before{content:\"\\f42f\"}.fa-landmark:before{content:\"\\f66f\"}.fa-language:before{content:\"\\f1ab\"}.fa-laptop:before{content:\"\\f109\"}.fa-laptop-code:before{content:\"\\f5fc\"}.fa-laptop-house:before{content:\"\\e066\"}.fa-laptop-medical:before{content:\"\\f812\"}.fa-laravel:before{content:\"\\f3bd\"}.fa-lastfm:before{content:\"\\f202\"}.fa-lastfm-square:before{content:\"\\f203\"}.fa-laugh:before{content:\"\\f599\"}.fa-laugh-beam:before{content:\"\\f59a\"}.fa-laugh-squint:before{content:\"\\f59b\"}.fa-laugh-wink:before{content:\"\\f59c\"}.fa-layer-group:before{content:\"\\f5fd\"}.fa-leaf:before{content:\"\\f06c\"}.fa-leanpub:before{content:\"\\f212\"}.fa-lemon:before{content:\"\\f094\"}.fa-less:before{content:\"\\f41d\"}.fa-less-than:before{content:\"\\f536\"}.fa-less-than-equal:before{content:\"\\f537\"}.fa-level-down-alt:before{content:\"\\f3be\"}.fa-level-up-alt:before{content:\"\\f3bf\"}.fa-life-ring:before{content:\"\\f1cd\"}.fa-lightbulb:before{content:\"\\f0eb\"}.fa-line:before{content:\"\\f3c0\"}.fa-link:before{content:\"\\f0c1\"}.fa-linkedin:before{content:\"\\f08c\"}.fa-linkedin-in:before{content:\"\\f0e1\"}.fa-linode:before{content:\"\\f2b8\"}.fa-linux:before{content:\"\\f17c\"}.fa-lira-sign:before{content:\"\\f195\"}.fa-list:before{content:\"\\f03a\"}.fa-list-alt:before{content:\"\\f022\"}.fa-list-ol:before{content:\"\\f0cb\"}.fa-list-ul:before{content:\"\\f0ca\"}.fa-location-arrow:before{content:\"\\f124\"}.fa-lock:before{content:\"\\f023\"}.fa-lock-open:before{content:\"\\f3c1\"}.fa-long-arrow-alt-down:before{content:\"\\f309\"}.fa-long-arrow-alt-left:before{content:\"\\f30a\"}.fa-long-arrow-alt-right:before{content:\"\\f30b\"}.fa-long-arrow-alt-up:before{content:\"\\f30c\"}.fa-low-vision:before{content:\"\\f2a8\"}.fa-luggage-cart:before{content:\"\\f59d\"}.fa-lungs:before{content:\"\\f604\"}.fa-lungs-virus:before{content:\"\\e067\"}.fa-lyft:before{content:\"\\f3c3\"}.fa-magento:before{content:\"\\f3c4\"}.fa-magic:before{content:\"\\f0d0\"}.fa-magnet:before{content:\"\\f076\"}.fa-mail-bulk:before{content:\"\\f674\"}.fa-mailchimp:before{content:\"\\f59e\"}.fa-male:before{content:\"\\f183\"}.fa-mandalorian:before{content:\"\\f50f\"}.fa-map:before{content:\"\\f279\"}.fa-map-marked:before{content:\"\\f59f\"}.fa-map-marked-alt:before{content:\"\\f5a0\"}.fa-map-marker:before{content:\"\\f041\"}.fa-map-marker-alt:before{content:\"\\f3c5\"}.fa-map-pin:before{content:\"\\f276\"}.fa-map-signs:before{content:\"\\f277\"}.fa-markdown:before{content:\"\\f60f\"}.fa-marker:before{content:\"\\f5a1\"}.fa-mars:before{content:\"\\f222\"}.fa-mars-double:before{content:\"\\f227\"}.fa-mars-stroke:before{content:\"\\f229\"}.fa-mars-stroke-h:before{content:\"\\f22b\"}.fa-mars-stroke-v:before{content:\"\\f22a\"}.fa-mask:before{content:\"\\f6fa\"}.fa-mastodon:before{content:\"\\f4f6\"}.fa-maxcdn:before{content:\"\\f136\"}.fa-mdb:before{content:\"\\f8ca\"}.fa-medal:before{content:\"\\f5a2\"}.fa-medapps:before{content:\"\\f3c6\"}.fa-medium:before{content:\"\\f23a\"}.fa-medium-m:before{content:\"\\f3c7\"}.fa-medkit:before{content:\"\\f0fa\"}.fa-medrt:before{content:\"\\f3c8\"}.fa-meetup:before{content:\"\\f2e0\"}.fa-megaport:before{content:\"\\f5a3\"}.fa-meh:before{content:\"\\f11a\"}.fa-meh-blank:before{content:\"\\f5a4\"}.fa-meh-rolling-eyes:before{content:\"\\f5a5\"}.fa-memory:before{content:\"\\f538\"}.fa-mendeley:before{content:\"\\f7b3\"}.fa-menorah:before{content:\"\\f676\"}.fa-mercury:before{content:\"\\f223\"}.fa-meteor:before{content:\"\\f753\"}.fa-microblog:before{content:\"\\e01a\"}.fa-microchip:before{content:\"\\f2db\"}.fa-microphone:before{content:\"\\f130\"}.fa-microphone-alt:before{content:\"\\f3c9\"}.fa-microphone-alt-slash:before{content:\"\\f539\"}.fa-microphone-slash:before{content:\"\\f131\"}.fa-microscope:before{content:\"\\f610\"}.fa-microsoft:before{content:\"\\f3ca\"}.fa-minus:before{content:\"\\f068\"}.fa-minus-circle:before{content:\"\\f056\"}.fa-minus-square:before{content:\"\\f146\"}.fa-mitten:before{content:\"\\f7b5\"}.fa-mix:before{content:\"\\f3cb\"}.fa-mixcloud:before{content:\"\\f289\"}.fa-mixer:before{content:\"\\e056\"}.fa-mizuni:before{content:\"\\f3cc\"}.fa-mobile:before{content:\"\\f10b\"}.fa-mobile-alt:before{content:\"\\f3cd\"}.fa-modx:before{content:\"\\f285\"}.fa-monero:before{content:\"\\f3d0\"}.fa-money-bill:before{content:\"\\f0d6\"}.fa-money-bill-alt:before{content:\"\\f3d1\"}.fa-money-bill-wave:before{content:\"\\f53a\"}.fa-money-bill-wave-alt:before{content:\"\\f53b\"}.fa-money-check:before{content:\"\\f53c\"}.fa-money-check-alt:before{content:\"\\f53d\"}.fa-monument:before{content:\"\\f5a6\"}.fa-moon:before{content:\"\\f186\"}.fa-mortar-pestle:before{content:\"\\f5a7\"}.fa-mosque:before{content:\"\\f678\"}.fa-motorcycle:before{content:\"\\f21c\"}.fa-mountain:before{content:\"\\f6fc\"}.fa-mouse:before{content:\"\\f8cc\"}.fa-mouse-pointer:before{content:\"\\f245\"}.fa-mug-hot:before{content:\"\\f7b6\"}.fa-music:before{content:\"\\f001\"}.fa-napster:before{content:\"\\f3d2\"}.fa-neos:before{content:\"\\f612\"}.fa-network-wired:before{content:\"\\f6ff\"}.fa-neuter:before{content:\"\\f22c\"}.fa-newspaper:before{content:\"\\f1ea\"}.fa-nimblr:before{content:\"\\f5a8\"}.fa-node:before{content:\"\\f419\"}.fa-node-js:before{content:\"\\f3d3\"}.fa-not-equal:before{content:\"\\f53e\"}.fa-notes-medical:before{content:\"\\f481\"}.fa-npm:before{content:\"\\f3d4\"}.fa-ns8:before{content:\"\\f3d5\"}.fa-nutritionix:before{content:\"\\f3d6\"}.fa-object-group:before{content:\"\\f247\"}.fa-object-ungroup:before{content:\"\\f248\"}.fa-octopus-deploy:before{content:\"\\e082\"}.fa-odnoklassniki:before{content:\"\\f263\"}.fa-odnoklassniki-square:before{content:\"\\f264\"}.fa-oil-can:before{content:\"\\f613\"}.fa-old-republic:before{content:\"\\f510\"}.fa-om:before{content:\"\\f679\"}.fa-opencart:before{content:\"\\f23d\"}.fa-openid:before{content:\"\\f19b\"}.fa-opera:before{content:\"\\f26a\"}.fa-optin-monster:before{content:\"\\f23c\"}.fa-orcid:before{content:\"\\f8d2\"}.fa-osi:before{content:\"\\f41a\"}.fa-otter:before{content:\"\\f700\"}.fa-outdent:before{content:\"\\f03b\"}.fa-page4:before{content:\"\\f3d7\"}.fa-pagelines:before{content:\"\\f18c\"}.fa-pager:before{content:\"\\f815\"}.fa-paint-brush:before{content:\"\\f1fc\"}.fa-paint-roller:before{content:\"\\f5aa\"}.fa-palette:before{content:\"\\f53f\"}.fa-palfed:before{content:\"\\f3d8\"}.fa-pallet:before{content:\"\\f482\"}.fa-paper-plane:before{content:\"\\f1d8\"}.fa-paperclip:before{content:\"\\f0c6\"}.fa-parachute-box:before{content:\"\\f4cd\"}.fa-paragraph:before{content:\"\\f1dd\"}.fa-parking:before{content:\"\\f540\"}.fa-passport:before{content:\"\\f5ab\"}.fa-pastafarianism:before{content:\"\\f67b\"}.fa-paste:before{content:\"\\f0ea\"}.fa-patreon:before{content:\"\\f3d9\"}.fa-pause:before{content:\"\\f04c\"}.fa-pause-circle:before{content:\"\\f28b\"}.fa-paw:before{content:\"\\f1b0\"}.fa-paypal:before{content:\"\\f1ed\"}.fa-peace:before{content:\"\\f67c\"}.fa-pen:before{content:\"\\f304\"}.fa-pen-alt:before{content:\"\\f305\"}.fa-pen-fancy:before{content:\"\\f5ac\"}.fa-pen-nib:before{content:\"\\f5ad\"}.fa-pen-square:before{content:\"\\f14b\"}.fa-pencil-alt:before{content:\"\\f303\"}.fa-pencil-ruler:before{content:\"\\f5ae\"}.fa-penny-arcade:before{content:\"\\f704\"}.fa-people-arrows:before{content:\"\\e068\"}.fa-people-carry:before{content:\"\\f4ce\"}.fa-pepper-hot:before{content:\"\\f816\"}.fa-perbyte:before{content:\"\\e083\"}.fa-percent:before{content:\"\\f295\"}.fa-percentage:before{content:\"\\f541\"}.fa-periscope:before{content:\"\\f3da\"}.fa-person-booth:before{content:\"\\f756\"}.fa-phabricator:before{content:\"\\f3db\"}.fa-phoenix-framework:before{content:\"\\f3dc\"}.fa-phoenix-squadron:before{content:\"\\f511\"}.fa-phone:before{content:\"\\f095\"}.fa-phone-alt:before{content:\"\\f879\"}.fa-phone-slash:before{content:\"\\f3dd\"}.fa-phone-square:before{content:\"\\f098\"}.fa-phone-square-alt:before{content:\"\\f87b\"}.fa-phone-volume:before{content:\"\\f2a0\"}.fa-photo-video:before{content:\"\\f87c\"}.fa-php:before{content:\"\\f457\"}.fa-pied-piper:before{content:\"\\f2ae\"}.fa-pied-piper-alt:before{content:\"\\f1a8\"}.fa-pied-piper-hat:before{content:\"\\f4e5\"}.fa-pied-piper-pp:before{content:\"\\f1a7\"}.fa-pied-piper-square:before{content:\"\\e01e\"}.fa-piggy-bank:before{content:\"\\f4d3\"}.fa-pills:before{content:\"\\f484\"}.fa-pinterest:before{content:\"\\f0d2\"}.fa-pinterest-p:before{content:\"\\f231\"}.fa-pinterest-square:before{content:\"\\f0d3\"}.fa-pizza-slice:before{content:\"\\f818\"}.fa-place-of-worship:before{content:\"\\f67f\"}.fa-plane:before{content:\"\\f072\"}.fa-plane-arrival:before{content:\"\\f5af\"}.fa-plane-departure:before{content:\"\\f5b0\"}.fa-plane-slash:before{content:\"\\e069\"}.fa-play:before{content:\"\\f04b\"}.fa-play-circle:before{content:\"\\f144\"}.fa-playstation:before{content:\"\\f3df\"}.fa-plug:before{content:\"\\f1e6\"}.fa-plus:before{content:\"\\f067\"}.fa-plus-circle:before{content:\"\\f055\"}.fa-plus-square:before{content:\"\\f0fe\"}.fa-podcast:before{content:\"\\f2ce\"}.fa-poll:before{content:\"\\f681\"}.fa-poll-h:before{content:\"\\f682\"}.fa-poo:before{content:\"\\f2fe\"}.fa-poo-storm:before{content:\"\\f75a\"}.fa-poop:before{content:\"\\f619\"}.fa-portrait:before{content:\"\\f3e0\"}.fa-pound-sign:before{content:\"\\f154\"}.fa-power-off:before{content:\"\\f011\"}.fa-pray:before{content:\"\\f683\"}.fa-praying-hands:before{content:\"\\f684\"}.fa-prescription:before{content:\"\\f5b1\"}.fa-prescription-bottle:before{content:\"\\f485\"}.fa-prescription-bottle-alt:before{content:\"\\f486\"}.fa-print:before{content:\"\\f02f\"}.fa-procedures:before{content:\"\\f487\"}.fa-product-hunt:before{content:\"\\f288\"}.fa-project-diagram:before{content:\"\\f542\"}.fa-pump-medical:before{content:\"\\e06a\"}.fa-pump-soap:before{content:\"\\e06b\"}.fa-pushed:before{content:\"\\f3e1\"}.fa-puzzle-piece:before{content:\"\\f12e\"}.fa-python:before{content:\"\\f3e2\"}.fa-qq:before{content:\"\\f1d6\"}.fa-qrcode:before{content:\"\\f029\"}.fa-question:before{content:\"\\f128\"}.fa-question-circle:before{content:\"\\f059\"}.fa-quidditch:before{content:\"\\f458\"}.fa-quinscape:before{content:\"\\f459\"}.fa-quora:before{content:\"\\f2c4\"}.fa-quote-left:before{content:\"\\f10d\"}.fa-quote-right:before{content:\"\\f10e\"}.fa-quran:before{content:\"\\f687\"}.fa-r-project:before{content:\"\\f4f7\"}.fa-radiation:before{content:\"\\f7b9\"}.fa-radiation-alt:before{content:\"\\f7ba\"}.fa-rainbow:before{content:\"\\f75b\"}.fa-random:before{content:\"\\f074\"}.fa-raspberry-pi:before{content:\"\\f7bb\"}.fa-ravelry:before{content:\"\\f2d9\"}.fa-react:before{content:\"\\f41b\"}.fa-reacteurope:before{content:\"\\f75d\"}.fa-readme:before{content:\"\\f4d5\"}.fa-rebel:before{content:\"\\f1d0\"}.fa-receipt:before{content:\"\\f543\"}.fa-record-vinyl:before{content:\"\\f8d9\"}.fa-recycle:before{content:\"\\f1b8\"}.fa-red-river:before{content:\"\\f3e3\"}.fa-reddit:before{content:\"\\f1a1\"}.fa-reddit-alien:before{content:\"\\f281\"}.fa-reddit-square:before{content:\"\\f1a2\"}.fa-redhat:before{content:\"\\f7bc\"}.fa-redo:before{content:\"\\f01e\"}.fa-redo-alt:before{content:\"\\f2f9\"}.fa-registered:before{content:\"\\f25d\"}.fa-remove-format:before{content:\"\\f87d\"}.fa-renren:before{content:\"\\f18b\"}.fa-reply:before{content:\"\\f3e5\"}.fa-reply-all:before{content:\"\\f122\"}.fa-replyd:before{content:\"\\f3e6\"}.fa-republican:before{content:\"\\f75e\"}.fa-researchgate:before{content:\"\\f4f8\"}.fa-resolving:before{content:\"\\f3e7\"}.fa-restroom:before{content:\"\\f7bd\"}.fa-retweet:before{content:\"\\f079\"}.fa-rev:before{content:\"\\f5b2\"}.fa-ribbon:before{content:\"\\f4d6\"}.fa-ring:before{content:\"\\f70b\"}.fa-road:before{content:\"\\f018\"}.fa-robot:before{content:\"\\f544\"}.fa-rocket:before{content:\"\\f135\"}.fa-rocketchat:before{content:\"\\f3e8\"}.fa-rockrms:before{content:\"\\f3e9\"}.fa-route:before{content:\"\\f4d7\"}.fa-rss:before{content:\"\\f09e\"}.fa-rss-square:before{content:\"\\f143\"}.fa-ruble-sign:before{content:\"\\f158\"}.fa-ruler:before{content:\"\\f545\"}.fa-ruler-combined:before{content:\"\\f546\"}.fa-ruler-horizontal:before{content:\"\\f547\"}.fa-ruler-vertical:before{content:\"\\f548\"}.fa-running:before{content:\"\\f70c\"}.fa-rupee-sign:before{content:\"\\f156\"}.fa-rust:before{content:\"\\e07a\"}.fa-sad-cry:before{content:\"\\f5b3\"}.fa-sad-tear:before{content:\"\\f5b4\"}.fa-safari:before{content:\"\\f267\"}.fa-salesforce:before{content:\"\\f83b\"}.fa-sass:before{content:\"\\f41e\"}.fa-satellite:before{content:\"\\f7bf\"}.fa-satellite-dish:before{content:\"\\f7c0\"}.fa-save:before{content:\"\\f0c7\"}.fa-schlix:before{content:\"\\f3ea\"}.fa-school:before{content:\"\\f549\"}.fa-screwdriver:before{content:\"\\f54a\"}.fa-scribd:before{content:\"\\f28a\"}.fa-scroll:before{content:\"\\f70e\"}.fa-sd-card:before{content:\"\\f7c2\"}.fa-search:before{content:\"\\f002\"}.fa-search-dollar:before{content:\"\\f688\"}.fa-search-location:before{content:\"\\f689\"}.fa-search-minus:before{content:\"\\f010\"}.fa-search-plus:before{content:\"\\f00e\"}.fa-searchengin:before{content:\"\\f3eb\"}.fa-seedling:before{content:\"\\f4d8\"}.fa-sellcast:before{content:\"\\f2da\"}.fa-sellsy:before{content:\"\\f213\"}.fa-server:before{content:\"\\f233\"}.fa-servicestack:before{content:\"\\f3ec\"}.fa-shapes:before{content:\"\\f61f\"}.fa-share:before{content:\"\\f064\"}.fa-share-alt:before{content:\"\\f1e0\"}.fa-share-alt-square:before{content:\"\\f1e1\"}.fa-share-square:before{content:\"\\f14d\"}.fa-shekel-sign:before{content:\"\\f20b\"}.fa-shield-alt:before{content:\"\\f3ed\"}.fa-shield-virus:before{content:\"\\e06c\"}.fa-ship:before{content:\"\\f21a\"}.fa-shipping-fast:before{content:\"\\f48b\"}.fa-shirtsinbulk:before{content:\"\\f214\"}.fa-shoe-prints:before{content:\"\\f54b\"}.fa-shopify:before{content:\"\\e057\"}.fa-shopping-bag:before{content:\"\\f290\"}.fa-shopping-basket:before{content:\"\\f291\"}.fa-shopping-cart:before{content:\"\\f07a\"}.fa-shopware:before{content:\"\\f5b5\"}.fa-shower:before{content:\"\\f2cc\"}.fa-shuttle-van:before{content:\"\\f5b6\"}.fa-sign:before{content:\"\\f4d9\"}.fa-sign-in-alt:before{content:\"\\f2f6\"}.fa-sign-language:before{content:\"\\f2a7\"}.fa-sign-out-alt:before{content:\"\\f2f5\"}.fa-signal:before{content:\"\\f012\"}.fa-signature:before{content:\"\\f5b7\"}.fa-sim-card:before{content:\"\\f7c4\"}.fa-simplybuilt:before{content:\"\\f215\"}.fa-sink:before{content:\"\\e06d\"}.fa-sistrix:before{content:\"\\f3ee\"}.fa-sitemap:before{content:\"\\f0e8\"}.fa-sith:before{content:\"\\f512\"}.fa-skating:before{content:\"\\f7c5\"}.fa-sketch:before{content:\"\\f7c6\"}.fa-skiing:before{content:\"\\f7c9\"}.fa-skiing-nordic:before{content:\"\\f7ca\"}.fa-skull:before{content:\"\\f54c\"}.fa-skull-crossbones:before{content:\"\\f714\"}.fa-skyatlas:before{content:\"\\f216\"}.fa-skype:before{content:\"\\f17e\"}.fa-slack:before{content:\"\\f198\"}.fa-slack-hash:before{content:\"\\f3ef\"}.fa-slash:before{content:\"\\f715\"}.fa-sleigh:before{content:\"\\f7cc\"}.fa-sliders-h:before{content:\"\\f1de\"}.fa-slideshare:before{content:\"\\f1e7\"}.fa-smile:before{content:\"\\f118\"}.fa-smile-beam:before{content:\"\\f5b8\"}.fa-smile-wink:before{content:\"\\f4da\"}.fa-smog:before{content:\"\\f75f\"}.fa-smoking:before{content:\"\\f48d\"}.fa-smoking-ban:before{content:\"\\f54d\"}.fa-sms:before{content:\"\\f7cd\"}.fa-snapchat:before{content:\"\\f2ab\"}.fa-snapchat-ghost:before{content:\"\\f2ac\"}.fa-snapchat-square:before{content:\"\\f2ad\"}.fa-snowboarding:before{content:\"\\f7ce\"}.fa-snowflake:before{content:\"\\f2dc\"}.fa-snowman:before{content:\"\\f7d0\"}.fa-snowplow:before{content:\"\\f7d2\"}.fa-soap:before{content:\"\\e06e\"}.fa-socks:before{content:\"\\f696\"}.fa-solar-panel:before{content:\"\\f5ba\"}.fa-sort:before{content:\"\\f0dc\"}.fa-sort-alpha-down:before{content:\"\\f15d\"}.fa-sort-alpha-down-alt:before{content:\"\\f881\"}.fa-sort-alpha-up:before{content:\"\\f15e\"}.fa-sort-alpha-up-alt:before{content:\"\\f882\"}.fa-sort-amount-down:before{content:\"\\f160\"}.fa-sort-amount-down-alt:before{content:\"\\f884\"}.fa-sort-amount-up:before{content:\"\\f161\"}.fa-sort-amount-up-alt:before{content:\"\\f885\"}.fa-sort-down:before{content:\"\\f0dd\"}.fa-sort-numeric-down:before{content:\"\\f162\"}.fa-sort-numeric-down-alt:before{content:\"\\f886\"}.fa-sort-numeric-up:before{content:\"\\f163\"}.fa-sort-numeric-up-alt:before{content:\"\\f887\"}.fa-sort-up:before{content:\"\\f0de\"}.fa-soundcloud:before{content:\"\\f1be\"}.fa-sourcetree:before{content:\"\\f7d3\"}.fa-spa:before{content:\"\\f5bb\"}.fa-space-shuttle:before{content:\"\\f197\"}.fa-speakap:before{content:\"\\f3f3\"}.fa-speaker-deck:before{content:\"\\f83c\"}.fa-spell-check:before{content:\"\\f891\"}.fa-spider:before{content:\"\\f717\"}.fa-spinner:before{content:\"\\f110\"}.fa-splotch:before{content:\"\\f5bc\"}.fa-spotify:before{content:\"\\f1bc\"}.fa-spray-can:before{content:\"\\f5bd\"}.fa-square:before{content:\"\\f0c8\"}.fa-square-full:before{content:\"\\f45c\"}.fa-square-root-alt:before{content:\"\\f698\"}.fa-squarespace:before{content:\"\\f5be\"}.fa-stack-exchange:before{content:\"\\f18d\"}.fa-stack-overflow:before{content:\"\\f16c\"}.fa-stackpath:before{content:\"\\f842\"}.fa-stamp:before{content:\"\\f5bf\"}.fa-star:before{content:\"\\f005\"}.fa-star-and-crescent:before{content:\"\\f699\"}.fa-star-half:before{content:\"\\f089\"}.fa-star-half-alt:before{content:\"\\f5c0\"}.fa-star-of-david:before{content:\"\\f69a\"}.fa-star-of-life:before{content:\"\\f621\"}.fa-staylinked:before{content:\"\\f3f5\"}.fa-steam:before{content:\"\\f1b6\"}.fa-steam-square:before{content:\"\\f1b7\"}.fa-steam-symbol:before{content:\"\\f3f6\"}.fa-step-backward:before{content:\"\\f048\"}.fa-step-forward:before{content:\"\\f051\"}.fa-stethoscope:before{content:\"\\f0f1\"}.fa-sticker-mule:before{content:\"\\f3f7\"}.fa-sticky-note:before{content:\"\\f249\"}.fa-stop:before{content:\"\\f04d\"}.fa-stop-circle:before{content:\"\\f28d\"}.fa-stopwatch:before{content:\"\\f2f2\"}.fa-stopwatch-20:before{content:\"\\e06f\"}.fa-store:before{content:\"\\f54e\"}.fa-store-alt:before{content:\"\\f54f\"}.fa-store-alt-slash:before{content:\"\\e070\"}.fa-store-slash:before{content:\"\\e071\"}.fa-strava:before{content:\"\\f428\"}.fa-stream:before{content:\"\\f550\"}.fa-street-view:before{content:\"\\f21d\"}.fa-strikethrough:before{content:\"\\f0cc\"}.fa-stripe:before{content:\"\\f429\"}.fa-stripe-s:before{content:\"\\f42a\"}.fa-stroopwafel:before{content:\"\\f551\"}.fa-studiovinari:before{content:\"\\f3f8\"}.fa-stumbleupon:before{content:\"\\f1a4\"}.fa-stumbleupon-circle:before{content:\"\\f1a3\"}.fa-subscript:before{content:\"\\f12c\"}.fa-subway:before{content:\"\\f239\"}.fa-suitcase:before{content:\"\\f0f2\"}.fa-suitcase-rolling:before{content:\"\\f5c1\"}.fa-sun:before{content:\"\\f185\"}.fa-superpowers:before{content:\"\\f2dd\"}.fa-superscript:before{content:\"\\f12b\"}.fa-supple:before{content:\"\\f3f9\"}.fa-surprise:before{content:\"\\f5c2\"}.fa-suse:before{content:\"\\f7d6\"}.fa-swatchbook:before{content:\"\\f5c3\"}.fa-swift:before{content:\"\\f8e1\"}.fa-swimmer:before{content:\"\\f5c4\"}.fa-swimming-pool:before{content:\"\\f5c5\"}.fa-symfony:before{content:\"\\f83d\"}.fa-synagogue:before{content:\"\\f69b\"}.fa-sync:before{content:\"\\f021\"}.fa-sync-alt:before{content:\"\\f2f1\"}.fa-syringe:before{content:\"\\f48e\"}.fa-table:before{content:\"\\f0ce\"}.fa-table-tennis:before{content:\"\\f45d\"}.fa-tablet:before{content:\"\\f10a\"}.fa-tablet-alt:before{content:\"\\f3fa\"}.fa-tablets:before{content:\"\\f490\"}.fa-tachometer-alt:before{content:\"\\f3fd\"}.fa-tag:before{content:\"\\f02b\"}.fa-tags:before{content:\"\\f02c\"}.fa-tape:before{content:\"\\f4db\"}.fa-tasks:before{content:\"\\f0ae\"}.fa-taxi:before{content:\"\\f1ba\"}.fa-teamspeak:before{content:\"\\f4f9\"}.fa-teeth:before{content:\"\\f62e\"}.fa-teeth-open:before{content:\"\\f62f\"}.fa-telegram:before{content:\"\\f2c6\"}.fa-telegram-plane:before{content:\"\\f3fe\"}.fa-temperature-high:before{content:\"\\f769\"}.fa-temperature-low:before{content:\"\\f76b\"}.fa-tencent-weibo:before{content:\"\\f1d5\"}.fa-tenge:before{content:\"\\f7d7\"}.fa-terminal:before{content:\"\\f120\"}.fa-text-height:before{content:\"\\f034\"}.fa-text-width:before{content:\"\\f035\"}.fa-th:before{content:\"\\f00a\"}.fa-th-large:before{content:\"\\f009\"}.fa-th-list:before{content:\"\\f00b\"}.fa-the-red-yeti:before{content:\"\\f69d\"}.fa-theater-masks:before{content:\"\\f630\"}.fa-themeco:before{content:\"\\f5c6\"}.fa-themeisle:before{content:\"\\f2b2\"}.fa-thermometer:before{content:\"\\f491\"}.fa-thermometer-empty:before{content:\"\\f2cb\"}.fa-thermometer-full:before{content:\"\\f2c7\"}.fa-thermometer-half:before{content:\"\\f2c9\"}.fa-thermometer-quarter:before{content:\"\\f2ca\"}.fa-thermometer-three-quarters:before{content:\"\\f2c8\"}.fa-think-peaks:before{content:\"\\f731\"}.fa-thumbs-down:before{content:\"\\f165\"}.fa-thumbs-up:before{content:\"\\f164\"}.fa-thumbtack:before{content:\"\\f08d\"}.fa-ticket-alt:before{content:\"\\f3ff\"}.fa-tiktok:before{content:\"\\e07b\"}.fa-times:before{content:\"\\f00d\"}.fa-times-circle:before{content:\"\\f057\"}.fa-tint:before{content:\"\\f043\"}.fa-tint-slash:before{content:\"\\f5c7\"}.fa-tired:before{content:\"\\f5c8\"}.fa-toggle-off:before{content:\"\\f204\"}.fa-toggle-on:before{content:\"\\f205\"}.fa-toilet:before{content:\"\\f7d8\"}.fa-toilet-paper:before{content:\"\\f71e\"}.fa-toilet-paper-slash:before{content:\"\\e072\"}.fa-toolbox:before{content:\"\\f552\"}.fa-tools:before{content:\"\\f7d9\"}.fa-tooth:before{content:\"\\f5c9\"}.fa-torah:before{content:\"\\f6a0\"}.fa-torii-gate:before{content:\"\\f6a1\"}.fa-tractor:before{content:\"\\f722\"}.fa-trade-federation:before{content:\"\\f513\"}.fa-trademark:before{content:\"\\f25c\"}.fa-traffic-light:before{content:\"\\f637\"}.fa-trailer:before{content:\"\\e041\"}.fa-train:before{content:\"\\f238\"}.fa-tram:before{content:\"\\f7da\"}.fa-transgender:before{content:\"\\f224\"}.fa-transgender-alt:before{content:\"\\f225\"}.fa-trash:before{content:\"\\f1f8\"}.fa-trash-alt:before{content:\"\\f2ed\"}.fa-trash-restore:before{content:\"\\f829\"}.fa-trash-restore-alt:before{content:\"\\f82a\"}.fa-tree:before{content:\"\\f1bb\"}.fa-trello:before{content:\"\\f181\"}.fa-trophy:before{content:\"\\f091\"}.fa-truck:before{content:\"\\f0d1\"}.fa-truck-loading:before{content:\"\\f4de\"}.fa-truck-monster:before{content:\"\\f63b\"}.fa-truck-moving:before{content:\"\\f4df\"}.fa-truck-pickup:before{content:\"\\f63c\"}.fa-tshirt:before{content:\"\\f553\"}.fa-tty:before{content:\"\\f1e4\"}.fa-tumblr:before{content:\"\\f173\"}.fa-tumblr-square:before{content:\"\\f174\"}.fa-tv:before{content:\"\\f26c\"}.fa-twitch:before{content:\"\\f1e8\"}.fa-twitter:before{content:\"\\f099\"}.fa-twitter-square:before{content:\"\\f081\"}.fa-typo3:before{content:\"\\f42b\"}.fa-uber:before{content:\"\\f402\"}.fa-ubuntu:before{content:\"\\f7df\"}.fa-uikit:before{content:\"\\f403\"}.fa-umbraco:before{content:\"\\f8e8\"}.fa-umbrella:before{content:\"\\f0e9\"}.fa-umbrella-beach:before{content:\"\\f5ca\"}.fa-uncharted:before{content:\"\\e084\"}.fa-underline:before{content:\"\\f0cd\"}.fa-undo:before{content:\"\\f0e2\"}.fa-undo-alt:before{content:\"\\f2ea\"}.fa-uniregistry:before{content:\"\\f404\"}.fa-unity:before{content:\"\\e049\"}.fa-universal-access:before{content:\"\\f29a\"}.fa-university:before{content:\"\\f19c\"}.fa-unlink:before{content:\"\\f127\"}.fa-unlock:before{content:\"\\f09c\"}.fa-unlock-alt:before{content:\"\\f13e\"}.fa-unsplash:before{content:\"\\e07c\"}.fa-untappd:before{content:\"\\f405\"}.fa-upload:before{content:\"\\f093\"}.fa-ups:before{content:\"\\f7e0\"}.fa-usb:before{content:\"\\f287\"}.fa-user:before{content:\"\\f007\"}.fa-user-alt:before{content:\"\\f406\"}.fa-user-alt-slash:before{content:\"\\f4fa\"}.fa-user-astronaut:before{content:\"\\f4fb\"}.fa-user-check:before{content:\"\\f4fc\"}.fa-user-circle:before{content:\"\\f2bd\"}.fa-user-clock:before{content:\"\\f4fd\"}.fa-user-cog:before{content:\"\\f4fe\"}.fa-user-edit:before{content:\"\\f4ff\"}.fa-user-friends:before{content:\"\\f500\"}.fa-user-graduate:before{content:\"\\f501\"}.fa-user-injured:before{content:\"\\f728\"}.fa-user-lock:before{content:\"\\f502\"}.fa-user-md:before{content:\"\\f0f0\"}.fa-user-minus:before{content:\"\\f503\"}.fa-user-ninja:before{content:\"\\f504\"}.fa-user-nurse:before{content:\"\\f82f\"}.fa-user-plus:before{content:\"\\f234\"}.fa-user-secret:before{content:\"\\f21b\"}.fa-user-shield:before{content:\"\\f505\"}.fa-user-slash:before{content:\"\\f506\"}.fa-user-tag:before{content:\"\\f507\"}.fa-user-tie:before{content:\"\\f508\"}.fa-user-times:before{content:\"\\f235\"}.fa-users:before{content:\"\\f0c0\"}.fa-users-cog:before{content:\"\\f509\"}.fa-users-slash:before{content:\"\\e073\"}.fa-usps:before{content:\"\\f7e1\"}.fa-ussunnah:before{content:\"\\f407\"}.fa-utensil-spoon:before{content:\"\\f2e5\"}.fa-utensils:before{content:\"\\f2e7\"}.fa-vaadin:before{content:\"\\f408\"}.fa-vector-square:before{content:\"\\f5cb\"}.fa-venus:before{content:\"\\f221\"}.fa-venus-double:before{content:\"\\f226\"}.fa-venus-mars:before{content:\"\\f228\"}.fa-vest:before{content:\"\\e085\"}.fa-vest-patches:before{content:\"\\e086\"}.fa-viacoin:before{content:\"\\f237\"}.fa-viadeo:before{content:\"\\f2a9\"}.fa-viadeo-square:before{content:\"\\f2aa\"}.fa-vial:before{content:\"\\f492\"}.fa-vials:before{content:\"\\f493\"}.fa-viber:before{content:\"\\f409\"}.fa-video:before{content:\"\\f03d\"}.fa-video-slash:before{content:\"\\f4e2\"}.fa-vihara:before{content:\"\\f6a7\"}.fa-vimeo:before{content:\"\\f40a\"}.fa-vimeo-square:before{content:\"\\f194\"}.fa-vimeo-v:before{content:\"\\f27d\"}.fa-vine:before{content:\"\\f1ca\"}.fa-virus:before{content:\"\\e074\"}.fa-virus-slash:before{content:\"\\e075\"}.fa-viruses:before{content:\"\\e076\"}.fa-vk:before{content:\"\\f189\"}.fa-vnv:before{content:\"\\f40b\"}.fa-voicemail:before{content:\"\\f897\"}.fa-volleyball-ball:before{content:\"\\f45f\"}.fa-volume-down:before{content:\"\\f027\"}.fa-volume-mute:before{content:\"\\f6a9\"}.fa-volume-off:before{content:\"\\f026\"}.fa-volume-up:before{content:\"\\f028\"}.fa-vote-yea:before{content:\"\\f772\"}.fa-vr-cardboard:before{content:\"\\f729\"}.fa-vuejs:before{content:\"\\f41f\"}.fa-walking:before{content:\"\\f554\"}.fa-wallet:before{content:\"\\f555\"}.fa-warehouse:before{content:\"\\f494\"}.fa-watchman-monitoring:before{content:\"\\e087\"}.fa-water:before{content:\"\\f773\"}.fa-wave-square:before{content:\"\\f83e\"}.fa-waze:before{content:\"\\f83f\"}.fa-weebly:before{content:\"\\f5cc\"}.fa-weibo:before{content:\"\\f18a\"}.fa-weight:before{content:\"\\f496\"}.fa-weight-hanging:before{content:\"\\f5cd\"}.fa-weixin:before{content:\"\\f1d7\"}.fa-whatsapp:before{content:\"\\f232\"}.fa-whatsapp-square:before{content:\"\\f40c\"}.fa-wheelchair:before{content:\"\\f193\"}.fa-whmcs:before{content:\"\\f40d\"}.fa-wifi:before{content:\"\\f1eb\"}.fa-wikipedia-w:before{content:\"\\f266\"}.fa-wind:before{content:\"\\f72e\"}.fa-window-close:before{content:\"\\f410\"}.fa-window-maximize:before{content:\"\\f2d0\"}.fa-window-minimize:before{content:\"\\f2d1\"}.fa-window-restore:before{content:\"\\f2d2\"}.fa-windows:before{content:\"\\f17a\"}.fa-wine-bottle:before{content:\"\\f72f\"}.fa-wine-glass:before{content:\"\\f4e3\"}.fa-wine-glass-alt:before{content:\"\\f5ce\"}.fa-wix:before{content:\"\\f5cf\"}.fa-wizards-of-the-coast:before{content:\"\\f730\"}.fa-wodu:before{content:\"\\e088\"}.fa-wolf-pack-battalion:before{content:\"\\f514\"}.fa-won-sign:before{content:\"\\f159\"}.fa-wordpress:before{content:\"\\f19a\"}.fa-wordpress-simple:before{content:\"\\f411\"}.fa-wpbeginner:before{content:\"\\f297\"}.fa-wpexplorer:before{content:\"\\f2de\"}.fa-wpforms:before{content:\"\\f298\"}.fa-wpressr:before{content:\"\\f3e4\"}.fa-wrench:before{content:\"\\f0ad\"}.fa-x-ray:before{content:\"\\f497\"}.fa-xbox:before{content:\"\\f412\"}.fa-xing:before{content:\"\\f168\"}.fa-xing-square:before{content:\"\\f169\"}.fa-y-combinator:before{content:\"\\f23b\"}.fa-yahoo:before{content:\"\\f19e\"}.fa-yammer:before{content:\"\\f840\"}.fa-yandex:before{content:\"\\f413\"}.fa-yandex-international:before{content:\"\\f414\"}.fa-yarn:before{content:\"\\f7e3\"}.fa-yelp:before{content:\"\\f1e9\"}.fa-yen-sign:before{content:\"\\f157\"}.fa-yin-yang:before{content:\"\\f6ad\"}.fa-yoast:before{content:\"\\f2b1\"}.fa-youtube:before{content:\"\\f167\"}.fa-youtube-square:before{content:\"\\f431\"}.fa-zhihu:before{content:\"\\f63f\"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:\"Font Awesome 5 Brands\";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format(\"embedded-opentype\"),url(../webfonts/fa-brands-400.woff2) format(\"woff2\"),url(../webfonts/fa-brands-400.woff) format(\"woff\"),url(../webfonts/fa-brands-400.ttf) format(\"truetype\"),url(../webfonts/fa-brands-400.svg#fontawesome) format(\"svg\")}.fab{font-family:\"Font Awesome 5 Brands\"}@font-face{font-family:\"Font Awesome 5 Free\";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format(\"embedded-opentype\"),url(../webfonts/fa-regular-400.woff2) format(\"woff2\"),url(../webfonts/fa-regular-400.woff) format(\"woff\"),url(../webfonts/fa-regular-400.ttf) format(\"truetype\"),url(../webfonts/fa-regular-400.svg#fontawesome) format(\"svg\")}.fab,.far{font-weight:400}@font-face{font-family:\"Font Awesome 5 Free\";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format(\"embedded-opentype\"),url(../webfonts/fa-solid-900.woff2) format(\"woff2\"),url(../webfonts/fa-solid-900.woff) format(\"woff\"),url(../webfonts/fa-solid-900.ttf) format(\"truetype\"),url(../webfonts/fa-solid-900.svg#fontawesome) format(\"svg\")}.fa,.far,.fas{font-family:\"Font Awesome 5 Free\"}.fa,.fas{font-weight:900}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/brands.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n@font-face {\n  font-family: 'Font Awesome 5 Brands';\n  font-style: normal;\n  font-weight: 400;\n  font-display: block;\n  src: url(\"../webfonts/fa-brands-400.eot\");\n  src: url(\"../webfonts/fa-brands-400.eot?#iefix\") format(\"embedded-opentype\"), url(\"../webfonts/fa-brands-400.woff2\") format(\"woff2\"), url(\"../webfonts/fa-brands-400.woff\") format(\"woff\"), url(\"../webfonts/fa-brands-400.ttf\") format(\"truetype\"), url(\"../webfonts/fa-brands-400.svg#fontawesome\") format(\"svg\"); }\n\n.fab {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/brands.min.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n@font-face{font-family:\"Font Awesome 5 Brands\";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format(\"embedded-opentype\"),url(../webfonts/fa-brands-400.woff2) format(\"woff2\"),url(../webfonts/fa-brands-400.woff) format(\"woff\"),url(../webfonts/fa-brands-400.ttf) format(\"truetype\"),url(../webfonts/fa-brands-400.svg#fontawesome) format(\"svg\")}.fab{font-family:\"Font Awesome 5 Brands\";font-weight:400}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/fontawesome.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n.fa,\n.fas,\n.far,\n.fal,\n.fad,\n.fab {\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-font-smoothing: antialiased;\n  display: inline-block;\n  font-style: normal;\n  font-variant: normal;\n  text-rendering: auto;\n  line-height: 1; }\n\n.fa-lg {\n  font-size: 1.33333em;\n  line-height: 0.75em;\n  vertical-align: -.0667em; }\n\n.fa-xs {\n  font-size: .75em; }\n\n.fa-sm {\n  font-size: .875em; }\n\n.fa-1x {\n  font-size: 1em; }\n\n.fa-2x {\n  font-size: 2em; }\n\n.fa-3x {\n  font-size: 3em; }\n\n.fa-4x {\n  font-size: 4em; }\n\n.fa-5x {\n  font-size: 5em; }\n\n.fa-6x {\n  font-size: 6em; }\n\n.fa-7x {\n  font-size: 7em; }\n\n.fa-8x {\n  font-size: 8em; }\n\n.fa-9x {\n  font-size: 9em; }\n\n.fa-10x {\n  font-size: 10em; }\n\n.fa-fw {\n  text-align: center;\n  width: 1.25em; }\n\n.fa-ul {\n  list-style-type: none;\n  margin-left: 2.5em;\n  padding-left: 0; }\n  .fa-ul > li {\n    position: relative; }\n\n.fa-li {\n  left: -2em;\n  position: absolute;\n  text-align: center;\n  width: 2em;\n  line-height: inherit; }\n\n.fa-border {\n  border: solid 0.08em #eee;\n  border-radius: .1em;\n  padding: .2em .25em .15em; }\n\n.fa-pull-left {\n  float: left; }\n\n.fa-pull-right {\n  float: right; }\n\n.fa.fa-pull-left,\n.fas.fa-pull-left,\n.far.fa-pull-left,\n.fal.fa-pull-left,\n.fab.fa-pull-left {\n  margin-right: .3em; }\n\n.fa.fa-pull-right,\n.fas.fa-pull-right,\n.far.fa-pull-right,\n.fal.fa-pull-right,\n.fab.fa-pull-right {\n  margin-left: .3em; }\n\n.fa-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n          animation: fa-spin 2s infinite linear; }\n\n.fa-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n          animation: fa-spin 1s infinite steps(8); }\n\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg); }\n  100% {\n    -webkit-transform: rotate(360deg);\n            transform: rotate(360deg); } }\n\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg); }\n  100% {\n    -webkit-transform: rotate(360deg);\n            transform: rotate(360deg); } }\n\n.fa-rotate-90 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";\n  -webkit-transform: rotate(90deg);\n          transform: rotate(90deg); }\n\n.fa-rotate-180 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";\n  -webkit-transform: rotate(180deg);\n          transform: rotate(180deg); }\n\n.fa-rotate-270 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";\n  -webkit-transform: rotate(270deg);\n          transform: rotate(270deg); }\n\n.fa-flip-horizontal {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";\n  -webkit-transform: scale(-1, 1);\n          transform: scale(-1, 1); }\n\n.fa-flip-vertical {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";\n  -webkit-transform: scale(1, -1);\n          transform: scale(1, -1); }\n\n.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";\n  -webkit-transform: scale(-1, -1);\n          transform: scale(-1, -1); }\n\n:root .fa-rotate-90,\n:root .fa-rotate-180,\n:root .fa-rotate-270,\n:root .fa-flip-horizontal,\n:root .fa-flip-vertical,\n:root .fa-flip-both {\n  -webkit-filter: none;\n          filter: none; }\n\n.fa-stack {\n  display: inline-block;\n  height: 2em;\n  line-height: 2em;\n  position: relative;\n  vertical-align: middle;\n  width: 2.5em; }\n\n.fa-stack-1x,\n.fa-stack-2x {\n  left: 0;\n  position: absolute;\n  text-align: center;\n  width: 100%; }\n\n.fa-stack-1x {\n  line-height: inherit; }\n\n.fa-stack-2x {\n  font-size: 2em; }\n\n.fa-inverse {\n  color: #fff; }\n\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\nreaders do not read off random characters that represent icons */\n.fa-500px:before {\n  content: \"\\f26e\"; }\n\n.fa-accessible-icon:before {\n  content: \"\\f368\"; }\n\n.fa-accusoft:before {\n  content: \"\\f369\"; }\n\n.fa-acquisitions-incorporated:before {\n  content: \"\\f6af\"; }\n\n.fa-ad:before {\n  content: \"\\f641\"; }\n\n.fa-address-book:before {\n  content: \"\\f2b9\"; }\n\n.fa-address-card:before {\n  content: \"\\f2bb\"; }\n\n.fa-adjust:before {\n  content: \"\\f042\"; }\n\n.fa-adn:before {\n  content: \"\\f170\"; }\n\n.fa-adversal:before {\n  content: \"\\f36a\"; }\n\n.fa-affiliatetheme:before {\n  content: \"\\f36b\"; }\n\n.fa-air-freshener:before {\n  content: \"\\f5d0\"; }\n\n.fa-airbnb:before {\n  content: \"\\f834\"; }\n\n.fa-algolia:before {\n  content: \"\\f36c\"; }\n\n.fa-align-center:before {\n  content: \"\\f037\"; }\n\n.fa-align-justify:before {\n  content: \"\\f039\"; }\n\n.fa-align-left:before {\n  content: \"\\f036\"; }\n\n.fa-align-right:before {\n  content: \"\\f038\"; }\n\n.fa-alipay:before {\n  content: \"\\f642\"; }\n\n.fa-allergies:before {\n  content: \"\\f461\"; }\n\n.fa-amazon:before {\n  content: \"\\f270\"; }\n\n.fa-amazon-pay:before {\n  content: \"\\f42c\"; }\n\n.fa-ambulance:before {\n  content: \"\\f0f9\"; }\n\n.fa-american-sign-language-interpreting:before {\n  content: \"\\f2a3\"; }\n\n.fa-amilia:before {\n  content: \"\\f36d\"; }\n\n.fa-anchor:before {\n  content: \"\\f13d\"; }\n\n.fa-android:before {\n  content: \"\\f17b\"; }\n\n.fa-angellist:before {\n  content: \"\\f209\"; }\n\n.fa-angle-double-down:before {\n  content: \"\\f103\"; }\n\n.fa-angle-double-left:before {\n  content: \"\\f100\"; }\n\n.fa-angle-double-right:before {\n  content: \"\\f101\"; }\n\n.fa-angle-double-up:before {\n  content: \"\\f102\"; }\n\n.fa-angle-down:before {\n  content: \"\\f107\"; }\n\n.fa-angle-left:before {\n  content: \"\\f104\"; }\n\n.fa-angle-right:before {\n  content: \"\\f105\"; }\n\n.fa-angle-up:before {\n  content: \"\\f106\"; }\n\n.fa-angry:before {\n  content: \"\\f556\"; }\n\n.fa-angrycreative:before {\n  content: \"\\f36e\"; }\n\n.fa-angular:before {\n  content: \"\\f420\"; }\n\n.fa-ankh:before {\n  content: \"\\f644\"; }\n\n.fa-app-store:before {\n  content: \"\\f36f\"; }\n\n.fa-app-store-ios:before {\n  content: \"\\f370\"; }\n\n.fa-apper:before {\n  content: \"\\f371\"; }\n\n.fa-apple:before {\n  content: \"\\f179\"; }\n\n.fa-apple-alt:before {\n  content: \"\\f5d1\"; }\n\n.fa-apple-pay:before {\n  content: \"\\f415\"; }\n\n.fa-archive:before {\n  content: \"\\f187\"; }\n\n.fa-archway:before {\n  content: \"\\f557\"; }\n\n.fa-arrow-alt-circle-down:before {\n  content: \"\\f358\"; }\n\n.fa-arrow-alt-circle-left:before {\n  content: \"\\f359\"; }\n\n.fa-arrow-alt-circle-right:before {\n  content: \"\\f35a\"; }\n\n.fa-arrow-alt-circle-up:before {\n  content: \"\\f35b\"; }\n\n.fa-arrow-circle-down:before {\n  content: \"\\f0ab\"; }\n\n.fa-arrow-circle-left:before {\n  content: \"\\f0a8\"; }\n\n.fa-arrow-circle-right:before {\n  content: \"\\f0a9\"; }\n\n.fa-arrow-circle-up:before {\n  content: \"\\f0aa\"; }\n\n.fa-arrow-down:before {\n  content: \"\\f063\"; }\n\n.fa-arrow-left:before {\n  content: \"\\f060\"; }\n\n.fa-arrow-right:before {\n  content: \"\\f061\"; }\n\n.fa-arrow-up:before {\n  content: \"\\f062\"; }\n\n.fa-arrows-alt:before {\n  content: \"\\f0b2\"; }\n\n.fa-arrows-alt-h:before {\n  content: \"\\f337\"; }\n\n.fa-arrows-alt-v:before {\n  content: \"\\f338\"; }\n\n.fa-artstation:before {\n  content: \"\\f77a\"; }\n\n.fa-assistive-listening-systems:before {\n  content: \"\\f2a2\"; }\n\n.fa-asterisk:before {\n  content: \"\\f069\"; }\n\n.fa-asymmetrik:before {\n  content: \"\\f372\"; }\n\n.fa-at:before {\n  content: \"\\f1fa\"; }\n\n.fa-atlas:before {\n  content: \"\\f558\"; }\n\n.fa-atlassian:before {\n  content: \"\\f77b\"; }\n\n.fa-atom:before {\n  content: \"\\f5d2\"; }\n\n.fa-audible:before {\n  content: \"\\f373\"; }\n\n.fa-audio-description:before {\n  content: \"\\f29e\"; }\n\n.fa-autoprefixer:before {\n  content: \"\\f41c\"; }\n\n.fa-avianex:before {\n  content: \"\\f374\"; }\n\n.fa-aviato:before {\n  content: \"\\f421\"; }\n\n.fa-award:before {\n  content: \"\\f559\"; }\n\n.fa-aws:before {\n  content: \"\\f375\"; }\n\n.fa-baby:before {\n  content: \"\\f77c\"; }\n\n.fa-baby-carriage:before {\n  content: \"\\f77d\"; }\n\n.fa-backspace:before {\n  content: \"\\f55a\"; }\n\n.fa-backward:before {\n  content: \"\\f04a\"; }\n\n.fa-bacon:before {\n  content: \"\\f7e5\"; }\n\n.fa-bacteria:before {\n  content: \"\\e059\"; }\n\n.fa-bacterium:before {\n  content: \"\\e05a\"; }\n\n.fa-bahai:before {\n  content: \"\\f666\"; }\n\n.fa-balance-scale:before {\n  content: \"\\f24e\"; }\n\n.fa-balance-scale-left:before {\n  content: \"\\f515\"; }\n\n.fa-balance-scale-right:before {\n  content: \"\\f516\"; }\n\n.fa-ban:before {\n  content: \"\\f05e\"; }\n\n.fa-band-aid:before {\n  content: \"\\f462\"; }\n\n.fa-bandcamp:before {\n  content: \"\\f2d5\"; }\n\n.fa-barcode:before {\n  content: \"\\f02a\"; }\n\n.fa-bars:before {\n  content: \"\\f0c9\"; }\n\n.fa-baseball-ball:before {\n  content: \"\\f433\"; }\n\n.fa-basketball-ball:before {\n  content: \"\\f434\"; }\n\n.fa-bath:before {\n  content: \"\\f2cd\"; }\n\n.fa-battery-empty:before {\n  content: \"\\f244\"; }\n\n.fa-battery-full:before {\n  content: \"\\f240\"; }\n\n.fa-battery-half:before {\n  content: \"\\f242\"; }\n\n.fa-battery-quarter:before {\n  content: \"\\f243\"; }\n\n.fa-battery-three-quarters:before {\n  content: \"\\f241\"; }\n\n.fa-battle-net:before {\n  content: \"\\f835\"; }\n\n.fa-bed:before {\n  content: \"\\f236\"; }\n\n.fa-beer:before {\n  content: \"\\f0fc\"; }\n\n.fa-behance:before {\n  content: \"\\f1b4\"; }\n\n.fa-behance-square:before {\n  content: \"\\f1b5\"; }\n\n.fa-bell:before {\n  content: \"\\f0f3\"; }\n\n.fa-bell-slash:before {\n  content: \"\\f1f6\"; }\n\n.fa-bezier-curve:before {\n  content: \"\\f55b\"; }\n\n.fa-bible:before {\n  content: \"\\f647\"; }\n\n.fa-bicycle:before {\n  content: \"\\f206\"; }\n\n.fa-biking:before {\n  content: \"\\f84a\"; }\n\n.fa-bimobject:before {\n  content: \"\\f378\"; }\n\n.fa-binoculars:before {\n  content: \"\\f1e5\"; }\n\n.fa-biohazard:before {\n  content: \"\\f780\"; }\n\n.fa-birthday-cake:before {\n  content: \"\\f1fd\"; }\n\n.fa-bitbucket:before {\n  content: \"\\f171\"; }\n\n.fa-bitcoin:before {\n  content: \"\\f379\"; }\n\n.fa-bity:before {\n  content: \"\\f37a\"; }\n\n.fa-black-tie:before {\n  content: \"\\f27e\"; }\n\n.fa-blackberry:before {\n  content: \"\\f37b\"; }\n\n.fa-blender:before {\n  content: \"\\f517\"; }\n\n.fa-blender-phone:before {\n  content: \"\\f6b6\"; }\n\n.fa-blind:before {\n  content: \"\\f29d\"; }\n\n.fa-blog:before {\n  content: \"\\f781\"; }\n\n.fa-blogger:before {\n  content: \"\\f37c\"; }\n\n.fa-blogger-b:before {\n  content: \"\\f37d\"; }\n\n.fa-bluetooth:before {\n  content: \"\\f293\"; }\n\n.fa-bluetooth-b:before {\n  content: \"\\f294\"; }\n\n.fa-bold:before {\n  content: \"\\f032\"; }\n\n.fa-bolt:before {\n  content: \"\\f0e7\"; }\n\n.fa-bomb:before {\n  content: \"\\f1e2\"; }\n\n.fa-bone:before {\n  content: \"\\f5d7\"; }\n\n.fa-bong:before {\n  content: \"\\f55c\"; }\n\n.fa-book:before {\n  content: \"\\f02d\"; }\n\n.fa-book-dead:before {\n  content: \"\\f6b7\"; }\n\n.fa-book-medical:before {\n  content: \"\\f7e6\"; }\n\n.fa-book-open:before {\n  content: \"\\f518\"; }\n\n.fa-book-reader:before {\n  content: \"\\f5da\"; }\n\n.fa-bookmark:before {\n  content: \"\\f02e\"; }\n\n.fa-bootstrap:before {\n  content: \"\\f836\"; }\n\n.fa-border-all:before {\n  content: \"\\f84c\"; }\n\n.fa-border-none:before {\n  content: \"\\f850\"; }\n\n.fa-border-style:before {\n  content: \"\\f853\"; }\n\n.fa-bowling-ball:before {\n  content: \"\\f436\"; }\n\n.fa-box:before {\n  content: \"\\f466\"; }\n\n.fa-box-open:before {\n  content: \"\\f49e\"; }\n\n.fa-box-tissue:before {\n  content: \"\\e05b\"; }\n\n.fa-boxes:before {\n  content: \"\\f468\"; }\n\n.fa-braille:before {\n  content: \"\\f2a1\"; }\n\n.fa-brain:before {\n  content: \"\\f5dc\"; }\n\n.fa-bread-slice:before {\n  content: \"\\f7ec\"; }\n\n.fa-briefcase:before {\n  content: \"\\f0b1\"; }\n\n.fa-briefcase-medical:before {\n  content: \"\\f469\"; }\n\n.fa-broadcast-tower:before {\n  content: \"\\f519\"; }\n\n.fa-broom:before {\n  content: \"\\f51a\"; }\n\n.fa-brush:before {\n  content: \"\\f55d\"; }\n\n.fa-btc:before {\n  content: \"\\f15a\"; }\n\n.fa-buffer:before {\n  content: \"\\f837\"; }\n\n.fa-bug:before {\n  content: \"\\f188\"; }\n\n.fa-building:before {\n  content: \"\\f1ad\"; }\n\n.fa-bullhorn:before {\n  content: \"\\f0a1\"; }\n\n.fa-bullseye:before {\n  content: \"\\f140\"; }\n\n.fa-burn:before {\n  content: \"\\f46a\"; }\n\n.fa-buromobelexperte:before {\n  content: \"\\f37f\"; }\n\n.fa-bus:before {\n  content: \"\\f207\"; }\n\n.fa-bus-alt:before {\n  content: \"\\f55e\"; }\n\n.fa-business-time:before {\n  content: \"\\f64a\"; }\n\n.fa-buy-n-large:before {\n  content: \"\\f8a6\"; }\n\n.fa-buysellads:before {\n  content: \"\\f20d\"; }\n\n.fa-calculator:before {\n  content: \"\\f1ec\"; }\n\n.fa-calendar:before {\n  content: \"\\f133\"; }\n\n.fa-calendar-alt:before {\n  content: \"\\f073\"; }\n\n.fa-calendar-check:before {\n  content: \"\\f274\"; }\n\n.fa-calendar-day:before {\n  content: \"\\f783\"; }\n\n.fa-calendar-minus:before {\n  content: \"\\f272\"; }\n\n.fa-calendar-plus:before {\n  content: \"\\f271\"; }\n\n.fa-calendar-times:before {\n  content: \"\\f273\"; }\n\n.fa-calendar-week:before {\n  content: \"\\f784\"; }\n\n.fa-camera:before {\n  content: \"\\f030\"; }\n\n.fa-camera-retro:before {\n  content: \"\\f083\"; }\n\n.fa-campground:before {\n  content: \"\\f6bb\"; }\n\n.fa-canadian-maple-leaf:before {\n  content: \"\\f785\"; }\n\n.fa-candy-cane:before {\n  content: \"\\f786\"; }\n\n.fa-cannabis:before {\n  content: \"\\f55f\"; }\n\n.fa-capsules:before {\n  content: \"\\f46b\"; }\n\n.fa-car:before {\n  content: \"\\f1b9\"; }\n\n.fa-car-alt:before {\n  content: \"\\f5de\"; }\n\n.fa-car-battery:before {\n  content: \"\\f5df\"; }\n\n.fa-car-crash:before {\n  content: \"\\f5e1\"; }\n\n.fa-car-side:before {\n  content: \"\\f5e4\"; }\n\n.fa-caravan:before {\n  content: \"\\f8ff\"; }\n\n.fa-caret-down:before {\n  content: \"\\f0d7\"; }\n\n.fa-caret-left:before {\n  content: \"\\f0d9\"; }\n\n.fa-caret-right:before {\n  content: \"\\f0da\"; }\n\n.fa-caret-square-down:before {\n  content: \"\\f150\"; }\n\n.fa-caret-square-left:before {\n  content: \"\\f191\"; }\n\n.fa-caret-square-right:before {\n  content: \"\\f152\"; }\n\n.fa-caret-square-up:before {\n  content: \"\\f151\"; }\n\n.fa-caret-up:before {\n  content: \"\\f0d8\"; }\n\n.fa-carrot:before {\n  content: \"\\f787\"; }\n\n.fa-cart-arrow-down:before {\n  content: \"\\f218\"; }\n\n.fa-cart-plus:before {\n  content: \"\\f217\"; }\n\n.fa-cash-register:before {\n  content: \"\\f788\"; }\n\n.fa-cat:before {\n  content: \"\\f6be\"; }\n\n.fa-cc-amazon-pay:before {\n  content: \"\\f42d\"; }\n\n.fa-cc-amex:before {\n  content: \"\\f1f3\"; }\n\n.fa-cc-apple-pay:before {\n  content: \"\\f416\"; }\n\n.fa-cc-diners-club:before {\n  content: \"\\f24c\"; }\n\n.fa-cc-discover:before {\n  content: \"\\f1f2\"; }\n\n.fa-cc-jcb:before {\n  content: \"\\f24b\"; }\n\n.fa-cc-mastercard:before {\n  content: \"\\f1f1\"; }\n\n.fa-cc-paypal:before {\n  content: \"\\f1f4\"; }\n\n.fa-cc-stripe:before {\n  content: \"\\f1f5\"; }\n\n.fa-cc-visa:before {\n  content: \"\\f1f0\"; }\n\n.fa-centercode:before {\n  content: \"\\f380\"; }\n\n.fa-centos:before {\n  content: \"\\f789\"; }\n\n.fa-certificate:before {\n  content: \"\\f0a3\"; }\n\n.fa-chair:before {\n  content: \"\\f6c0\"; }\n\n.fa-chalkboard:before {\n  content: \"\\f51b\"; }\n\n.fa-chalkboard-teacher:before {\n  content: \"\\f51c\"; }\n\n.fa-charging-station:before {\n  content: \"\\f5e7\"; }\n\n.fa-chart-area:before {\n  content: \"\\f1fe\"; }\n\n.fa-chart-bar:before {\n  content: \"\\f080\"; }\n\n.fa-chart-line:before {\n  content: \"\\f201\"; }\n\n.fa-chart-pie:before {\n  content: \"\\f200\"; }\n\n.fa-check:before {\n  content: \"\\f00c\"; }\n\n.fa-check-circle:before {\n  content: \"\\f058\"; }\n\n.fa-check-double:before {\n  content: \"\\f560\"; }\n\n.fa-check-square:before {\n  content: \"\\f14a\"; }\n\n.fa-cheese:before {\n  content: \"\\f7ef\"; }\n\n.fa-chess:before {\n  content: \"\\f439\"; }\n\n.fa-chess-bishop:before {\n  content: \"\\f43a\"; }\n\n.fa-chess-board:before {\n  content: \"\\f43c\"; }\n\n.fa-chess-king:before {\n  content: \"\\f43f\"; }\n\n.fa-chess-knight:before {\n  content: \"\\f441\"; }\n\n.fa-chess-pawn:before {\n  content: \"\\f443\"; }\n\n.fa-chess-queen:before {\n  content: \"\\f445\"; }\n\n.fa-chess-rook:before {\n  content: \"\\f447\"; }\n\n.fa-chevron-circle-down:before {\n  content: \"\\f13a\"; }\n\n.fa-chevron-circle-left:before {\n  content: \"\\f137\"; }\n\n.fa-chevron-circle-right:before {\n  content: \"\\f138\"; }\n\n.fa-chevron-circle-up:before {\n  content: \"\\f139\"; }\n\n.fa-chevron-down:before {\n  content: \"\\f078\"; }\n\n.fa-chevron-left:before {\n  content: \"\\f053\"; }\n\n.fa-chevron-right:before {\n  content: \"\\f054\"; }\n\n.fa-chevron-up:before {\n  content: \"\\f077\"; }\n\n.fa-child:before {\n  content: \"\\f1ae\"; }\n\n.fa-chrome:before {\n  content: \"\\f268\"; }\n\n.fa-chromecast:before {\n  content: \"\\f838\"; }\n\n.fa-church:before {\n  content: \"\\f51d\"; }\n\n.fa-circle:before {\n  content: \"\\f111\"; }\n\n.fa-circle-notch:before {\n  content: \"\\f1ce\"; }\n\n.fa-city:before {\n  content: \"\\f64f\"; }\n\n.fa-clinic-medical:before {\n  content: \"\\f7f2\"; }\n\n.fa-clipboard:before {\n  content: \"\\f328\"; }\n\n.fa-clipboard-check:before {\n  content: \"\\f46c\"; }\n\n.fa-clipboard-list:before {\n  content: \"\\f46d\"; }\n\n.fa-clock:before {\n  content: \"\\f017\"; }\n\n.fa-clone:before {\n  content: \"\\f24d\"; }\n\n.fa-closed-captioning:before {\n  content: \"\\f20a\"; }\n\n.fa-cloud:before {\n  content: \"\\f0c2\"; }\n\n.fa-cloud-download-alt:before {\n  content: \"\\f381\"; }\n\n.fa-cloud-meatball:before {\n  content: \"\\f73b\"; }\n\n.fa-cloud-moon:before {\n  content: \"\\f6c3\"; }\n\n.fa-cloud-moon-rain:before {\n  content: \"\\f73c\"; }\n\n.fa-cloud-rain:before {\n  content: \"\\f73d\"; }\n\n.fa-cloud-showers-heavy:before {\n  content: \"\\f740\"; }\n\n.fa-cloud-sun:before {\n  content: \"\\f6c4\"; }\n\n.fa-cloud-sun-rain:before {\n  content: \"\\f743\"; }\n\n.fa-cloud-upload-alt:before {\n  content: \"\\f382\"; }\n\n.fa-cloudflare:before {\n  content: \"\\e07d\"; }\n\n.fa-cloudscale:before {\n  content: \"\\f383\"; }\n\n.fa-cloudsmith:before {\n  content: \"\\f384\"; }\n\n.fa-cloudversify:before {\n  content: \"\\f385\"; }\n\n.fa-cocktail:before {\n  content: \"\\f561\"; }\n\n.fa-code:before {\n  content: \"\\f121\"; }\n\n.fa-code-branch:before {\n  content: \"\\f126\"; }\n\n.fa-codepen:before {\n  content: \"\\f1cb\"; }\n\n.fa-codiepie:before {\n  content: \"\\f284\"; }\n\n.fa-coffee:before {\n  content: \"\\f0f4\"; }\n\n.fa-cog:before {\n  content: \"\\f013\"; }\n\n.fa-cogs:before {\n  content: \"\\f085\"; }\n\n.fa-coins:before {\n  content: \"\\f51e\"; }\n\n.fa-columns:before {\n  content: \"\\f0db\"; }\n\n.fa-comment:before {\n  content: \"\\f075\"; }\n\n.fa-comment-alt:before {\n  content: \"\\f27a\"; }\n\n.fa-comment-dollar:before {\n  content: \"\\f651\"; }\n\n.fa-comment-dots:before {\n  content: \"\\f4ad\"; }\n\n.fa-comment-medical:before {\n  content: \"\\f7f5\"; }\n\n.fa-comment-slash:before {\n  content: \"\\f4b3\"; }\n\n.fa-comments:before {\n  content: \"\\f086\"; }\n\n.fa-comments-dollar:before {\n  content: \"\\f653\"; }\n\n.fa-compact-disc:before {\n  content: \"\\f51f\"; }\n\n.fa-compass:before {\n  content: \"\\f14e\"; }\n\n.fa-compress:before {\n  content: \"\\f066\"; }\n\n.fa-compress-alt:before {\n  content: \"\\f422\"; }\n\n.fa-compress-arrows-alt:before {\n  content: \"\\f78c\"; }\n\n.fa-concierge-bell:before {\n  content: \"\\f562\"; }\n\n.fa-confluence:before {\n  content: \"\\f78d\"; }\n\n.fa-connectdevelop:before {\n  content: \"\\f20e\"; }\n\n.fa-contao:before {\n  content: \"\\f26d\"; }\n\n.fa-cookie:before {\n  content: \"\\f563\"; }\n\n.fa-cookie-bite:before {\n  content: \"\\f564\"; }\n\n.fa-copy:before {\n  content: \"\\f0c5\"; }\n\n.fa-copyright:before {\n  content: \"\\f1f9\"; }\n\n.fa-cotton-bureau:before {\n  content: \"\\f89e\"; }\n\n.fa-couch:before {\n  content: \"\\f4b8\"; }\n\n.fa-cpanel:before {\n  content: \"\\f388\"; }\n\n.fa-creative-commons:before {\n  content: \"\\f25e\"; }\n\n.fa-creative-commons-by:before {\n  content: \"\\f4e7\"; }\n\n.fa-creative-commons-nc:before {\n  content: \"\\f4e8\"; }\n\n.fa-creative-commons-nc-eu:before {\n  content: \"\\f4e9\"; }\n\n.fa-creative-commons-nc-jp:before {\n  content: \"\\f4ea\"; }\n\n.fa-creative-commons-nd:before {\n  content: \"\\f4eb\"; }\n\n.fa-creative-commons-pd:before {\n  content: \"\\f4ec\"; }\n\n.fa-creative-commons-pd-alt:before {\n  content: \"\\f4ed\"; }\n\n.fa-creative-commons-remix:before {\n  content: \"\\f4ee\"; }\n\n.fa-creative-commons-sa:before {\n  content: \"\\f4ef\"; }\n\n.fa-creative-commons-sampling:before {\n  content: \"\\f4f0\"; }\n\n.fa-creative-commons-sampling-plus:before {\n  content: \"\\f4f1\"; }\n\n.fa-creative-commons-share:before {\n  content: \"\\f4f2\"; }\n\n.fa-creative-commons-zero:before {\n  content: \"\\f4f3\"; }\n\n.fa-credit-card:before {\n  content: \"\\f09d\"; }\n\n.fa-critical-role:before {\n  content: \"\\f6c9\"; }\n\n.fa-crop:before {\n  content: \"\\f125\"; }\n\n.fa-crop-alt:before {\n  content: \"\\f565\"; }\n\n.fa-cross:before {\n  content: \"\\f654\"; }\n\n.fa-crosshairs:before {\n  content: \"\\f05b\"; }\n\n.fa-crow:before {\n  content: \"\\f520\"; }\n\n.fa-crown:before {\n  content: \"\\f521\"; }\n\n.fa-crutch:before {\n  content: \"\\f7f7\"; }\n\n.fa-css3:before {\n  content: \"\\f13c\"; }\n\n.fa-css3-alt:before {\n  content: \"\\f38b\"; }\n\n.fa-cube:before {\n  content: \"\\f1b2\"; }\n\n.fa-cubes:before {\n  content: \"\\f1b3\"; }\n\n.fa-cut:before {\n  content: \"\\f0c4\"; }\n\n.fa-cuttlefish:before {\n  content: \"\\f38c\"; }\n\n.fa-d-and-d:before {\n  content: \"\\f38d\"; }\n\n.fa-d-and-d-beyond:before {\n  content: \"\\f6ca\"; }\n\n.fa-dailymotion:before {\n  content: \"\\e052\"; }\n\n.fa-dashcube:before {\n  content: \"\\f210\"; }\n\n.fa-database:before {\n  content: \"\\f1c0\"; }\n\n.fa-deaf:before {\n  content: \"\\f2a4\"; }\n\n.fa-deezer:before {\n  content: \"\\e077\"; }\n\n.fa-delicious:before {\n  content: \"\\f1a5\"; }\n\n.fa-democrat:before {\n  content: \"\\f747\"; }\n\n.fa-deploydog:before {\n  content: \"\\f38e\"; }\n\n.fa-deskpro:before {\n  content: \"\\f38f\"; }\n\n.fa-desktop:before {\n  content: \"\\f108\"; }\n\n.fa-dev:before {\n  content: \"\\f6cc\"; }\n\n.fa-deviantart:before {\n  content: \"\\f1bd\"; }\n\n.fa-dharmachakra:before {\n  content: \"\\f655\"; }\n\n.fa-dhl:before {\n  content: \"\\f790\"; }\n\n.fa-diagnoses:before {\n  content: \"\\f470\"; }\n\n.fa-diaspora:before {\n  content: \"\\f791\"; }\n\n.fa-dice:before {\n  content: \"\\f522\"; }\n\n.fa-dice-d20:before {\n  content: \"\\f6cf\"; }\n\n.fa-dice-d6:before {\n  content: \"\\f6d1\"; }\n\n.fa-dice-five:before {\n  content: \"\\f523\"; }\n\n.fa-dice-four:before {\n  content: \"\\f524\"; }\n\n.fa-dice-one:before {\n  content: \"\\f525\"; }\n\n.fa-dice-six:before {\n  content: \"\\f526\"; }\n\n.fa-dice-three:before {\n  content: \"\\f527\"; }\n\n.fa-dice-two:before {\n  content: \"\\f528\"; }\n\n.fa-digg:before {\n  content: \"\\f1a6\"; }\n\n.fa-digital-ocean:before {\n  content: \"\\f391\"; }\n\n.fa-digital-tachograph:before {\n  content: \"\\f566\"; }\n\n.fa-directions:before {\n  content: \"\\f5eb\"; }\n\n.fa-discord:before {\n  content: \"\\f392\"; }\n\n.fa-discourse:before {\n  content: \"\\f393\"; }\n\n.fa-disease:before {\n  content: \"\\f7fa\"; }\n\n.fa-divide:before {\n  content: \"\\f529\"; }\n\n.fa-dizzy:before {\n  content: \"\\f567\"; }\n\n.fa-dna:before {\n  content: \"\\f471\"; }\n\n.fa-dochub:before {\n  content: \"\\f394\"; }\n\n.fa-docker:before {\n  content: \"\\f395\"; }\n\n.fa-dog:before {\n  content: \"\\f6d3\"; }\n\n.fa-dollar-sign:before {\n  content: \"\\f155\"; }\n\n.fa-dolly:before {\n  content: \"\\f472\"; }\n\n.fa-dolly-flatbed:before {\n  content: \"\\f474\"; }\n\n.fa-donate:before {\n  content: \"\\f4b9\"; }\n\n.fa-door-closed:before {\n  content: \"\\f52a\"; }\n\n.fa-door-open:before {\n  content: \"\\f52b\"; }\n\n.fa-dot-circle:before {\n  content: \"\\f192\"; }\n\n.fa-dove:before {\n  content: \"\\f4ba\"; }\n\n.fa-download:before {\n  content: \"\\f019\"; }\n\n.fa-draft2digital:before {\n  content: \"\\f396\"; }\n\n.fa-drafting-compass:before {\n  content: \"\\f568\"; }\n\n.fa-dragon:before {\n  content: \"\\f6d5\"; }\n\n.fa-draw-polygon:before {\n  content: \"\\f5ee\"; }\n\n.fa-dribbble:before {\n  content: \"\\f17d\"; }\n\n.fa-dribbble-square:before {\n  content: \"\\f397\"; }\n\n.fa-dropbox:before {\n  content: \"\\f16b\"; }\n\n.fa-drum:before {\n  content: \"\\f569\"; }\n\n.fa-drum-steelpan:before {\n  content: \"\\f56a\"; }\n\n.fa-drumstick-bite:before {\n  content: \"\\f6d7\"; }\n\n.fa-drupal:before {\n  content: \"\\f1a9\"; }\n\n.fa-dumbbell:before {\n  content: \"\\f44b\"; }\n\n.fa-dumpster:before {\n  content: \"\\f793\"; }\n\n.fa-dumpster-fire:before {\n  content: \"\\f794\"; }\n\n.fa-dungeon:before {\n  content: \"\\f6d9\"; }\n\n.fa-dyalog:before {\n  content: \"\\f399\"; }\n\n.fa-earlybirds:before {\n  content: \"\\f39a\"; }\n\n.fa-ebay:before {\n  content: \"\\f4f4\"; }\n\n.fa-edge:before {\n  content: \"\\f282\"; }\n\n.fa-edge-legacy:before {\n  content: \"\\e078\"; }\n\n.fa-edit:before {\n  content: \"\\f044\"; }\n\n.fa-egg:before {\n  content: \"\\f7fb\"; }\n\n.fa-eject:before {\n  content: \"\\f052\"; }\n\n.fa-elementor:before {\n  content: \"\\f430\"; }\n\n.fa-ellipsis-h:before {\n  content: \"\\f141\"; }\n\n.fa-ellipsis-v:before {\n  content: \"\\f142\"; }\n\n.fa-ello:before {\n  content: \"\\f5f1\"; }\n\n.fa-ember:before {\n  content: \"\\f423\"; }\n\n.fa-empire:before {\n  content: \"\\f1d1\"; }\n\n.fa-envelope:before {\n  content: \"\\f0e0\"; }\n\n.fa-envelope-open:before {\n  content: \"\\f2b6\"; }\n\n.fa-envelope-open-text:before {\n  content: \"\\f658\"; }\n\n.fa-envelope-square:before {\n  content: \"\\f199\"; }\n\n.fa-envira:before {\n  content: \"\\f299\"; }\n\n.fa-equals:before {\n  content: \"\\f52c\"; }\n\n.fa-eraser:before {\n  content: \"\\f12d\"; }\n\n.fa-erlang:before {\n  content: \"\\f39d\"; }\n\n.fa-ethereum:before {\n  content: \"\\f42e\"; }\n\n.fa-ethernet:before {\n  content: \"\\f796\"; }\n\n.fa-etsy:before {\n  content: \"\\f2d7\"; }\n\n.fa-euro-sign:before {\n  content: \"\\f153\"; }\n\n.fa-evernote:before {\n  content: \"\\f839\"; }\n\n.fa-exchange-alt:before {\n  content: \"\\f362\"; }\n\n.fa-exclamation:before {\n  content: \"\\f12a\"; }\n\n.fa-exclamation-circle:before {\n  content: \"\\f06a\"; }\n\n.fa-exclamation-triangle:before {\n  content: \"\\f071\"; }\n\n.fa-expand:before {\n  content: \"\\f065\"; }\n\n.fa-expand-alt:before {\n  content: \"\\f424\"; }\n\n.fa-expand-arrows-alt:before {\n  content: \"\\f31e\"; }\n\n.fa-expeditedssl:before {\n  content: \"\\f23e\"; }\n\n.fa-external-link-alt:before {\n  content: \"\\f35d\"; }\n\n.fa-external-link-square-alt:before {\n  content: \"\\f360\"; }\n\n.fa-eye:before {\n  content: \"\\f06e\"; }\n\n.fa-eye-dropper:before {\n  content: \"\\f1fb\"; }\n\n.fa-eye-slash:before {\n  content: \"\\f070\"; }\n\n.fa-facebook:before {\n  content: \"\\f09a\"; }\n\n.fa-facebook-f:before {\n  content: \"\\f39e\"; }\n\n.fa-facebook-messenger:before {\n  content: \"\\f39f\"; }\n\n.fa-facebook-square:before {\n  content: \"\\f082\"; }\n\n.fa-fan:before {\n  content: \"\\f863\"; }\n\n.fa-fantasy-flight-games:before {\n  content: \"\\f6dc\"; }\n\n.fa-fast-backward:before {\n  content: \"\\f049\"; }\n\n.fa-fast-forward:before {\n  content: \"\\f050\"; }\n\n.fa-faucet:before {\n  content: \"\\e005\"; }\n\n.fa-fax:before {\n  content: \"\\f1ac\"; }\n\n.fa-feather:before {\n  content: \"\\f52d\"; }\n\n.fa-feather-alt:before {\n  content: \"\\f56b\"; }\n\n.fa-fedex:before {\n  content: \"\\f797\"; }\n\n.fa-fedora:before {\n  content: \"\\f798\"; }\n\n.fa-female:before {\n  content: \"\\f182\"; }\n\n.fa-fighter-jet:before {\n  content: \"\\f0fb\"; }\n\n.fa-figma:before {\n  content: \"\\f799\"; }\n\n.fa-file:before {\n  content: \"\\f15b\"; }\n\n.fa-file-alt:before {\n  content: \"\\f15c\"; }\n\n.fa-file-archive:before {\n  content: \"\\f1c6\"; }\n\n.fa-file-audio:before {\n  content: \"\\f1c7\"; }\n\n.fa-file-code:before {\n  content: \"\\f1c9\"; }\n\n.fa-file-contract:before {\n  content: \"\\f56c\"; }\n\n.fa-file-csv:before {\n  content: \"\\f6dd\"; }\n\n.fa-file-download:before {\n  content: \"\\f56d\"; }\n\n.fa-file-excel:before {\n  content: \"\\f1c3\"; }\n\n.fa-file-export:before {\n  content: \"\\f56e\"; }\n\n.fa-file-image:before {\n  content: \"\\f1c5\"; }\n\n.fa-file-import:before {\n  content: \"\\f56f\"; }\n\n.fa-file-invoice:before {\n  content: \"\\f570\"; }\n\n.fa-file-invoice-dollar:before {\n  content: \"\\f571\"; }\n\n.fa-file-medical:before {\n  content: \"\\f477\"; }\n\n.fa-file-medical-alt:before {\n  content: \"\\f478\"; }\n\n.fa-file-pdf:before {\n  content: \"\\f1c1\"; }\n\n.fa-file-powerpoint:before {\n  content: \"\\f1c4\"; }\n\n.fa-file-prescription:before {\n  content: \"\\f572\"; }\n\n.fa-file-signature:before {\n  content: \"\\f573\"; }\n\n.fa-file-upload:before {\n  content: \"\\f574\"; }\n\n.fa-file-video:before {\n  content: \"\\f1c8\"; }\n\n.fa-file-word:before {\n  content: \"\\f1c2\"; }\n\n.fa-fill:before {\n  content: \"\\f575\"; }\n\n.fa-fill-drip:before {\n  content: \"\\f576\"; }\n\n.fa-film:before {\n  content: \"\\f008\"; }\n\n.fa-filter:before {\n  content: \"\\f0b0\"; }\n\n.fa-fingerprint:before {\n  content: \"\\f577\"; }\n\n.fa-fire:before {\n  content: \"\\f06d\"; }\n\n.fa-fire-alt:before {\n  content: \"\\f7e4\"; }\n\n.fa-fire-extinguisher:before {\n  content: \"\\f134\"; }\n\n.fa-firefox:before {\n  content: \"\\f269\"; }\n\n.fa-firefox-browser:before {\n  content: \"\\e007\"; }\n\n.fa-first-aid:before {\n  content: \"\\f479\"; }\n\n.fa-first-order:before {\n  content: \"\\f2b0\"; }\n\n.fa-first-order-alt:before {\n  content: \"\\f50a\"; }\n\n.fa-firstdraft:before {\n  content: \"\\f3a1\"; }\n\n.fa-fish:before {\n  content: \"\\f578\"; }\n\n.fa-fist-raised:before {\n  content: \"\\f6de\"; }\n\n.fa-flag:before {\n  content: \"\\f024\"; }\n\n.fa-flag-checkered:before {\n  content: \"\\f11e\"; }\n\n.fa-flag-usa:before {\n  content: \"\\f74d\"; }\n\n.fa-flask:before {\n  content: \"\\f0c3\"; }\n\n.fa-flickr:before {\n  content: \"\\f16e\"; }\n\n.fa-flipboard:before {\n  content: \"\\f44d\"; }\n\n.fa-flushed:before {\n  content: \"\\f579\"; }\n\n.fa-fly:before {\n  content: \"\\f417\"; }\n\n.fa-folder:before {\n  content: \"\\f07b\"; }\n\n.fa-folder-minus:before {\n  content: \"\\f65d\"; }\n\n.fa-folder-open:before {\n  content: \"\\f07c\"; }\n\n.fa-folder-plus:before {\n  content: \"\\f65e\"; }\n\n.fa-font:before {\n  content: \"\\f031\"; }\n\n.fa-font-awesome:before {\n  content: \"\\f2b4\"; }\n\n.fa-font-awesome-alt:before {\n  content: \"\\f35c\"; }\n\n.fa-font-awesome-flag:before {\n  content: \"\\f425\"; }\n\n.fa-font-awesome-logo-full:before {\n  content: \"\\f4e6\"; }\n\n.fa-fonticons:before {\n  content: \"\\f280\"; }\n\n.fa-fonticons-fi:before {\n  content: \"\\f3a2\"; }\n\n.fa-football-ball:before {\n  content: \"\\f44e\"; }\n\n.fa-fort-awesome:before {\n  content: \"\\f286\"; }\n\n.fa-fort-awesome-alt:before {\n  content: \"\\f3a3\"; }\n\n.fa-forumbee:before {\n  content: \"\\f211\"; }\n\n.fa-forward:before {\n  content: \"\\f04e\"; }\n\n.fa-foursquare:before {\n  content: \"\\f180\"; }\n\n.fa-free-code-camp:before {\n  content: \"\\f2c5\"; }\n\n.fa-freebsd:before {\n  content: \"\\f3a4\"; }\n\n.fa-frog:before {\n  content: \"\\f52e\"; }\n\n.fa-frown:before {\n  content: \"\\f119\"; }\n\n.fa-frown-open:before {\n  content: \"\\f57a\"; }\n\n.fa-fulcrum:before {\n  content: \"\\f50b\"; }\n\n.fa-funnel-dollar:before {\n  content: \"\\f662\"; }\n\n.fa-futbol:before {\n  content: \"\\f1e3\"; }\n\n.fa-galactic-republic:before {\n  content: \"\\f50c\"; }\n\n.fa-galactic-senate:before {\n  content: \"\\f50d\"; }\n\n.fa-gamepad:before {\n  content: \"\\f11b\"; }\n\n.fa-gas-pump:before {\n  content: \"\\f52f\"; }\n\n.fa-gavel:before {\n  content: \"\\f0e3\"; }\n\n.fa-gem:before {\n  content: \"\\f3a5\"; }\n\n.fa-genderless:before {\n  content: \"\\f22d\"; }\n\n.fa-get-pocket:before {\n  content: \"\\f265\"; }\n\n.fa-gg:before {\n  content: \"\\f260\"; }\n\n.fa-gg-circle:before {\n  content: \"\\f261\"; }\n\n.fa-ghost:before {\n  content: \"\\f6e2\"; }\n\n.fa-gift:before {\n  content: \"\\f06b\"; }\n\n.fa-gifts:before {\n  content: \"\\f79c\"; }\n\n.fa-git:before {\n  content: \"\\f1d3\"; }\n\n.fa-git-alt:before {\n  content: \"\\f841\"; }\n\n.fa-git-square:before {\n  content: \"\\f1d2\"; }\n\n.fa-github:before {\n  content: \"\\f09b\"; }\n\n.fa-github-alt:before {\n  content: \"\\f113\"; }\n\n.fa-github-square:before {\n  content: \"\\f092\"; }\n\n.fa-gitkraken:before {\n  content: \"\\f3a6\"; }\n\n.fa-gitlab:before {\n  content: \"\\f296\"; }\n\n.fa-gitter:before {\n  content: \"\\f426\"; }\n\n.fa-glass-cheers:before {\n  content: \"\\f79f\"; }\n\n.fa-glass-martini:before {\n  content: \"\\f000\"; }\n\n.fa-glass-martini-alt:before {\n  content: \"\\f57b\"; }\n\n.fa-glass-whiskey:before {\n  content: \"\\f7a0\"; }\n\n.fa-glasses:before {\n  content: \"\\f530\"; }\n\n.fa-glide:before {\n  content: \"\\f2a5\"; }\n\n.fa-glide-g:before {\n  content: \"\\f2a6\"; }\n\n.fa-globe:before {\n  content: \"\\f0ac\"; }\n\n.fa-globe-africa:before {\n  content: \"\\f57c\"; }\n\n.fa-globe-americas:before {\n  content: \"\\f57d\"; }\n\n.fa-globe-asia:before {\n  content: \"\\f57e\"; }\n\n.fa-globe-europe:before {\n  content: \"\\f7a2\"; }\n\n.fa-gofore:before {\n  content: \"\\f3a7\"; }\n\n.fa-golf-ball:before {\n  content: \"\\f450\"; }\n\n.fa-goodreads:before {\n  content: \"\\f3a8\"; }\n\n.fa-goodreads-g:before {\n  content: \"\\f3a9\"; }\n\n.fa-google:before {\n  content: \"\\f1a0\"; }\n\n.fa-google-drive:before {\n  content: \"\\f3aa\"; }\n\n.fa-google-pay:before {\n  content: \"\\e079\"; }\n\n.fa-google-play:before {\n  content: \"\\f3ab\"; }\n\n.fa-google-plus:before {\n  content: \"\\f2b3\"; }\n\n.fa-google-plus-g:before {\n  content: \"\\f0d5\"; }\n\n.fa-google-plus-square:before {\n  content: \"\\f0d4\"; }\n\n.fa-google-wallet:before {\n  content: \"\\f1ee\"; }\n\n.fa-gopuram:before {\n  content: \"\\f664\"; }\n\n.fa-graduation-cap:before {\n  content: \"\\f19d\"; }\n\n.fa-gratipay:before {\n  content: \"\\f184\"; }\n\n.fa-grav:before {\n  content: \"\\f2d6\"; }\n\n.fa-greater-than:before {\n  content: \"\\f531\"; }\n\n.fa-greater-than-equal:before {\n  content: \"\\f532\"; }\n\n.fa-grimace:before {\n  content: \"\\f57f\"; }\n\n.fa-grin:before {\n  content: \"\\f580\"; }\n\n.fa-grin-alt:before {\n  content: \"\\f581\"; }\n\n.fa-grin-beam:before {\n  content: \"\\f582\"; }\n\n.fa-grin-beam-sweat:before {\n  content: \"\\f583\"; }\n\n.fa-grin-hearts:before {\n  content: \"\\f584\"; }\n\n.fa-grin-squint:before {\n  content: \"\\f585\"; }\n\n.fa-grin-squint-tears:before {\n  content: \"\\f586\"; }\n\n.fa-grin-stars:before {\n  content: \"\\f587\"; }\n\n.fa-grin-tears:before {\n  content: \"\\f588\"; }\n\n.fa-grin-tongue:before {\n  content: \"\\f589\"; }\n\n.fa-grin-tongue-squint:before {\n  content: \"\\f58a\"; }\n\n.fa-grin-tongue-wink:before {\n  content: \"\\f58b\"; }\n\n.fa-grin-wink:before {\n  content: \"\\f58c\"; }\n\n.fa-grip-horizontal:before {\n  content: \"\\f58d\"; }\n\n.fa-grip-lines:before {\n  content: \"\\f7a4\"; }\n\n.fa-grip-lines-vertical:before {\n  content: \"\\f7a5\"; }\n\n.fa-grip-vertical:before {\n  content: \"\\f58e\"; }\n\n.fa-gripfire:before {\n  content: \"\\f3ac\"; }\n\n.fa-grunt:before {\n  content: \"\\f3ad\"; }\n\n.fa-guilded:before {\n  content: \"\\e07e\"; }\n\n.fa-guitar:before {\n  content: \"\\f7a6\"; }\n\n.fa-gulp:before {\n  content: \"\\f3ae\"; }\n\n.fa-h-square:before {\n  content: \"\\f0fd\"; }\n\n.fa-hacker-news:before {\n  content: \"\\f1d4\"; }\n\n.fa-hacker-news-square:before {\n  content: \"\\f3af\"; }\n\n.fa-hackerrank:before {\n  content: \"\\f5f7\"; }\n\n.fa-hamburger:before {\n  content: \"\\f805\"; }\n\n.fa-hammer:before {\n  content: \"\\f6e3\"; }\n\n.fa-hamsa:before {\n  content: \"\\f665\"; }\n\n.fa-hand-holding:before {\n  content: \"\\f4bd\"; }\n\n.fa-hand-holding-heart:before {\n  content: \"\\f4be\"; }\n\n.fa-hand-holding-medical:before {\n  content: \"\\e05c\"; }\n\n.fa-hand-holding-usd:before {\n  content: \"\\f4c0\"; }\n\n.fa-hand-holding-water:before {\n  content: \"\\f4c1\"; }\n\n.fa-hand-lizard:before {\n  content: \"\\f258\"; }\n\n.fa-hand-middle-finger:before {\n  content: \"\\f806\"; }\n\n.fa-hand-paper:before {\n  content: \"\\f256\"; }\n\n.fa-hand-peace:before {\n  content: \"\\f25b\"; }\n\n.fa-hand-point-down:before {\n  content: \"\\f0a7\"; }\n\n.fa-hand-point-left:before {\n  content: \"\\f0a5\"; }\n\n.fa-hand-point-right:before {\n  content: \"\\f0a4\"; }\n\n.fa-hand-point-up:before {\n  content: \"\\f0a6\"; }\n\n.fa-hand-pointer:before {\n  content: \"\\f25a\"; }\n\n.fa-hand-rock:before {\n  content: \"\\f255\"; }\n\n.fa-hand-scissors:before {\n  content: \"\\f257\"; }\n\n.fa-hand-sparkles:before {\n  content: \"\\e05d\"; }\n\n.fa-hand-spock:before {\n  content: \"\\f259\"; }\n\n.fa-hands:before {\n  content: \"\\f4c2\"; }\n\n.fa-hands-helping:before {\n  content: \"\\f4c4\"; }\n\n.fa-hands-wash:before {\n  content: \"\\e05e\"; }\n\n.fa-handshake:before {\n  content: \"\\f2b5\"; }\n\n.fa-handshake-alt-slash:before {\n  content: \"\\e05f\"; }\n\n.fa-handshake-slash:before {\n  content: \"\\e060\"; }\n\n.fa-hanukiah:before {\n  content: \"\\f6e6\"; }\n\n.fa-hard-hat:before {\n  content: \"\\f807\"; }\n\n.fa-hashtag:before {\n  content: \"\\f292\"; }\n\n.fa-hat-cowboy:before {\n  content: \"\\f8c0\"; }\n\n.fa-hat-cowboy-side:before {\n  content: \"\\f8c1\"; }\n\n.fa-hat-wizard:before {\n  content: \"\\f6e8\"; }\n\n.fa-hdd:before {\n  content: \"\\f0a0\"; }\n\n.fa-head-side-cough:before {\n  content: \"\\e061\"; }\n\n.fa-head-side-cough-slash:before {\n  content: \"\\e062\"; }\n\n.fa-head-side-mask:before {\n  content: \"\\e063\"; }\n\n.fa-head-side-virus:before {\n  content: \"\\e064\"; }\n\n.fa-heading:before {\n  content: \"\\f1dc\"; }\n\n.fa-headphones:before {\n  content: \"\\f025\"; }\n\n.fa-headphones-alt:before {\n  content: \"\\f58f\"; }\n\n.fa-headset:before {\n  content: \"\\f590\"; }\n\n.fa-heart:before {\n  content: \"\\f004\"; }\n\n.fa-heart-broken:before {\n  content: \"\\f7a9\"; }\n\n.fa-heartbeat:before {\n  content: \"\\f21e\"; }\n\n.fa-helicopter:before {\n  content: \"\\f533\"; }\n\n.fa-highlighter:before {\n  content: \"\\f591\"; }\n\n.fa-hiking:before {\n  content: \"\\f6ec\"; }\n\n.fa-hippo:before {\n  content: \"\\f6ed\"; }\n\n.fa-hips:before {\n  content: \"\\f452\"; }\n\n.fa-hire-a-helper:before {\n  content: \"\\f3b0\"; }\n\n.fa-history:before {\n  content: \"\\f1da\"; }\n\n.fa-hive:before {\n  content: \"\\e07f\"; }\n\n.fa-hockey-puck:before {\n  content: \"\\f453\"; }\n\n.fa-holly-berry:before {\n  content: \"\\f7aa\"; }\n\n.fa-home:before {\n  content: \"\\f015\"; }\n\n.fa-hooli:before {\n  content: \"\\f427\"; }\n\n.fa-hornbill:before {\n  content: \"\\f592\"; }\n\n.fa-horse:before {\n  content: \"\\f6f0\"; }\n\n.fa-horse-head:before {\n  content: \"\\f7ab\"; }\n\n.fa-hospital:before {\n  content: \"\\f0f8\"; }\n\n.fa-hospital-alt:before {\n  content: \"\\f47d\"; }\n\n.fa-hospital-symbol:before {\n  content: \"\\f47e\"; }\n\n.fa-hospital-user:before {\n  content: \"\\f80d\"; }\n\n.fa-hot-tub:before {\n  content: \"\\f593\"; }\n\n.fa-hotdog:before {\n  content: \"\\f80f\"; }\n\n.fa-hotel:before {\n  content: \"\\f594\"; }\n\n.fa-hotjar:before {\n  content: \"\\f3b1\"; }\n\n.fa-hourglass:before {\n  content: \"\\f254\"; }\n\n.fa-hourglass-end:before {\n  content: \"\\f253\"; }\n\n.fa-hourglass-half:before {\n  content: \"\\f252\"; }\n\n.fa-hourglass-start:before {\n  content: \"\\f251\"; }\n\n.fa-house-damage:before {\n  content: \"\\f6f1\"; }\n\n.fa-house-user:before {\n  content: \"\\e065\"; }\n\n.fa-houzz:before {\n  content: \"\\f27c\"; }\n\n.fa-hryvnia:before {\n  content: \"\\f6f2\"; }\n\n.fa-html5:before {\n  content: \"\\f13b\"; }\n\n.fa-hubspot:before {\n  content: \"\\f3b2\"; }\n\n.fa-i-cursor:before {\n  content: \"\\f246\"; }\n\n.fa-ice-cream:before {\n  content: \"\\f810\"; }\n\n.fa-icicles:before {\n  content: \"\\f7ad\"; }\n\n.fa-icons:before {\n  content: \"\\f86d\"; }\n\n.fa-id-badge:before {\n  content: \"\\f2c1\"; }\n\n.fa-id-card:before {\n  content: \"\\f2c2\"; }\n\n.fa-id-card-alt:before {\n  content: \"\\f47f\"; }\n\n.fa-ideal:before {\n  content: \"\\e013\"; }\n\n.fa-igloo:before {\n  content: \"\\f7ae\"; }\n\n.fa-image:before {\n  content: \"\\f03e\"; }\n\n.fa-images:before {\n  content: \"\\f302\"; }\n\n.fa-imdb:before {\n  content: \"\\f2d8\"; }\n\n.fa-inbox:before {\n  content: \"\\f01c\"; }\n\n.fa-indent:before {\n  content: \"\\f03c\"; }\n\n.fa-industry:before {\n  content: \"\\f275\"; }\n\n.fa-infinity:before {\n  content: \"\\f534\"; }\n\n.fa-info:before {\n  content: \"\\f129\"; }\n\n.fa-info-circle:before {\n  content: \"\\f05a\"; }\n\n.fa-innosoft:before {\n  content: \"\\e080\"; }\n\n.fa-instagram:before {\n  content: \"\\f16d\"; }\n\n.fa-instagram-square:before {\n  content: \"\\e055\"; }\n\n.fa-instalod:before {\n  content: \"\\e081\"; }\n\n.fa-intercom:before {\n  content: \"\\f7af\"; }\n\n.fa-internet-explorer:before {\n  content: \"\\f26b\"; }\n\n.fa-invision:before {\n  content: \"\\f7b0\"; }\n\n.fa-ioxhost:before {\n  content: \"\\f208\"; }\n\n.fa-italic:before {\n  content: \"\\f033\"; }\n\n.fa-itch-io:before {\n  content: \"\\f83a\"; }\n\n.fa-itunes:before {\n  content: \"\\f3b4\"; }\n\n.fa-itunes-note:before {\n  content: \"\\f3b5\"; }\n\n.fa-java:before {\n  content: \"\\f4e4\"; }\n\n.fa-jedi:before {\n  content: \"\\f669\"; }\n\n.fa-jedi-order:before {\n  content: \"\\f50e\"; }\n\n.fa-jenkins:before {\n  content: \"\\f3b6\"; }\n\n.fa-jira:before {\n  content: \"\\f7b1\"; }\n\n.fa-joget:before {\n  content: \"\\f3b7\"; }\n\n.fa-joint:before {\n  content: \"\\f595\"; }\n\n.fa-joomla:before {\n  content: \"\\f1aa\"; }\n\n.fa-journal-whills:before {\n  content: \"\\f66a\"; }\n\n.fa-js:before {\n  content: \"\\f3b8\"; }\n\n.fa-js-square:before {\n  content: \"\\f3b9\"; }\n\n.fa-jsfiddle:before {\n  content: \"\\f1cc\"; }\n\n.fa-kaaba:before {\n  content: \"\\f66b\"; }\n\n.fa-kaggle:before {\n  content: \"\\f5fa\"; }\n\n.fa-key:before {\n  content: \"\\f084\"; }\n\n.fa-keybase:before {\n  content: \"\\f4f5\"; }\n\n.fa-keyboard:before {\n  content: \"\\f11c\"; }\n\n.fa-keycdn:before {\n  content: \"\\f3ba\"; }\n\n.fa-khanda:before {\n  content: \"\\f66d\"; }\n\n.fa-kickstarter:before {\n  content: \"\\f3bb\"; }\n\n.fa-kickstarter-k:before {\n  content: \"\\f3bc\"; }\n\n.fa-kiss:before {\n  content: \"\\f596\"; }\n\n.fa-kiss-beam:before {\n  content: \"\\f597\"; }\n\n.fa-kiss-wink-heart:before {\n  content: \"\\f598\"; }\n\n.fa-kiwi-bird:before {\n  content: \"\\f535\"; }\n\n.fa-korvue:before {\n  content: \"\\f42f\"; }\n\n.fa-landmark:before {\n  content: \"\\f66f\"; }\n\n.fa-language:before {\n  content: \"\\f1ab\"; }\n\n.fa-laptop:before {\n  content: \"\\f109\"; }\n\n.fa-laptop-code:before {\n  content: \"\\f5fc\"; }\n\n.fa-laptop-house:before {\n  content: \"\\e066\"; }\n\n.fa-laptop-medical:before {\n  content: \"\\f812\"; }\n\n.fa-laravel:before {\n  content: \"\\f3bd\"; }\n\n.fa-lastfm:before {\n  content: \"\\f202\"; }\n\n.fa-lastfm-square:before {\n  content: \"\\f203\"; }\n\n.fa-laugh:before {\n  content: \"\\f599\"; }\n\n.fa-laugh-beam:before {\n  content: \"\\f59a\"; }\n\n.fa-laugh-squint:before {\n  content: \"\\f59b\"; }\n\n.fa-laugh-wink:before {\n  content: \"\\f59c\"; }\n\n.fa-layer-group:before {\n  content: \"\\f5fd\"; }\n\n.fa-leaf:before {\n  content: \"\\f06c\"; }\n\n.fa-leanpub:before {\n  content: \"\\f212\"; }\n\n.fa-lemon:before {\n  content: \"\\f094\"; }\n\n.fa-less:before {\n  content: \"\\f41d\"; }\n\n.fa-less-than:before {\n  content: \"\\f536\"; }\n\n.fa-less-than-equal:before {\n  content: \"\\f537\"; }\n\n.fa-level-down-alt:before {\n  content: \"\\f3be\"; }\n\n.fa-level-up-alt:before {\n  content: \"\\f3bf\"; }\n\n.fa-life-ring:before {\n  content: \"\\f1cd\"; }\n\n.fa-lightbulb:before {\n  content: \"\\f0eb\"; }\n\n.fa-line:before {\n  content: \"\\f3c0\"; }\n\n.fa-link:before {\n  content: \"\\f0c1\"; }\n\n.fa-linkedin:before {\n  content: \"\\f08c\"; }\n\n.fa-linkedin-in:before {\n  content: \"\\f0e1\"; }\n\n.fa-linode:before {\n  content: \"\\f2b8\"; }\n\n.fa-linux:before {\n  content: \"\\f17c\"; }\n\n.fa-lira-sign:before {\n  content: \"\\f195\"; }\n\n.fa-list:before {\n  content: \"\\f03a\"; }\n\n.fa-list-alt:before {\n  content: \"\\f022\"; }\n\n.fa-list-ol:before {\n  content: \"\\f0cb\"; }\n\n.fa-list-ul:before {\n  content: \"\\f0ca\"; }\n\n.fa-location-arrow:before {\n  content: \"\\f124\"; }\n\n.fa-lock:before {\n  content: \"\\f023\"; }\n\n.fa-lock-open:before {\n  content: \"\\f3c1\"; }\n\n.fa-long-arrow-alt-down:before {\n  content: \"\\f309\"; }\n\n.fa-long-arrow-alt-left:before {\n  content: \"\\f30a\"; }\n\n.fa-long-arrow-alt-right:before {\n  content: \"\\f30b\"; }\n\n.fa-long-arrow-alt-up:before {\n  content: \"\\f30c\"; }\n\n.fa-low-vision:before {\n  content: \"\\f2a8\"; }\n\n.fa-luggage-cart:before {\n  content: \"\\f59d\"; }\n\n.fa-lungs:before {\n  content: \"\\f604\"; }\n\n.fa-lungs-virus:before {\n  content: \"\\e067\"; }\n\n.fa-lyft:before {\n  content: \"\\f3c3\"; }\n\n.fa-magento:before {\n  content: \"\\f3c4\"; }\n\n.fa-magic:before {\n  content: \"\\f0d0\"; }\n\n.fa-magnet:before {\n  content: \"\\f076\"; }\n\n.fa-mail-bulk:before {\n  content: \"\\f674\"; }\n\n.fa-mailchimp:before {\n  content: \"\\f59e\"; }\n\n.fa-male:before {\n  content: \"\\f183\"; }\n\n.fa-mandalorian:before {\n  content: \"\\f50f\"; }\n\n.fa-map:before {\n  content: \"\\f279\"; }\n\n.fa-map-marked:before {\n  content: \"\\f59f\"; }\n\n.fa-map-marked-alt:before {\n  content: \"\\f5a0\"; }\n\n.fa-map-marker:before {\n  content: \"\\f041\"; }\n\n.fa-map-marker-alt:before {\n  content: \"\\f3c5\"; }\n\n.fa-map-pin:before {\n  content: \"\\f276\"; }\n\n.fa-map-signs:before {\n  content: \"\\f277\"; }\n\n.fa-markdown:before {\n  content: \"\\f60f\"; }\n\n.fa-marker:before {\n  content: \"\\f5a1\"; }\n\n.fa-mars:before {\n  content: \"\\f222\"; }\n\n.fa-mars-double:before {\n  content: \"\\f227\"; }\n\n.fa-mars-stroke:before {\n  content: \"\\f229\"; }\n\n.fa-mars-stroke-h:before {\n  content: \"\\f22b\"; }\n\n.fa-mars-stroke-v:before {\n  content: \"\\f22a\"; }\n\n.fa-mask:before {\n  content: \"\\f6fa\"; }\n\n.fa-mastodon:before {\n  content: \"\\f4f6\"; }\n\n.fa-maxcdn:before {\n  content: \"\\f136\"; }\n\n.fa-mdb:before {\n  content: \"\\f8ca\"; }\n\n.fa-medal:before {\n  content: \"\\f5a2\"; }\n\n.fa-medapps:before {\n  content: \"\\f3c6\"; }\n\n.fa-medium:before {\n  content: \"\\f23a\"; }\n\n.fa-medium-m:before {\n  content: \"\\f3c7\"; }\n\n.fa-medkit:before {\n  content: \"\\f0fa\"; }\n\n.fa-medrt:before {\n  content: \"\\f3c8\"; }\n\n.fa-meetup:before {\n  content: \"\\f2e0\"; }\n\n.fa-megaport:before {\n  content: \"\\f5a3\"; }\n\n.fa-meh:before {\n  content: \"\\f11a\"; }\n\n.fa-meh-blank:before {\n  content: \"\\f5a4\"; }\n\n.fa-meh-rolling-eyes:before {\n  content: \"\\f5a5\"; }\n\n.fa-memory:before {\n  content: \"\\f538\"; }\n\n.fa-mendeley:before {\n  content: \"\\f7b3\"; }\n\n.fa-menorah:before {\n  content: \"\\f676\"; }\n\n.fa-mercury:before {\n  content: \"\\f223\"; }\n\n.fa-meteor:before {\n  content: \"\\f753\"; }\n\n.fa-microblog:before {\n  content: \"\\e01a\"; }\n\n.fa-microchip:before {\n  content: \"\\f2db\"; }\n\n.fa-microphone:before {\n  content: \"\\f130\"; }\n\n.fa-microphone-alt:before {\n  content: \"\\f3c9\"; }\n\n.fa-microphone-alt-slash:before {\n  content: \"\\f539\"; }\n\n.fa-microphone-slash:before {\n  content: \"\\f131\"; }\n\n.fa-microscope:before {\n  content: \"\\f610\"; }\n\n.fa-microsoft:before {\n  content: \"\\f3ca\"; }\n\n.fa-minus:before {\n  content: \"\\f068\"; }\n\n.fa-minus-circle:before {\n  content: \"\\f056\"; }\n\n.fa-minus-square:before {\n  content: \"\\f146\"; }\n\n.fa-mitten:before {\n  content: \"\\f7b5\"; }\n\n.fa-mix:before {\n  content: \"\\f3cb\"; }\n\n.fa-mixcloud:before {\n  content: \"\\f289\"; }\n\n.fa-mixer:before {\n  content: \"\\e056\"; }\n\n.fa-mizuni:before {\n  content: \"\\f3cc\"; }\n\n.fa-mobile:before {\n  content: \"\\f10b\"; }\n\n.fa-mobile-alt:before {\n  content: \"\\f3cd\"; }\n\n.fa-modx:before {\n  content: \"\\f285\"; }\n\n.fa-monero:before {\n  content: \"\\f3d0\"; }\n\n.fa-money-bill:before {\n  content: \"\\f0d6\"; }\n\n.fa-money-bill-alt:before {\n  content: \"\\f3d1\"; }\n\n.fa-money-bill-wave:before {\n  content: \"\\f53a\"; }\n\n.fa-money-bill-wave-alt:before {\n  content: \"\\f53b\"; }\n\n.fa-money-check:before {\n  content: \"\\f53c\"; }\n\n.fa-money-check-alt:before {\n  content: \"\\f53d\"; }\n\n.fa-monument:before {\n  content: \"\\f5a6\"; }\n\n.fa-moon:before {\n  content: \"\\f186\"; }\n\n.fa-mortar-pestle:before {\n  content: \"\\f5a7\"; }\n\n.fa-mosque:before {\n  content: \"\\f678\"; }\n\n.fa-motorcycle:before {\n  content: \"\\f21c\"; }\n\n.fa-mountain:before {\n  content: \"\\f6fc\"; }\n\n.fa-mouse:before {\n  content: \"\\f8cc\"; }\n\n.fa-mouse-pointer:before {\n  content: \"\\f245\"; }\n\n.fa-mug-hot:before {\n  content: \"\\f7b6\"; }\n\n.fa-music:before {\n  content: \"\\f001\"; }\n\n.fa-napster:before {\n  content: \"\\f3d2\"; }\n\n.fa-neos:before {\n  content: \"\\f612\"; }\n\n.fa-network-wired:before {\n  content: \"\\f6ff\"; }\n\n.fa-neuter:before {\n  content: \"\\f22c\"; }\n\n.fa-newspaper:before {\n  content: \"\\f1ea\"; }\n\n.fa-nimblr:before {\n  content: \"\\f5a8\"; }\n\n.fa-node:before {\n  content: \"\\f419\"; }\n\n.fa-node-js:before {\n  content: \"\\f3d3\"; }\n\n.fa-not-equal:before {\n  content: \"\\f53e\"; }\n\n.fa-notes-medical:before {\n  content: \"\\f481\"; }\n\n.fa-npm:before {\n  content: \"\\f3d4\"; }\n\n.fa-ns8:before {\n  content: \"\\f3d5\"; }\n\n.fa-nutritionix:before {\n  content: \"\\f3d6\"; }\n\n.fa-object-group:before {\n  content: \"\\f247\"; }\n\n.fa-object-ungroup:before {\n  content: \"\\f248\"; }\n\n.fa-octopus-deploy:before {\n  content: \"\\e082\"; }\n\n.fa-odnoklassniki:before {\n  content: \"\\f263\"; }\n\n.fa-odnoklassniki-square:before {\n  content: \"\\f264\"; }\n\n.fa-oil-can:before {\n  content: \"\\f613\"; }\n\n.fa-old-republic:before {\n  content: \"\\f510\"; }\n\n.fa-om:before {\n  content: \"\\f679\"; }\n\n.fa-opencart:before {\n  content: \"\\f23d\"; }\n\n.fa-openid:before {\n  content: \"\\f19b\"; }\n\n.fa-opera:before {\n  content: \"\\f26a\"; }\n\n.fa-optin-monster:before {\n  content: \"\\f23c\"; }\n\n.fa-orcid:before {\n  content: \"\\f8d2\"; }\n\n.fa-osi:before {\n  content: \"\\f41a\"; }\n\n.fa-otter:before {\n  content: \"\\f700\"; }\n\n.fa-outdent:before {\n  content: \"\\f03b\"; }\n\n.fa-page4:before {\n  content: \"\\f3d7\"; }\n\n.fa-pagelines:before {\n  content: \"\\f18c\"; }\n\n.fa-pager:before {\n  content: \"\\f815\"; }\n\n.fa-paint-brush:before {\n  content: \"\\f1fc\"; }\n\n.fa-paint-roller:before {\n  content: \"\\f5aa\"; }\n\n.fa-palette:before {\n  content: \"\\f53f\"; }\n\n.fa-palfed:before {\n  content: \"\\f3d8\"; }\n\n.fa-pallet:before {\n  content: \"\\f482\"; }\n\n.fa-paper-plane:before {\n  content: \"\\f1d8\"; }\n\n.fa-paperclip:before {\n  content: \"\\f0c6\"; }\n\n.fa-parachute-box:before {\n  content: \"\\f4cd\"; }\n\n.fa-paragraph:before {\n  content: \"\\f1dd\"; }\n\n.fa-parking:before {\n  content: \"\\f540\"; }\n\n.fa-passport:before {\n  content: \"\\f5ab\"; }\n\n.fa-pastafarianism:before {\n  content: \"\\f67b\"; }\n\n.fa-paste:before {\n  content: \"\\f0ea\"; }\n\n.fa-patreon:before {\n  content: \"\\f3d9\"; }\n\n.fa-pause:before {\n  content: \"\\f04c\"; }\n\n.fa-pause-circle:before {\n  content: \"\\f28b\"; }\n\n.fa-paw:before {\n  content: \"\\f1b0\"; }\n\n.fa-paypal:before {\n  content: \"\\f1ed\"; }\n\n.fa-peace:before {\n  content: \"\\f67c\"; }\n\n.fa-pen:before {\n  content: \"\\f304\"; }\n\n.fa-pen-alt:before {\n  content: \"\\f305\"; }\n\n.fa-pen-fancy:before {\n  content: \"\\f5ac\"; }\n\n.fa-pen-nib:before {\n  content: \"\\f5ad\"; }\n\n.fa-pen-square:before {\n  content: \"\\f14b\"; }\n\n.fa-pencil-alt:before {\n  content: \"\\f303\"; }\n\n.fa-pencil-ruler:before {\n  content: \"\\f5ae\"; }\n\n.fa-penny-arcade:before {\n  content: \"\\f704\"; }\n\n.fa-people-arrows:before {\n  content: \"\\e068\"; }\n\n.fa-people-carry:before {\n  content: \"\\f4ce\"; }\n\n.fa-pepper-hot:before {\n  content: \"\\f816\"; }\n\n.fa-perbyte:before {\n  content: \"\\e083\"; }\n\n.fa-percent:before {\n  content: \"\\f295\"; }\n\n.fa-percentage:before {\n  content: \"\\f541\"; }\n\n.fa-periscope:before {\n  content: \"\\f3da\"; }\n\n.fa-person-booth:before {\n  content: \"\\f756\"; }\n\n.fa-phabricator:before {\n  content: \"\\f3db\"; }\n\n.fa-phoenix-framework:before {\n  content: \"\\f3dc\"; }\n\n.fa-phoenix-squadron:before {\n  content: \"\\f511\"; }\n\n.fa-phone:before {\n  content: \"\\f095\"; }\n\n.fa-phone-alt:before {\n  content: \"\\f879\"; }\n\n.fa-phone-slash:before {\n  content: \"\\f3dd\"; }\n\n.fa-phone-square:before {\n  content: \"\\f098\"; }\n\n.fa-phone-square-alt:before {\n  content: \"\\f87b\"; }\n\n.fa-phone-volume:before {\n  content: \"\\f2a0\"; }\n\n.fa-photo-video:before {\n  content: \"\\f87c\"; }\n\n.fa-php:before {\n  content: \"\\f457\"; }\n\n.fa-pied-piper:before {\n  content: \"\\f2ae\"; }\n\n.fa-pied-piper-alt:before {\n  content: \"\\f1a8\"; }\n\n.fa-pied-piper-hat:before {\n  content: \"\\f4e5\"; }\n\n.fa-pied-piper-pp:before {\n  content: \"\\f1a7\"; }\n\n.fa-pied-piper-square:before {\n  content: \"\\e01e\"; }\n\n.fa-piggy-bank:before {\n  content: \"\\f4d3\"; }\n\n.fa-pills:before {\n  content: \"\\f484\"; }\n\n.fa-pinterest:before {\n  content: \"\\f0d2\"; }\n\n.fa-pinterest-p:before {\n  content: \"\\f231\"; }\n\n.fa-pinterest-square:before {\n  content: \"\\f0d3\"; }\n\n.fa-pizza-slice:before {\n  content: \"\\f818\"; }\n\n.fa-place-of-worship:before {\n  content: \"\\f67f\"; }\n\n.fa-plane:before {\n  content: \"\\f072\"; }\n\n.fa-plane-arrival:before {\n  content: \"\\f5af\"; }\n\n.fa-plane-departure:before {\n  content: \"\\f5b0\"; }\n\n.fa-plane-slash:before {\n  content: \"\\e069\"; }\n\n.fa-play:before {\n  content: \"\\f04b\"; }\n\n.fa-play-circle:before {\n  content: \"\\f144\"; }\n\n.fa-playstation:before {\n  content: \"\\f3df\"; }\n\n.fa-plug:before {\n  content: \"\\f1e6\"; }\n\n.fa-plus:before {\n  content: \"\\f067\"; }\n\n.fa-plus-circle:before {\n  content: \"\\f055\"; }\n\n.fa-plus-square:before {\n  content: \"\\f0fe\"; }\n\n.fa-podcast:before {\n  content: \"\\f2ce\"; }\n\n.fa-poll:before {\n  content: \"\\f681\"; }\n\n.fa-poll-h:before {\n  content: \"\\f682\"; }\n\n.fa-poo:before {\n  content: \"\\f2fe\"; }\n\n.fa-poo-storm:before {\n  content: \"\\f75a\"; }\n\n.fa-poop:before {\n  content: \"\\f619\"; }\n\n.fa-portrait:before {\n  content: \"\\f3e0\"; }\n\n.fa-pound-sign:before {\n  content: \"\\f154\"; }\n\n.fa-power-off:before {\n  content: \"\\f011\"; }\n\n.fa-pray:before {\n  content: \"\\f683\"; }\n\n.fa-praying-hands:before {\n  content: \"\\f684\"; }\n\n.fa-prescription:before {\n  content: \"\\f5b1\"; }\n\n.fa-prescription-bottle:before {\n  content: \"\\f485\"; }\n\n.fa-prescription-bottle-alt:before {\n  content: \"\\f486\"; }\n\n.fa-print:before {\n  content: \"\\f02f\"; }\n\n.fa-procedures:before {\n  content: \"\\f487\"; }\n\n.fa-product-hunt:before {\n  content: \"\\f288\"; }\n\n.fa-project-diagram:before {\n  content: \"\\f542\"; }\n\n.fa-pump-medical:before {\n  content: \"\\e06a\"; }\n\n.fa-pump-soap:before {\n  content: \"\\e06b\"; }\n\n.fa-pushed:before {\n  content: \"\\f3e1\"; }\n\n.fa-puzzle-piece:before {\n  content: \"\\f12e\"; }\n\n.fa-python:before {\n  content: \"\\f3e2\"; }\n\n.fa-qq:before {\n  content: \"\\f1d6\"; }\n\n.fa-qrcode:before {\n  content: \"\\f029\"; }\n\n.fa-question:before {\n  content: \"\\f128\"; }\n\n.fa-question-circle:before {\n  content: \"\\f059\"; }\n\n.fa-quidditch:before {\n  content: \"\\f458\"; }\n\n.fa-quinscape:before {\n  content: \"\\f459\"; }\n\n.fa-quora:before {\n  content: \"\\f2c4\"; }\n\n.fa-quote-left:before {\n  content: \"\\f10d\"; }\n\n.fa-quote-right:before {\n  content: \"\\f10e\"; }\n\n.fa-quran:before {\n  content: \"\\f687\"; }\n\n.fa-r-project:before {\n  content: \"\\f4f7\"; }\n\n.fa-radiation:before {\n  content: \"\\f7b9\"; }\n\n.fa-radiation-alt:before {\n  content: \"\\f7ba\"; }\n\n.fa-rainbow:before {\n  content: \"\\f75b\"; }\n\n.fa-random:before {\n  content: \"\\f074\"; }\n\n.fa-raspberry-pi:before {\n  content: \"\\f7bb\"; }\n\n.fa-ravelry:before {\n  content: \"\\f2d9\"; }\n\n.fa-react:before {\n  content: \"\\f41b\"; }\n\n.fa-reacteurope:before {\n  content: \"\\f75d\"; }\n\n.fa-readme:before {\n  content: \"\\f4d5\"; }\n\n.fa-rebel:before {\n  content: \"\\f1d0\"; }\n\n.fa-receipt:before {\n  content: \"\\f543\"; }\n\n.fa-record-vinyl:before {\n  content: \"\\f8d9\"; }\n\n.fa-recycle:before {\n  content: \"\\f1b8\"; }\n\n.fa-red-river:before {\n  content: \"\\f3e3\"; }\n\n.fa-reddit:before {\n  content: \"\\f1a1\"; }\n\n.fa-reddit-alien:before {\n  content: \"\\f281\"; }\n\n.fa-reddit-square:before {\n  content: \"\\f1a2\"; }\n\n.fa-redhat:before {\n  content: \"\\f7bc\"; }\n\n.fa-redo:before {\n  content: \"\\f01e\"; }\n\n.fa-redo-alt:before {\n  content: \"\\f2f9\"; }\n\n.fa-registered:before {\n  content: \"\\f25d\"; }\n\n.fa-remove-format:before {\n  content: \"\\f87d\"; }\n\n.fa-renren:before {\n  content: \"\\f18b\"; }\n\n.fa-reply:before {\n  content: \"\\f3e5\"; }\n\n.fa-reply-all:before {\n  content: \"\\f122\"; }\n\n.fa-replyd:before {\n  content: \"\\f3e6\"; }\n\n.fa-republican:before {\n  content: \"\\f75e\"; }\n\n.fa-researchgate:before {\n  content: \"\\f4f8\"; }\n\n.fa-resolving:before {\n  content: \"\\f3e7\"; }\n\n.fa-restroom:before {\n  content: \"\\f7bd\"; }\n\n.fa-retweet:before {\n  content: \"\\f079\"; }\n\n.fa-rev:before {\n  content: \"\\f5b2\"; }\n\n.fa-ribbon:before {\n  content: \"\\f4d6\"; }\n\n.fa-ring:before {\n  content: \"\\f70b\"; }\n\n.fa-road:before {\n  content: \"\\f018\"; }\n\n.fa-robot:before {\n  content: \"\\f544\"; }\n\n.fa-rocket:before {\n  content: \"\\f135\"; }\n\n.fa-rocketchat:before {\n  content: \"\\f3e8\"; }\n\n.fa-rockrms:before {\n  content: \"\\f3e9\"; }\n\n.fa-route:before {\n  content: \"\\f4d7\"; }\n\n.fa-rss:before {\n  content: \"\\f09e\"; }\n\n.fa-rss-square:before {\n  content: \"\\f143\"; }\n\n.fa-ruble-sign:before {\n  content: \"\\f158\"; }\n\n.fa-ruler:before {\n  content: \"\\f545\"; }\n\n.fa-ruler-combined:before {\n  content: \"\\f546\"; }\n\n.fa-ruler-horizontal:before {\n  content: \"\\f547\"; }\n\n.fa-ruler-vertical:before {\n  content: \"\\f548\"; }\n\n.fa-running:before {\n  content: \"\\f70c\"; }\n\n.fa-rupee-sign:before {\n  content: \"\\f156\"; }\n\n.fa-rust:before {\n  content: \"\\e07a\"; }\n\n.fa-sad-cry:before {\n  content: \"\\f5b3\"; }\n\n.fa-sad-tear:before {\n  content: \"\\f5b4\"; }\n\n.fa-safari:before {\n  content: \"\\f267\"; }\n\n.fa-salesforce:before {\n  content: \"\\f83b\"; }\n\n.fa-sass:before {\n  content: \"\\f41e\"; }\n\n.fa-satellite:before {\n  content: \"\\f7bf\"; }\n\n.fa-satellite-dish:before {\n  content: \"\\f7c0\"; }\n\n.fa-save:before {\n  content: \"\\f0c7\"; }\n\n.fa-schlix:before {\n  content: \"\\f3ea\"; }\n\n.fa-school:before {\n  content: \"\\f549\"; }\n\n.fa-screwdriver:before {\n  content: \"\\f54a\"; }\n\n.fa-scribd:before {\n  content: \"\\f28a\"; }\n\n.fa-scroll:before {\n  content: \"\\f70e\"; }\n\n.fa-sd-card:before {\n  content: \"\\f7c2\"; }\n\n.fa-search:before {\n  content: \"\\f002\"; }\n\n.fa-search-dollar:before {\n  content: \"\\f688\"; }\n\n.fa-search-location:before {\n  content: \"\\f689\"; }\n\n.fa-search-minus:before {\n  content: \"\\f010\"; }\n\n.fa-search-plus:before {\n  content: \"\\f00e\"; }\n\n.fa-searchengin:before {\n  content: \"\\f3eb\"; }\n\n.fa-seedling:before {\n  content: \"\\f4d8\"; }\n\n.fa-sellcast:before {\n  content: \"\\f2da\"; }\n\n.fa-sellsy:before {\n  content: \"\\f213\"; }\n\n.fa-server:before {\n  content: \"\\f233\"; }\n\n.fa-servicestack:before {\n  content: \"\\f3ec\"; }\n\n.fa-shapes:before {\n  content: \"\\f61f\"; }\n\n.fa-share:before {\n  content: \"\\f064\"; }\n\n.fa-share-alt:before {\n  content: \"\\f1e0\"; }\n\n.fa-share-alt-square:before {\n  content: \"\\f1e1\"; }\n\n.fa-share-square:before {\n  content: \"\\f14d\"; }\n\n.fa-shekel-sign:before {\n  content: \"\\f20b\"; }\n\n.fa-shield-alt:before {\n  content: \"\\f3ed\"; }\n\n.fa-shield-virus:before {\n  content: \"\\e06c\"; }\n\n.fa-ship:before {\n  content: \"\\f21a\"; }\n\n.fa-shipping-fast:before {\n  content: \"\\f48b\"; }\n\n.fa-shirtsinbulk:before {\n  content: \"\\f214\"; }\n\n.fa-shoe-prints:before {\n  content: \"\\f54b\"; }\n\n.fa-shopify:before {\n  content: \"\\e057\"; }\n\n.fa-shopping-bag:before {\n  content: \"\\f290\"; }\n\n.fa-shopping-basket:before {\n  content: \"\\f291\"; }\n\n.fa-shopping-cart:before {\n  content: \"\\f07a\"; }\n\n.fa-shopware:before {\n  content: \"\\f5b5\"; }\n\n.fa-shower:before {\n  content: \"\\f2cc\"; }\n\n.fa-shuttle-van:before {\n  content: \"\\f5b6\"; }\n\n.fa-sign:before {\n  content: \"\\f4d9\"; }\n\n.fa-sign-in-alt:before {\n  content: \"\\f2f6\"; }\n\n.fa-sign-language:before {\n  content: \"\\f2a7\"; }\n\n.fa-sign-out-alt:before {\n  content: \"\\f2f5\"; }\n\n.fa-signal:before {\n  content: \"\\f012\"; }\n\n.fa-signature:before {\n  content: \"\\f5b7\"; }\n\n.fa-sim-card:before {\n  content: \"\\f7c4\"; }\n\n.fa-simplybuilt:before {\n  content: \"\\f215\"; }\n\n.fa-sink:before {\n  content: \"\\e06d\"; }\n\n.fa-sistrix:before {\n  content: \"\\f3ee\"; }\n\n.fa-sitemap:before {\n  content: \"\\f0e8\"; }\n\n.fa-sith:before {\n  content: \"\\f512\"; }\n\n.fa-skating:before {\n  content: \"\\f7c5\"; }\n\n.fa-sketch:before {\n  content: \"\\f7c6\"; }\n\n.fa-skiing:before {\n  content: \"\\f7c9\"; }\n\n.fa-skiing-nordic:before {\n  content: \"\\f7ca\"; }\n\n.fa-skull:before {\n  content: \"\\f54c\"; }\n\n.fa-skull-crossbones:before {\n  content: \"\\f714\"; }\n\n.fa-skyatlas:before {\n  content: \"\\f216\"; }\n\n.fa-skype:before {\n  content: \"\\f17e\"; }\n\n.fa-slack:before {\n  content: \"\\f198\"; }\n\n.fa-slack-hash:before {\n  content: \"\\f3ef\"; }\n\n.fa-slash:before {\n  content: \"\\f715\"; }\n\n.fa-sleigh:before {\n  content: \"\\f7cc\"; }\n\n.fa-sliders-h:before {\n  content: \"\\f1de\"; }\n\n.fa-slideshare:before {\n  content: \"\\f1e7\"; }\n\n.fa-smile:before {\n  content: \"\\f118\"; }\n\n.fa-smile-beam:before {\n  content: \"\\f5b8\"; }\n\n.fa-smile-wink:before {\n  content: \"\\f4da\"; }\n\n.fa-smog:before {\n  content: \"\\f75f\"; }\n\n.fa-smoking:before {\n  content: \"\\f48d\"; }\n\n.fa-smoking-ban:before {\n  content: \"\\f54d\"; }\n\n.fa-sms:before {\n  content: \"\\f7cd\"; }\n\n.fa-snapchat:before {\n  content: \"\\f2ab\"; }\n\n.fa-snapchat-ghost:before {\n  content: \"\\f2ac\"; }\n\n.fa-snapchat-square:before {\n  content: \"\\f2ad\"; }\n\n.fa-snowboarding:before {\n  content: \"\\f7ce\"; }\n\n.fa-snowflake:before {\n  content: \"\\f2dc\"; }\n\n.fa-snowman:before {\n  content: \"\\f7d0\"; }\n\n.fa-snowplow:before {\n  content: \"\\f7d2\"; }\n\n.fa-soap:before {\n  content: \"\\e06e\"; }\n\n.fa-socks:before {\n  content: \"\\f696\"; }\n\n.fa-solar-panel:before {\n  content: \"\\f5ba\"; }\n\n.fa-sort:before {\n  content: \"\\f0dc\"; }\n\n.fa-sort-alpha-down:before {\n  content: \"\\f15d\"; }\n\n.fa-sort-alpha-down-alt:before {\n  content: \"\\f881\"; }\n\n.fa-sort-alpha-up:before {\n  content: \"\\f15e\"; }\n\n.fa-sort-alpha-up-alt:before {\n  content: \"\\f882\"; }\n\n.fa-sort-amount-down:before {\n  content: \"\\f160\"; }\n\n.fa-sort-amount-down-alt:before {\n  content: \"\\f884\"; }\n\n.fa-sort-amount-up:before {\n  content: \"\\f161\"; }\n\n.fa-sort-amount-up-alt:before {\n  content: \"\\f885\"; }\n\n.fa-sort-down:before {\n  content: \"\\f0dd\"; }\n\n.fa-sort-numeric-down:before {\n  content: \"\\f162\"; }\n\n.fa-sort-numeric-down-alt:before {\n  content: \"\\f886\"; }\n\n.fa-sort-numeric-up:before {\n  content: \"\\f163\"; }\n\n.fa-sort-numeric-up-alt:before {\n  content: \"\\f887\"; }\n\n.fa-sort-up:before {\n  content: \"\\f0de\"; }\n\n.fa-soundcloud:before {\n  content: \"\\f1be\"; }\n\n.fa-sourcetree:before {\n  content: \"\\f7d3\"; }\n\n.fa-spa:before {\n  content: \"\\f5bb\"; }\n\n.fa-space-shuttle:before {\n  content: \"\\f197\"; }\n\n.fa-speakap:before {\n  content: \"\\f3f3\"; }\n\n.fa-speaker-deck:before {\n  content: \"\\f83c\"; }\n\n.fa-spell-check:before {\n  content: \"\\f891\"; }\n\n.fa-spider:before {\n  content: \"\\f717\"; }\n\n.fa-spinner:before {\n  content: \"\\f110\"; }\n\n.fa-splotch:before {\n  content: \"\\f5bc\"; }\n\n.fa-spotify:before {\n  content: \"\\f1bc\"; }\n\n.fa-spray-can:before {\n  content: \"\\f5bd\"; }\n\n.fa-square:before {\n  content: \"\\f0c8\"; }\n\n.fa-square-full:before {\n  content: \"\\f45c\"; }\n\n.fa-square-root-alt:before {\n  content: \"\\f698\"; }\n\n.fa-squarespace:before {\n  content: \"\\f5be\"; }\n\n.fa-stack-exchange:before {\n  content: \"\\f18d\"; }\n\n.fa-stack-overflow:before {\n  content: \"\\f16c\"; }\n\n.fa-stackpath:before {\n  content: \"\\f842\"; }\n\n.fa-stamp:before {\n  content: \"\\f5bf\"; }\n\n.fa-star:before {\n  content: \"\\f005\"; }\n\n.fa-star-and-crescent:before {\n  content: \"\\f699\"; }\n\n.fa-star-half:before {\n  content: \"\\f089\"; }\n\n.fa-star-half-alt:before {\n  content: \"\\f5c0\"; }\n\n.fa-star-of-david:before {\n  content: \"\\f69a\"; }\n\n.fa-star-of-life:before {\n  content: \"\\f621\"; }\n\n.fa-staylinked:before {\n  content: \"\\f3f5\"; }\n\n.fa-steam:before {\n  content: \"\\f1b6\"; }\n\n.fa-steam-square:before {\n  content: \"\\f1b7\"; }\n\n.fa-steam-symbol:before {\n  content: \"\\f3f6\"; }\n\n.fa-step-backward:before {\n  content: \"\\f048\"; }\n\n.fa-step-forward:before {\n  content: \"\\f051\"; }\n\n.fa-stethoscope:before {\n  content: \"\\f0f1\"; }\n\n.fa-sticker-mule:before {\n  content: \"\\f3f7\"; }\n\n.fa-sticky-note:before {\n  content: \"\\f249\"; }\n\n.fa-stop:before {\n  content: \"\\f04d\"; }\n\n.fa-stop-circle:before {\n  content: \"\\f28d\"; }\n\n.fa-stopwatch:before {\n  content: \"\\f2f2\"; }\n\n.fa-stopwatch-20:before {\n  content: \"\\e06f\"; }\n\n.fa-store:before {\n  content: \"\\f54e\"; }\n\n.fa-store-alt:before {\n  content: \"\\f54f\"; }\n\n.fa-store-alt-slash:before {\n  content: \"\\e070\"; }\n\n.fa-store-slash:before {\n  content: \"\\e071\"; }\n\n.fa-strava:before {\n  content: \"\\f428\"; }\n\n.fa-stream:before {\n  content: \"\\f550\"; }\n\n.fa-street-view:before {\n  content: \"\\f21d\"; }\n\n.fa-strikethrough:before {\n  content: \"\\f0cc\"; }\n\n.fa-stripe:before {\n  content: \"\\f429\"; }\n\n.fa-stripe-s:before {\n  content: \"\\f42a\"; }\n\n.fa-stroopwafel:before {\n  content: \"\\f551\"; }\n\n.fa-studiovinari:before {\n  content: \"\\f3f8\"; }\n\n.fa-stumbleupon:before {\n  content: \"\\f1a4\"; }\n\n.fa-stumbleupon-circle:before {\n  content: \"\\f1a3\"; }\n\n.fa-subscript:before {\n  content: \"\\f12c\"; }\n\n.fa-subway:before {\n  content: \"\\f239\"; }\n\n.fa-suitcase:before {\n  content: \"\\f0f2\"; }\n\n.fa-suitcase-rolling:before {\n  content: \"\\f5c1\"; }\n\n.fa-sun:before {\n  content: \"\\f185\"; }\n\n.fa-superpowers:before {\n  content: \"\\f2dd\"; }\n\n.fa-superscript:before {\n  content: \"\\f12b\"; }\n\n.fa-supple:before {\n  content: \"\\f3f9\"; }\n\n.fa-surprise:before {\n  content: \"\\f5c2\"; }\n\n.fa-suse:before {\n  content: \"\\f7d6\"; }\n\n.fa-swatchbook:before {\n  content: \"\\f5c3\"; }\n\n.fa-swift:before {\n  content: \"\\f8e1\"; }\n\n.fa-swimmer:before {\n  content: \"\\f5c4\"; }\n\n.fa-swimming-pool:before {\n  content: \"\\f5c5\"; }\n\n.fa-symfony:before {\n  content: \"\\f83d\"; }\n\n.fa-synagogue:before {\n  content: \"\\f69b\"; }\n\n.fa-sync:before {\n  content: \"\\f021\"; }\n\n.fa-sync-alt:before {\n  content: \"\\f2f1\"; }\n\n.fa-syringe:before {\n  content: \"\\f48e\"; }\n\n.fa-table:before {\n  content: \"\\f0ce\"; }\n\n.fa-table-tennis:before {\n  content: \"\\f45d\"; }\n\n.fa-tablet:before {\n  content: \"\\f10a\"; }\n\n.fa-tablet-alt:before {\n  content: \"\\f3fa\"; }\n\n.fa-tablets:before {\n  content: \"\\f490\"; }\n\n.fa-tachometer-alt:before {\n  content: \"\\f3fd\"; }\n\n.fa-tag:before {\n  content: \"\\f02b\"; }\n\n.fa-tags:before {\n  content: \"\\f02c\"; }\n\n.fa-tape:before {\n  content: \"\\f4db\"; }\n\n.fa-tasks:before {\n  content: \"\\f0ae\"; }\n\n.fa-taxi:before {\n  content: \"\\f1ba\"; }\n\n.fa-teamspeak:before {\n  content: \"\\f4f9\"; }\n\n.fa-teeth:before {\n  content: \"\\f62e\"; }\n\n.fa-teeth-open:before {\n  content: \"\\f62f\"; }\n\n.fa-telegram:before {\n  content: \"\\f2c6\"; }\n\n.fa-telegram-plane:before {\n  content: \"\\f3fe\"; }\n\n.fa-temperature-high:before {\n  content: \"\\f769\"; }\n\n.fa-temperature-low:before {\n  content: \"\\f76b\"; }\n\n.fa-tencent-weibo:before {\n  content: \"\\f1d5\"; }\n\n.fa-tenge:before {\n  content: \"\\f7d7\"; }\n\n.fa-terminal:before {\n  content: \"\\f120\"; }\n\n.fa-text-height:before {\n  content: \"\\f034\"; }\n\n.fa-text-width:before {\n  content: \"\\f035\"; }\n\n.fa-th:before {\n  content: \"\\f00a\"; }\n\n.fa-th-large:before {\n  content: \"\\f009\"; }\n\n.fa-th-list:before {\n  content: \"\\f00b\"; }\n\n.fa-the-red-yeti:before {\n  content: \"\\f69d\"; }\n\n.fa-theater-masks:before {\n  content: \"\\f630\"; }\n\n.fa-themeco:before {\n  content: \"\\f5c6\"; }\n\n.fa-themeisle:before {\n  content: \"\\f2b2\"; }\n\n.fa-thermometer:before {\n  content: \"\\f491\"; }\n\n.fa-thermometer-empty:before {\n  content: \"\\f2cb\"; }\n\n.fa-thermometer-full:before {\n  content: \"\\f2c7\"; }\n\n.fa-thermometer-half:before {\n  content: \"\\f2c9\"; }\n\n.fa-thermometer-quarter:before {\n  content: \"\\f2ca\"; }\n\n.fa-thermometer-three-quarters:before {\n  content: \"\\f2c8\"; }\n\n.fa-think-peaks:before {\n  content: \"\\f731\"; }\n\n.fa-thumbs-down:before {\n  content: \"\\f165\"; }\n\n.fa-thumbs-up:before {\n  content: \"\\f164\"; }\n\n.fa-thumbtack:before {\n  content: \"\\f08d\"; }\n\n.fa-ticket-alt:before {\n  content: \"\\f3ff\"; }\n\n.fa-tiktok:before {\n  content: \"\\e07b\"; }\n\n.fa-times:before {\n  content: \"\\f00d\"; }\n\n.fa-times-circle:before {\n  content: \"\\f057\"; }\n\n.fa-tint:before {\n  content: \"\\f043\"; }\n\n.fa-tint-slash:before {\n  content: \"\\f5c7\"; }\n\n.fa-tired:before {\n  content: \"\\f5c8\"; }\n\n.fa-toggle-off:before {\n  content: \"\\f204\"; }\n\n.fa-toggle-on:before {\n  content: \"\\f205\"; }\n\n.fa-toilet:before {\n  content: \"\\f7d8\"; }\n\n.fa-toilet-paper:before {\n  content: \"\\f71e\"; }\n\n.fa-toilet-paper-slash:before {\n  content: \"\\e072\"; }\n\n.fa-toolbox:before {\n  content: \"\\f552\"; }\n\n.fa-tools:before {\n  content: \"\\f7d9\"; }\n\n.fa-tooth:before {\n  content: \"\\f5c9\"; }\n\n.fa-torah:before {\n  content: \"\\f6a0\"; }\n\n.fa-torii-gate:before {\n  content: \"\\f6a1\"; }\n\n.fa-tractor:before {\n  content: \"\\f722\"; }\n\n.fa-trade-federation:before {\n  content: \"\\f513\"; }\n\n.fa-trademark:before {\n  content: \"\\f25c\"; }\n\n.fa-traffic-light:before {\n  content: \"\\f637\"; }\n\n.fa-trailer:before {\n  content: \"\\e041\"; }\n\n.fa-train:before {\n  content: \"\\f238\"; }\n\n.fa-tram:before {\n  content: \"\\f7da\"; }\n\n.fa-transgender:before {\n  content: \"\\f224\"; }\n\n.fa-transgender-alt:before {\n  content: \"\\f225\"; }\n\n.fa-trash:before {\n  content: \"\\f1f8\"; }\n\n.fa-trash-alt:before {\n  content: \"\\f2ed\"; }\n\n.fa-trash-restore:before {\n  content: \"\\f829\"; }\n\n.fa-trash-restore-alt:before {\n  content: \"\\f82a\"; }\n\n.fa-tree:before {\n  content: \"\\f1bb\"; }\n\n.fa-trello:before {\n  content: \"\\f181\"; }\n\n.fa-trophy:before {\n  content: \"\\f091\"; }\n\n.fa-truck:before {\n  content: \"\\f0d1\"; }\n\n.fa-truck-loading:before {\n  content: \"\\f4de\"; }\n\n.fa-truck-monster:before {\n  content: \"\\f63b\"; }\n\n.fa-truck-moving:before {\n  content: \"\\f4df\"; }\n\n.fa-truck-pickup:before {\n  content: \"\\f63c\"; }\n\n.fa-tshirt:before {\n  content: \"\\f553\"; }\n\n.fa-tty:before {\n  content: \"\\f1e4\"; }\n\n.fa-tumblr:before {\n  content: \"\\f173\"; }\n\n.fa-tumblr-square:before {\n  content: \"\\f174\"; }\n\n.fa-tv:before {\n  content: \"\\f26c\"; }\n\n.fa-twitch:before {\n  content: \"\\f1e8\"; }\n\n.fa-twitter:before {\n  content: \"\\f099\"; }\n\n.fa-twitter-square:before {\n  content: \"\\f081\"; }\n\n.fa-typo3:before {\n  content: \"\\f42b\"; }\n\n.fa-uber:before {\n  content: \"\\f402\"; }\n\n.fa-ubuntu:before {\n  content: \"\\f7df\"; }\n\n.fa-uikit:before {\n  content: \"\\f403\"; }\n\n.fa-umbraco:before {\n  content: \"\\f8e8\"; }\n\n.fa-umbrella:before {\n  content: \"\\f0e9\"; }\n\n.fa-umbrella-beach:before {\n  content: \"\\f5ca\"; }\n\n.fa-uncharted:before {\n  content: \"\\e084\"; }\n\n.fa-underline:before {\n  content: \"\\f0cd\"; }\n\n.fa-undo:before {\n  content: \"\\f0e2\"; }\n\n.fa-undo-alt:before {\n  content: \"\\f2ea\"; }\n\n.fa-uniregistry:before {\n  content: \"\\f404\"; }\n\n.fa-unity:before {\n  content: \"\\e049\"; }\n\n.fa-universal-access:before {\n  content: \"\\f29a\"; }\n\n.fa-university:before {\n  content: \"\\f19c\"; }\n\n.fa-unlink:before {\n  content: \"\\f127\"; }\n\n.fa-unlock:before {\n  content: \"\\f09c\"; }\n\n.fa-unlock-alt:before {\n  content: \"\\f13e\"; }\n\n.fa-unsplash:before {\n  content: \"\\e07c\"; }\n\n.fa-untappd:before {\n  content: \"\\f405\"; }\n\n.fa-upload:before {\n  content: \"\\f093\"; }\n\n.fa-ups:before {\n  content: \"\\f7e0\"; }\n\n.fa-usb:before {\n  content: \"\\f287\"; }\n\n.fa-user:before {\n  content: \"\\f007\"; }\n\n.fa-user-alt:before {\n  content: \"\\f406\"; }\n\n.fa-user-alt-slash:before {\n  content: \"\\f4fa\"; }\n\n.fa-user-astronaut:before {\n  content: \"\\f4fb\"; }\n\n.fa-user-check:before {\n  content: \"\\f4fc\"; }\n\n.fa-user-circle:before {\n  content: \"\\f2bd\"; }\n\n.fa-user-clock:before {\n  content: \"\\f4fd\"; }\n\n.fa-user-cog:before {\n  content: \"\\f4fe\"; }\n\n.fa-user-edit:before {\n  content: \"\\f4ff\"; }\n\n.fa-user-friends:before {\n  content: \"\\f500\"; }\n\n.fa-user-graduate:before {\n  content: \"\\f501\"; }\n\n.fa-user-injured:before {\n  content: \"\\f728\"; }\n\n.fa-user-lock:before {\n  content: \"\\f502\"; }\n\n.fa-user-md:before {\n  content: \"\\f0f0\"; }\n\n.fa-user-minus:before {\n  content: \"\\f503\"; }\n\n.fa-user-ninja:before {\n  content: \"\\f504\"; }\n\n.fa-user-nurse:before {\n  content: \"\\f82f\"; }\n\n.fa-user-plus:before {\n  content: \"\\f234\"; }\n\n.fa-user-secret:before {\n  content: \"\\f21b\"; }\n\n.fa-user-shield:before {\n  content: \"\\f505\"; }\n\n.fa-user-slash:before {\n  content: \"\\f506\"; }\n\n.fa-user-tag:before {\n  content: \"\\f507\"; }\n\n.fa-user-tie:before {\n  content: \"\\f508\"; }\n\n.fa-user-times:before {\n  content: \"\\f235\"; }\n\n.fa-users:before {\n  content: \"\\f0c0\"; }\n\n.fa-users-cog:before {\n  content: \"\\f509\"; }\n\n.fa-users-slash:before {\n  content: \"\\e073\"; }\n\n.fa-usps:before {\n  content: \"\\f7e1\"; }\n\n.fa-ussunnah:before {\n  content: \"\\f407\"; }\n\n.fa-utensil-spoon:before {\n  content: \"\\f2e5\"; }\n\n.fa-utensils:before {\n  content: \"\\f2e7\"; }\n\n.fa-vaadin:before {\n  content: \"\\f408\"; }\n\n.fa-vector-square:before {\n  content: \"\\f5cb\"; }\n\n.fa-venus:before {\n  content: \"\\f221\"; }\n\n.fa-venus-double:before {\n  content: \"\\f226\"; }\n\n.fa-venus-mars:before {\n  content: \"\\f228\"; }\n\n.fa-vest:before {\n  content: \"\\e085\"; }\n\n.fa-vest-patches:before {\n  content: \"\\e086\"; }\n\n.fa-viacoin:before {\n  content: \"\\f237\"; }\n\n.fa-viadeo:before {\n  content: \"\\f2a9\"; }\n\n.fa-viadeo-square:before {\n  content: \"\\f2aa\"; }\n\n.fa-vial:before {\n  content: \"\\f492\"; }\n\n.fa-vials:before {\n  content: \"\\f493\"; }\n\n.fa-viber:before {\n  content: \"\\f409\"; }\n\n.fa-video:before {\n  content: \"\\f03d\"; }\n\n.fa-video-slash:before {\n  content: \"\\f4e2\"; }\n\n.fa-vihara:before {\n  content: \"\\f6a7\"; }\n\n.fa-vimeo:before {\n  content: \"\\f40a\"; }\n\n.fa-vimeo-square:before {\n  content: \"\\f194\"; }\n\n.fa-vimeo-v:before {\n  content: \"\\f27d\"; }\n\n.fa-vine:before {\n  content: \"\\f1ca\"; }\n\n.fa-virus:before {\n  content: \"\\e074\"; }\n\n.fa-virus-slash:before {\n  content: \"\\e075\"; }\n\n.fa-viruses:before {\n  content: \"\\e076\"; }\n\n.fa-vk:before {\n  content: \"\\f189\"; }\n\n.fa-vnv:before {\n  content: \"\\f40b\"; }\n\n.fa-voicemail:before {\n  content: \"\\f897\"; }\n\n.fa-volleyball-ball:before {\n  content: \"\\f45f\"; }\n\n.fa-volume-down:before {\n  content: \"\\f027\"; }\n\n.fa-volume-mute:before {\n  content: \"\\f6a9\"; }\n\n.fa-volume-off:before {\n  content: \"\\f026\"; }\n\n.fa-volume-up:before {\n  content: \"\\f028\"; }\n\n.fa-vote-yea:before {\n  content: \"\\f772\"; }\n\n.fa-vr-cardboard:before {\n  content: \"\\f729\"; }\n\n.fa-vuejs:before {\n  content: \"\\f41f\"; }\n\n.fa-walking:before {\n  content: \"\\f554\"; }\n\n.fa-wallet:before {\n  content: \"\\f555\"; }\n\n.fa-warehouse:before {\n  content: \"\\f494\"; }\n\n.fa-watchman-monitoring:before {\n  content: \"\\e087\"; }\n\n.fa-water:before {\n  content: \"\\f773\"; }\n\n.fa-wave-square:before {\n  content: \"\\f83e\"; }\n\n.fa-waze:before {\n  content: \"\\f83f\"; }\n\n.fa-weebly:before {\n  content: \"\\f5cc\"; }\n\n.fa-weibo:before {\n  content: \"\\f18a\"; }\n\n.fa-weight:before {\n  content: \"\\f496\"; }\n\n.fa-weight-hanging:before {\n  content: \"\\f5cd\"; }\n\n.fa-weixin:before {\n  content: \"\\f1d7\"; }\n\n.fa-whatsapp:before {\n  content: \"\\f232\"; }\n\n.fa-whatsapp-square:before {\n  content: \"\\f40c\"; }\n\n.fa-wheelchair:before {\n  content: \"\\f193\"; }\n\n.fa-whmcs:before {\n  content: \"\\f40d\"; }\n\n.fa-wifi:before {\n  content: \"\\f1eb\"; }\n\n.fa-wikipedia-w:before {\n  content: \"\\f266\"; }\n\n.fa-wind:before {\n  content: \"\\f72e\"; }\n\n.fa-window-close:before {\n  content: \"\\f410\"; }\n\n.fa-window-maximize:before {\n  content: \"\\f2d0\"; }\n\n.fa-window-minimize:before {\n  content: \"\\f2d1\"; }\n\n.fa-window-restore:before {\n  content: \"\\f2d2\"; }\n\n.fa-windows:before {\n  content: \"\\f17a\"; }\n\n.fa-wine-bottle:before {\n  content: \"\\f72f\"; }\n\n.fa-wine-glass:before {\n  content: \"\\f4e3\"; }\n\n.fa-wine-glass-alt:before {\n  content: \"\\f5ce\"; }\n\n.fa-wix:before {\n  content: \"\\f5cf\"; }\n\n.fa-wizards-of-the-coast:before {\n  content: \"\\f730\"; }\n\n.fa-wodu:before {\n  content: \"\\e088\"; }\n\n.fa-wolf-pack-battalion:before {\n  content: \"\\f514\"; }\n\n.fa-won-sign:before {\n  content: \"\\f159\"; }\n\n.fa-wordpress:before {\n  content: \"\\f19a\"; }\n\n.fa-wordpress-simple:before {\n  content: \"\\f411\"; }\n\n.fa-wpbeginner:before {\n  content: \"\\f297\"; }\n\n.fa-wpexplorer:before {\n  content: \"\\f2de\"; }\n\n.fa-wpforms:before {\n  content: \"\\f298\"; }\n\n.fa-wpressr:before {\n  content: \"\\f3e4\"; }\n\n.fa-wrench:before {\n  content: \"\\f0ad\"; }\n\n.fa-x-ray:before {\n  content: \"\\f497\"; }\n\n.fa-xbox:before {\n  content: \"\\f412\"; }\n\n.fa-xing:before {\n  content: \"\\f168\"; }\n\n.fa-xing-square:before {\n  content: \"\\f169\"; }\n\n.fa-y-combinator:before {\n  content: \"\\f23b\"; }\n\n.fa-yahoo:before {\n  content: \"\\f19e\"; }\n\n.fa-yammer:before {\n  content: \"\\f840\"; }\n\n.fa-yandex:before {\n  content: \"\\f413\"; }\n\n.fa-yandex-international:before {\n  content: \"\\f414\"; }\n\n.fa-yarn:before {\n  content: \"\\f7e3\"; }\n\n.fa-yelp:before {\n  content: \"\\f1e9\"; }\n\n.fa-yen-sign:before {\n  content: \"\\f157\"; }\n\n.fa-yin-yang:before {\n  content: \"\\f6ad\"; }\n\n.fa-yoast:before {\n  content: \"\\f2b1\"; }\n\n.fa-youtube:before {\n  content: \"\\f167\"; }\n\n.fa-youtube-square:before {\n  content: \"\\f431\"; }\n\n.fa-zhihu:before {\n  content: \"\\f63f\"; }\n\n.sr-only {\n  border: 0;\n  clip: rect(0, 0, 0, 0);\n  height: 1px;\n  margin: -1px;\n  overflow: hidden;\n  padding: 0;\n  position: absolute;\n  width: 1px; }\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n  clip: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  position: static;\n  width: auto; }\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/fontawesome.min.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.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-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:\"\\f26e\"}.fa-accessible-icon:before{content:\"\\f368\"}.fa-accusoft:before{content:\"\\f369\"}.fa-acquisitions-incorporated:before{content:\"\\f6af\"}.fa-ad:before{content:\"\\f641\"}.fa-address-book:before{content:\"\\f2b9\"}.fa-address-card:before{content:\"\\f2bb\"}.fa-adjust:before{content:\"\\f042\"}.fa-adn:before{content:\"\\f170\"}.fa-adversal:before{content:\"\\f36a\"}.fa-affiliatetheme:before{content:\"\\f36b\"}.fa-air-freshener:before{content:\"\\f5d0\"}.fa-airbnb:before{content:\"\\f834\"}.fa-algolia:before{content:\"\\f36c\"}.fa-align-center:before{content:\"\\f037\"}.fa-align-justify:before{content:\"\\f039\"}.fa-align-left:before{content:\"\\f036\"}.fa-align-right:before{content:\"\\f038\"}.fa-alipay:before{content:\"\\f642\"}.fa-allergies:before{content:\"\\f461\"}.fa-amazon:before{content:\"\\f270\"}.fa-amazon-pay:before{content:\"\\f42c\"}.fa-ambulance:before{content:\"\\f0f9\"}.fa-american-sign-language-interpreting:before{content:\"\\f2a3\"}.fa-amilia:before{content:\"\\f36d\"}.fa-anchor:before{content:\"\\f13d\"}.fa-android:before{content:\"\\f17b\"}.fa-angellist:before{content:\"\\f209\"}.fa-angle-double-down:before{content:\"\\f103\"}.fa-angle-double-left:before{content:\"\\f100\"}.fa-angle-double-right:before{content:\"\\f101\"}.fa-angle-double-up:before{content:\"\\f102\"}.fa-angle-down:before{content:\"\\f107\"}.fa-angle-left:before{content:\"\\f104\"}.fa-angle-right:before{content:\"\\f105\"}.fa-angle-up:before{content:\"\\f106\"}.fa-angry:before{content:\"\\f556\"}.fa-angrycreative:before{content:\"\\f36e\"}.fa-angular:before{content:\"\\f420\"}.fa-ankh:before{content:\"\\f644\"}.fa-app-store:before{content:\"\\f36f\"}.fa-app-store-ios:before{content:\"\\f370\"}.fa-apper:before{content:\"\\f371\"}.fa-apple:before{content:\"\\f179\"}.fa-apple-alt:before{content:\"\\f5d1\"}.fa-apple-pay:before{content:\"\\f415\"}.fa-archive:before{content:\"\\f187\"}.fa-archway:before{content:\"\\f557\"}.fa-arrow-alt-circle-down:before{content:\"\\f358\"}.fa-arrow-alt-circle-left:before{content:\"\\f359\"}.fa-arrow-alt-circle-right:before{content:\"\\f35a\"}.fa-arrow-alt-circle-up:before{content:\"\\f35b\"}.fa-arrow-circle-down:before{content:\"\\f0ab\"}.fa-arrow-circle-left:before{content:\"\\f0a8\"}.fa-arrow-circle-right:before{content:\"\\f0a9\"}.fa-arrow-circle-up:before{content:\"\\f0aa\"}.fa-arrow-down:before{content:\"\\f063\"}.fa-arrow-left:before{content:\"\\f060\"}.fa-arrow-right:before{content:\"\\f061\"}.fa-arrow-up:before{content:\"\\f062\"}.fa-arrows-alt:before{content:\"\\f0b2\"}.fa-arrows-alt-h:before{content:\"\\f337\"}.fa-arrows-alt-v:before{content:\"\\f338\"}.fa-artstation:before{content:\"\\f77a\"}.fa-assistive-listening-systems:before{content:\"\\f2a2\"}.fa-asterisk:before{content:\"\\f069\"}.fa-asymmetrik:before{content:\"\\f372\"}.fa-at:before{content:\"\\f1fa\"}.fa-atlas:before{content:\"\\f558\"}.fa-atlassian:before{content:\"\\f77b\"}.fa-atom:before{content:\"\\f5d2\"}.fa-audible:before{content:\"\\f373\"}.fa-audio-description:before{content:\"\\f29e\"}.fa-autoprefixer:before{content:\"\\f41c\"}.fa-avianex:before{content:\"\\f374\"}.fa-aviato:before{content:\"\\f421\"}.fa-award:before{content:\"\\f559\"}.fa-aws:before{content:\"\\f375\"}.fa-baby:before{content:\"\\f77c\"}.fa-baby-carriage:before{content:\"\\f77d\"}.fa-backspace:before{content:\"\\f55a\"}.fa-backward:before{content:\"\\f04a\"}.fa-bacon:before{content:\"\\f7e5\"}.fa-bacteria:before{content:\"\\e059\"}.fa-bacterium:before{content:\"\\e05a\"}.fa-bahai:before{content:\"\\f666\"}.fa-balance-scale:before{content:\"\\f24e\"}.fa-balance-scale-left:before{content:\"\\f515\"}.fa-balance-scale-right:before{content:\"\\f516\"}.fa-ban:before{content:\"\\f05e\"}.fa-band-aid:before{content:\"\\f462\"}.fa-bandcamp:before{content:\"\\f2d5\"}.fa-barcode:before{content:\"\\f02a\"}.fa-bars:before{content:\"\\f0c9\"}.fa-baseball-ball:before{content:\"\\f433\"}.fa-basketball-ball:before{content:\"\\f434\"}.fa-bath:before{content:\"\\f2cd\"}.fa-battery-empty:before{content:\"\\f244\"}.fa-battery-full:before{content:\"\\f240\"}.fa-battery-half:before{content:\"\\f242\"}.fa-battery-quarter:before{content:\"\\f243\"}.fa-battery-three-quarters:before{content:\"\\f241\"}.fa-battle-net:before{content:\"\\f835\"}.fa-bed:before{content:\"\\f236\"}.fa-beer:before{content:\"\\f0fc\"}.fa-behance:before{content:\"\\f1b4\"}.fa-behance-square:before{content:\"\\f1b5\"}.fa-bell:before{content:\"\\f0f3\"}.fa-bell-slash:before{content:\"\\f1f6\"}.fa-bezier-curve:before{content:\"\\f55b\"}.fa-bible:before{content:\"\\f647\"}.fa-bicycle:before{content:\"\\f206\"}.fa-biking:before{content:\"\\f84a\"}.fa-bimobject:before{content:\"\\f378\"}.fa-binoculars:before{content:\"\\f1e5\"}.fa-biohazard:before{content:\"\\f780\"}.fa-birthday-cake:before{content:\"\\f1fd\"}.fa-bitbucket:before{content:\"\\f171\"}.fa-bitcoin:before{content:\"\\f379\"}.fa-bity:before{content:\"\\f37a\"}.fa-black-tie:before{content:\"\\f27e\"}.fa-blackberry:before{content:\"\\f37b\"}.fa-blender:before{content:\"\\f517\"}.fa-blender-phone:before{content:\"\\f6b6\"}.fa-blind:before{content:\"\\f29d\"}.fa-blog:before{content:\"\\f781\"}.fa-blogger:before{content:\"\\f37c\"}.fa-blogger-b:before{content:\"\\f37d\"}.fa-bluetooth:before{content:\"\\f293\"}.fa-bluetooth-b:before{content:\"\\f294\"}.fa-bold:before{content:\"\\f032\"}.fa-bolt:before{content:\"\\f0e7\"}.fa-bomb:before{content:\"\\f1e2\"}.fa-bone:before{content:\"\\f5d7\"}.fa-bong:before{content:\"\\f55c\"}.fa-book:before{content:\"\\f02d\"}.fa-book-dead:before{content:\"\\f6b7\"}.fa-book-medical:before{content:\"\\f7e6\"}.fa-book-open:before{content:\"\\f518\"}.fa-book-reader:before{content:\"\\f5da\"}.fa-bookmark:before{content:\"\\f02e\"}.fa-bootstrap:before{content:\"\\f836\"}.fa-border-all:before{content:\"\\f84c\"}.fa-border-none:before{content:\"\\f850\"}.fa-border-style:before{content:\"\\f853\"}.fa-bowling-ball:before{content:\"\\f436\"}.fa-box:before{content:\"\\f466\"}.fa-box-open:before{content:\"\\f49e\"}.fa-box-tissue:before{content:\"\\e05b\"}.fa-boxes:before{content:\"\\f468\"}.fa-braille:before{content:\"\\f2a1\"}.fa-brain:before{content:\"\\f5dc\"}.fa-bread-slice:before{content:\"\\f7ec\"}.fa-briefcase:before{content:\"\\f0b1\"}.fa-briefcase-medical:before{content:\"\\f469\"}.fa-broadcast-tower:before{content:\"\\f519\"}.fa-broom:before{content:\"\\f51a\"}.fa-brush:before{content:\"\\f55d\"}.fa-btc:before{content:\"\\f15a\"}.fa-buffer:before{content:\"\\f837\"}.fa-bug:before{content:\"\\f188\"}.fa-building:before{content:\"\\f1ad\"}.fa-bullhorn:before{content:\"\\f0a1\"}.fa-bullseye:before{content:\"\\f140\"}.fa-burn:before{content:\"\\f46a\"}.fa-buromobelexperte:before{content:\"\\f37f\"}.fa-bus:before{content:\"\\f207\"}.fa-bus-alt:before{content:\"\\f55e\"}.fa-business-time:before{content:\"\\f64a\"}.fa-buy-n-large:before{content:\"\\f8a6\"}.fa-buysellads:before{content:\"\\f20d\"}.fa-calculator:before{content:\"\\f1ec\"}.fa-calendar:before{content:\"\\f133\"}.fa-calendar-alt:before{content:\"\\f073\"}.fa-calendar-check:before{content:\"\\f274\"}.fa-calendar-day:before{content:\"\\f783\"}.fa-calendar-minus:before{content:\"\\f272\"}.fa-calendar-plus:before{content:\"\\f271\"}.fa-calendar-times:before{content:\"\\f273\"}.fa-calendar-week:before{content:\"\\f784\"}.fa-camera:before{content:\"\\f030\"}.fa-camera-retro:before{content:\"\\f083\"}.fa-campground:before{content:\"\\f6bb\"}.fa-canadian-maple-leaf:before{content:\"\\f785\"}.fa-candy-cane:before{content:\"\\f786\"}.fa-cannabis:before{content:\"\\f55f\"}.fa-capsules:before{content:\"\\f46b\"}.fa-car:before{content:\"\\f1b9\"}.fa-car-alt:before{content:\"\\f5de\"}.fa-car-battery:before{content:\"\\f5df\"}.fa-car-crash:before{content:\"\\f5e1\"}.fa-car-side:before{content:\"\\f5e4\"}.fa-caravan:before{content:\"\\f8ff\"}.fa-caret-down:before{content:\"\\f0d7\"}.fa-caret-left:before{content:\"\\f0d9\"}.fa-caret-right:before{content:\"\\f0da\"}.fa-caret-square-down:before{content:\"\\f150\"}.fa-caret-square-left:before{content:\"\\f191\"}.fa-caret-square-right:before{content:\"\\f152\"}.fa-caret-square-up:before{content:\"\\f151\"}.fa-caret-up:before{content:\"\\f0d8\"}.fa-carrot:before{content:\"\\f787\"}.fa-cart-arrow-down:before{content:\"\\f218\"}.fa-cart-plus:before{content:\"\\f217\"}.fa-cash-register:before{content:\"\\f788\"}.fa-cat:before{content:\"\\f6be\"}.fa-cc-amazon-pay:before{content:\"\\f42d\"}.fa-cc-amex:before{content:\"\\f1f3\"}.fa-cc-apple-pay:before{content:\"\\f416\"}.fa-cc-diners-club:before{content:\"\\f24c\"}.fa-cc-discover:before{content:\"\\f1f2\"}.fa-cc-jcb:before{content:\"\\f24b\"}.fa-cc-mastercard:before{content:\"\\f1f1\"}.fa-cc-paypal:before{content:\"\\f1f4\"}.fa-cc-stripe:before{content:\"\\f1f5\"}.fa-cc-visa:before{content:\"\\f1f0\"}.fa-centercode:before{content:\"\\f380\"}.fa-centos:before{content:\"\\f789\"}.fa-certificate:before{content:\"\\f0a3\"}.fa-chair:before{content:\"\\f6c0\"}.fa-chalkboard:before{content:\"\\f51b\"}.fa-chalkboard-teacher:before{content:\"\\f51c\"}.fa-charging-station:before{content:\"\\f5e7\"}.fa-chart-area:before{content:\"\\f1fe\"}.fa-chart-bar:before{content:\"\\f080\"}.fa-chart-line:before{content:\"\\f201\"}.fa-chart-pie:before{content:\"\\f200\"}.fa-check:before{content:\"\\f00c\"}.fa-check-circle:before{content:\"\\f058\"}.fa-check-double:before{content:\"\\f560\"}.fa-check-square:before{content:\"\\f14a\"}.fa-cheese:before{content:\"\\f7ef\"}.fa-chess:before{content:\"\\f439\"}.fa-chess-bishop:before{content:\"\\f43a\"}.fa-chess-board:before{content:\"\\f43c\"}.fa-chess-king:before{content:\"\\f43f\"}.fa-chess-knight:before{content:\"\\f441\"}.fa-chess-pawn:before{content:\"\\f443\"}.fa-chess-queen:before{content:\"\\f445\"}.fa-chess-rook:before{content:\"\\f447\"}.fa-chevron-circle-down:before{content:\"\\f13a\"}.fa-chevron-circle-left:before{content:\"\\f137\"}.fa-chevron-circle-right:before{content:\"\\f138\"}.fa-chevron-circle-up:before{content:\"\\f139\"}.fa-chevron-down:before{content:\"\\f078\"}.fa-chevron-left:before{content:\"\\f053\"}.fa-chevron-right:before{content:\"\\f054\"}.fa-chevron-up:before{content:\"\\f077\"}.fa-child:before{content:\"\\f1ae\"}.fa-chrome:before{content:\"\\f268\"}.fa-chromecast:before{content:\"\\f838\"}.fa-church:before{content:\"\\f51d\"}.fa-circle:before{content:\"\\f111\"}.fa-circle-notch:before{content:\"\\f1ce\"}.fa-city:before{content:\"\\f64f\"}.fa-clinic-medical:before{content:\"\\f7f2\"}.fa-clipboard:before{content:\"\\f328\"}.fa-clipboard-check:before{content:\"\\f46c\"}.fa-clipboard-list:before{content:\"\\f46d\"}.fa-clock:before{content:\"\\f017\"}.fa-clone:before{content:\"\\f24d\"}.fa-closed-captioning:before{content:\"\\f20a\"}.fa-cloud:before{content:\"\\f0c2\"}.fa-cloud-download-alt:before{content:\"\\f381\"}.fa-cloud-meatball:before{content:\"\\f73b\"}.fa-cloud-moon:before{content:\"\\f6c3\"}.fa-cloud-moon-rain:before{content:\"\\f73c\"}.fa-cloud-rain:before{content:\"\\f73d\"}.fa-cloud-showers-heavy:before{content:\"\\f740\"}.fa-cloud-sun:before{content:\"\\f6c4\"}.fa-cloud-sun-rain:before{content:\"\\f743\"}.fa-cloud-upload-alt:before{content:\"\\f382\"}.fa-cloudflare:before{content:\"\\e07d\"}.fa-cloudscale:before{content:\"\\f383\"}.fa-cloudsmith:before{content:\"\\f384\"}.fa-cloudversify:before{content:\"\\f385\"}.fa-cocktail:before{content:\"\\f561\"}.fa-code:before{content:\"\\f121\"}.fa-code-branch:before{content:\"\\f126\"}.fa-codepen:before{content:\"\\f1cb\"}.fa-codiepie:before{content:\"\\f284\"}.fa-coffee:before{content:\"\\f0f4\"}.fa-cog:before{content:\"\\f013\"}.fa-cogs:before{content:\"\\f085\"}.fa-coins:before{content:\"\\f51e\"}.fa-columns:before{content:\"\\f0db\"}.fa-comment:before{content:\"\\f075\"}.fa-comment-alt:before{content:\"\\f27a\"}.fa-comment-dollar:before{content:\"\\f651\"}.fa-comment-dots:before{content:\"\\f4ad\"}.fa-comment-medical:before{content:\"\\f7f5\"}.fa-comment-slash:before{content:\"\\f4b3\"}.fa-comments:before{content:\"\\f086\"}.fa-comments-dollar:before{content:\"\\f653\"}.fa-compact-disc:before{content:\"\\f51f\"}.fa-compass:before{content:\"\\f14e\"}.fa-compress:before{content:\"\\f066\"}.fa-compress-alt:before{content:\"\\f422\"}.fa-compress-arrows-alt:before{content:\"\\f78c\"}.fa-concierge-bell:before{content:\"\\f562\"}.fa-confluence:before{content:\"\\f78d\"}.fa-connectdevelop:before{content:\"\\f20e\"}.fa-contao:before{content:\"\\f26d\"}.fa-cookie:before{content:\"\\f563\"}.fa-cookie-bite:before{content:\"\\f564\"}.fa-copy:before{content:\"\\f0c5\"}.fa-copyright:before{content:\"\\f1f9\"}.fa-cotton-bureau:before{content:\"\\f89e\"}.fa-couch:before{content:\"\\f4b8\"}.fa-cpanel:before{content:\"\\f388\"}.fa-creative-commons:before{content:\"\\f25e\"}.fa-creative-commons-by:before{content:\"\\f4e7\"}.fa-creative-commons-nc:before{content:\"\\f4e8\"}.fa-creative-commons-nc-eu:before{content:\"\\f4e9\"}.fa-creative-commons-nc-jp:before{content:\"\\f4ea\"}.fa-creative-commons-nd:before{content:\"\\f4eb\"}.fa-creative-commons-pd:before{content:\"\\f4ec\"}.fa-creative-commons-pd-alt:before{content:\"\\f4ed\"}.fa-creative-commons-remix:before{content:\"\\f4ee\"}.fa-creative-commons-sa:before{content:\"\\f4ef\"}.fa-creative-commons-sampling:before{content:\"\\f4f0\"}.fa-creative-commons-sampling-plus:before{content:\"\\f4f1\"}.fa-creative-commons-share:before{content:\"\\f4f2\"}.fa-creative-commons-zero:before{content:\"\\f4f3\"}.fa-credit-card:before{content:\"\\f09d\"}.fa-critical-role:before{content:\"\\f6c9\"}.fa-crop:before{content:\"\\f125\"}.fa-crop-alt:before{content:\"\\f565\"}.fa-cross:before{content:\"\\f654\"}.fa-crosshairs:before{content:\"\\f05b\"}.fa-crow:before{content:\"\\f520\"}.fa-crown:before{content:\"\\f521\"}.fa-crutch:before{content:\"\\f7f7\"}.fa-css3:before{content:\"\\f13c\"}.fa-css3-alt:before{content:\"\\f38b\"}.fa-cube:before{content:\"\\f1b2\"}.fa-cubes:before{content:\"\\f1b3\"}.fa-cut:before{content:\"\\f0c4\"}.fa-cuttlefish:before{content:\"\\f38c\"}.fa-d-and-d:before{content:\"\\f38d\"}.fa-d-and-d-beyond:before{content:\"\\f6ca\"}.fa-dailymotion:before{content:\"\\e052\"}.fa-dashcube:before{content:\"\\f210\"}.fa-database:before{content:\"\\f1c0\"}.fa-deaf:before{content:\"\\f2a4\"}.fa-deezer:before{content:\"\\e077\"}.fa-delicious:before{content:\"\\f1a5\"}.fa-democrat:before{content:\"\\f747\"}.fa-deploydog:before{content:\"\\f38e\"}.fa-deskpro:before{content:\"\\f38f\"}.fa-desktop:before{content:\"\\f108\"}.fa-dev:before{content:\"\\f6cc\"}.fa-deviantart:before{content:\"\\f1bd\"}.fa-dharmachakra:before{content:\"\\f655\"}.fa-dhl:before{content:\"\\f790\"}.fa-diagnoses:before{content:\"\\f470\"}.fa-diaspora:before{content:\"\\f791\"}.fa-dice:before{content:\"\\f522\"}.fa-dice-d20:before{content:\"\\f6cf\"}.fa-dice-d6:before{content:\"\\f6d1\"}.fa-dice-five:before{content:\"\\f523\"}.fa-dice-four:before{content:\"\\f524\"}.fa-dice-one:before{content:\"\\f525\"}.fa-dice-six:before{content:\"\\f526\"}.fa-dice-three:before{content:\"\\f527\"}.fa-dice-two:before{content:\"\\f528\"}.fa-digg:before{content:\"\\f1a6\"}.fa-digital-ocean:before{content:\"\\f391\"}.fa-digital-tachograph:before{content:\"\\f566\"}.fa-directions:before{content:\"\\f5eb\"}.fa-discord:before{content:\"\\f392\"}.fa-discourse:before{content:\"\\f393\"}.fa-disease:before{content:\"\\f7fa\"}.fa-divide:before{content:\"\\f529\"}.fa-dizzy:before{content:\"\\f567\"}.fa-dna:before{content:\"\\f471\"}.fa-dochub:before{content:\"\\f394\"}.fa-docker:before{content:\"\\f395\"}.fa-dog:before{content:\"\\f6d3\"}.fa-dollar-sign:before{content:\"\\f155\"}.fa-dolly:before{content:\"\\f472\"}.fa-dolly-flatbed:before{content:\"\\f474\"}.fa-donate:before{content:\"\\f4b9\"}.fa-door-closed:before{content:\"\\f52a\"}.fa-door-open:before{content:\"\\f52b\"}.fa-dot-circle:before{content:\"\\f192\"}.fa-dove:before{content:\"\\f4ba\"}.fa-download:before{content:\"\\f019\"}.fa-draft2digital:before{content:\"\\f396\"}.fa-drafting-compass:before{content:\"\\f568\"}.fa-dragon:before{content:\"\\f6d5\"}.fa-draw-polygon:before{content:\"\\f5ee\"}.fa-dribbble:before{content:\"\\f17d\"}.fa-dribbble-square:before{content:\"\\f397\"}.fa-dropbox:before{content:\"\\f16b\"}.fa-drum:before{content:\"\\f569\"}.fa-drum-steelpan:before{content:\"\\f56a\"}.fa-drumstick-bite:before{content:\"\\f6d7\"}.fa-drupal:before{content:\"\\f1a9\"}.fa-dumbbell:before{content:\"\\f44b\"}.fa-dumpster:before{content:\"\\f793\"}.fa-dumpster-fire:before{content:\"\\f794\"}.fa-dungeon:before{content:\"\\f6d9\"}.fa-dyalog:before{content:\"\\f399\"}.fa-earlybirds:before{content:\"\\f39a\"}.fa-ebay:before{content:\"\\f4f4\"}.fa-edge:before{content:\"\\f282\"}.fa-edge-legacy:before{content:\"\\e078\"}.fa-edit:before{content:\"\\f044\"}.fa-egg:before{content:\"\\f7fb\"}.fa-eject:before{content:\"\\f052\"}.fa-elementor:before{content:\"\\f430\"}.fa-ellipsis-h:before{content:\"\\f141\"}.fa-ellipsis-v:before{content:\"\\f142\"}.fa-ello:before{content:\"\\f5f1\"}.fa-ember:before{content:\"\\f423\"}.fa-empire:before{content:\"\\f1d1\"}.fa-envelope:before{content:\"\\f0e0\"}.fa-envelope-open:before{content:\"\\f2b6\"}.fa-envelope-open-text:before{content:\"\\f658\"}.fa-envelope-square:before{content:\"\\f199\"}.fa-envira:before{content:\"\\f299\"}.fa-equals:before{content:\"\\f52c\"}.fa-eraser:before{content:\"\\f12d\"}.fa-erlang:before{content:\"\\f39d\"}.fa-ethereum:before{content:\"\\f42e\"}.fa-ethernet:before{content:\"\\f796\"}.fa-etsy:before{content:\"\\f2d7\"}.fa-euro-sign:before{content:\"\\f153\"}.fa-evernote:before{content:\"\\f839\"}.fa-exchange-alt:before{content:\"\\f362\"}.fa-exclamation:before{content:\"\\f12a\"}.fa-exclamation-circle:before{content:\"\\f06a\"}.fa-exclamation-triangle:before{content:\"\\f071\"}.fa-expand:before{content:\"\\f065\"}.fa-expand-alt:before{content:\"\\f424\"}.fa-expand-arrows-alt:before{content:\"\\f31e\"}.fa-expeditedssl:before{content:\"\\f23e\"}.fa-external-link-alt:before{content:\"\\f35d\"}.fa-external-link-square-alt:before{content:\"\\f360\"}.fa-eye:before{content:\"\\f06e\"}.fa-eye-dropper:before{content:\"\\f1fb\"}.fa-eye-slash:before{content:\"\\f070\"}.fa-facebook:before{content:\"\\f09a\"}.fa-facebook-f:before{content:\"\\f39e\"}.fa-facebook-messenger:before{content:\"\\f39f\"}.fa-facebook-square:before{content:\"\\f082\"}.fa-fan:before{content:\"\\f863\"}.fa-fantasy-flight-games:before{content:\"\\f6dc\"}.fa-fast-backward:before{content:\"\\f049\"}.fa-fast-forward:before{content:\"\\f050\"}.fa-faucet:before{content:\"\\e005\"}.fa-fax:before{content:\"\\f1ac\"}.fa-feather:before{content:\"\\f52d\"}.fa-feather-alt:before{content:\"\\f56b\"}.fa-fedex:before{content:\"\\f797\"}.fa-fedora:before{content:\"\\f798\"}.fa-female:before{content:\"\\f182\"}.fa-fighter-jet:before{content:\"\\f0fb\"}.fa-figma:before{content:\"\\f799\"}.fa-file:before{content:\"\\f15b\"}.fa-file-alt:before{content:\"\\f15c\"}.fa-file-archive:before{content:\"\\f1c6\"}.fa-file-audio:before{content:\"\\f1c7\"}.fa-file-code:before{content:\"\\f1c9\"}.fa-file-contract:before{content:\"\\f56c\"}.fa-file-csv:before{content:\"\\f6dd\"}.fa-file-download:before{content:\"\\f56d\"}.fa-file-excel:before{content:\"\\f1c3\"}.fa-file-export:before{content:\"\\f56e\"}.fa-file-image:before{content:\"\\f1c5\"}.fa-file-import:before{content:\"\\f56f\"}.fa-file-invoice:before{content:\"\\f570\"}.fa-file-invoice-dollar:before{content:\"\\f571\"}.fa-file-medical:before{content:\"\\f477\"}.fa-file-medical-alt:before{content:\"\\f478\"}.fa-file-pdf:before{content:\"\\f1c1\"}.fa-file-powerpoint:before{content:\"\\f1c4\"}.fa-file-prescription:before{content:\"\\f572\"}.fa-file-signature:before{content:\"\\f573\"}.fa-file-upload:before{content:\"\\f574\"}.fa-file-video:before{content:\"\\f1c8\"}.fa-file-word:before{content:\"\\f1c2\"}.fa-fill:before{content:\"\\f575\"}.fa-fill-drip:before{content:\"\\f576\"}.fa-film:before{content:\"\\f008\"}.fa-filter:before{content:\"\\f0b0\"}.fa-fingerprint:before{content:\"\\f577\"}.fa-fire:before{content:\"\\f06d\"}.fa-fire-alt:before{content:\"\\f7e4\"}.fa-fire-extinguisher:before{content:\"\\f134\"}.fa-firefox:before{content:\"\\f269\"}.fa-firefox-browser:before{content:\"\\e007\"}.fa-first-aid:before{content:\"\\f479\"}.fa-first-order:before{content:\"\\f2b0\"}.fa-first-order-alt:before{content:\"\\f50a\"}.fa-firstdraft:before{content:\"\\f3a1\"}.fa-fish:before{content:\"\\f578\"}.fa-fist-raised:before{content:\"\\f6de\"}.fa-flag:before{content:\"\\f024\"}.fa-flag-checkered:before{content:\"\\f11e\"}.fa-flag-usa:before{content:\"\\f74d\"}.fa-flask:before{content:\"\\f0c3\"}.fa-flickr:before{content:\"\\f16e\"}.fa-flipboard:before{content:\"\\f44d\"}.fa-flushed:before{content:\"\\f579\"}.fa-fly:before{content:\"\\f417\"}.fa-folder:before{content:\"\\f07b\"}.fa-folder-minus:before{content:\"\\f65d\"}.fa-folder-open:before{content:\"\\f07c\"}.fa-folder-plus:before{content:\"\\f65e\"}.fa-font:before{content:\"\\f031\"}.fa-font-awesome:before{content:\"\\f2b4\"}.fa-font-awesome-alt:before{content:\"\\f35c\"}.fa-font-awesome-flag:before{content:\"\\f425\"}.fa-font-awesome-logo-full:before{content:\"\\f4e6\"}.fa-fonticons:before{content:\"\\f280\"}.fa-fonticons-fi:before{content:\"\\f3a2\"}.fa-football-ball:before{content:\"\\f44e\"}.fa-fort-awesome:before{content:\"\\f286\"}.fa-fort-awesome-alt:before{content:\"\\f3a3\"}.fa-forumbee:before{content:\"\\f211\"}.fa-forward:before{content:\"\\f04e\"}.fa-foursquare:before{content:\"\\f180\"}.fa-free-code-camp:before{content:\"\\f2c5\"}.fa-freebsd:before{content:\"\\f3a4\"}.fa-frog:before{content:\"\\f52e\"}.fa-frown:before{content:\"\\f119\"}.fa-frown-open:before{content:\"\\f57a\"}.fa-fulcrum:before{content:\"\\f50b\"}.fa-funnel-dollar:before{content:\"\\f662\"}.fa-futbol:before{content:\"\\f1e3\"}.fa-galactic-republic:before{content:\"\\f50c\"}.fa-galactic-senate:before{content:\"\\f50d\"}.fa-gamepad:before{content:\"\\f11b\"}.fa-gas-pump:before{content:\"\\f52f\"}.fa-gavel:before{content:\"\\f0e3\"}.fa-gem:before{content:\"\\f3a5\"}.fa-genderless:before{content:\"\\f22d\"}.fa-get-pocket:before{content:\"\\f265\"}.fa-gg:before{content:\"\\f260\"}.fa-gg-circle:before{content:\"\\f261\"}.fa-ghost:before{content:\"\\f6e2\"}.fa-gift:before{content:\"\\f06b\"}.fa-gifts:before{content:\"\\f79c\"}.fa-git:before{content:\"\\f1d3\"}.fa-git-alt:before{content:\"\\f841\"}.fa-git-square:before{content:\"\\f1d2\"}.fa-github:before{content:\"\\f09b\"}.fa-github-alt:before{content:\"\\f113\"}.fa-github-square:before{content:\"\\f092\"}.fa-gitkraken:before{content:\"\\f3a6\"}.fa-gitlab:before{content:\"\\f296\"}.fa-gitter:before{content:\"\\f426\"}.fa-glass-cheers:before{content:\"\\f79f\"}.fa-glass-martini:before{content:\"\\f000\"}.fa-glass-martini-alt:before{content:\"\\f57b\"}.fa-glass-whiskey:before{content:\"\\f7a0\"}.fa-glasses:before{content:\"\\f530\"}.fa-glide:before{content:\"\\f2a5\"}.fa-glide-g:before{content:\"\\f2a6\"}.fa-globe:before{content:\"\\f0ac\"}.fa-globe-africa:before{content:\"\\f57c\"}.fa-globe-americas:before{content:\"\\f57d\"}.fa-globe-asia:before{content:\"\\f57e\"}.fa-globe-europe:before{content:\"\\f7a2\"}.fa-gofore:before{content:\"\\f3a7\"}.fa-golf-ball:before{content:\"\\f450\"}.fa-goodreads:before{content:\"\\f3a8\"}.fa-goodreads-g:before{content:\"\\f3a9\"}.fa-google:before{content:\"\\f1a0\"}.fa-google-drive:before{content:\"\\f3aa\"}.fa-google-pay:before{content:\"\\e079\"}.fa-google-play:before{content:\"\\f3ab\"}.fa-google-plus:before{content:\"\\f2b3\"}.fa-google-plus-g:before{content:\"\\f0d5\"}.fa-google-plus-square:before{content:\"\\f0d4\"}.fa-google-wallet:before{content:\"\\f1ee\"}.fa-gopuram:before{content:\"\\f664\"}.fa-graduation-cap:before{content:\"\\f19d\"}.fa-gratipay:before{content:\"\\f184\"}.fa-grav:before{content:\"\\f2d6\"}.fa-greater-than:before{content:\"\\f531\"}.fa-greater-than-equal:before{content:\"\\f532\"}.fa-grimace:before{content:\"\\f57f\"}.fa-grin:before{content:\"\\f580\"}.fa-grin-alt:before{content:\"\\f581\"}.fa-grin-beam:before{content:\"\\f582\"}.fa-grin-beam-sweat:before{content:\"\\f583\"}.fa-grin-hearts:before{content:\"\\f584\"}.fa-grin-squint:before{content:\"\\f585\"}.fa-grin-squint-tears:before{content:\"\\f586\"}.fa-grin-stars:before{content:\"\\f587\"}.fa-grin-tears:before{content:\"\\f588\"}.fa-grin-tongue:before{content:\"\\f589\"}.fa-grin-tongue-squint:before{content:\"\\f58a\"}.fa-grin-tongue-wink:before{content:\"\\f58b\"}.fa-grin-wink:before{content:\"\\f58c\"}.fa-grip-horizontal:before{content:\"\\f58d\"}.fa-grip-lines:before{content:\"\\f7a4\"}.fa-grip-lines-vertical:before{content:\"\\f7a5\"}.fa-grip-vertical:before{content:\"\\f58e\"}.fa-gripfire:before{content:\"\\f3ac\"}.fa-grunt:before{content:\"\\f3ad\"}.fa-guilded:before{content:\"\\e07e\"}.fa-guitar:before{content:\"\\f7a6\"}.fa-gulp:before{content:\"\\f3ae\"}.fa-h-square:before{content:\"\\f0fd\"}.fa-hacker-news:before{content:\"\\f1d4\"}.fa-hacker-news-square:before{content:\"\\f3af\"}.fa-hackerrank:before{content:\"\\f5f7\"}.fa-hamburger:before{content:\"\\f805\"}.fa-hammer:before{content:\"\\f6e3\"}.fa-hamsa:before{content:\"\\f665\"}.fa-hand-holding:before{content:\"\\f4bd\"}.fa-hand-holding-heart:before{content:\"\\f4be\"}.fa-hand-holding-medical:before{content:\"\\e05c\"}.fa-hand-holding-usd:before{content:\"\\f4c0\"}.fa-hand-holding-water:before{content:\"\\f4c1\"}.fa-hand-lizard:before{content:\"\\f258\"}.fa-hand-middle-finger:before{content:\"\\f806\"}.fa-hand-paper:before{content:\"\\f256\"}.fa-hand-peace:before{content:\"\\f25b\"}.fa-hand-point-down:before{content:\"\\f0a7\"}.fa-hand-point-left:before{content:\"\\f0a5\"}.fa-hand-point-right:before{content:\"\\f0a4\"}.fa-hand-point-up:before{content:\"\\f0a6\"}.fa-hand-pointer:before{content:\"\\f25a\"}.fa-hand-rock:before{content:\"\\f255\"}.fa-hand-scissors:before{content:\"\\f257\"}.fa-hand-sparkles:before{content:\"\\e05d\"}.fa-hand-spock:before{content:\"\\f259\"}.fa-hands:before{content:\"\\f4c2\"}.fa-hands-helping:before{content:\"\\f4c4\"}.fa-hands-wash:before{content:\"\\e05e\"}.fa-handshake:before{content:\"\\f2b5\"}.fa-handshake-alt-slash:before{content:\"\\e05f\"}.fa-handshake-slash:before{content:\"\\e060\"}.fa-hanukiah:before{content:\"\\f6e6\"}.fa-hard-hat:before{content:\"\\f807\"}.fa-hashtag:before{content:\"\\f292\"}.fa-hat-cowboy:before{content:\"\\f8c0\"}.fa-hat-cowboy-side:before{content:\"\\f8c1\"}.fa-hat-wizard:before{content:\"\\f6e8\"}.fa-hdd:before{content:\"\\f0a0\"}.fa-head-side-cough:before{content:\"\\e061\"}.fa-head-side-cough-slash:before{content:\"\\e062\"}.fa-head-side-mask:before{content:\"\\e063\"}.fa-head-side-virus:before{content:\"\\e064\"}.fa-heading:before{content:\"\\f1dc\"}.fa-headphones:before{content:\"\\f025\"}.fa-headphones-alt:before{content:\"\\f58f\"}.fa-headset:before{content:\"\\f590\"}.fa-heart:before{content:\"\\f004\"}.fa-heart-broken:before{content:\"\\f7a9\"}.fa-heartbeat:before{content:\"\\f21e\"}.fa-helicopter:before{content:\"\\f533\"}.fa-highlighter:before{content:\"\\f591\"}.fa-hiking:before{content:\"\\f6ec\"}.fa-hippo:before{content:\"\\f6ed\"}.fa-hips:before{content:\"\\f452\"}.fa-hire-a-helper:before{content:\"\\f3b0\"}.fa-history:before{content:\"\\f1da\"}.fa-hive:before{content:\"\\e07f\"}.fa-hockey-puck:before{content:\"\\f453\"}.fa-holly-berry:before{content:\"\\f7aa\"}.fa-home:before{content:\"\\f015\"}.fa-hooli:before{content:\"\\f427\"}.fa-hornbill:before{content:\"\\f592\"}.fa-horse:before{content:\"\\f6f0\"}.fa-horse-head:before{content:\"\\f7ab\"}.fa-hospital:before{content:\"\\f0f8\"}.fa-hospital-alt:before{content:\"\\f47d\"}.fa-hospital-symbol:before{content:\"\\f47e\"}.fa-hospital-user:before{content:\"\\f80d\"}.fa-hot-tub:before{content:\"\\f593\"}.fa-hotdog:before{content:\"\\f80f\"}.fa-hotel:before{content:\"\\f594\"}.fa-hotjar:before{content:\"\\f3b1\"}.fa-hourglass:before{content:\"\\f254\"}.fa-hourglass-end:before{content:\"\\f253\"}.fa-hourglass-half:before{content:\"\\f252\"}.fa-hourglass-start:before{content:\"\\f251\"}.fa-house-damage:before{content:\"\\f6f1\"}.fa-house-user:before{content:\"\\e065\"}.fa-houzz:before{content:\"\\f27c\"}.fa-hryvnia:before{content:\"\\f6f2\"}.fa-html5:before{content:\"\\f13b\"}.fa-hubspot:before{content:\"\\f3b2\"}.fa-i-cursor:before{content:\"\\f246\"}.fa-ice-cream:before{content:\"\\f810\"}.fa-icicles:before{content:\"\\f7ad\"}.fa-icons:before{content:\"\\f86d\"}.fa-id-badge:before{content:\"\\f2c1\"}.fa-id-card:before{content:\"\\f2c2\"}.fa-id-card-alt:before{content:\"\\f47f\"}.fa-ideal:before{content:\"\\e013\"}.fa-igloo:before{content:\"\\f7ae\"}.fa-image:before{content:\"\\f03e\"}.fa-images:before{content:\"\\f302\"}.fa-imdb:before{content:\"\\f2d8\"}.fa-inbox:before{content:\"\\f01c\"}.fa-indent:before{content:\"\\f03c\"}.fa-industry:before{content:\"\\f275\"}.fa-infinity:before{content:\"\\f534\"}.fa-info:before{content:\"\\f129\"}.fa-info-circle:before{content:\"\\f05a\"}.fa-innosoft:before{content:\"\\e080\"}.fa-instagram:before{content:\"\\f16d\"}.fa-instagram-square:before{content:\"\\e055\"}.fa-instalod:before{content:\"\\e081\"}.fa-intercom:before{content:\"\\f7af\"}.fa-internet-explorer:before{content:\"\\f26b\"}.fa-invision:before{content:\"\\f7b0\"}.fa-ioxhost:before{content:\"\\f208\"}.fa-italic:before{content:\"\\f033\"}.fa-itch-io:before{content:\"\\f83a\"}.fa-itunes:before{content:\"\\f3b4\"}.fa-itunes-note:before{content:\"\\f3b5\"}.fa-java:before{content:\"\\f4e4\"}.fa-jedi:before{content:\"\\f669\"}.fa-jedi-order:before{content:\"\\f50e\"}.fa-jenkins:before{content:\"\\f3b6\"}.fa-jira:before{content:\"\\f7b1\"}.fa-joget:before{content:\"\\f3b7\"}.fa-joint:before{content:\"\\f595\"}.fa-joomla:before{content:\"\\f1aa\"}.fa-journal-whills:before{content:\"\\f66a\"}.fa-js:before{content:\"\\f3b8\"}.fa-js-square:before{content:\"\\f3b9\"}.fa-jsfiddle:before{content:\"\\f1cc\"}.fa-kaaba:before{content:\"\\f66b\"}.fa-kaggle:before{content:\"\\f5fa\"}.fa-key:before{content:\"\\f084\"}.fa-keybase:before{content:\"\\f4f5\"}.fa-keyboard:before{content:\"\\f11c\"}.fa-keycdn:before{content:\"\\f3ba\"}.fa-khanda:before{content:\"\\f66d\"}.fa-kickstarter:before{content:\"\\f3bb\"}.fa-kickstarter-k:before{content:\"\\f3bc\"}.fa-kiss:before{content:\"\\f596\"}.fa-kiss-beam:before{content:\"\\f597\"}.fa-kiss-wink-heart:before{content:\"\\f598\"}.fa-kiwi-bird:before{content:\"\\f535\"}.fa-korvue:before{content:\"\\f42f\"}.fa-landmark:before{content:\"\\f66f\"}.fa-language:before{content:\"\\f1ab\"}.fa-laptop:before{content:\"\\f109\"}.fa-laptop-code:before{content:\"\\f5fc\"}.fa-laptop-house:before{content:\"\\e066\"}.fa-laptop-medical:before{content:\"\\f812\"}.fa-laravel:before{content:\"\\f3bd\"}.fa-lastfm:before{content:\"\\f202\"}.fa-lastfm-square:before{content:\"\\f203\"}.fa-laugh:before{content:\"\\f599\"}.fa-laugh-beam:before{content:\"\\f59a\"}.fa-laugh-squint:before{content:\"\\f59b\"}.fa-laugh-wink:before{content:\"\\f59c\"}.fa-layer-group:before{content:\"\\f5fd\"}.fa-leaf:before{content:\"\\f06c\"}.fa-leanpub:before{content:\"\\f212\"}.fa-lemon:before{content:\"\\f094\"}.fa-less:before{content:\"\\f41d\"}.fa-less-than:before{content:\"\\f536\"}.fa-less-than-equal:before{content:\"\\f537\"}.fa-level-down-alt:before{content:\"\\f3be\"}.fa-level-up-alt:before{content:\"\\f3bf\"}.fa-life-ring:before{content:\"\\f1cd\"}.fa-lightbulb:before{content:\"\\f0eb\"}.fa-line:before{content:\"\\f3c0\"}.fa-link:before{content:\"\\f0c1\"}.fa-linkedin:before{content:\"\\f08c\"}.fa-linkedin-in:before{content:\"\\f0e1\"}.fa-linode:before{content:\"\\f2b8\"}.fa-linux:before{content:\"\\f17c\"}.fa-lira-sign:before{content:\"\\f195\"}.fa-list:before{content:\"\\f03a\"}.fa-list-alt:before{content:\"\\f022\"}.fa-list-ol:before{content:\"\\f0cb\"}.fa-list-ul:before{content:\"\\f0ca\"}.fa-location-arrow:before{content:\"\\f124\"}.fa-lock:before{content:\"\\f023\"}.fa-lock-open:before{content:\"\\f3c1\"}.fa-long-arrow-alt-down:before{content:\"\\f309\"}.fa-long-arrow-alt-left:before{content:\"\\f30a\"}.fa-long-arrow-alt-right:before{content:\"\\f30b\"}.fa-long-arrow-alt-up:before{content:\"\\f30c\"}.fa-low-vision:before{content:\"\\f2a8\"}.fa-luggage-cart:before{content:\"\\f59d\"}.fa-lungs:before{content:\"\\f604\"}.fa-lungs-virus:before{content:\"\\e067\"}.fa-lyft:before{content:\"\\f3c3\"}.fa-magento:before{content:\"\\f3c4\"}.fa-magic:before{content:\"\\f0d0\"}.fa-magnet:before{content:\"\\f076\"}.fa-mail-bulk:before{content:\"\\f674\"}.fa-mailchimp:before{content:\"\\f59e\"}.fa-male:before{content:\"\\f183\"}.fa-mandalorian:before{content:\"\\f50f\"}.fa-map:before{content:\"\\f279\"}.fa-map-marked:before{content:\"\\f59f\"}.fa-map-marked-alt:before{content:\"\\f5a0\"}.fa-map-marker:before{content:\"\\f041\"}.fa-map-marker-alt:before{content:\"\\f3c5\"}.fa-map-pin:before{content:\"\\f276\"}.fa-map-signs:before{content:\"\\f277\"}.fa-markdown:before{content:\"\\f60f\"}.fa-marker:before{content:\"\\f5a1\"}.fa-mars:before{content:\"\\f222\"}.fa-mars-double:before{content:\"\\f227\"}.fa-mars-stroke:before{content:\"\\f229\"}.fa-mars-stroke-h:before{content:\"\\f22b\"}.fa-mars-stroke-v:before{content:\"\\f22a\"}.fa-mask:before{content:\"\\f6fa\"}.fa-mastodon:before{content:\"\\f4f6\"}.fa-maxcdn:before{content:\"\\f136\"}.fa-mdb:before{content:\"\\f8ca\"}.fa-medal:before{content:\"\\f5a2\"}.fa-medapps:before{content:\"\\f3c6\"}.fa-medium:before{content:\"\\f23a\"}.fa-medium-m:before{content:\"\\f3c7\"}.fa-medkit:before{content:\"\\f0fa\"}.fa-medrt:before{content:\"\\f3c8\"}.fa-meetup:before{content:\"\\f2e0\"}.fa-megaport:before{content:\"\\f5a3\"}.fa-meh:before{content:\"\\f11a\"}.fa-meh-blank:before{content:\"\\f5a4\"}.fa-meh-rolling-eyes:before{content:\"\\f5a5\"}.fa-memory:before{content:\"\\f538\"}.fa-mendeley:before{content:\"\\f7b3\"}.fa-menorah:before{content:\"\\f676\"}.fa-mercury:before{content:\"\\f223\"}.fa-meteor:before{content:\"\\f753\"}.fa-microblog:before{content:\"\\e01a\"}.fa-microchip:before{content:\"\\f2db\"}.fa-microphone:before{content:\"\\f130\"}.fa-microphone-alt:before{content:\"\\f3c9\"}.fa-microphone-alt-slash:before{content:\"\\f539\"}.fa-microphone-slash:before{content:\"\\f131\"}.fa-microscope:before{content:\"\\f610\"}.fa-microsoft:before{content:\"\\f3ca\"}.fa-minus:before{content:\"\\f068\"}.fa-minus-circle:before{content:\"\\f056\"}.fa-minus-square:before{content:\"\\f146\"}.fa-mitten:before{content:\"\\f7b5\"}.fa-mix:before{content:\"\\f3cb\"}.fa-mixcloud:before{content:\"\\f289\"}.fa-mixer:before{content:\"\\e056\"}.fa-mizuni:before{content:\"\\f3cc\"}.fa-mobile:before{content:\"\\f10b\"}.fa-mobile-alt:before{content:\"\\f3cd\"}.fa-modx:before{content:\"\\f285\"}.fa-monero:before{content:\"\\f3d0\"}.fa-money-bill:before{content:\"\\f0d6\"}.fa-money-bill-alt:before{content:\"\\f3d1\"}.fa-money-bill-wave:before{content:\"\\f53a\"}.fa-money-bill-wave-alt:before{content:\"\\f53b\"}.fa-money-check:before{content:\"\\f53c\"}.fa-money-check-alt:before{content:\"\\f53d\"}.fa-monument:before{content:\"\\f5a6\"}.fa-moon:before{content:\"\\f186\"}.fa-mortar-pestle:before{content:\"\\f5a7\"}.fa-mosque:before{content:\"\\f678\"}.fa-motorcycle:before{content:\"\\f21c\"}.fa-mountain:before{content:\"\\f6fc\"}.fa-mouse:before{content:\"\\f8cc\"}.fa-mouse-pointer:before{content:\"\\f245\"}.fa-mug-hot:before{content:\"\\f7b6\"}.fa-music:before{content:\"\\f001\"}.fa-napster:before{content:\"\\f3d2\"}.fa-neos:before{content:\"\\f612\"}.fa-network-wired:before{content:\"\\f6ff\"}.fa-neuter:before{content:\"\\f22c\"}.fa-newspaper:before{content:\"\\f1ea\"}.fa-nimblr:before{content:\"\\f5a8\"}.fa-node:before{content:\"\\f419\"}.fa-node-js:before{content:\"\\f3d3\"}.fa-not-equal:before{content:\"\\f53e\"}.fa-notes-medical:before{content:\"\\f481\"}.fa-npm:before{content:\"\\f3d4\"}.fa-ns8:before{content:\"\\f3d5\"}.fa-nutritionix:before{content:\"\\f3d6\"}.fa-object-group:before{content:\"\\f247\"}.fa-object-ungroup:before{content:\"\\f248\"}.fa-octopus-deploy:before{content:\"\\e082\"}.fa-odnoklassniki:before{content:\"\\f263\"}.fa-odnoklassniki-square:before{content:\"\\f264\"}.fa-oil-can:before{content:\"\\f613\"}.fa-old-republic:before{content:\"\\f510\"}.fa-om:before{content:\"\\f679\"}.fa-opencart:before{content:\"\\f23d\"}.fa-openid:before{content:\"\\f19b\"}.fa-opera:before{content:\"\\f26a\"}.fa-optin-monster:before{content:\"\\f23c\"}.fa-orcid:before{content:\"\\f8d2\"}.fa-osi:before{content:\"\\f41a\"}.fa-otter:before{content:\"\\f700\"}.fa-outdent:before{content:\"\\f03b\"}.fa-page4:before{content:\"\\f3d7\"}.fa-pagelines:before{content:\"\\f18c\"}.fa-pager:before{content:\"\\f815\"}.fa-paint-brush:before{content:\"\\f1fc\"}.fa-paint-roller:before{content:\"\\f5aa\"}.fa-palette:before{content:\"\\f53f\"}.fa-palfed:before{content:\"\\f3d8\"}.fa-pallet:before{content:\"\\f482\"}.fa-paper-plane:before{content:\"\\f1d8\"}.fa-paperclip:before{content:\"\\f0c6\"}.fa-parachute-box:before{content:\"\\f4cd\"}.fa-paragraph:before{content:\"\\f1dd\"}.fa-parking:before{content:\"\\f540\"}.fa-passport:before{content:\"\\f5ab\"}.fa-pastafarianism:before{content:\"\\f67b\"}.fa-paste:before{content:\"\\f0ea\"}.fa-patreon:before{content:\"\\f3d9\"}.fa-pause:before{content:\"\\f04c\"}.fa-pause-circle:before{content:\"\\f28b\"}.fa-paw:before{content:\"\\f1b0\"}.fa-paypal:before{content:\"\\f1ed\"}.fa-peace:before{content:\"\\f67c\"}.fa-pen:before{content:\"\\f304\"}.fa-pen-alt:before{content:\"\\f305\"}.fa-pen-fancy:before{content:\"\\f5ac\"}.fa-pen-nib:before{content:\"\\f5ad\"}.fa-pen-square:before{content:\"\\f14b\"}.fa-pencil-alt:before{content:\"\\f303\"}.fa-pencil-ruler:before{content:\"\\f5ae\"}.fa-penny-arcade:before{content:\"\\f704\"}.fa-people-arrows:before{content:\"\\e068\"}.fa-people-carry:before{content:\"\\f4ce\"}.fa-pepper-hot:before{content:\"\\f816\"}.fa-perbyte:before{content:\"\\e083\"}.fa-percent:before{content:\"\\f295\"}.fa-percentage:before{content:\"\\f541\"}.fa-periscope:before{content:\"\\f3da\"}.fa-person-booth:before{content:\"\\f756\"}.fa-phabricator:before{content:\"\\f3db\"}.fa-phoenix-framework:before{content:\"\\f3dc\"}.fa-phoenix-squadron:before{content:\"\\f511\"}.fa-phone:before{content:\"\\f095\"}.fa-phone-alt:before{content:\"\\f879\"}.fa-phone-slash:before{content:\"\\f3dd\"}.fa-phone-square:before{content:\"\\f098\"}.fa-phone-square-alt:before{content:\"\\f87b\"}.fa-phone-volume:before{content:\"\\f2a0\"}.fa-photo-video:before{content:\"\\f87c\"}.fa-php:before{content:\"\\f457\"}.fa-pied-piper:before{content:\"\\f2ae\"}.fa-pied-piper-alt:before{content:\"\\f1a8\"}.fa-pied-piper-hat:before{content:\"\\f4e5\"}.fa-pied-piper-pp:before{content:\"\\f1a7\"}.fa-pied-piper-square:before{content:\"\\e01e\"}.fa-piggy-bank:before{content:\"\\f4d3\"}.fa-pills:before{content:\"\\f484\"}.fa-pinterest:before{content:\"\\f0d2\"}.fa-pinterest-p:before{content:\"\\f231\"}.fa-pinterest-square:before{content:\"\\f0d3\"}.fa-pizza-slice:before{content:\"\\f818\"}.fa-place-of-worship:before{content:\"\\f67f\"}.fa-plane:before{content:\"\\f072\"}.fa-plane-arrival:before{content:\"\\f5af\"}.fa-plane-departure:before{content:\"\\f5b0\"}.fa-plane-slash:before{content:\"\\e069\"}.fa-play:before{content:\"\\f04b\"}.fa-play-circle:before{content:\"\\f144\"}.fa-playstation:before{content:\"\\f3df\"}.fa-plug:before{content:\"\\f1e6\"}.fa-plus:before{content:\"\\f067\"}.fa-plus-circle:before{content:\"\\f055\"}.fa-plus-square:before{content:\"\\f0fe\"}.fa-podcast:before{content:\"\\f2ce\"}.fa-poll:before{content:\"\\f681\"}.fa-poll-h:before{content:\"\\f682\"}.fa-poo:before{content:\"\\f2fe\"}.fa-poo-storm:before{content:\"\\f75a\"}.fa-poop:before{content:\"\\f619\"}.fa-portrait:before{content:\"\\f3e0\"}.fa-pound-sign:before{content:\"\\f154\"}.fa-power-off:before{content:\"\\f011\"}.fa-pray:before{content:\"\\f683\"}.fa-praying-hands:before{content:\"\\f684\"}.fa-prescription:before{content:\"\\f5b1\"}.fa-prescription-bottle:before{content:\"\\f485\"}.fa-prescription-bottle-alt:before{content:\"\\f486\"}.fa-print:before{content:\"\\f02f\"}.fa-procedures:before{content:\"\\f487\"}.fa-product-hunt:before{content:\"\\f288\"}.fa-project-diagram:before{content:\"\\f542\"}.fa-pump-medical:before{content:\"\\e06a\"}.fa-pump-soap:before{content:\"\\e06b\"}.fa-pushed:before{content:\"\\f3e1\"}.fa-puzzle-piece:before{content:\"\\f12e\"}.fa-python:before{content:\"\\f3e2\"}.fa-qq:before{content:\"\\f1d6\"}.fa-qrcode:before{content:\"\\f029\"}.fa-question:before{content:\"\\f128\"}.fa-question-circle:before{content:\"\\f059\"}.fa-quidditch:before{content:\"\\f458\"}.fa-quinscape:before{content:\"\\f459\"}.fa-quora:before{content:\"\\f2c4\"}.fa-quote-left:before{content:\"\\f10d\"}.fa-quote-right:before{content:\"\\f10e\"}.fa-quran:before{content:\"\\f687\"}.fa-r-project:before{content:\"\\f4f7\"}.fa-radiation:before{content:\"\\f7b9\"}.fa-radiation-alt:before{content:\"\\f7ba\"}.fa-rainbow:before{content:\"\\f75b\"}.fa-random:before{content:\"\\f074\"}.fa-raspberry-pi:before{content:\"\\f7bb\"}.fa-ravelry:before{content:\"\\f2d9\"}.fa-react:before{content:\"\\f41b\"}.fa-reacteurope:before{content:\"\\f75d\"}.fa-readme:before{content:\"\\f4d5\"}.fa-rebel:before{content:\"\\f1d0\"}.fa-receipt:before{content:\"\\f543\"}.fa-record-vinyl:before{content:\"\\f8d9\"}.fa-recycle:before{content:\"\\f1b8\"}.fa-red-river:before{content:\"\\f3e3\"}.fa-reddit:before{content:\"\\f1a1\"}.fa-reddit-alien:before{content:\"\\f281\"}.fa-reddit-square:before{content:\"\\f1a2\"}.fa-redhat:before{content:\"\\f7bc\"}.fa-redo:before{content:\"\\f01e\"}.fa-redo-alt:before{content:\"\\f2f9\"}.fa-registered:before{content:\"\\f25d\"}.fa-remove-format:before{content:\"\\f87d\"}.fa-renren:before{content:\"\\f18b\"}.fa-reply:before{content:\"\\f3e5\"}.fa-reply-all:before{content:\"\\f122\"}.fa-replyd:before{content:\"\\f3e6\"}.fa-republican:before{content:\"\\f75e\"}.fa-researchgate:before{content:\"\\f4f8\"}.fa-resolving:before{content:\"\\f3e7\"}.fa-restroom:before{content:\"\\f7bd\"}.fa-retweet:before{content:\"\\f079\"}.fa-rev:before{content:\"\\f5b2\"}.fa-ribbon:before{content:\"\\f4d6\"}.fa-ring:before{content:\"\\f70b\"}.fa-road:before{content:\"\\f018\"}.fa-robot:before{content:\"\\f544\"}.fa-rocket:before{content:\"\\f135\"}.fa-rocketchat:before{content:\"\\f3e8\"}.fa-rockrms:before{content:\"\\f3e9\"}.fa-route:before{content:\"\\f4d7\"}.fa-rss:before{content:\"\\f09e\"}.fa-rss-square:before{content:\"\\f143\"}.fa-ruble-sign:before{content:\"\\f158\"}.fa-ruler:before{content:\"\\f545\"}.fa-ruler-combined:before{content:\"\\f546\"}.fa-ruler-horizontal:before{content:\"\\f547\"}.fa-ruler-vertical:before{content:\"\\f548\"}.fa-running:before{content:\"\\f70c\"}.fa-rupee-sign:before{content:\"\\f156\"}.fa-rust:before{content:\"\\e07a\"}.fa-sad-cry:before{content:\"\\f5b3\"}.fa-sad-tear:before{content:\"\\f5b4\"}.fa-safari:before{content:\"\\f267\"}.fa-salesforce:before{content:\"\\f83b\"}.fa-sass:before{content:\"\\f41e\"}.fa-satellite:before{content:\"\\f7bf\"}.fa-satellite-dish:before{content:\"\\f7c0\"}.fa-save:before{content:\"\\f0c7\"}.fa-schlix:before{content:\"\\f3ea\"}.fa-school:before{content:\"\\f549\"}.fa-screwdriver:before{content:\"\\f54a\"}.fa-scribd:before{content:\"\\f28a\"}.fa-scroll:before{content:\"\\f70e\"}.fa-sd-card:before{content:\"\\f7c2\"}.fa-search:before{content:\"\\f002\"}.fa-search-dollar:before{content:\"\\f688\"}.fa-search-location:before{content:\"\\f689\"}.fa-search-minus:before{content:\"\\f010\"}.fa-search-plus:before{content:\"\\f00e\"}.fa-searchengin:before{content:\"\\f3eb\"}.fa-seedling:before{content:\"\\f4d8\"}.fa-sellcast:before{content:\"\\f2da\"}.fa-sellsy:before{content:\"\\f213\"}.fa-server:before{content:\"\\f233\"}.fa-servicestack:before{content:\"\\f3ec\"}.fa-shapes:before{content:\"\\f61f\"}.fa-share:before{content:\"\\f064\"}.fa-share-alt:before{content:\"\\f1e0\"}.fa-share-alt-square:before{content:\"\\f1e1\"}.fa-share-square:before{content:\"\\f14d\"}.fa-shekel-sign:before{content:\"\\f20b\"}.fa-shield-alt:before{content:\"\\f3ed\"}.fa-shield-virus:before{content:\"\\e06c\"}.fa-ship:before{content:\"\\f21a\"}.fa-shipping-fast:before{content:\"\\f48b\"}.fa-shirtsinbulk:before{content:\"\\f214\"}.fa-shoe-prints:before{content:\"\\f54b\"}.fa-shopify:before{content:\"\\e057\"}.fa-shopping-bag:before{content:\"\\f290\"}.fa-shopping-basket:before{content:\"\\f291\"}.fa-shopping-cart:before{content:\"\\f07a\"}.fa-shopware:before{content:\"\\f5b5\"}.fa-shower:before{content:\"\\f2cc\"}.fa-shuttle-van:before{content:\"\\f5b6\"}.fa-sign:before{content:\"\\f4d9\"}.fa-sign-in-alt:before{content:\"\\f2f6\"}.fa-sign-language:before{content:\"\\f2a7\"}.fa-sign-out-alt:before{content:\"\\f2f5\"}.fa-signal:before{content:\"\\f012\"}.fa-signature:before{content:\"\\f5b7\"}.fa-sim-card:before{content:\"\\f7c4\"}.fa-simplybuilt:before{content:\"\\f215\"}.fa-sink:before{content:\"\\e06d\"}.fa-sistrix:before{content:\"\\f3ee\"}.fa-sitemap:before{content:\"\\f0e8\"}.fa-sith:before{content:\"\\f512\"}.fa-skating:before{content:\"\\f7c5\"}.fa-sketch:before{content:\"\\f7c6\"}.fa-skiing:before{content:\"\\f7c9\"}.fa-skiing-nordic:before{content:\"\\f7ca\"}.fa-skull:before{content:\"\\f54c\"}.fa-skull-crossbones:before{content:\"\\f714\"}.fa-skyatlas:before{content:\"\\f216\"}.fa-skype:before{content:\"\\f17e\"}.fa-slack:before{content:\"\\f198\"}.fa-slack-hash:before{content:\"\\f3ef\"}.fa-slash:before{content:\"\\f715\"}.fa-sleigh:before{content:\"\\f7cc\"}.fa-sliders-h:before{content:\"\\f1de\"}.fa-slideshare:before{content:\"\\f1e7\"}.fa-smile:before{content:\"\\f118\"}.fa-smile-beam:before{content:\"\\f5b8\"}.fa-smile-wink:before{content:\"\\f4da\"}.fa-smog:before{content:\"\\f75f\"}.fa-smoking:before{content:\"\\f48d\"}.fa-smoking-ban:before{content:\"\\f54d\"}.fa-sms:before{content:\"\\f7cd\"}.fa-snapchat:before{content:\"\\f2ab\"}.fa-snapchat-ghost:before{content:\"\\f2ac\"}.fa-snapchat-square:before{content:\"\\f2ad\"}.fa-snowboarding:before{content:\"\\f7ce\"}.fa-snowflake:before{content:\"\\f2dc\"}.fa-snowman:before{content:\"\\f7d0\"}.fa-snowplow:before{content:\"\\f7d2\"}.fa-soap:before{content:\"\\e06e\"}.fa-socks:before{content:\"\\f696\"}.fa-solar-panel:before{content:\"\\f5ba\"}.fa-sort:before{content:\"\\f0dc\"}.fa-sort-alpha-down:before{content:\"\\f15d\"}.fa-sort-alpha-down-alt:before{content:\"\\f881\"}.fa-sort-alpha-up:before{content:\"\\f15e\"}.fa-sort-alpha-up-alt:before{content:\"\\f882\"}.fa-sort-amount-down:before{content:\"\\f160\"}.fa-sort-amount-down-alt:before{content:\"\\f884\"}.fa-sort-amount-up:before{content:\"\\f161\"}.fa-sort-amount-up-alt:before{content:\"\\f885\"}.fa-sort-down:before{content:\"\\f0dd\"}.fa-sort-numeric-down:before{content:\"\\f162\"}.fa-sort-numeric-down-alt:before{content:\"\\f886\"}.fa-sort-numeric-up:before{content:\"\\f163\"}.fa-sort-numeric-up-alt:before{content:\"\\f887\"}.fa-sort-up:before{content:\"\\f0de\"}.fa-soundcloud:before{content:\"\\f1be\"}.fa-sourcetree:before{content:\"\\f7d3\"}.fa-spa:before{content:\"\\f5bb\"}.fa-space-shuttle:before{content:\"\\f197\"}.fa-speakap:before{content:\"\\f3f3\"}.fa-speaker-deck:before{content:\"\\f83c\"}.fa-spell-check:before{content:\"\\f891\"}.fa-spider:before{content:\"\\f717\"}.fa-spinner:before{content:\"\\f110\"}.fa-splotch:before{content:\"\\f5bc\"}.fa-spotify:before{content:\"\\f1bc\"}.fa-spray-can:before{content:\"\\f5bd\"}.fa-square:before{content:\"\\f0c8\"}.fa-square-full:before{content:\"\\f45c\"}.fa-square-root-alt:before{content:\"\\f698\"}.fa-squarespace:before{content:\"\\f5be\"}.fa-stack-exchange:before{content:\"\\f18d\"}.fa-stack-overflow:before{content:\"\\f16c\"}.fa-stackpath:before{content:\"\\f842\"}.fa-stamp:before{content:\"\\f5bf\"}.fa-star:before{content:\"\\f005\"}.fa-star-and-crescent:before{content:\"\\f699\"}.fa-star-half:before{content:\"\\f089\"}.fa-star-half-alt:before{content:\"\\f5c0\"}.fa-star-of-david:before{content:\"\\f69a\"}.fa-star-of-life:before{content:\"\\f621\"}.fa-staylinked:before{content:\"\\f3f5\"}.fa-steam:before{content:\"\\f1b6\"}.fa-steam-square:before{content:\"\\f1b7\"}.fa-steam-symbol:before{content:\"\\f3f6\"}.fa-step-backward:before{content:\"\\f048\"}.fa-step-forward:before{content:\"\\f051\"}.fa-stethoscope:before{content:\"\\f0f1\"}.fa-sticker-mule:before{content:\"\\f3f7\"}.fa-sticky-note:before{content:\"\\f249\"}.fa-stop:before{content:\"\\f04d\"}.fa-stop-circle:before{content:\"\\f28d\"}.fa-stopwatch:before{content:\"\\f2f2\"}.fa-stopwatch-20:before{content:\"\\e06f\"}.fa-store:before{content:\"\\f54e\"}.fa-store-alt:before{content:\"\\f54f\"}.fa-store-alt-slash:before{content:\"\\e070\"}.fa-store-slash:before{content:\"\\e071\"}.fa-strava:before{content:\"\\f428\"}.fa-stream:before{content:\"\\f550\"}.fa-street-view:before{content:\"\\f21d\"}.fa-strikethrough:before{content:\"\\f0cc\"}.fa-stripe:before{content:\"\\f429\"}.fa-stripe-s:before{content:\"\\f42a\"}.fa-stroopwafel:before{content:\"\\f551\"}.fa-studiovinari:before{content:\"\\f3f8\"}.fa-stumbleupon:before{content:\"\\f1a4\"}.fa-stumbleupon-circle:before{content:\"\\f1a3\"}.fa-subscript:before{content:\"\\f12c\"}.fa-subway:before{content:\"\\f239\"}.fa-suitcase:before{content:\"\\f0f2\"}.fa-suitcase-rolling:before{content:\"\\f5c1\"}.fa-sun:before{content:\"\\f185\"}.fa-superpowers:before{content:\"\\f2dd\"}.fa-superscript:before{content:\"\\f12b\"}.fa-supple:before{content:\"\\f3f9\"}.fa-surprise:before{content:\"\\f5c2\"}.fa-suse:before{content:\"\\f7d6\"}.fa-swatchbook:before{content:\"\\f5c3\"}.fa-swift:before{content:\"\\f8e1\"}.fa-swimmer:before{content:\"\\f5c4\"}.fa-swimming-pool:before{content:\"\\f5c5\"}.fa-symfony:before{content:\"\\f83d\"}.fa-synagogue:before{content:\"\\f69b\"}.fa-sync:before{content:\"\\f021\"}.fa-sync-alt:before{content:\"\\f2f1\"}.fa-syringe:before{content:\"\\f48e\"}.fa-table:before{content:\"\\f0ce\"}.fa-table-tennis:before{content:\"\\f45d\"}.fa-tablet:before{content:\"\\f10a\"}.fa-tablet-alt:before{content:\"\\f3fa\"}.fa-tablets:before{content:\"\\f490\"}.fa-tachometer-alt:before{content:\"\\f3fd\"}.fa-tag:before{content:\"\\f02b\"}.fa-tags:before{content:\"\\f02c\"}.fa-tape:before{content:\"\\f4db\"}.fa-tasks:before{content:\"\\f0ae\"}.fa-taxi:before{content:\"\\f1ba\"}.fa-teamspeak:before{content:\"\\f4f9\"}.fa-teeth:before{content:\"\\f62e\"}.fa-teeth-open:before{content:\"\\f62f\"}.fa-telegram:before{content:\"\\f2c6\"}.fa-telegram-plane:before{content:\"\\f3fe\"}.fa-temperature-high:before{content:\"\\f769\"}.fa-temperature-low:before{content:\"\\f76b\"}.fa-tencent-weibo:before{content:\"\\f1d5\"}.fa-tenge:before{content:\"\\f7d7\"}.fa-terminal:before{content:\"\\f120\"}.fa-text-height:before{content:\"\\f034\"}.fa-text-width:before{content:\"\\f035\"}.fa-th:before{content:\"\\f00a\"}.fa-th-large:before{content:\"\\f009\"}.fa-th-list:before{content:\"\\f00b\"}.fa-the-red-yeti:before{content:\"\\f69d\"}.fa-theater-masks:before{content:\"\\f630\"}.fa-themeco:before{content:\"\\f5c6\"}.fa-themeisle:before{content:\"\\f2b2\"}.fa-thermometer:before{content:\"\\f491\"}.fa-thermometer-empty:before{content:\"\\f2cb\"}.fa-thermometer-full:before{content:\"\\f2c7\"}.fa-thermometer-half:before{content:\"\\f2c9\"}.fa-thermometer-quarter:before{content:\"\\f2ca\"}.fa-thermometer-three-quarters:before{content:\"\\f2c8\"}.fa-think-peaks:before{content:\"\\f731\"}.fa-thumbs-down:before{content:\"\\f165\"}.fa-thumbs-up:before{content:\"\\f164\"}.fa-thumbtack:before{content:\"\\f08d\"}.fa-ticket-alt:before{content:\"\\f3ff\"}.fa-tiktok:before{content:\"\\e07b\"}.fa-times:before{content:\"\\f00d\"}.fa-times-circle:before{content:\"\\f057\"}.fa-tint:before{content:\"\\f043\"}.fa-tint-slash:before{content:\"\\f5c7\"}.fa-tired:before{content:\"\\f5c8\"}.fa-toggle-off:before{content:\"\\f204\"}.fa-toggle-on:before{content:\"\\f205\"}.fa-toilet:before{content:\"\\f7d8\"}.fa-toilet-paper:before{content:\"\\f71e\"}.fa-toilet-paper-slash:before{content:\"\\e072\"}.fa-toolbox:before{content:\"\\f552\"}.fa-tools:before{content:\"\\f7d9\"}.fa-tooth:before{content:\"\\f5c9\"}.fa-torah:before{content:\"\\f6a0\"}.fa-torii-gate:before{content:\"\\f6a1\"}.fa-tractor:before{content:\"\\f722\"}.fa-trade-federation:before{content:\"\\f513\"}.fa-trademark:before{content:\"\\f25c\"}.fa-traffic-light:before{content:\"\\f637\"}.fa-trailer:before{content:\"\\e041\"}.fa-train:before{content:\"\\f238\"}.fa-tram:before{content:\"\\f7da\"}.fa-transgender:before{content:\"\\f224\"}.fa-transgender-alt:before{content:\"\\f225\"}.fa-trash:before{content:\"\\f1f8\"}.fa-trash-alt:before{content:\"\\f2ed\"}.fa-trash-restore:before{content:\"\\f829\"}.fa-trash-restore-alt:before{content:\"\\f82a\"}.fa-tree:before{content:\"\\f1bb\"}.fa-trello:before{content:\"\\f181\"}.fa-trophy:before{content:\"\\f091\"}.fa-truck:before{content:\"\\f0d1\"}.fa-truck-loading:before{content:\"\\f4de\"}.fa-truck-monster:before{content:\"\\f63b\"}.fa-truck-moving:before{content:\"\\f4df\"}.fa-truck-pickup:before{content:\"\\f63c\"}.fa-tshirt:before{content:\"\\f553\"}.fa-tty:before{content:\"\\f1e4\"}.fa-tumblr:before{content:\"\\f173\"}.fa-tumblr-square:before{content:\"\\f174\"}.fa-tv:before{content:\"\\f26c\"}.fa-twitch:before{content:\"\\f1e8\"}.fa-twitter:before{content:\"\\f099\"}.fa-twitter-square:before{content:\"\\f081\"}.fa-typo3:before{content:\"\\f42b\"}.fa-uber:before{content:\"\\f402\"}.fa-ubuntu:before{content:\"\\f7df\"}.fa-uikit:before{content:\"\\f403\"}.fa-umbraco:before{content:\"\\f8e8\"}.fa-umbrella:before{content:\"\\f0e9\"}.fa-umbrella-beach:before{content:\"\\f5ca\"}.fa-uncharted:before{content:\"\\e084\"}.fa-underline:before{content:\"\\f0cd\"}.fa-undo:before{content:\"\\f0e2\"}.fa-undo-alt:before{content:\"\\f2ea\"}.fa-uniregistry:before{content:\"\\f404\"}.fa-unity:before{content:\"\\e049\"}.fa-universal-access:before{content:\"\\f29a\"}.fa-university:before{content:\"\\f19c\"}.fa-unlink:before{content:\"\\f127\"}.fa-unlock:before{content:\"\\f09c\"}.fa-unlock-alt:before{content:\"\\f13e\"}.fa-unsplash:before{content:\"\\e07c\"}.fa-untappd:before{content:\"\\f405\"}.fa-upload:before{content:\"\\f093\"}.fa-ups:before{content:\"\\f7e0\"}.fa-usb:before{content:\"\\f287\"}.fa-user:before{content:\"\\f007\"}.fa-user-alt:before{content:\"\\f406\"}.fa-user-alt-slash:before{content:\"\\f4fa\"}.fa-user-astronaut:before{content:\"\\f4fb\"}.fa-user-check:before{content:\"\\f4fc\"}.fa-user-circle:before{content:\"\\f2bd\"}.fa-user-clock:before{content:\"\\f4fd\"}.fa-user-cog:before{content:\"\\f4fe\"}.fa-user-edit:before{content:\"\\f4ff\"}.fa-user-friends:before{content:\"\\f500\"}.fa-user-graduate:before{content:\"\\f501\"}.fa-user-injured:before{content:\"\\f728\"}.fa-user-lock:before{content:\"\\f502\"}.fa-user-md:before{content:\"\\f0f0\"}.fa-user-minus:before{content:\"\\f503\"}.fa-user-ninja:before{content:\"\\f504\"}.fa-user-nurse:before{content:\"\\f82f\"}.fa-user-plus:before{content:\"\\f234\"}.fa-user-secret:before{content:\"\\f21b\"}.fa-user-shield:before{content:\"\\f505\"}.fa-user-slash:before{content:\"\\f506\"}.fa-user-tag:before{content:\"\\f507\"}.fa-user-tie:before{content:\"\\f508\"}.fa-user-times:before{content:\"\\f235\"}.fa-users:before{content:\"\\f0c0\"}.fa-users-cog:before{content:\"\\f509\"}.fa-users-slash:before{content:\"\\e073\"}.fa-usps:before{content:\"\\f7e1\"}.fa-ussunnah:before{content:\"\\f407\"}.fa-utensil-spoon:before{content:\"\\f2e5\"}.fa-utensils:before{content:\"\\f2e7\"}.fa-vaadin:before{content:\"\\f408\"}.fa-vector-square:before{content:\"\\f5cb\"}.fa-venus:before{content:\"\\f221\"}.fa-venus-double:before{content:\"\\f226\"}.fa-venus-mars:before{content:\"\\f228\"}.fa-vest:before{content:\"\\e085\"}.fa-vest-patches:before{content:\"\\e086\"}.fa-viacoin:before{content:\"\\f237\"}.fa-viadeo:before{content:\"\\f2a9\"}.fa-viadeo-square:before{content:\"\\f2aa\"}.fa-vial:before{content:\"\\f492\"}.fa-vials:before{content:\"\\f493\"}.fa-viber:before{content:\"\\f409\"}.fa-video:before{content:\"\\f03d\"}.fa-video-slash:before{content:\"\\f4e2\"}.fa-vihara:before{content:\"\\f6a7\"}.fa-vimeo:before{content:\"\\f40a\"}.fa-vimeo-square:before{content:\"\\f194\"}.fa-vimeo-v:before{content:\"\\f27d\"}.fa-vine:before{content:\"\\f1ca\"}.fa-virus:before{content:\"\\e074\"}.fa-virus-slash:before{content:\"\\e075\"}.fa-viruses:before{content:\"\\e076\"}.fa-vk:before{content:\"\\f189\"}.fa-vnv:before{content:\"\\f40b\"}.fa-voicemail:before{content:\"\\f897\"}.fa-volleyball-ball:before{content:\"\\f45f\"}.fa-volume-down:before{content:\"\\f027\"}.fa-volume-mute:before{content:\"\\f6a9\"}.fa-volume-off:before{content:\"\\f026\"}.fa-volume-up:before{content:\"\\f028\"}.fa-vote-yea:before{content:\"\\f772\"}.fa-vr-cardboard:before{content:\"\\f729\"}.fa-vuejs:before{content:\"\\f41f\"}.fa-walking:before{content:\"\\f554\"}.fa-wallet:before{content:\"\\f555\"}.fa-warehouse:before{content:\"\\f494\"}.fa-watchman-monitoring:before{content:\"\\e087\"}.fa-water:before{content:\"\\f773\"}.fa-wave-square:before{content:\"\\f83e\"}.fa-waze:before{content:\"\\f83f\"}.fa-weebly:before{content:\"\\f5cc\"}.fa-weibo:before{content:\"\\f18a\"}.fa-weight:before{content:\"\\f496\"}.fa-weight-hanging:before{content:\"\\f5cd\"}.fa-weixin:before{content:\"\\f1d7\"}.fa-whatsapp:before{content:\"\\f232\"}.fa-whatsapp-square:before{content:\"\\f40c\"}.fa-wheelchair:before{content:\"\\f193\"}.fa-whmcs:before{content:\"\\f40d\"}.fa-wifi:before{content:\"\\f1eb\"}.fa-wikipedia-w:before{content:\"\\f266\"}.fa-wind:before{content:\"\\f72e\"}.fa-window-close:before{content:\"\\f410\"}.fa-window-maximize:before{content:\"\\f2d0\"}.fa-window-minimize:before{content:\"\\f2d1\"}.fa-window-restore:before{content:\"\\f2d2\"}.fa-windows:before{content:\"\\f17a\"}.fa-wine-bottle:before{content:\"\\f72f\"}.fa-wine-glass:before{content:\"\\f4e3\"}.fa-wine-glass-alt:before{content:\"\\f5ce\"}.fa-wix:before{content:\"\\f5cf\"}.fa-wizards-of-the-coast:before{content:\"\\f730\"}.fa-wodu:before{content:\"\\e088\"}.fa-wolf-pack-battalion:before{content:\"\\f514\"}.fa-won-sign:before{content:\"\\f159\"}.fa-wordpress:before{content:\"\\f19a\"}.fa-wordpress-simple:before{content:\"\\f411\"}.fa-wpbeginner:before{content:\"\\f297\"}.fa-wpexplorer:before{content:\"\\f2de\"}.fa-wpforms:before{content:\"\\f298\"}.fa-wpressr:before{content:\"\\f3e4\"}.fa-wrench:before{content:\"\\f0ad\"}.fa-x-ray:before{content:\"\\f497\"}.fa-xbox:before{content:\"\\f412\"}.fa-xing:before{content:\"\\f168\"}.fa-xing-square:before{content:\"\\f169\"}.fa-y-combinator:before{content:\"\\f23b\"}.fa-yahoo:before{content:\"\\f19e\"}.fa-yammer:before{content:\"\\f840\"}.fa-yandex:before{content:\"\\f413\"}.fa-yandex-international:before{content:\"\\f414\"}.fa-yarn:before{content:\"\\f7e3\"}.fa-yelp:before{content:\"\\f1e9\"}.fa-yen-sign:before{content:\"\\f157\"}.fa-yin-yang:before{content:\"\\f6ad\"}.fa-yoast:before{content:\"\\f2b1\"}.fa-youtube:before{content:\"\\f167\"}.fa-youtube-square:before{content:\"\\f431\"}.fa-zhihu:before{content:\"\\f63f\"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/regular.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n@font-face {\n  font-family: 'Font Awesome 5 Free';\n  font-style: normal;\n  font-weight: 400;\n  font-display: block;\n  src: url(\"../webfonts/fa-regular-400.eot\");\n  src: url(\"../webfonts/fa-regular-400.eot?#iefix\") format(\"embedded-opentype\"), url(\"../webfonts/fa-regular-400.woff2\") format(\"woff2\"), url(\"../webfonts/fa-regular-400.woff\") format(\"woff\"), url(\"../webfonts/fa-regular-400.ttf\") format(\"truetype\"), url(\"../webfonts/fa-regular-400.svg#fontawesome\") format(\"svg\"); }\n\n.far {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/regular.min.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n@font-face{font-family:\"Font Awesome 5 Free\";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format(\"embedded-opentype\"),url(../webfonts/fa-regular-400.woff2) format(\"woff2\"),url(../webfonts/fa-regular-400.woff) format(\"woff\"),url(../webfonts/fa-regular-400.ttf) format(\"truetype\"),url(../webfonts/fa-regular-400.svg#fontawesome) format(\"svg\")}.far{font-family:\"Font Awesome 5 Free\";font-weight:400}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/solid.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n@font-face {\n  font-family: 'Font Awesome 5 Free';\n  font-style: normal;\n  font-weight: 900;\n  font-display: block;\n  src: url(\"../webfonts/fa-solid-900.eot\");\n  src: url(\"../webfonts/fa-solid-900.eot?#iefix\") format(\"embedded-opentype\"), url(\"../webfonts/fa-solid-900.woff2\") format(\"woff2\"), url(\"../webfonts/fa-solid-900.woff\") format(\"woff\"), url(\"../webfonts/fa-solid-900.ttf\") format(\"truetype\"), url(\"../webfonts/fa-solid-900.svg#fontawesome\") format(\"svg\"); }\n\n.fa,\n.fas {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 900; }\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/solid.min.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n@font-face{font-family:\"Font Awesome 5 Free\";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format(\"embedded-opentype\"),url(../webfonts/fa-solid-900.woff2) format(\"woff2\"),url(../webfonts/fa-solid-900.woff) format(\"woff\"),url(../webfonts/fa-solid-900.ttf) format(\"truetype\"),url(../webfonts/fa-solid-900.svg#fontawesome) format(\"svg\")}.fa,.fas{font-family:\"Font Awesome 5 Free\";font-weight:900}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/svg-with-js.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\nsvg:not(:root).svg-inline--fa {\n  overflow: visible; }\n\n.svg-inline--fa {\n  display: inline-block;\n  font-size: inherit;\n  height: 1em;\n  overflow: visible;\n  vertical-align: -.125em; }\n  .svg-inline--fa.fa-lg {\n    vertical-align: -.225em; }\n  .svg-inline--fa.fa-w-1 {\n    width: 0.0625em; }\n  .svg-inline--fa.fa-w-2 {\n    width: 0.125em; }\n  .svg-inline--fa.fa-w-3 {\n    width: 0.1875em; }\n  .svg-inline--fa.fa-w-4 {\n    width: 0.25em; }\n  .svg-inline--fa.fa-w-5 {\n    width: 0.3125em; }\n  .svg-inline--fa.fa-w-6 {\n    width: 0.375em; }\n  .svg-inline--fa.fa-w-7 {\n    width: 0.4375em; }\n  .svg-inline--fa.fa-w-8 {\n    width: 0.5em; }\n  .svg-inline--fa.fa-w-9 {\n    width: 0.5625em; }\n  .svg-inline--fa.fa-w-10 {\n    width: 0.625em; }\n  .svg-inline--fa.fa-w-11 {\n    width: 0.6875em; }\n  .svg-inline--fa.fa-w-12 {\n    width: 0.75em; }\n  .svg-inline--fa.fa-w-13 {\n    width: 0.8125em; }\n  .svg-inline--fa.fa-w-14 {\n    width: 0.875em; }\n  .svg-inline--fa.fa-w-15 {\n    width: 0.9375em; }\n  .svg-inline--fa.fa-w-16 {\n    width: 1em; }\n  .svg-inline--fa.fa-w-17 {\n    width: 1.0625em; }\n  .svg-inline--fa.fa-w-18 {\n    width: 1.125em; }\n  .svg-inline--fa.fa-w-19 {\n    width: 1.1875em; }\n  .svg-inline--fa.fa-w-20 {\n    width: 1.25em; }\n  .svg-inline--fa.fa-pull-left {\n    margin-right: .3em;\n    width: auto; }\n  .svg-inline--fa.fa-pull-right {\n    margin-left: .3em;\n    width: auto; }\n  .svg-inline--fa.fa-border {\n    height: 1.5em; }\n  .svg-inline--fa.fa-li {\n    width: 2em; }\n  .svg-inline--fa.fa-fw {\n    width: 1.25em; }\n\n.fa-layers svg.svg-inline--fa {\n  bottom: 0;\n  left: 0;\n  margin: auto;\n  position: absolute;\n  right: 0;\n  top: 0; }\n\n.fa-layers {\n  display: inline-block;\n  height: 1em;\n  position: relative;\n  text-align: center;\n  vertical-align: -.125em;\n  width: 1em; }\n  .fa-layers svg.svg-inline--fa {\n    -webkit-transform-origin: center center;\n            transform-origin: center center; }\n\n.fa-layers-text, .fa-layers-counter {\n  display: inline-block;\n  position: absolute;\n  text-align: center; }\n\n.fa-layers-text {\n  left: 50%;\n  top: 50%;\n  -webkit-transform: translate(-50%, -50%);\n          transform: translate(-50%, -50%);\n  -webkit-transform-origin: center center;\n          transform-origin: center center; }\n\n.fa-layers-counter {\n  background-color: #ff253a;\n  border-radius: 1em;\n  -webkit-box-sizing: border-box;\n          box-sizing: border-box;\n  color: #fff;\n  height: 1.5em;\n  line-height: 1;\n  max-width: 5em;\n  min-width: 1.5em;\n  overflow: hidden;\n  padding: .25em;\n  right: 0;\n  text-overflow: ellipsis;\n  top: 0;\n  -webkit-transform: scale(0.25);\n          transform: scale(0.25);\n  -webkit-transform-origin: top right;\n          transform-origin: top right; }\n\n.fa-layers-bottom-right {\n  bottom: 0;\n  right: 0;\n  top: auto;\n  -webkit-transform: scale(0.25);\n          transform: scale(0.25);\n  -webkit-transform-origin: bottom right;\n          transform-origin: bottom right; }\n\n.fa-layers-bottom-left {\n  bottom: 0;\n  left: 0;\n  right: auto;\n  top: auto;\n  -webkit-transform: scale(0.25);\n          transform: scale(0.25);\n  -webkit-transform-origin: bottom left;\n          transform-origin: bottom left; }\n\n.fa-layers-top-right {\n  right: 0;\n  top: 0;\n  -webkit-transform: scale(0.25);\n          transform: scale(0.25);\n  -webkit-transform-origin: top right;\n          transform-origin: top right; }\n\n.fa-layers-top-left {\n  left: 0;\n  right: auto;\n  top: 0;\n  -webkit-transform: scale(0.25);\n          transform: scale(0.25);\n  -webkit-transform-origin: top left;\n          transform-origin: top left; }\n\n.fa-lg {\n  font-size: 1.33333em;\n  line-height: 0.75em;\n  vertical-align: -.0667em; }\n\n.fa-xs {\n  font-size: .75em; }\n\n.fa-sm {\n  font-size: .875em; }\n\n.fa-1x {\n  font-size: 1em; }\n\n.fa-2x {\n  font-size: 2em; }\n\n.fa-3x {\n  font-size: 3em; }\n\n.fa-4x {\n  font-size: 4em; }\n\n.fa-5x {\n  font-size: 5em; }\n\n.fa-6x {\n  font-size: 6em; }\n\n.fa-7x {\n  font-size: 7em; }\n\n.fa-8x {\n  font-size: 8em; }\n\n.fa-9x {\n  font-size: 9em; }\n\n.fa-10x {\n  font-size: 10em; }\n\n.fa-fw {\n  text-align: center;\n  width: 1.25em; }\n\n.fa-ul {\n  list-style-type: none;\n  margin-left: 2.5em;\n  padding-left: 0; }\n  .fa-ul > li {\n    position: relative; }\n\n.fa-li {\n  left: -2em;\n  position: absolute;\n  text-align: center;\n  width: 2em;\n  line-height: inherit; }\n\n.fa-border {\n  border: solid 0.08em #eee;\n  border-radius: .1em;\n  padding: .2em .25em .15em; }\n\n.fa-pull-left {\n  float: left; }\n\n.fa-pull-right {\n  float: right; }\n\n.fa.fa-pull-left,\n.fas.fa-pull-left,\n.far.fa-pull-left,\n.fal.fa-pull-left,\n.fab.fa-pull-left {\n  margin-right: .3em; }\n\n.fa.fa-pull-right,\n.fas.fa-pull-right,\n.far.fa-pull-right,\n.fal.fa-pull-right,\n.fab.fa-pull-right {\n  margin-left: .3em; }\n\n.fa-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n          animation: fa-spin 2s infinite linear; }\n\n.fa-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n          animation: fa-spin 1s infinite steps(8); }\n\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg); }\n  100% {\n    -webkit-transform: rotate(360deg);\n            transform: rotate(360deg); } }\n\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg); }\n  100% {\n    -webkit-transform: rotate(360deg);\n            transform: rotate(360deg); } }\n\n.fa-rotate-90 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";\n  -webkit-transform: rotate(90deg);\n          transform: rotate(90deg); }\n\n.fa-rotate-180 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";\n  -webkit-transform: rotate(180deg);\n          transform: rotate(180deg); }\n\n.fa-rotate-270 {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";\n  -webkit-transform: rotate(270deg);\n          transform: rotate(270deg); }\n\n.fa-flip-horizontal {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";\n  -webkit-transform: scale(-1, 1);\n          transform: scale(-1, 1); }\n\n.fa-flip-vertical {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";\n  -webkit-transform: scale(1, -1);\n          transform: scale(1, -1); }\n\n.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {\n  -ms-filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";\n  -webkit-transform: scale(-1, -1);\n          transform: scale(-1, -1); }\n\n:root .fa-rotate-90,\n:root .fa-rotate-180,\n:root .fa-rotate-270,\n:root .fa-flip-horizontal,\n:root .fa-flip-vertical,\n:root .fa-flip-both {\n  -webkit-filter: none;\n          filter: none; }\n\n.fa-stack {\n  display: inline-block;\n  height: 2em;\n  position: relative;\n  width: 2.5em; }\n\n.fa-stack-1x,\n.fa-stack-2x {\n  bottom: 0;\n  left: 0;\n  margin: auto;\n  position: absolute;\n  right: 0;\n  top: 0; }\n\n.svg-inline--fa.fa-stack-1x {\n  height: 1em;\n  width: 1.25em; }\n\n.svg-inline--fa.fa-stack-2x {\n  height: 2em;\n  width: 2.5em; }\n\n.fa-inverse {\n  color: #fff; }\n\n.sr-only {\n  border: 0;\n  clip: rect(0, 0, 0, 0);\n  height: 1px;\n  margin: -1px;\n  overflow: hidden;\n  padding: 0;\n  position: absolute;\n  width: 1px; }\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n  clip: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  position: static;\n  width: auto; }\n\n.svg-inline--fa .fa-primary {\n  fill: var(--fa-primary-color, currentColor);\n  opacity: 1;\n  opacity: var(--fa-primary-opacity, 1); }\n\n.svg-inline--fa .fa-secondary {\n  fill: var(--fa-secondary-color, currentColor);\n  opacity: 0.4;\n  opacity: var(--fa-secondary-opacity, 0.4); }\n\n.svg-inline--fa.fa-swap-opacity .fa-primary {\n  opacity: 0.4;\n  opacity: var(--fa-secondary-opacity, 0.4); }\n\n.svg-inline--fa.fa-swap-opacity .fa-secondary {\n  opacity: 1;\n  opacity: var(--fa-primary-opacity, 1); }\n\n.svg-inline--fa mask .fa-primary,\n.svg-inline--fa mask .fa-secondary {\n  fill: black; }\n\n.fad.fa-inverse {\n  color: #fff; }\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/svg-with-js.min.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n.svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.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{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom right;transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom left;transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top left;transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.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-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;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}.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:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.svg-inline--fa .fa-primary{fill:var(--fa-primary-color,currentColor);opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa .fa-secondary{fill:var(--fa-secondary-color,currentColor)}.svg-inline--fa .fa-secondary,.svg-inline--fa.fa-swap-opacity .fa-primary{opacity:.4;opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-secondary{opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa mask .fa-primary,.svg-inline--fa mask .fa-secondary{fill:#000}.fad.fa-inverse{color:#fff}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/v4-shims.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n.fa.fa-glass:before {\n  content: \"\\f000\"; }\n\n.fa.fa-meetup {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-star-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-star-o:before {\n  content: \"\\f005\"; }\n\n.fa.fa-remove:before {\n  content: \"\\f00d\"; }\n\n.fa.fa-close:before {\n  content: \"\\f00d\"; }\n\n.fa.fa-gear:before {\n  content: \"\\f013\"; }\n\n.fa.fa-trash-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-trash-o:before {\n  content: \"\\f2ed\"; }\n\n.fa.fa-file-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-o:before {\n  content: \"\\f15b\"; }\n\n.fa.fa-clock-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-clock-o:before {\n  content: \"\\f017\"; }\n\n.fa.fa-arrow-circle-o-down {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-arrow-circle-o-down:before {\n  content: \"\\f358\"; }\n\n.fa.fa-arrow-circle-o-up {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-arrow-circle-o-up:before {\n  content: \"\\f35b\"; }\n\n.fa.fa-play-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-play-circle-o:before {\n  content: \"\\f144\"; }\n\n.fa.fa-repeat:before {\n  content: \"\\f01e\"; }\n\n.fa.fa-rotate-right:before {\n  content: \"\\f01e\"; }\n\n.fa.fa-refresh:before {\n  content: \"\\f021\"; }\n\n.fa.fa-list-alt {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-dedent:before {\n  content: \"\\f03b\"; }\n\n.fa.fa-video-camera:before {\n  content: \"\\f03d\"; }\n\n.fa.fa-picture-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-picture-o:before {\n  content: \"\\f03e\"; }\n\n.fa.fa-photo {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-photo:before {\n  content: \"\\f03e\"; }\n\n.fa.fa-image {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-image:before {\n  content: \"\\f03e\"; }\n\n.fa.fa-pencil:before {\n  content: \"\\f303\"; }\n\n.fa.fa-map-marker:before {\n  content: \"\\f3c5\"; }\n\n.fa.fa-pencil-square-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-pencil-square-o:before {\n  content: \"\\f044\"; }\n\n.fa.fa-share-square-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-share-square-o:before {\n  content: \"\\f14d\"; }\n\n.fa.fa-check-square-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-check-square-o:before {\n  content: \"\\f14a\"; }\n\n.fa.fa-arrows:before {\n  content: \"\\f0b2\"; }\n\n.fa.fa-times-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-times-circle-o:before {\n  content: \"\\f057\"; }\n\n.fa.fa-check-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-check-circle-o:before {\n  content: \"\\f058\"; }\n\n.fa.fa-mail-forward:before {\n  content: \"\\f064\"; }\n\n.fa.fa-expand:before {\n  content: \"\\f424\"; }\n\n.fa.fa-compress:before {\n  content: \"\\f422\"; }\n\n.fa.fa-eye {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-eye-slash {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-warning:before {\n  content: \"\\f071\"; }\n\n.fa.fa-calendar:before {\n  content: \"\\f073\"; }\n\n.fa.fa-arrows-v:before {\n  content: \"\\f338\"; }\n\n.fa.fa-arrows-h:before {\n  content: \"\\f337\"; }\n\n.fa.fa-bar-chart {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-bar-chart:before {\n  content: \"\\f080\"; }\n\n.fa.fa-bar-chart-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-bar-chart-o:before {\n  content: \"\\f080\"; }\n\n.fa.fa-twitter-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-facebook-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-gears:before {\n  content: \"\\f085\"; }\n\n.fa.fa-thumbs-o-up {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-thumbs-o-up:before {\n  content: \"\\f164\"; }\n\n.fa.fa-thumbs-o-down {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-thumbs-o-down:before {\n  content: \"\\f165\"; }\n\n.fa.fa-heart-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-heart-o:before {\n  content: \"\\f004\"; }\n\n.fa.fa-sign-out:before {\n  content: \"\\f2f5\"; }\n\n.fa.fa-linkedin-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-linkedin-square:before {\n  content: \"\\f08c\"; }\n\n.fa.fa-thumb-tack:before {\n  content: \"\\f08d\"; }\n\n.fa.fa-external-link:before {\n  content: \"\\f35d\"; }\n\n.fa.fa-sign-in:before {\n  content: \"\\f2f6\"; }\n\n.fa.fa-github-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-lemon-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-lemon-o:before {\n  content: \"\\f094\"; }\n\n.fa.fa-square-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-square-o:before {\n  content: \"\\f0c8\"; }\n\n.fa.fa-bookmark-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-bookmark-o:before {\n  content: \"\\f02e\"; }\n\n.fa.fa-twitter {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-facebook {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-facebook:before {\n  content: \"\\f39e\"; }\n\n.fa.fa-facebook-f {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-facebook-f:before {\n  content: \"\\f39e\"; }\n\n.fa.fa-github {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-credit-card {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-feed:before {\n  content: \"\\f09e\"; }\n\n.fa.fa-hdd-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hdd-o:before {\n  content: \"\\f0a0\"; }\n\n.fa.fa-hand-o-right {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-o-right:before {\n  content: \"\\f0a4\"; }\n\n.fa.fa-hand-o-left {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-o-left:before {\n  content: \"\\f0a5\"; }\n\n.fa.fa-hand-o-up {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-o-up:before {\n  content: \"\\f0a6\"; }\n\n.fa.fa-hand-o-down {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-o-down:before {\n  content: \"\\f0a7\"; }\n\n.fa.fa-arrows-alt:before {\n  content: \"\\f31e\"; }\n\n.fa.fa-group:before {\n  content: \"\\f0c0\"; }\n\n.fa.fa-chain:before {\n  content: \"\\f0c1\"; }\n\n.fa.fa-scissors:before {\n  content: \"\\f0c4\"; }\n\n.fa.fa-files-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-files-o:before {\n  content: \"\\f0c5\"; }\n\n.fa.fa-floppy-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-floppy-o:before {\n  content: \"\\f0c7\"; }\n\n.fa.fa-navicon:before {\n  content: \"\\f0c9\"; }\n\n.fa.fa-reorder:before {\n  content: \"\\f0c9\"; }\n\n.fa.fa-pinterest {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-pinterest-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-google-plus-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-google-plus {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-google-plus:before {\n  content: \"\\f0d5\"; }\n\n.fa.fa-money {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-money:before {\n  content: \"\\f3d1\"; }\n\n.fa.fa-unsorted:before {\n  content: \"\\f0dc\"; }\n\n.fa.fa-sort-desc:before {\n  content: \"\\f0dd\"; }\n\n.fa.fa-sort-asc:before {\n  content: \"\\f0de\"; }\n\n.fa.fa-linkedin {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-linkedin:before {\n  content: \"\\f0e1\"; }\n\n.fa.fa-rotate-left:before {\n  content: \"\\f0e2\"; }\n\n.fa.fa-legal:before {\n  content: \"\\f0e3\"; }\n\n.fa.fa-tachometer:before {\n  content: \"\\f3fd\"; }\n\n.fa.fa-dashboard:before {\n  content: \"\\f3fd\"; }\n\n.fa.fa-comment-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-comment-o:before {\n  content: \"\\f075\"; }\n\n.fa.fa-comments-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-comments-o:before {\n  content: \"\\f086\"; }\n\n.fa.fa-flash:before {\n  content: \"\\f0e7\"; }\n\n.fa.fa-clipboard {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-paste {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-paste:before {\n  content: \"\\f328\"; }\n\n.fa.fa-lightbulb-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-lightbulb-o:before {\n  content: \"\\f0eb\"; }\n\n.fa.fa-exchange:before {\n  content: \"\\f362\"; }\n\n.fa.fa-cloud-download:before {\n  content: \"\\f381\"; }\n\n.fa.fa-cloud-upload:before {\n  content: \"\\f382\"; }\n\n.fa.fa-bell-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-bell-o:before {\n  content: \"\\f0f3\"; }\n\n.fa.fa-cutlery:before {\n  content: \"\\f2e7\"; }\n\n.fa.fa-file-text-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-text-o:before {\n  content: \"\\f15c\"; }\n\n.fa.fa-building-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-building-o:before {\n  content: \"\\f1ad\"; }\n\n.fa.fa-hospital-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hospital-o:before {\n  content: \"\\f0f8\"; }\n\n.fa.fa-tablet:before {\n  content: \"\\f3fa\"; }\n\n.fa.fa-mobile:before {\n  content: \"\\f3cd\"; }\n\n.fa.fa-mobile-phone:before {\n  content: \"\\f3cd\"; }\n\n.fa.fa-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-circle-o:before {\n  content: \"\\f111\"; }\n\n.fa.fa-mail-reply:before {\n  content: \"\\f3e5\"; }\n\n.fa.fa-github-alt {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-folder-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-folder-o:before {\n  content: \"\\f07b\"; }\n\n.fa.fa-folder-open-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-folder-open-o:before {\n  content: \"\\f07c\"; }\n\n.fa.fa-smile-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-smile-o:before {\n  content: \"\\f118\"; }\n\n.fa.fa-frown-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-frown-o:before {\n  content: \"\\f119\"; }\n\n.fa.fa-meh-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-meh-o:before {\n  content: \"\\f11a\"; }\n\n.fa.fa-keyboard-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-keyboard-o:before {\n  content: \"\\f11c\"; }\n\n.fa.fa-flag-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-flag-o:before {\n  content: \"\\f024\"; }\n\n.fa.fa-mail-reply-all:before {\n  content: \"\\f122\"; }\n\n.fa.fa-star-half-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-star-half-o:before {\n  content: \"\\f089\"; }\n\n.fa.fa-star-half-empty {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-star-half-empty:before {\n  content: \"\\f089\"; }\n\n.fa.fa-star-half-full {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-star-half-full:before {\n  content: \"\\f089\"; }\n\n.fa.fa-code-fork:before {\n  content: \"\\f126\"; }\n\n.fa.fa-chain-broken:before {\n  content: \"\\f127\"; }\n\n.fa.fa-shield:before {\n  content: \"\\f3ed\"; }\n\n.fa.fa-calendar-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-calendar-o:before {\n  content: \"\\f133\"; }\n\n.fa.fa-maxcdn {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-html5 {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-css3 {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-ticket:before {\n  content: \"\\f3ff\"; }\n\n.fa.fa-minus-square-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-minus-square-o:before {\n  content: \"\\f146\"; }\n\n.fa.fa-level-up:before {\n  content: \"\\f3bf\"; }\n\n.fa.fa-level-down:before {\n  content: \"\\f3be\"; }\n\n.fa.fa-pencil-square:before {\n  content: \"\\f14b\"; }\n\n.fa.fa-external-link-square:before {\n  content: \"\\f360\"; }\n\n.fa.fa-compass {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-caret-square-o-down {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-caret-square-o-down:before {\n  content: \"\\f150\"; }\n\n.fa.fa-toggle-down {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-toggle-down:before {\n  content: \"\\f150\"; }\n\n.fa.fa-caret-square-o-up {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-caret-square-o-up:before {\n  content: \"\\f151\"; }\n\n.fa.fa-toggle-up {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-toggle-up:before {\n  content: \"\\f151\"; }\n\n.fa.fa-caret-square-o-right {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-caret-square-o-right:before {\n  content: \"\\f152\"; }\n\n.fa.fa-toggle-right {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-toggle-right:before {\n  content: \"\\f152\"; }\n\n.fa.fa-eur:before {\n  content: \"\\f153\"; }\n\n.fa.fa-euro:before {\n  content: \"\\f153\"; }\n\n.fa.fa-gbp:before {\n  content: \"\\f154\"; }\n\n.fa.fa-usd:before {\n  content: \"\\f155\"; }\n\n.fa.fa-dollar:before {\n  content: \"\\f155\"; }\n\n.fa.fa-inr:before {\n  content: \"\\f156\"; }\n\n.fa.fa-rupee:before {\n  content: \"\\f156\"; }\n\n.fa.fa-jpy:before {\n  content: \"\\f157\"; }\n\n.fa.fa-cny:before {\n  content: \"\\f157\"; }\n\n.fa.fa-rmb:before {\n  content: \"\\f157\"; }\n\n.fa.fa-yen:before {\n  content: \"\\f157\"; }\n\n.fa.fa-rub:before {\n  content: \"\\f158\"; }\n\n.fa.fa-ruble:before {\n  content: \"\\f158\"; }\n\n.fa.fa-rouble:before {\n  content: \"\\f158\"; }\n\n.fa.fa-krw:before {\n  content: \"\\f159\"; }\n\n.fa.fa-won:before {\n  content: \"\\f159\"; }\n\n.fa.fa-btc {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-bitcoin {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-bitcoin:before {\n  content: \"\\f15a\"; }\n\n.fa.fa-file-text:before {\n  content: \"\\f15c\"; }\n\n.fa.fa-sort-alpha-asc:before {\n  content: \"\\f15d\"; }\n\n.fa.fa-sort-alpha-desc:before {\n  content: \"\\f881\"; }\n\n.fa.fa-sort-amount-asc:before {\n  content: \"\\f160\"; }\n\n.fa.fa-sort-amount-desc:before {\n  content: \"\\f884\"; }\n\n.fa.fa-sort-numeric-asc:before {\n  content: \"\\f162\"; }\n\n.fa.fa-sort-numeric-desc:before {\n  content: \"\\f886\"; }\n\n.fa.fa-youtube-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-youtube {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-xing {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-xing-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-youtube-play {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-youtube-play:before {\n  content: \"\\f167\"; }\n\n.fa.fa-dropbox {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-stack-overflow {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-instagram {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-flickr {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-adn {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-bitbucket {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-bitbucket-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-bitbucket-square:before {\n  content: \"\\f171\"; }\n\n.fa.fa-tumblr {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-tumblr-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-long-arrow-down:before {\n  content: \"\\f309\"; }\n\n.fa.fa-long-arrow-up:before {\n  content: \"\\f30c\"; }\n\n.fa.fa-long-arrow-left:before {\n  content: \"\\f30a\"; }\n\n.fa.fa-long-arrow-right:before {\n  content: \"\\f30b\"; }\n\n.fa.fa-apple {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-windows {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-android {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-linux {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-dribbble {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-skype {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-foursquare {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-trello {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-gratipay {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-gittip {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-gittip:before {\n  content: \"\\f184\"; }\n\n.fa.fa-sun-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-sun-o:before {\n  content: \"\\f185\"; }\n\n.fa.fa-moon-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-moon-o:before {\n  content: \"\\f186\"; }\n\n.fa.fa-vk {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-weibo {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-renren {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-pagelines {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-stack-exchange {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-arrow-circle-o-right {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-arrow-circle-o-right:before {\n  content: \"\\f35a\"; }\n\n.fa.fa-arrow-circle-o-left {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-arrow-circle-o-left:before {\n  content: \"\\f359\"; }\n\n.fa.fa-caret-square-o-left {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-caret-square-o-left:before {\n  content: \"\\f191\"; }\n\n.fa.fa-toggle-left {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-toggle-left:before {\n  content: \"\\f191\"; }\n\n.fa.fa-dot-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-dot-circle-o:before {\n  content: \"\\f192\"; }\n\n.fa.fa-vimeo-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-try:before {\n  content: \"\\f195\"; }\n\n.fa.fa-turkish-lira:before {\n  content: \"\\f195\"; }\n\n.fa.fa-plus-square-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-plus-square-o:before {\n  content: \"\\f0fe\"; }\n\n.fa.fa-slack {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wordpress {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-openid {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-institution:before {\n  content: \"\\f19c\"; }\n\n.fa.fa-bank:before {\n  content: \"\\f19c\"; }\n\n.fa.fa-mortar-board:before {\n  content: \"\\f19d\"; }\n\n.fa.fa-yahoo {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-google {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-reddit {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-reddit-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-stumbleupon-circle {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-stumbleupon {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-delicious {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-digg {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-pied-piper-pp {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-pied-piper-alt {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-drupal {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-joomla {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-spoon:before {\n  content: \"\\f2e5\"; }\n\n.fa.fa-behance {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-behance-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-steam {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-steam-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-automobile:before {\n  content: \"\\f1b9\"; }\n\n.fa.fa-envelope-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-envelope-o:before {\n  content: \"\\f0e0\"; }\n\n.fa.fa-spotify {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-deviantart {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-soundcloud {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-file-pdf-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-pdf-o:before {\n  content: \"\\f1c1\"; }\n\n.fa.fa-file-word-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-word-o:before {\n  content: \"\\f1c2\"; }\n\n.fa.fa-file-excel-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-excel-o:before {\n  content: \"\\f1c3\"; }\n\n.fa.fa-file-powerpoint-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-powerpoint-o:before {\n  content: \"\\f1c4\"; }\n\n.fa.fa-file-image-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-image-o:before {\n  content: \"\\f1c5\"; }\n\n.fa.fa-file-photo-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-photo-o:before {\n  content: \"\\f1c5\"; }\n\n.fa.fa-file-picture-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-picture-o:before {\n  content: \"\\f1c5\"; }\n\n.fa.fa-file-archive-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-archive-o:before {\n  content: \"\\f1c6\"; }\n\n.fa.fa-file-zip-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-zip-o:before {\n  content: \"\\f1c6\"; }\n\n.fa.fa-file-audio-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-audio-o:before {\n  content: \"\\f1c7\"; }\n\n.fa.fa-file-sound-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-sound-o:before {\n  content: \"\\f1c7\"; }\n\n.fa.fa-file-video-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-video-o:before {\n  content: \"\\f1c8\"; }\n\n.fa.fa-file-movie-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-movie-o:before {\n  content: \"\\f1c8\"; }\n\n.fa.fa-file-code-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-file-code-o:before {\n  content: \"\\f1c9\"; }\n\n.fa.fa-vine {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-codepen {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-jsfiddle {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-life-ring {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-life-bouy {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-life-bouy:before {\n  content: \"\\f1cd\"; }\n\n.fa.fa-life-buoy {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-life-buoy:before {\n  content: \"\\f1cd\"; }\n\n.fa.fa-life-saver {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-life-saver:before {\n  content: \"\\f1cd\"; }\n\n.fa.fa-support {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-support:before {\n  content: \"\\f1cd\"; }\n\n.fa.fa-circle-o-notch:before {\n  content: \"\\f1ce\"; }\n\n.fa.fa-rebel {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-ra {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-ra:before {\n  content: \"\\f1d0\"; }\n\n.fa.fa-resistance {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-resistance:before {\n  content: \"\\f1d0\"; }\n\n.fa.fa-empire {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-ge {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-ge:before {\n  content: \"\\f1d1\"; }\n\n.fa.fa-git-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-git {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-hacker-news {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-y-combinator-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-y-combinator-square:before {\n  content: \"\\f1d4\"; }\n\n.fa.fa-yc-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-yc-square:before {\n  content: \"\\f1d4\"; }\n\n.fa.fa-tencent-weibo {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-qq {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-weixin {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wechat {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wechat:before {\n  content: \"\\f1d7\"; }\n\n.fa.fa-send:before {\n  content: \"\\f1d8\"; }\n\n.fa.fa-paper-plane-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-paper-plane-o:before {\n  content: \"\\f1d8\"; }\n\n.fa.fa-send-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-send-o:before {\n  content: \"\\f1d8\"; }\n\n.fa.fa-circle-thin {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-circle-thin:before {\n  content: \"\\f111\"; }\n\n.fa.fa-header:before {\n  content: \"\\f1dc\"; }\n\n.fa.fa-sliders:before {\n  content: \"\\f1de\"; }\n\n.fa.fa-futbol-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-futbol-o:before {\n  content: \"\\f1e3\"; }\n\n.fa.fa-soccer-ball-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-soccer-ball-o:before {\n  content: \"\\f1e3\"; }\n\n.fa.fa-slideshare {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-twitch {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-yelp {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-newspaper-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-newspaper-o:before {\n  content: \"\\f1ea\"; }\n\n.fa.fa-paypal {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-google-wallet {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cc-visa {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cc-mastercard {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cc-discover {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cc-amex {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cc-paypal {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cc-stripe {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-bell-slash-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-bell-slash-o:before {\n  content: \"\\f1f6\"; }\n\n.fa.fa-trash:before {\n  content: \"\\f2ed\"; }\n\n.fa.fa-copyright {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-eyedropper:before {\n  content: \"\\f1fb\"; }\n\n.fa.fa-area-chart:before {\n  content: \"\\f1fe\"; }\n\n.fa.fa-pie-chart:before {\n  content: \"\\f200\"; }\n\n.fa.fa-line-chart:before {\n  content: \"\\f201\"; }\n\n.fa.fa-lastfm {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-lastfm-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-ioxhost {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-angellist {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cc {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-cc:before {\n  content: \"\\f20a\"; }\n\n.fa.fa-ils:before {\n  content: \"\\f20b\"; }\n\n.fa.fa-shekel:before {\n  content: \"\\f20b\"; }\n\n.fa.fa-sheqel:before {\n  content: \"\\f20b\"; }\n\n.fa.fa-meanpath {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-meanpath:before {\n  content: \"\\f2b4\"; }\n\n.fa.fa-buysellads {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-connectdevelop {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-dashcube {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-forumbee {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-leanpub {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-sellsy {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-shirtsinbulk {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-simplybuilt {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-skyatlas {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-diamond {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-diamond:before {\n  content: \"\\f3a5\"; }\n\n.fa.fa-intersex:before {\n  content: \"\\f224\"; }\n\n.fa.fa-facebook-official {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-facebook-official:before {\n  content: \"\\f09a\"; }\n\n.fa.fa-pinterest-p {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-whatsapp {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-hotel:before {\n  content: \"\\f236\"; }\n\n.fa.fa-viacoin {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-medium {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-y-combinator {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-yc {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-yc:before {\n  content: \"\\f23b\"; }\n\n.fa.fa-optin-monster {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-opencart {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-expeditedssl {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-battery-4:before {\n  content: \"\\f240\"; }\n\n.fa.fa-battery:before {\n  content: \"\\f240\"; }\n\n.fa.fa-battery-3:before {\n  content: \"\\f241\"; }\n\n.fa.fa-battery-2:before {\n  content: \"\\f242\"; }\n\n.fa.fa-battery-1:before {\n  content: \"\\f243\"; }\n\n.fa.fa-battery-0:before {\n  content: \"\\f244\"; }\n\n.fa.fa-object-group {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-object-ungroup {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-sticky-note-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-sticky-note-o:before {\n  content: \"\\f249\"; }\n\n.fa.fa-cc-jcb {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cc-diners-club {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-clone {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hourglass-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hourglass-o:before {\n  content: \"\\f254\"; }\n\n.fa.fa-hourglass-1:before {\n  content: \"\\f251\"; }\n\n.fa.fa-hourglass-2:before {\n  content: \"\\f252\"; }\n\n.fa.fa-hourglass-3:before {\n  content: \"\\f253\"; }\n\n.fa.fa-hand-rock-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-rock-o:before {\n  content: \"\\f255\"; }\n\n.fa.fa-hand-grab-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-grab-o:before {\n  content: \"\\f255\"; }\n\n.fa.fa-hand-paper-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-paper-o:before {\n  content: \"\\f256\"; }\n\n.fa.fa-hand-stop-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-stop-o:before {\n  content: \"\\f256\"; }\n\n.fa.fa-hand-scissors-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-scissors-o:before {\n  content: \"\\f257\"; }\n\n.fa.fa-hand-lizard-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-lizard-o:before {\n  content: \"\\f258\"; }\n\n.fa.fa-hand-spock-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-spock-o:before {\n  content: \"\\f259\"; }\n\n.fa.fa-hand-pointer-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-pointer-o:before {\n  content: \"\\f25a\"; }\n\n.fa.fa-hand-peace-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-hand-peace-o:before {\n  content: \"\\f25b\"; }\n\n.fa.fa-registered {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-creative-commons {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-gg {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-gg-circle {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-tripadvisor {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-odnoklassniki {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-odnoklassniki-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-get-pocket {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wikipedia-w {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-safari {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-chrome {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-firefox {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-opera {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-internet-explorer {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-television:before {\n  content: \"\\f26c\"; }\n\n.fa.fa-contao {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-500px {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-amazon {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-calendar-plus-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-calendar-plus-o:before {\n  content: \"\\f271\"; }\n\n.fa.fa-calendar-minus-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-calendar-minus-o:before {\n  content: \"\\f272\"; }\n\n.fa.fa-calendar-times-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-calendar-times-o:before {\n  content: \"\\f273\"; }\n\n.fa.fa-calendar-check-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-calendar-check-o:before {\n  content: \"\\f274\"; }\n\n.fa.fa-map-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-map-o:before {\n  content: \"\\f279\"; }\n\n.fa.fa-commenting:before {\n  content: \"\\f4ad\"; }\n\n.fa.fa-commenting-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-commenting-o:before {\n  content: \"\\f4ad\"; }\n\n.fa.fa-houzz {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-vimeo {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-vimeo:before {\n  content: \"\\f27d\"; }\n\n.fa.fa-black-tie {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-fonticons {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-reddit-alien {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-edge {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-credit-card-alt:before {\n  content: \"\\f09d\"; }\n\n.fa.fa-codiepie {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-modx {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-fort-awesome {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-usb {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-product-hunt {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-mixcloud {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-scribd {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-pause-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-pause-circle-o:before {\n  content: \"\\f28b\"; }\n\n.fa.fa-stop-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-stop-circle-o:before {\n  content: \"\\f28d\"; }\n\n.fa.fa-bluetooth {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-bluetooth-b {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-gitlab {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wpbeginner {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wpforms {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-envira {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wheelchair-alt {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wheelchair-alt:before {\n  content: \"\\f368\"; }\n\n.fa.fa-question-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-question-circle-o:before {\n  content: \"\\f059\"; }\n\n.fa.fa-volume-control-phone:before {\n  content: \"\\f2a0\"; }\n\n.fa.fa-asl-interpreting:before {\n  content: \"\\f2a3\"; }\n\n.fa.fa-deafness:before {\n  content: \"\\f2a4\"; }\n\n.fa.fa-hard-of-hearing:before {\n  content: \"\\f2a4\"; }\n\n.fa.fa-glide {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-glide-g {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-signing:before {\n  content: \"\\f2a7\"; }\n\n.fa.fa-viadeo {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-viadeo-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-snapchat {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-snapchat-ghost {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-snapchat-square {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-pied-piper {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-first-order {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-yoast {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-themeisle {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-google-plus-official {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-google-plus-official:before {\n  content: \"\\f2b3\"; }\n\n.fa.fa-google-plus-circle {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-google-plus-circle:before {\n  content: \"\\f2b3\"; }\n\n.fa.fa-font-awesome {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-fa {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-fa:before {\n  content: \"\\f2b4\"; }\n\n.fa.fa-handshake-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-handshake-o:before {\n  content: \"\\f2b5\"; }\n\n.fa.fa-envelope-open-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-envelope-open-o:before {\n  content: \"\\f2b6\"; }\n\n.fa.fa-linode {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-address-book-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-address-book-o:before {\n  content: \"\\f2b9\"; }\n\n.fa.fa-vcard:before {\n  content: \"\\f2bb\"; }\n\n.fa.fa-address-card-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-address-card-o:before {\n  content: \"\\f2bb\"; }\n\n.fa.fa-vcard-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-vcard-o:before {\n  content: \"\\f2bb\"; }\n\n.fa.fa-user-circle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-user-circle-o:before {\n  content: \"\\f2bd\"; }\n\n.fa.fa-user-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-user-o:before {\n  content: \"\\f007\"; }\n\n.fa.fa-id-badge {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-drivers-license:before {\n  content: \"\\f2c2\"; }\n\n.fa.fa-id-card-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-id-card-o:before {\n  content: \"\\f2c2\"; }\n\n.fa.fa-drivers-license-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-drivers-license-o:before {\n  content: \"\\f2c2\"; }\n\n.fa.fa-quora {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-free-code-camp {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-telegram {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-thermometer-4:before {\n  content: \"\\f2c7\"; }\n\n.fa.fa-thermometer:before {\n  content: \"\\f2c7\"; }\n\n.fa.fa-thermometer-3:before {\n  content: \"\\f2c8\"; }\n\n.fa.fa-thermometer-2:before {\n  content: \"\\f2c9\"; }\n\n.fa.fa-thermometer-1:before {\n  content: \"\\f2ca\"; }\n\n.fa.fa-thermometer-0:before {\n  content: \"\\f2cb\"; }\n\n.fa.fa-bathtub:before {\n  content: \"\\f2cd\"; }\n\n.fa.fa-s15:before {\n  content: \"\\f2cd\"; }\n\n.fa.fa-window-maximize {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-window-restore {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-times-rectangle:before {\n  content: \"\\f410\"; }\n\n.fa.fa-window-close-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-window-close-o:before {\n  content: \"\\f410\"; }\n\n.fa.fa-times-rectangle-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-times-rectangle-o:before {\n  content: \"\\f410\"; }\n\n.fa.fa-bandcamp {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-grav {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-etsy {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-imdb {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-ravelry {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-eercast {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-eercast:before {\n  content: \"\\f2da\"; }\n\n.fa.fa-snowflake-o {\n  font-family: 'Font Awesome 5 Free';\n  font-weight: 400; }\n\n.fa.fa-snowflake-o:before {\n  content: \"\\f2dc\"; }\n\n.fa.fa-superpowers {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-wpexplorer {\n  font-family: 'Font Awesome 5 Brands';\n  font-weight: 400; }\n\n.fa.fa-cab:before {\n  content: \"\\f1ba\"; }\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/fontawesome-5.15.4/css/v4-shims.min.css",
    "content": "/*!\n * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com\n * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)\n */\n.fa.fa-glass:before{content:\"\\f000\"}.fa.fa-meetup{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-star-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-star-o:before{content:\"\\f005\"}.fa.fa-close:before,.fa.fa-remove:before{content:\"\\f00d\"}.fa.fa-gear:before{content:\"\\f013\"}.fa.fa-trash-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-trash-o:before{content:\"\\f2ed\"}.fa.fa-file-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-o:before{content:\"\\f15b\"}.fa.fa-clock-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-clock-o:before{content:\"\\f017\"}.fa.fa-arrow-circle-o-down{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:\"\\f358\"}.fa.fa-arrow-circle-o-up{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:\"\\f35b\"}.fa.fa-play-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-play-circle-o:before{content:\"\\f144\"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:\"\\f01e\"}.fa.fa-refresh:before{content:\"\\f021\"}.fa.fa-list-alt{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-dedent:before{content:\"\\f03b\"}.fa.fa-video-camera:before{content:\"\\f03d\"}.fa.fa-picture-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-picture-o:before{content:\"\\f03e\"}.fa.fa-photo{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-photo:before{content:\"\\f03e\"}.fa.fa-image{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-image:before{content:\"\\f03e\"}.fa.fa-pencil:before{content:\"\\f303\"}.fa.fa-map-marker:before{content:\"\\f3c5\"}.fa.fa-pencil-square-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-pencil-square-o:before{content:\"\\f044\"}.fa.fa-share-square-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-share-square-o:before{content:\"\\f14d\"}.fa.fa-check-square-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-check-square-o:before{content:\"\\f14a\"}.fa.fa-arrows:before{content:\"\\f0b2\"}.fa.fa-times-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-times-circle-o:before{content:\"\\f057\"}.fa.fa-check-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-check-circle-o:before{content:\"\\f058\"}.fa.fa-mail-forward:before{content:\"\\f064\"}.fa.fa-expand:before{content:\"\\f424\"}.fa.fa-compress:before{content:\"\\f422\"}.fa.fa-eye,.fa.fa-eye-slash{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-warning:before{content:\"\\f071\"}.fa.fa-calendar:before{content:\"\\f073\"}.fa.fa-arrows-v:before{content:\"\\f338\"}.fa.fa-arrows-h:before{content:\"\\f337\"}.fa.fa-bar-chart{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-bar-chart:before{content:\"\\f080\"}.fa.fa-bar-chart-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-bar-chart-o:before{content:\"\\f080\"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-gears:before{content:\"\\f085\"}.fa.fa-thumbs-o-up{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-thumbs-o-up:before{content:\"\\f164\"}.fa.fa-thumbs-o-down{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-thumbs-o-down:before{content:\"\\f165\"}.fa.fa-heart-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-heart-o:before{content:\"\\f004\"}.fa.fa-sign-out:before{content:\"\\f2f5\"}.fa.fa-linkedin-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-linkedin-square:before{content:\"\\f08c\"}.fa.fa-thumb-tack:before{content:\"\\f08d\"}.fa.fa-external-link:before{content:\"\\f35d\"}.fa.fa-sign-in:before{content:\"\\f2f6\"}.fa.fa-github-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-lemon-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-lemon-o:before{content:\"\\f094\"}.fa.fa-square-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-square-o:before{content:\"\\f0c8\"}.fa.fa-bookmark-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-bookmark-o:before{content:\"\\f02e\"}.fa.fa-facebook,.fa.fa-twitter{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-facebook:before{content:\"\\f39e\"}.fa.fa-facebook-f{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-facebook-f:before{content:\"\\f39e\"}.fa.fa-github{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-credit-card{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-feed:before{content:\"\\f09e\"}.fa.fa-hdd-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hdd-o:before{content:\"\\f0a0\"}.fa.fa-hand-o-right{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-o-right:before{content:\"\\f0a4\"}.fa.fa-hand-o-left{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-o-left:before{content:\"\\f0a5\"}.fa.fa-hand-o-up{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-o-up:before{content:\"\\f0a6\"}.fa.fa-hand-o-down{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-o-down:before{content:\"\\f0a7\"}.fa.fa-arrows-alt:before{content:\"\\f31e\"}.fa.fa-group:before{content:\"\\f0c0\"}.fa.fa-chain:before{content:\"\\f0c1\"}.fa.fa-scissors:before{content:\"\\f0c4\"}.fa.fa-files-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-files-o:before{content:\"\\f0c5\"}.fa.fa-floppy-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-floppy-o:before{content:\"\\f0c7\"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:\"\\f0c9\"}.fa.fa-google-plus,.fa.fa-google-plus-square,.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-google-plus:before{content:\"\\f0d5\"}.fa.fa-money{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-money:before{content:\"\\f3d1\"}.fa.fa-unsorted:before{content:\"\\f0dc\"}.fa.fa-sort-desc:before{content:\"\\f0dd\"}.fa.fa-sort-asc:before{content:\"\\f0de\"}.fa.fa-linkedin{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-linkedin:before{content:\"\\f0e1\"}.fa.fa-rotate-left:before{content:\"\\f0e2\"}.fa.fa-legal:before{content:\"\\f0e3\"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:\"\\f3fd\"}.fa.fa-comment-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-comment-o:before{content:\"\\f075\"}.fa.fa-comments-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-comments-o:before{content:\"\\f086\"}.fa.fa-flash:before{content:\"\\f0e7\"}.fa.fa-clipboard,.fa.fa-paste{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-paste:before{content:\"\\f328\"}.fa.fa-lightbulb-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-lightbulb-o:before{content:\"\\f0eb\"}.fa.fa-exchange:before{content:\"\\f362\"}.fa.fa-cloud-download:before{content:\"\\f381\"}.fa.fa-cloud-upload:before{content:\"\\f382\"}.fa.fa-bell-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-bell-o:before{content:\"\\f0f3\"}.fa.fa-cutlery:before{content:\"\\f2e7\"}.fa.fa-file-text-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-text-o:before{content:\"\\f15c\"}.fa.fa-building-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-building-o:before{content:\"\\f1ad\"}.fa.fa-hospital-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hospital-o:before{content:\"\\f0f8\"}.fa.fa-tablet:before{content:\"\\f3fa\"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:\"\\f3cd\"}.fa.fa-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-circle-o:before{content:\"\\f111\"}.fa.fa-mail-reply:before{content:\"\\f3e5\"}.fa.fa-github-alt{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-folder-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-folder-o:before{content:\"\\f07b\"}.fa.fa-folder-open-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-folder-open-o:before{content:\"\\f07c\"}.fa.fa-smile-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-smile-o:before{content:\"\\f118\"}.fa.fa-frown-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-frown-o:before{content:\"\\f119\"}.fa.fa-meh-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-meh-o:before{content:\"\\f11a\"}.fa.fa-keyboard-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-keyboard-o:before{content:\"\\f11c\"}.fa.fa-flag-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-flag-o:before{content:\"\\f024\"}.fa.fa-mail-reply-all:before{content:\"\\f122\"}.fa.fa-star-half-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-star-half-o:before{content:\"\\f089\"}.fa.fa-star-half-empty{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-star-half-empty:before{content:\"\\f089\"}.fa.fa-star-half-full{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-star-half-full:before{content:\"\\f089\"}.fa.fa-code-fork:before{content:\"\\f126\"}.fa.fa-chain-broken:before{content:\"\\f127\"}.fa.fa-shield:before{content:\"\\f3ed\"}.fa.fa-calendar-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-calendar-o:before{content:\"\\f133\"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-ticket:before{content:\"\\f3ff\"}.fa.fa-minus-square-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-minus-square-o:before{content:\"\\f146\"}.fa.fa-level-up:before{content:\"\\f3bf\"}.fa.fa-level-down:before{content:\"\\f3be\"}.fa.fa-pencil-square:before{content:\"\\f14b\"}.fa.fa-external-link-square:before{content:\"\\f360\"}.fa.fa-compass{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-caret-square-o-down{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-caret-square-o-down:before{content:\"\\f150\"}.fa.fa-toggle-down{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-toggle-down:before{content:\"\\f150\"}.fa.fa-caret-square-o-up{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-caret-square-o-up:before{content:\"\\f151\"}.fa.fa-toggle-up{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-toggle-up:before{content:\"\\f151\"}.fa.fa-caret-square-o-right{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-caret-square-o-right:before{content:\"\\f152\"}.fa.fa-toggle-right{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-toggle-right:before{content:\"\\f152\"}.fa.fa-eur:before,.fa.fa-euro:before{content:\"\\f153\"}.fa.fa-gbp:before{content:\"\\f154\"}.fa.fa-dollar:before,.fa.fa-usd:before{content:\"\\f155\"}.fa.fa-inr:before,.fa.fa-rupee:before{content:\"\\f156\"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:\"\\f157\"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:\"\\f158\"}.fa.fa-krw:before,.fa.fa-won:before{content:\"\\f159\"}.fa.fa-bitcoin,.fa.fa-btc{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-bitcoin:before{content:\"\\f15a\"}.fa.fa-file-text:before{content:\"\\f15c\"}.fa.fa-sort-alpha-asc:before{content:\"\\f15d\"}.fa.fa-sort-alpha-desc:before{content:\"\\f881\"}.fa.fa-sort-amount-asc:before{content:\"\\f160\"}.fa.fa-sort-amount-desc:before{content:\"\\f884\"}.fa.fa-sort-numeric-asc:before{content:\"\\f162\"}.fa.fa-sort-numeric-desc:before{content:\"\\f886\"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-play,.fa.fa-youtube-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-youtube-play:before{content:\"\\f167\"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-bitbucket-square:before{content:\"\\f171\"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-long-arrow-down:before{content:\"\\f309\"}.fa.fa-long-arrow-up:before{content:\"\\f30c\"}.fa.fa-long-arrow-left:before{content:\"\\f30a\"}.fa.fa-long-arrow-right:before{content:\"\\f30b\"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-gittip:before{content:\"\\f184\"}.fa.fa-sun-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-sun-o:before{content:\"\\f185\"}.fa.fa-moon-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-moon-o:before{content:\"\\f186\"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:\"\\f35a\"}.fa.fa-arrow-circle-o-left{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:\"\\f359\"}.fa.fa-caret-square-o-left{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-caret-square-o-left:before{content:\"\\f191\"}.fa.fa-toggle-left{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-toggle-left:before{content:\"\\f191\"}.fa.fa-dot-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-dot-circle-o:before{content:\"\\f192\"}.fa.fa-vimeo-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:\"\\f195\"}.fa.fa-plus-square-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-plus-square-o:before{content:\"\\f0fe\"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:\"\\f19c\"}.fa.fa-mortar-board:before{content:\"\\f19d\"}.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-google,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle,.fa.fa-yahoo{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-spoon:before{content:\"\\f2e5\"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-steam,.fa.fa-steam-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-automobile:before{content:\"\\f1b9\"}.fa.fa-envelope-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-envelope-o:before{content:\"\\f0e0\"}.fa.fa-deviantart,.fa.fa-soundcloud,.fa.fa-spotify{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-file-pdf-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-pdf-o:before{content:\"\\f1c1\"}.fa.fa-file-word-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-word-o:before{content:\"\\f1c2\"}.fa.fa-file-excel-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-excel-o:before{content:\"\\f1c3\"}.fa.fa-file-powerpoint-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-powerpoint-o:before{content:\"\\f1c4\"}.fa.fa-file-image-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-image-o:before{content:\"\\f1c5\"}.fa.fa-file-photo-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-photo-o:before{content:\"\\f1c5\"}.fa.fa-file-picture-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-picture-o:before{content:\"\\f1c5\"}.fa.fa-file-archive-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-archive-o:before{content:\"\\f1c6\"}.fa.fa-file-zip-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-zip-o:before{content:\"\\f1c6\"}.fa.fa-file-audio-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-audio-o:before{content:\"\\f1c7\"}.fa.fa-file-sound-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-sound-o:before{content:\"\\f1c7\"}.fa.fa-file-video-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-video-o:before{content:\"\\f1c8\"}.fa.fa-file-movie-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-movie-o:before{content:\"\\f1c8\"}.fa.fa-file-code-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-file-code-o:before{content:\"\\f1c9\"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-life-bouy,.fa.fa-life-ring{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-life-bouy:before{content:\"\\f1cd\"}.fa.fa-life-buoy{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-life-buoy:before{content:\"\\f1cd\"}.fa.fa-life-saver{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-life-saver:before{content:\"\\f1cd\"}.fa.fa-support{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-support:before{content:\"\\f1cd\"}.fa.fa-circle-o-notch:before{content:\"\\f1ce\"}.fa.fa-ra,.fa.fa-rebel{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-ra:before{content:\"\\f1d0\"}.fa.fa-resistance{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-resistance:before{content:\"\\f1d0\"}.fa.fa-empire,.fa.fa-ge{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-ge:before{content:\"\\f1d1\"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-y-combinator-square:before{content:\"\\f1d4\"}.fa.fa-yc-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-yc-square:before{content:\"\\f1d4\"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-wechat:before{content:\"\\f1d7\"}.fa.fa-send:before{content:\"\\f1d8\"}.fa.fa-paper-plane-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-paper-plane-o:before{content:\"\\f1d8\"}.fa.fa-send-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-send-o:before{content:\"\\f1d8\"}.fa.fa-circle-thin{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-circle-thin:before{content:\"\\f111\"}.fa.fa-header:before{content:\"\\f1dc\"}.fa.fa-sliders:before{content:\"\\f1de\"}.fa.fa-futbol-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-futbol-o:before{content:\"\\f1e3\"}.fa.fa-soccer-ball-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-soccer-ball-o:before{content:\"\\f1e3\"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-newspaper-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-newspaper-o:before{content:\"\\f1ea\"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-bell-slash-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-bell-slash-o:before{content:\"\\f1f6\"}.fa.fa-trash:before{content:\"\\f2ed\"}.fa.fa-copyright{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-eyedropper:before{content:\"\\f1fb\"}.fa.fa-area-chart:before{content:\"\\f1fe\"}.fa.fa-pie-chart:before{content:\"\\f200\"}.fa.fa-line-chart:before{content:\"\\f201\"}.fa.fa-angellist,.fa.fa-ioxhost,.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-cc{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-cc:before{content:\"\\f20a\"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:\"\\f20b\"}.fa.fa-meanpath{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-meanpath:before{content:\"\\f2b4\"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-diamond{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-diamond:before{content:\"\\f3a5\"}.fa.fa-intersex:before{content:\"\\f224\"}.fa.fa-facebook-official{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-facebook-official:before{content:\"\\f09a\"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-hotel:before{content:\"\\f236\"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-yc:before{content:\"\\f23b\"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:\"\\f240\"}.fa.fa-battery-3:before{content:\"\\f241\"}.fa.fa-battery-2:before{content:\"\\f242\"}.fa.fa-battery-1:before{content:\"\\f243\"}.fa.fa-battery-0:before{content:\"\\f244\"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-sticky-note-o:before{content:\"\\f249\"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-clone,.fa.fa-hourglass-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hourglass-o:before{content:\"\\f254\"}.fa.fa-hourglass-1:before{content:\"\\f251\"}.fa.fa-hourglass-2:before{content:\"\\f252\"}.fa.fa-hourglass-3:before{content:\"\\f253\"}.fa.fa-hand-rock-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-rock-o:before{content:\"\\f255\"}.fa.fa-hand-grab-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-grab-o:before{content:\"\\f255\"}.fa.fa-hand-paper-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-paper-o:before{content:\"\\f256\"}.fa.fa-hand-stop-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-stop-o:before{content:\"\\f256\"}.fa.fa-hand-scissors-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-scissors-o:before{content:\"\\f257\"}.fa.fa-hand-lizard-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-lizard-o:before{content:\"\\f258\"}.fa.fa-hand-spock-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-spock-o:before{content:\"\\f259\"}.fa.fa-hand-pointer-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-pointer-o:before{content:\"\\f25a\"}.fa.fa-hand-peace-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-hand-peace-o:before{content:\"\\f25b\"}.fa.fa-registered{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-chrome,.fa.fa-creative-commons,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-internet-explorer,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square,.fa.fa-opera,.fa.fa-safari,.fa.fa-tripadvisor,.fa.fa-wikipedia-w{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-television:before{content:\"\\f26c\"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-calendar-plus-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-calendar-plus-o:before{content:\"\\f271\"}.fa.fa-calendar-minus-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-calendar-minus-o:before{content:\"\\f272\"}.fa.fa-calendar-times-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-calendar-times-o:before{content:\"\\f273\"}.fa.fa-calendar-check-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-calendar-check-o:before{content:\"\\f274\"}.fa.fa-map-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-map-o:before{content:\"\\f279\"}.fa.fa-commenting:before{content:\"\\f4ad\"}.fa.fa-commenting-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-commenting-o:before{content:\"\\f4ad\"}.fa.fa-houzz,.fa.fa-vimeo{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-vimeo:before{content:\"\\f27d\"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-credit-card-alt:before{content:\"\\f09d\"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-pause-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-pause-circle-o:before{content:\"\\f28b\"}.fa.fa-stop-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-stop-circle-o:before{content:\"\\f28d\"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-wheelchair-alt:before{content:\"\\f368\"}.fa.fa-question-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-question-circle-o:before{content:\"\\f059\"}.fa.fa-volume-control-phone:before{content:\"\\f2a0\"}.fa.fa-asl-interpreting:before{content:\"\\f2a3\"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:\"\\f2a4\"}.fa.fa-glide,.fa.fa-glide-g{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-signing:before{content:\"\\f2a7\"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat,.fa.fa-snapchat-ghost,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-viadeo,.fa.fa-viadeo-square,.fa.fa-yoast{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-google-plus-official:before{content:\"\\f2b3\"}.fa.fa-google-plus-circle{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-google-plus-circle:before{content:\"\\f2b3\"}.fa.fa-fa,.fa.fa-font-awesome{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-fa:before{content:\"\\f2b4\"}.fa.fa-handshake-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-handshake-o:before{content:\"\\f2b5\"}.fa.fa-envelope-open-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-envelope-open-o:before{content:\"\\f2b6\"}.fa.fa-linode{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-address-book-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-address-book-o:before{content:\"\\f2b9\"}.fa.fa-vcard:before{content:\"\\f2bb\"}.fa.fa-address-card-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-address-card-o:before{content:\"\\f2bb\"}.fa.fa-vcard-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-vcard-o:before{content:\"\\f2bb\"}.fa.fa-user-circle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-user-circle-o:before{content:\"\\f2bd\"}.fa.fa-user-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-user-o:before{content:\"\\f007\"}.fa.fa-id-badge{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-drivers-license:before{content:\"\\f2c2\"}.fa.fa-id-card-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-id-card-o:before{content:\"\\f2c2\"}.fa.fa-drivers-license-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-drivers-license-o:before{content:\"\\f2c2\"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:\"\\f2c7\"}.fa.fa-thermometer-3:before{content:\"\\f2c8\"}.fa.fa-thermometer-2:before{content:\"\\f2c9\"}.fa.fa-thermometer-1:before{content:\"\\f2ca\"}.fa.fa-thermometer-0:before{content:\"\\f2cb\"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:\"\\f2cd\"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-times-rectangle:before{content:\"\\f410\"}.fa.fa-window-close-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-window-close-o:before{content:\"\\f410\"}.fa.fa-times-rectangle-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-times-rectangle-o:before{content:\"\\f410\"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-eercast:before{content:\"\\f2da\"}.fa.fa-snowflake-o{font-family:\"Font Awesome 5 Free\";font-weight:400}.fa.fa-snowflake-o:before{content:\"\\f2dc\"}.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:\"Font Awesome 5 Brands\";font-weight:400}.fa.fa-cab:before{content:\"\\f1ba\"}"
  },
  {
    "path": "hiauth-server/src/main/resources/static/js/depTree.js",
    "content": "(function($){\n\n    // 定义默认选项\n    const defaults = {\n        corpId: null,\n        nodeOnClickCallback: function (id) {}\n    };\n\n    // 创建jQuery插件\n    $.fn.devTree = function(options){\n\n        // 合并选项\n        const opt = $.extend({}, defaults, options);\n        $this = $(this);\n\n        function depTreeNodeClick(e) {\n            const $e = $(e.target);\n            const pid = $e.attr(\"data-pid\");\n            $(\".bd-toc nav a.active\").removeClass(\"active\");\n            $e.addClass(\"active\");\n            options.nodeOnClickCallback(pid);\n        }\n\n        function buildSubNode(pe, deps, pid){\n            const ul = $(\"<ul></ul>\");\n            let hasSub = false;\n            deps.forEach(function (dep) {\n                if(dep.pid===pid){\n                    const li = $(\"<li><a class='rounded' href='#' data-pid='\" + dep.id + \"'>\" + dep.name + \"</a></li>\");\n                    li.click(function (e) {\n                        e.stopPropagation();\n                        depTreeNodeClick(e);\n                    })\n                    buildSubNode(li, deps, dep.id);\n                    ul.append(li);\n                    hasSub = true;\n                }\n            });\n            if(pid && hasSub){\n                pe.prepend(\"<div class='fa fa-caret-down' aria-hidden='true'></div>\");\n            }\n            pe.append(ul);\n        }\n\n        function depTree() {\n            $.ajax({\n                type: \"POST\",\n                url: \"/\" + opt.corpId + \"/orgMgr/listDep\",\n                contentType: 'application/json',\n                success: function (result) {\n                    $this.empty();\n                    buildSubNode($this, result.data, undefined);\n                    console.log(result.data);\n                }\n            });\n        }\n        depTree();\n        return this;\n    };\n\n})(jQuery);"
  },
  {
    "path": "hiauth-server/src/main/resources/static/js/jquery.min.js",
    "content": "/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */\n!function(a,b){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error(\"jQuery requires a window with a document\");return b(a)}:b(a)}(\"undefined\"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m=\"1.12.4\",n=function(a,b){return new n.fn.init(a,b)},o=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,p=/^-ms-/,q=/-([\\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:\"\",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for(\"boolean\"==typeof g&&(j=g,g=arguments[h]||{},h++),\"object\"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:\"jQuery\"+(m+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return\"function\"===n.type(a)},isArray:Array.isArray||function(a){return\"array\"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||\"object\"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,\"constructor\")&&!k.call(a.constructor.prototype,\"isPrototypeOf\"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+\"\":\"object\"==typeof a||\"function\"==typeof a?i[j.call(a)]||\"object\":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,\"ms-\").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?\"\":(a+\"\").replace(o,\"\")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,\"string\"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return\"string\"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),\"function\"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(a,b){i[\"[object \"+b+\"]\"]=b.toLowerCase()});function s(a){var b=!!a&&\"length\"in a&&a.length,c=n.type(a);return\"function\"===c||n.isWindow(a)?!1:\"array\"===c||0===b||\"number\"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u=\"sizzle\"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",L=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",M=\"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",N=\"\\\\[\"+L+\"*(\"+M+\")(?:\"+L+\"*([*^$|!~]?=)\"+L+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+M+\"))|)\"+L+\"*\\\\]\",O=\":(\"+M+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+N+\")*)|.*)\\\\)|)\",P=new RegExp(L+\"+\",\"g\"),Q=new RegExp(\"^\"+L+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+L+\"+$\",\"g\"),R=new RegExp(\"^\"+L+\"*,\"+L+\"*\"),S=new RegExp(\"^\"+L+\"*([>+~]|\"+L+\")\"+L+\"*\"),T=new RegExp(\"=\"+L+\"*([^\\\\]'\\\"]*?)\"+L+\"*\\\\]\",\"g\"),U=new RegExp(O),V=new RegExp(\"^\"+M+\"$\"),W={ID:new RegExp(\"^#(\"+M+\")\"),CLASS:new RegExp(\"^\\\\.(\"+M+\")\"),TAG:new RegExp(\"^(\"+M+\"|[*])\"),ATTR:new RegExp(\"^\"+N),PSEUDO:new RegExp(\"^\"+O),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+L+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+L+\"*(?:([+-]|)\"+L+\"*(\\\\d+)|))\"+L+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+K+\")$\",\"i\"),needsContext:new RegExp(\"^\"+L+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+L+\"*((?:-\\\\d)?\\\\d*)\"+L+\"*\\\\)|)(?=[^-]|$)\",\"i\")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\\d$/i,Z=/^[^{]+\\{\\s*\\[native \\w/,$=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,_=/[+~]/,aa=/'|\\\\/g,ba=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+L+\"?|(\"+L+\")|.)\",\"ig\"),ca=function(a,b,c){var d=\"0x\"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],\"string\"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+\" \"]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if(\"object\"!==b.nodeName.toLowerCase()){(k=b.getAttribute(\"id\"))?k=k.replace(aa,\"\\\\$&\"):b.setAttribute(\"id\",k=u),r=g(a),h=r.length,l=V.test(k)?\"#\"+k:\"[id='\"+k+\"']\";while(h--)r[h]=l+\" \"+qa(r[h]);s=r.join(\",\"),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute(\"id\")}}}return i(a.replace(Q,\"$1\"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+\" \")>d.cacheLength&&delete b[a.shift()],b[c+\" \"]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement(\"div\");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split(\"|\"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return\"input\"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return(\"input\"===c||\"button\"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&\"undefined\"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?\"HTML\"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener(\"unload\",da,!1):e.attachEvent&&e.attachEvent(\"onunload\",da)),c.attributes=ia(function(a){return a.className=\"i\",!a.getAttribute(\"className\")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment(\"\")),!a.getElementsByTagName(\"*\").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(\"undefined\"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute(\"id\")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c=\"undefined\"!=typeof a.getAttributeNode&&a.getAttributeNode(\"id\");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return\"undefined\"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if(\"*\"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return\"undefined\"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML=\"<a id='\"+u+\"'></a><select id='\"+u+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",a.querySelectorAll(\"[msallowcapture^='']\").length&&q.push(\"[*^$]=\"+L+\"*(?:''|\\\"\\\")\"),a.querySelectorAll(\"[selected]\").length||q.push(\"\\\\[\"+L+\"*(?:value|\"+K+\")\"),a.querySelectorAll(\"[id~=\"+u+\"-]\").length||q.push(\"~=\"),a.querySelectorAll(\":checked\").length||q.push(\":checked\"),a.querySelectorAll(\"a#\"+u+\"+*\").length||q.push(\".#.+[+~]\")}),ia(function(a){var b=n.createElement(\"input\");b.setAttribute(\"type\",\"hidden\"),a.appendChild(b).setAttribute(\"name\",\"D\"),a.querySelectorAll(\"[name=d]\").length&&q.push(\"name\"+L+\"*[*^$|!~]?=\"),a.querySelectorAll(\":enabled\").length||q.push(\":enabled\",\":disabled\"),a.querySelectorAll(\"*,:x\"),q.push(\",.*:\")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,\"div\"),s.call(a,\"[s!='']:x\"),r.push(\"!=\",O)}),q=q.length&&new RegExp(q.join(\"|\")),r=r.length&&new RegExp(r.join(\"|\")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,\"='$1']\"),c.matchesSelector&&p&&!A[b+\" \"]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error(\"Syntax error, unrecognized expression: \"+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c=\"\",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if(\"string\"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||\"\").replace(ba,ca),\"~=\"===a[2]&&(a[3]=\" \"+a[3]+\" \"),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),\"nth\"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*(\"even\"===a[3]||\"odd\"===a[3])),a[5]=+(a[7]+a[8]||\"odd\"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||\"\":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(\")\",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return\"*\"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+\" \"];return b||(b=new RegExp(\"(^|\"+L+\")\"+a+\"(\"+L+\"|$)\"))&&y(a,function(a){return b.test(\"string\"==typeof a.className&&a.className||\"undefined\"!=typeof a.getAttribute&&a.getAttribute(\"class\")||\"\")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?\"!=\"===b:b?(e+=\"\",\"=\"===b?e===c:\"!=\"===b?e!==c:\"^=\"===b?c&&0===e.indexOf(c):\"*=\"===b?c&&e.indexOf(c)>-1:\"$=\"===b?c&&e.slice(-c.length)===c:\"~=\"===b?(\" \"+e.replace(P,\" \")+\" \").indexOf(c)>-1:\"|=\"===b?e===c||e.slice(0,c.length+1)===c+\"-\":!1):!0}},CHILD:function(a,b,c,d,e){var f=\"nth\"!==a.slice(0,3),g=\"last\"!==a.slice(-4),h=\"of-type\"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?\"nextSibling\":\"previousSibling\",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p=\"only\"===a&&!o&&\"nextSibling\"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error(\"unsupported pseudo: \"+a);return e[u]?e(b):e.length>1?(c=[a,a,\"\",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,\"$1\"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||\"\")||fa.error(\"unsupported lang: \"+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute(\"xml:lang\")||b.getAttribute(\"lang\"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+\"-\");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return\"input\"===b&&!!a.checked||\"option\"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return\"input\"===b&&\"button\"===a.type||\"button\"===b},text:function(a){var b;return\"input\"===a.nodeName.toLowerCase()&&\"text\"===a.type&&(null==(b=a.getAttribute(\"type\"))||\"text\"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=la(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=ma(b);function pa(){}pa.prototype=d.filters=d.pseudos,d.setFilters=new pa,g=fa.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+\" \"];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=R.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=S.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(Q,\" \")}),h=h.slice(c.length));for(g in d.filter)!(e=W[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fa.error(a):z(a,i).slice(0)};function qa(a){for(var b=0,c=a.length,d=\"\";c>b;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&\"parentNode\"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||\"*\",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[\" \"],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:\" \"===a[i-2].type?\"*\":\"\"})).replace(Q,\"$1\"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s=\"0\",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG(\"*\",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+\" \"];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n=\"function\"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&\"ID\"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split(\"\").sort(B).join(\"\")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement(\"div\"))}),ia(function(a){return a.innerHTML=\"<a href='#'></a>\",\"#\"===a.firstChild.getAttribute(\"href\")})||ja(\"type|href|height|width\",function(a,b,c){return c?void 0:a.getAttribute(b,\"type\"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML=\"<input/>\",a.firstChild.setAttribute(\"value\",\"\"),\"\"===a.firstChild.getAttribute(\"value\")})||ja(\"value\",function(a,b,c){return c||\"input\"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute(\"disabled\")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[\":\"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\\w-]+)\\s*\\/?>(?:<\\/\\1>|)$/,y=/^.[^:#\\[\\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if(\"string\"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=\":not(\"+a+\")\"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if(\"string\"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+\" \"+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,\"string\"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,\"string\"==typeof a){if(e=\"<\"===a.charAt(0)&&\">\"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?\"undefined\"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||\"string\"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?\"string\"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,\"parentNode\")},parentsUntil:function(a,b,c){return u(a,\"parentNode\",c)},next:function(a){return F(a,\"nextSibling\")},prev:function(a){return F(a,\"previousSibling\")},nextAll:function(a){return u(a,\"nextSibling\")},prevAll:function(a){return u(a,\"previousSibling\")},nextUntil:function(a,b,c){return u(a,\"nextSibling\",c)},prevUntil:function(a,b,c){return u(a,\"previousSibling\",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return\"Until\"!==a.slice(-5)&&(d=c),d&&\"string\"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a=\"string\"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:\"\")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){n.each(b,function(b,c){n.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&\"string\"!==n.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return n.each(arguments,function(a,b){var c;while((c=n.inArray(b,f,c))>-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c=\"\",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[[\"resolve\",\"done\",n.Callbacks(\"once memory\"),\"resolved\"],[\"reject\",\"fail\",n.Callbacks(\"once memory\"),\"rejected\"],[\"notify\",\"progress\",n.Callbacks(\"memory\")]],c=\"pending\",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+\"With\"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+\"With\"](this===e?d:this,arguments),this},e[f[0]+\"With\"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler(\"ready\"),n(d).off(\"ready\"))))}});function J(){d.addEventListener?(d.removeEventListener(\"DOMContentLoaded\",K),a.removeEventListener(\"load\",K)):(d.detachEvent(\"onreadystatechange\",K),a.detachEvent(\"onload\",K))}function K(){(d.addEventListener||\"load\"===a.event.type||\"complete\"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),\"complete\"===d.readyState||\"loading\"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener(\"DOMContentLoaded\",K),a.addEventListener(\"load\",K);else{d.attachEvent(\"onreadystatechange\",K),a.attachEvent(\"onload\",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll(\"left\")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst=\"0\"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName(\"body\")[0],c&&c.style&&(b=d.createElement(\"div\"),e=d.createElement(\"div\"),e.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",c.appendChild(e).appendChild(b),\"undefined\"!=typeof b.style.zoom&&(b.style.cssText=\"display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1\",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement(\"div\");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+\" \").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute(\"classid\")===b},N=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d=\"data-\"+b.replace(O,\"-$1\").toLowerCase();if(c=a.getAttribute(d),\"string\"==typeof c){try{c=\"true\"===c?!0:\"false\"===c?!1:\"null\"===c?null:+c+\"\"===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0;\n}return c}function Q(a){var b;for(b in a)if((\"data\"!==b||!n.isEmptyObject(a[b]))&&\"toJSON\"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||\"string\"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),\"object\"!=typeof b&&\"function\"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),\"string\"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(\" \")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{\"applet \":!0,\"embed \":!0,\"object \":\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,\"parsedAttrs\"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf(\"data-\")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,\"parsedAttrs\",!0)}return e}return\"object\"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||\"fx\")+\"queue\",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||\"fx\";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};\"inprogress\"===e&&(e=c.shift(),d--),e&&(\"fx\"===b&&c.unshift(\"inprogress\"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+\"queueHooks\";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks(\"once memory\").add(function(){n._removeData(a,b+\"queue\"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return\"string\"!=typeof a&&(b=a,a=\"fx\",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),\"fx\"===a&&\"inprogress\"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||\"fx\",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};\"string\"!=typeof a&&(b=a,a=void 0),a=a||\"fx\";while(g--)c=n._data(f[g],a+\"queueHooks\"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}}),function(){var a;l.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,e;return c=d.getElementsByTagName(\"body\")[0],c&&c.style?(b=d.createElement(\"div\"),e=d.createElement(\"div\"),e.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",c.appendChild(e).appendChild(b),\"undefined\"!=typeof b.style.zoom&&(b.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1\",b.appendChild(d.createElement(\"div\")).style.width=\"5px\",a=3!==b.offsetWidth),c.removeChild(e),a):void 0}}();var T=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,U=new RegExp(\"^(?:([+-])=|)(\"+T+\")([a-z%]*)$\",\"i\"),V=[\"Top\",\"Right\",\"Bottom\",\"Left\"],W=function(a,b){return a=b||a,\"none\"===n.css(a,\"display\")||!n.contains(a.ownerDocument,a)};function X(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,\"\")},i=h(),j=c&&c[3]||(n.cssNumber[b]?\"\":\"px\"),k=(n.cssNumber[b]||\"px\"!==j&&+i)&&U.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||\".5\",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var Y=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if(\"object\"===n.type(c)){e=!0;for(h in c)Y(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\\w:-]+)/,_=/^$|\\/(?:java|ecma)script/i,aa=/^\\s+/,ba=\"abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video\";function ca(a){var b=ba.split(\"|\"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement(\"div\"),b=d.createDocumentFragment(),c=d.createElement(\"input\");a.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName(\"tbody\").length,l.htmlSerialize=!!a.getElementsByTagName(\"link\").length,l.html5Clone=\"<:nav></:nav>\"!==d.createElement(\"nav\").cloneNode(!0).outerHTML,c.type=\"checkbox\",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML=\"<textarea>x</textarea>\",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement(\"input\"),c.setAttribute(\"type\",\"radio\"),c.setAttribute(\"checked\",\"checked\"),c.setAttribute(\"name\",\"t\"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],area:[1,\"<map>\",\"</map>\"],param:[1,\"<object>\",\"</object>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:l.htmlSerialize?[0,\"\",\"\"]:[1,\"X<div>\",\"</div>\"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f=\"undefined\"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||\"*\"):\"undefined\"!=typeof a.querySelectorAll?a.querySelectorAll(b||\"*\"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,\"globalEval\",!b||n._data(b[d],\"globalEval\"))}var ga=/<|&#?\\w+;/,ha=/<tbody/i;function ia(a){Z.test(a.type)&&(a.defaultChecked=a.checked)}function ja(a,b,c,d,e){for(var f,g,h,i,j,k,m,o=a.length,p=ca(b),q=[],r=0;o>r;r++)if(g=a[r],g||0===g)if(\"object\"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement(\"div\")),j=($.exec(g)||[\"\",\"\"])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g=\"table\"!==j||ha.test(g)?\"<table>\"!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],\"tbody\")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent=\"\";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,\"input\"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),\"script\"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||\"\")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement(\"div\");for(b in{submit:!0,change:!0,focusin:!0})c=\"on\"+b,(l[b]=c in a)||(e.setAttribute(c,\"t\"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if(\"object\"==typeof b){\"string\"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&(\"string\"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return\"undefined\"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||\"\").match(G)||[\"\"],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||\"\").split(\".\").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(\".\")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent(\"on\"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||\"\").match(G)||[\"\"],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||\"\").split(\".\").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp(\"(^|\\\\.)\"+p.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&(\"**\"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,\"events\"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,\"type\")?b.type:b,r=k.call(b,\"namespace\")?b.namespace.split(\".\"):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(\".\")>-1&&(r=q.split(\".\"),q=r.shift(),r.sort()),h=q.indexOf(\":\")<0&&\"on\"+q,b=b[n.expando]?b:new n.Event(q,\"object\"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join(\".\"),b.rnamespace=b.namespace?new RegExp(\"(^|\\\\.)\"+r.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,\"events\")||{})[b.type]&&n._data(i,\"handle\"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,\"events\")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(\"click\"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||\"click\"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+\" \",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,e,f=a.type,g=a,h=this.fixHooks[f];h||(this.fixHooks[f]=h=ma.test(f)?this.mouseHooks:la.test(f)?this.keyHooks:{}),e=h.props?this.props.concat(h.props):this.props,a=new n.Event(g),b=e.length;while(b--)c=e[b],a[c]=g[c];return a.target||(a.target=g.srcElement||d),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,h.filter?h.filter(a,g):a},props:\"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(a,b){var c,e,f,g=b.button,h=b.fromElement;return null==a.pageX&&null!=b.clientX&&(e=a.target.ownerDocument||d,f=e.documentElement,c=e.body,a.pageX=b.clientX+(f&&f.scrollLeft||c&&c.scrollLeft||0)-(f&&f.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(f&&f.scrollTop||c&&c.scrollTop||0)-(f&&f.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&h&&(a.relatedTarget=h===a.target?b.toElement:h),a.which||void 0===g||(a.which=1&g?1:2&g?3:4&g?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==ra()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:\"focusin\"},blur:{trigger:function(){return this===ra()&&this.blur?(this.blur(),!1):void 0},delegateType:\"focusout\"},click:{trigger:function(){return n.nodeName(this,\"input\")&&\"checkbox\"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,\"a\")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c){var d=n.extend(new n.Event,c,{type:a,isSimulated:!0});n.event.trigger(d,null,b),d.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=d.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)}:function(a,b,c){var d=\"on\"+b;a.detachEvent&&(\"undefined\"==typeof a[d]&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?pa:qa):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={constructor:n.Event,isDefaultPrevented:qa,isPropagationStopped:qa,isImmediatePropagationStopped:qa,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=pa,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=pa,a&&!this.isSimulated&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=pa,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||n.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submit||(n.event.special.submit={setup:function(){return n.nodeName(this,\"form\")?!1:void n.event.add(this,\"click._submit keypress._submit\",function(a){var b=a.target,c=n.nodeName(b,\"input\")||n.nodeName(b,\"button\")?n.prop(b,\"form\"):void 0;c&&!n._data(c,\"submit\")&&(n.event.add(c,\"submit._submit\",function(a){a._submitBubble=!0}),n._data(c,\"submit\",!0))})},postDispatch:function(a){a._submitBubble&&(delete a._submitBubble,this.parentNode&&!a.isTrigger&&n.event.simulate(\"submit\",this.parentNode,a))},teardown:function(){return n.nodeName(this,\"form\")?!1:void n.event.remove(this,\"._submit\")}}),l.change||(n.event.special.change={setup:function(){return ka.test(this.nodeName)?(\"checkbox\"!==this.type&&\"radio\"!==this.type||(n.event.add(this,\"propertychange._change\",function(a){\"checked\"===a.originalEvent.propertyName&&(this._justChanged=!0)}),n.event.add(this,\"click._change\",function(a){this._justChanged&&!a.isTrigger&&(this._justChanged=!1),n.event.simulate(\"change\",this,a)})),!1):void n.event.add(this,\"beforeactivate._change\",function(a){var b=a.target;ka.test(b.nodeName)&&!n._data(b,\"change\")&&(n.event.add(b,\"change._change\",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate(\"change\",this.parentNode,a)}),n._data(b,\"change\",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||\"radio\"!==b.type&&\"checkbox\"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,\"._change\"),!ka.test(this.nodeName)}}),l.focusin||n.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a))};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d){return sa(this,a,b,c,d)},one:function(a,b,c,d){return sa(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+\".\"+d.namespace:d.origType,d.selector,d.handler),this;if(\"object\"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&\"function\"!=typeof b||(c=b,b=void 0),c===!1&&(c=qa),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ta=/ jQuery\\d+=\"(?:null|\\d+)\"/g,ua=new RegExp(\"<(?:\"+ba+\")[\\\\s/>]\",\"i\"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:-]+)[^>]*)\\/>/gi,wa=/<script|<style|<link/i,xa=/checked\\s*(?:[^=]|=\\s*.checked.)/i,ya=/^true\\/(.*)/,za=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement(\"div\"));function Ca(a,b){return n.nodeName(a,\"table\")&&n.nodeName(11!==b.nodeType?b:b.firstChild,\"tr\")?a.getElementsByTagName(\"tbody\")[0]||a.appendChild(a.ownerDocument.createElement(\"tbody\")):a}function Da(a){return a.type=(null!==n.find.attr(a,\"type\"))+\"/\"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute(\"type\"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}\"script\"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):\"object\"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):\"input\"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):\"option\"===c?b.defaultSelected=b.selected=a.defaultSelected:\"input\"!==c&&\"textarea\"!==c||(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&\"string\"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,\"script\"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,\"script\"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||\"\")&&!n._data(g,\"globalEval\")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||\"\").replace(za,\"\")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,\"script\")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,\"<$1></$2>\")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test(\"<\"+a.nodeName+\">\")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,\"script\"),d.length>0&&fa(d,!i&&ea(a,\"script\")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||\"undefined\"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,\"select\")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,\"\"):void 0;if(\"string\"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:\"block\",BODY:\"block\"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],\"display\");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),\"none\"!==c&&c||(Ja=(Ja||n(\"<iframe frameborder='0' width='0' height='0'/>\")).appendTo(b.documentElement),b=(Ja[0].contentWindow||Ja[0].contentDocument).document,b.write(),b.close(),c=La(a,b),Ja.detach()),Ka[a]=c),c}var Na=/^margin/,Oa=new RegExp(\"^(\"+T+\")(?!px)[a-z%]+$\",\"i\"),Pa=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},Qa=d.documentElement;!function(){var b,c,e,f,g,h,i=d.createElement(\"div\"),j=d.createElement(\"div\");if(j.style){j.style.cssText=\"float:left;opacity:.5\",l.opacity=\"0.5\"===j.style.opacity,l.cssFloat=!!j.style.cssFloat,j.style.backgroundClip=\"content-box\",j.cloneNode(!0).style.backgroundClip=\"\",l.clearCloneStyle=\"content-box\"===j.style.backgroundClip,i=d.createElement(\"div\"),i.style.cssText=\"border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute\",j.innerHTML=\"\",i.appendChild(j),l.boxSizing=\"\"===j.style.boxSizing||\"\"===j.style.MozBoxSizing||\"\"===j.style.WebkitBoxSizing,n.extend(l,{reliableHiddenOffsets:function(){return null==b&&k(),f},boxSizingReliable:function(){return null==b&&k(),e},pixelMarginRight:function(){return null==b&&k(),c},pixelPosition:function(){return null==b&&k(),b},reliableMarginRight:function(){return null==b&&k(),g},reliableMarginLeft:function(){return null==b&&k(),h}});function k(){var k,l,m=d.documentElement;m.appendChild(i),j.style.cssText=\"-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%\",b=e=h=!1,c=g=!0,a.getComputedStyle&&(l=a.getComputedStyle(j),b=\"1%\"!==(l||{}).top,h=\"2px\"===(l||{}).marginLeft,e=\"4px\"===(l||{width:\"4px\"}).width,j.style.marginRight=\"50%\",c=\"4px\"===(l||{marginRight:\"4px\"}).marginRight,k=j.appendChild(d.createElement(\"div\")),k.style.cssText=j.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0\",k.style.marginRight=k.style.width=\"0\",j.style.width=\"1px\",g=!parseFloat((a.getComputedStyle(k)||{}).marginRight),j.removeChild(k)),j.style.display=\"none\",f=0===j.getClientRects().length,f&&(j.style.display=\"\",j.innerHTML=\"<table><tr><td></td><td>t</td></tr></table>\",j.childNodes[0].style.borderCollapse=\"separate\",k=j.getElementsByTagName(\"td\"),k[0].style.cssText=\"margin:0;border:0;padding:0;display:none\",f=0===k[0].offsetHeight,f&&(k[0].style.display=\"\",k[1].style.display=\"none\",f=0===k[0].offsetHeight)),m.removeChild(i)}}}();var Ra,Sa,Ta=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ra=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c.getPropertyValue(b)||c[b]:void 0,\"\"!==g&&void 0!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),c&&!l.pixelMarginRight()&&Oa.test(g)&&Na.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f),void 0===g?g:g+\"\"}):Qa.currentStyle&&(Ra=function(a){return a.currentStyle},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Oa.test(g)&&!Ta.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left=\"fontSize\"===b?\"1em\":g,g=h.pixelLeft+\"px\",h.left=d,f&&(e.left=f)),void 0===g?g:g+\"\"||\"auto\"});function Ua(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Va=/alpha\\([^)]*\\)/i,Wa=/opacity\\s*=\\s*([^)]*)/i,Xa=/^(none|table(?!-c[ea]).+)/,Ya=new RegExp(\"^(\"+T+\")(.*)$\",\"i\"),Za={position:\"absolute\",visibility:\"hidden\",display:\"block\"},$a={letterSpacing:\"0\",fontWeight:\"400\"},_a=[\"Webkit\",\"O\",\"Moz\",\"ms\"],ab=d.createElement(\"div\").style;function bb(a){if(a in ab)return a;var b=a.charAt(0).toUpperCase()+a.slice(1),c=_a.length;while(c--)if(a=_a[c]+b,a in ab)return a}function cb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,\"olddisplay\"),c=d.style.display,b?(f[g]||\"none\"!==c||(d.style.display=\"\"),\"\"===d.style.display&&W(d)&&(f[g]=n._data(d,\"olddisplay\",Ma(d.nodeName)))):(e=W(d),(c&&\"none\"!==c||!e)&&n._data(d,\"olddisplay\",e?c:n.css(d,\"display\"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&\"none\"!==d.style.display&&\"\"!==d.style.display||(d.style.display=b?f[g]||\"\":\"none\"));return a}function db(a,b,c){var d=Ya.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||\"px\"):b}function eb(a,b,c,d,e){for(var f=c===(d?\"border\":\"content\")?4:\"width\"===b?1:0,g=0;4>f;f+=2)\"margin\"===c&&(g+=n.css(a,c+V[f],!0,e)),d?(\"content\"===c&&(g-=n.css(a,\"padding\"+V[f],!0,e)),\"margin\"!==c&&(g-=n.css(a,\"border\"+V[f]+\"Width\",!0,e))):(g+=n.css(a,\"padding\"+V[f],!0,e),\"padding\"!==c&&(g+=n.css(a,\"border\"+V[f]+\"Width\",!0,e)));return g}function fb(a,b,c){var d=!0,e=\"width\"===b?a.offsetWidth:a.offsetHeight,f=Ra(a),g=l.boxSizing&&\"border-box\"===n.css(a,\"boxSizing\",!1,f);if(0>=e||null==e){if(e=Sa(a,b,f),(0>e||null==e)&&(e=a.style[b]),Oa.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+eb(a,b,c||(g?\"border\":\"content\"),d,f)+\"px\"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Sa(a,\"opacity\");return\"\"===c?\"1\":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":l.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&\"get\"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,\"string\"===f&&(e=U.exec(c))&&e[1]&&(c=X(a,b,e),f=\"number\"),null!=c&&c===c&&(\"number\"===f&&(c+=e&&e[3]||(n.cssNumber[h]?\"\":\"px\")),l.clearCloneStyle||\"\"!==c||0!==b.indexOf(\"background\")||(i[b]=\"inherit\"),!(g&&\"set\"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],g&&\"get\"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Sa(a,b,d)),\"normal\"===f&&b in $a&&(f=$a[b]),\"\"===c||c?(e=parseFloat(f),c===!0||isFinite(e)?e||0:f):f}}),n.each([\"height\",\"width\"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?Xa.test(n.css(a,\"display\"))&&0===a.offsetWidth?Pa(a,Za,function(){return fb(a,b,d)}):fb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ra(a);return db(a,c,d?eb(a,b,d,l.boxSizing&&\"border-box\"===n.css(a,\"boxSizing\",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Wa.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?.01*parseFloat(RegExp.$1)+\"\":b?\"1\":\"\"},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?\"alpha(opacity=\"+100*b+\")\":\"\",f=d&&d.filter||c.filter||\"\";c.zoom=1,(b>=1||\"\"===b)&&\"\"===n.trim(f.replace(Va,\"\"))&&c.removeAttribute&&(c.removeAttribute(\"filter\"),\"\"===b||d&&!d.filter)||(c.filter=Va.test(f)?f.replace(Va,e):f+\" \"+e)}}),n.cssHooks.marginRight=Ua(l.reliableMarginRight,function(a,b){return b?Pa(a,{display:\"inline-block\"},Sa,[a,\"marginRight\"]):void 0}),n.cssHooks.marginLeft=Ua(l.reliableMarginLeft,function(a,b){return b?(parseFloat(Sa(a,\"marginLeft\"))||(n.contains(a.ownerDocument,a)?a.getBoundingClientRect().left-Pa(a,{\nmarginLeft:0},function(){return a.getBoundingClientRect().left}):0))+\"px\":void 0}),n.each({margin:\"\",padding:\"\",border:\"Width\"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f=\"string\"==typeof c?c.split(\" \"):[c];4>d;d++)e[a+V[d]+b]=f[d]||f[d-2]||f[0];return e}},Na.test(a)||(n.cssHooks[a+b].set=db)}),n.fn.extend({css:function(a,b){return Y(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ra(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return cb(this,!0)},hide:function(){return cb(this)},toggle:function(a){return\"boolean\"==typeof a?a?this.show():this.hide():this.each(function(){W(this)?n(this).show():n(this).hide()})}});function gb(a,b,c,d,e){return new gb.prototype.init(a,b,c,d,e)}n.Tween=gb,gb.prototype={constructor:gb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?\"\":\"px\")},cur:function(){var a=gb.propHooks[this.prop];return a&&a.get?a.get(this):gb.propHooks._default.get(this)},run:function(a){var b,c=gb.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):gb.propHooks._default.set(this),this}},gb.prototype.init.prototype=gb.prototype,gb.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,\"\"),b&&\"auto\"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},gb.propHooks.scrollTop=gb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:\"swing\"},n.fx=gb.prototype.init,n.fx.step={};var hb,ib,jb=/^(?:toggle|show|hide)$/,kb=/queueHooks$/;function lb(){return a.setTimeout(function(){hb=void 0}),hb=n.now()}function mb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=V[e],d[\"margin\"+c]=d[\"padding\"+c]=a;return b&&(d.opacity=d.width=a),d}function nb(a,b,c){for(var d,e=(qb.tweeners[b]||[]).concat(qb.tweeners[\"*\"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ob(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&W(a),r=n._data(a,\"fxshow\");c.queue||(h=n._queueHooks(a,\"fx\"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,\"fx\").length||h.empty.fire()})})),1===a.nodeType&&(\"height\"in b||\"width\"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,\"display\"),k=\"none\"===j?n._data(a,\"olddisplay\")||Ma(a.nodeName):j,\"inline\"===k&&\"none\"===n.css(a,\"float\")&&(l.inlineBlockNeedsLayout&&\"inline\"!==Ma(a.nodeName)?p.zoom=1:p.display=\"inline-block\")),c.overflow&&(p.overflow=\"hidden\",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],jb.exec(e)){if(delete b[d],f=f||\"toggle\"===e,e===(q?\"hide\":\"show\")){if(\"show\"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(o))\"inline\"===(\"none\"===j?Ma(a.nodeName):j)&&(p.display=j);else{r?\"hidden\"in r&&(q=r.hidden):r=n._data(a,\"fxshow\",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,\"fxshow\");for(b in o)n.style(a,b,o[b])});for(d in o)g=nb(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start=\"width\"===d||\"height\"===d?1:0))}}function pb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&\"expand\"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function qb(a,b,c){var d,e,f=0,g=qb.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=hb||lb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:hb||lb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(pb(k,j.opts.specialEasing);g>f;f++)if(d=qb.prefilters[f].call(j,a,k,j.opts))return n.isFunction(d.stop)&&(n._queueHooks(j.elem,j.opts.queue).stop=n.proxy(d.stop,d)),d;return n.map(k,nb,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(qb,{tweeners:{\"*\":[function(a,b){var c=this.createTween(a,b);return X(c.elem,a,U.exec(b),c),c}]},tweener:function(a,b){n.isFunction(a)?(b=a,a=[\"*\"]):a=a.match(G);for(var c,d=0,e=a.length;e>d;d++)c=a[d],qb.tweeners[c]=qb.tweeners[c]||[],qb.tweeners[c].unshift(b)},prefilters:[ob],prefilter:function(a,b){b?qb.prefilters.unshift(a):qb.prefilters.push(a)}}),n.speed=function(a,b,c){var d=a&&\"object\"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:\"number\"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,null!=d.queue&&d.queue!==!0||(d.queue=\"fx\"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(W).css(\"opacity\",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=qb(this,n.extend({},a),f);(e||n._data(this,\"finish\"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return\"string\"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||\"fx\",[]),this.each(function(){var b=!0,e=null!=a&&a+\"queueHooks\",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&kb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||\"fx\"),this.each(function(){var b,c=n._data(this),d=c[a+\"queue\"],e=c[a+\"queueHooks\"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each([\"toggle\",\"show\",\"hide\"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||\"boolean\"==typeof a?c.apply(this,arguments):this.animate(mb(b,!0),a,d,e)}}),n.each({slideDown:mb(\"show\"),slideUp:mb(\"hide\"),slideToggle:mb(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(hb=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),hb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ib||(ib=a.setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){a.clearInterval(ib),ib=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(b,c){return b=n.fx?n.fx.speeds[b]||b:b,c=c||\"fx\",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a,b=d.createElement(\"input\"),c=d.createElement(\"div\"),e=d.createElement(\"select\"),f=e.appendChild(d.createElement(\"option\"));c=d.createElement(\"div\"),c.setAttribute(\"className\",\"t\"),c.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",a=c.getElementsByTagName(\"a\")[0],b.setAttribute(\"type\",\"checkbox\"),c.appendChild(b),a=c.getElementsByTagName(\"a\")[0],a.style.cssText=\"top:1px\",l.getSetAttribute=\"t\"!==c.className,l.style=/top/.test(a.getAttribute(\"style\")),l.hrefNormalized=\"/a\"===a.getAttribute(\"href\"),l.checkOn=!!b.value,l.optSelected=f.selected,l.enctype=!!d.createElement(\"form\").enctype,e.disabled=!0,l.optDisabled=!f.disabled,b=d.createElement(\"input\"),b.setAttribute(\"value\",\"\"),l.input=\"\"===b.getAttribute(\"value\"),b.value=\"t\",b.setAttribute(\"type\",\"radio\"),l.radioValue=\"t\"===b.value}();var rb=/\\r/g,sb=/[\\x20\\t\\r\\n\\f]+/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e=\"\":\"number\"==typeof e?e+=\"\":n.isArray(e)&&(e=n.map(e,function(a){return null==a?\"\":a+\"\"})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&\"set\"in b&&void 0!==b.set(this,e,\"value\")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&\"get\"in b&&void 0!==(c=b.get(e,\"value\"))?c:(c=e.value,\"string\"==typeof c?c.replace(rb,\"\"):null==c?\"\":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,\"value\");return null!=b?b:n.trim(n.text(a)).replace(sb,\" \")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f=\"select-one\"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute(\"disabled\"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,\"optgroup\"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>-1)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each([\"radio\",\"checkbox\"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute(\"value\")?\"on\":a.value})});var tb,ub,vb=n.expr.attrHandle,wb=/^(?:checked|selected)$/i,xb=l.getSetAttribute,yb=l.input;n.fn.extend({attr:function(a,b){return Y(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return\"undefined\"==typeof a.getAttribute?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),e=n.attrHooks[b]||(n.expr.match.bool.test(b)?ub:tb)),void 0!==c?null===c?void n.removeAttr(a,b):e&&\"set\"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+\"\"),c):e&&\"get\"in e&&null!==(d=e.get(a,b))?d:(d=n.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&\"radio\"===b&&n.nodeName(a,\"input\")){var c=a.value;return a.setAttribute(\"type\",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(G);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?yb&&xb||!wb.test(c)?a[d]=!1:a[n.camelCase(\"default-\"+c)]=a[d]=!1:n.attr(a,c,\"\"),a.removeAttribute(xb?c:d)}}),ub={set:function(a,b,c){return b===!1?n.removeAttr(a,c):yb&&xb||!wb.test(c)?a.setAttribute(!xb&&n.propFix[c]||c,c):a[n.camelCase(\"default-\"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\\w+/g),function(a,b){var c=vb[b]||n.find.attr;yb&&xb||!wb.test(b)?vb[b]=function(a,b,d){var e,f;return d||(f=vb[b],vb[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,vb[b]=f),e}:vb[b]=function(a,b,c){return c?void 0:a[n.camelCase(\"default-\"+b)]?b.toLowerCase():null}}),yb&&xb||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,\"input\")?void(a.defaultValue=b):tb&&tb.set(a,b,c)}}),xb||(tb={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+=\"\",\"value\"===c||b===a.getAttribute(c)?b:void 0}},vb.id=vb.name=vb.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&\"\"!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:tb.set},n.attrHooks.contenteditable={set:function(a,b,c){tb.set(a,\"\"===b?!1:b,c)}},n.each([\"width\",\"height\"],function(a,b){n.attrHooks[b]={set:function(a,c){return\"\"===c?(a.setAttribute(b,\"auto\"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+\"\"}});var zb=/^(?:input|select|textarea|button|object)$/i,Ab=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return Y(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&n.isXMLDoc(a)||(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&\"set\"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&\"get\"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,\"tabindex\");return b?parseInt(b,10):zb.test(a.nodeName)||Ab.test(a.nodeName)&&a.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),l.hrefNormalized||n.each([\"href\",\"src\"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),n.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype=\"encoding\");var Bb=/[\\t\\r\\n\\f]/g;function Cb(a){return n.attr(a,\"class\")||\"\"}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,Cb(this)))});if(\"string\"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(\" \"+e+\" \").replace(Bb,\" \")){g=0;while(f=b[g++])d.indexOf(\" \"+f+\" \")<0&&(d+=f+\" \");h=n.trim(d),e!==h&&n.attr(c,\"class\",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,Cb(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if(\"string\"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(\" \"+e+\" \").replace(Bb,\" \")){g=0;while(f=b[g++])while(d.indexOf(\" \"+f+\" \")>-1)d=d.replace(\" \"+f+\" \",\" \");h=n.trim(d),e!==h&&n.attr(c,\"class\",h)}}return this},toggleClass:function(a,b){var c=typeof a;return\"boolean\"==typeof b&&\"string\"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,Cb(this),b),b)}):this.each(function(){var b,d,e,f;if(\"string\"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&\"boolean\"!==c||(b=Cb(this),b&&n._data(this,\"__className__\",b),n.attr(this,\"class\",b||a===!1?\"\":n._data(this,\"__className__\")||\"\"))})},hasClass:function(a){var b,c,d=0;b=\" \"+a+\" \";while(c=this[d++])if(1===c.nodeType&&(\" \"+Cb(c)+\" \").replace(Bb,\" \").indexOf(b)>-1)return!0;return!1}}),n.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu\".split(\" \"),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Db=a.location,Eb=n.now(),Fb=/\\?/,Gb=/(,)|(\\[|{)|(}|])|\"(?:[^\"\\\\\\r\\n]|\\\\[\"\\\\\\/bfnrt]|\\\\u[\\da-fA-F]{4})*\"\\s*:?|true|false|null|-?(?!0\\d)\\d+(?:\\.\\d+|)(?:[eE][+-]?\\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+\"\");var c,d=null,e=n.trim(b+\"\");return e&&!n.trim(e.replace(Gb,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,\"\")}))?Function(\"return \"+e)():n.error(\"Invalid JSON: \"+b)},n.parseXML=function(b){var c,d;if(!b||\"string\"!=typeof b)return null;try{a.DOMParser?(d=new a.DOMParser,c=d.parseFromString(b,\"text/xml\")):(c=new a.ActiveXObject(\"Microsoft.XMLDOM\"),c.async=\"false\",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName(\"parsererror\").length||n.error(\"Invalid XML: \"+b),c};var Hb=/#.*$/,Ib=/([?&])_=[^&]*/,Jb=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/gm,Kb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Lb=/^(?:GET|HEAD)$/,Mb=/^\\/\\//,Nb=/^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,Ob={},Pb={},Qb=\"*/\".concat(\"*\"),Rb=Db.href,Sb=Nb.exec(Rb.toLowerCase())||[];function Tb(a){return function(b,c){\"string\"!=typeof b&&(c=b,b=\"*\");var d,e=0,f=b.toLowerCase().match(G)||[];if(n.isFunction(c))while(d=f[e++])\"+\"===d.charAt(0)?(d=d.slice(1)||\"*\",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Ub(a,b,c,d){var e={},f=a===Pb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return\"string\"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e[\"*\"]&&g(\"*\")}function Vb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Wb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while(\"*\"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader(\"Content-Type\"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+\" \"+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Xb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if(\"*\"===f)f=i;else if(\"*\"!==i&&i!==f){if(g=j[i+\" \"+f]||j[\"* \"+f],!g)for(e in j)if(h=e.split(\" \"),h[1]===f&&(g=j[i+\" \"+h[0]]||j[\"* \"+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a[\"throws\"])b=g(b);else try{b=g(b)}catch(l){return{state:\"parsererror\",error:g?l:\"No conversion from \"+i+\" to \"+f}}}return{state:\"success\",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Rb,type:\"GET\",isLocal:Kb.test(Sb[1]),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Qb,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":n.parseJSON,\"text xml\":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Vb(Vb(a,n.ajaxSettings),b):Vb(n.ajaxSettings,a)},ajaxPrefilter:Tb(Ob),ajaxTransport:Tb(Pb),ajax:function(b,c){\"object\"==typeof b&&(c=b,b=void 0),c=c||{};var d,e,f,g,h,i,j,k,l=n.ajaxSetup({},c),m=l.context||l,o=l.context&&(m.nodeType||m.jquery)?n(m):n.event,p=n.Deferred(),q=n.Callbacks(\"once memory\"),r=l.statusCode||{},s={},t={},u=0,v=\"canceled\",w={readyState:0,getResponseHeader:function(a){var b;if(2===u){if(!k){k={};while(b=Jb.exec(g))k[b[1].toLowerCase()]=b[2]}b=k[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===u?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return u||(a=t[c]=t[c]||a,s[a]=b),this},overrideMimeType:function(a){return u||(l.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>u)for(b in a)r[b]=[r[b],a[b]];else w.always(a[w.status]);return this},abort:function(a){var b=a||v;return j&&j.abort(b),y(0,b),this}};if(p.promise(w).complete=q.add,w.success=w.done,w.error=w.fail,l.url=((b||l.url||Rb)+\"\").replace(Hb,\"\").replace(Mb,Sb[1]+\"//\"),l.type=c.method||c.type||l.method||l.type,l.dataTypes=n.trim(l.dataType||\"*\").toLowerCase().match(G)||[\"\"],null==l.crossDomain&&(d=Nb.exec(l.url.toLowerCase()),l.crossDomain=!(!d||d[1]===Sb[1]&&d[2]===Sb[2]&&(d[3]||(\"http:\"===d[1]?\"80\":\"443\"))===(Sb[3]||(\"http:\"===Sb[1]?\"80\":\"443\")))),l.data&&l.processData&&\"string\"!=typeof l.data&&(l.data=n.param(l.data,l.traditional)),Ub(Ob,l,c,w),2===u)return w;i=n.event&&l.global,i&&0===n.active++&&n.event.trigger(\"ajaxStart\"),l.type=l.type.toUpperCase(),l.hasContent=!Lb.test(l.type),f=l.url,l.hasContent||(l.data&&(f=l.url+=(Fb.test(f)?\"&\":\"?\")+l.data,delete l.data),l.cache===!1&&(l.url=Ib.test(f)?f.replace(Ib,\"$1_=\"+Eb++):f+(Fb.test(f)?\"&\":\"?\")+\"_=\"+Eb++)),l.ifModified&&(n.lastModified[f]&&w.setRequestHeader(\"If-Modified-Since\",n.lastModified[f]),n.etag[f]&&w.setRequestHeader(\"If-None-Match\",n.etag[f])),(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&w.setRequestHeader(\"Content-Type\",l.contentType),w.setRequestHeader(\"Accept\",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(\"*\"!==l.dataTypes[0]?\", \"+Qb+\"; q=0.01\":\"\"):l.accepts[\"*\"]);for(e in l.headers)w.setRequestHeader(e,l.headers[e]);if(l.beforeSend&&(l.beforeSend.call(m,w,l)===!1||2===u))return w.abort();v=\"abort\";for(e in{success:1,error:1,complete:1})w[e](l[e]);if(j=Ub(Pb,l,c,w)){if(w.readyState=1,i&&o.trigger(\"ajaxSend\",[w,l]),2===u)return w;l.async&&l.timeout>0&&(h=a.setTimeout(function(){w.abort(\"timeout\")},l.timeout));try{u=1,j.send(s,y)}catch(x){if(!(2>u))throw x;y(-1,x)}}else y(-1,\"No Transport\");function y(b,c,d,e){var k,s,t,v,x,y=c;2!==u&&(u=2,h&&a.clearTimeout(h),j=void 0,g=e||\"\",w.readyState=b>0?4:0,k=b>=200&&300>b||304===b,d&&(v=Wb(l,w,d)),v=Xb(l,v,w,k),k?(l.ifModified&&(x=w.getResponseHeader(\"Last-Modified\"),x&&(n.lastModified[f]=x),x=w.getResponseHeader(\"etag\"),x&&(n.etag[f]=x)),204===b||\"HEAD\"===l.type?y=\"nocontent\":304===b?y=\"notmodified\":(y=v.state,s=v.data,t=v.error,k=!t)):(t=y,!b&&y||(y=\"error\",0>b&&(b=0))),w.status=b,w.statusText=(c||y)+\"\",k?p.resolveWith(m,[s,y,w]):p.rejectWith(m,[w,y,t]),w.statusCode(r),r=void 0,i&&o.trigger(k?\"ajaxSuccess\":\"ajaxError\",[w,l,k?s:t]),q.fireWith(m,[w,y]),i&&(o.trigger(\"ajaxComplete\",[w,l]),--n.active||n.event.trigger(\"ajaxStop\")))}return w},getJSON:function(a,b,c){return n.get(a,b,c,\"json\")},getScript:function(a,b){return n.get(a,void 0,b,\"script\")}}),n.each([\"get\",\"post\"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax(n.extend({url:a,type:b,dataType:e,data:c,success:d},n.isPlainObject(a)&&a))}}),n._evalUrl=function(a){return n.ajax({url:a,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,\"throws\":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return n.isFunction(a)?this.each(function(b){n(this).wrapInner(a.call(this,b))}):this.each(function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,\"body\")||n(this).replaceWith(this.childNodes)}).end()}});function Yb(a){return a.style&&a.style.display||n.css(a,\"display\")}function Zb(a){if(!n.contains(a.ownerDocument||d,a))return!0;while(a&&1===a.nodeType){if(\"none\"===Yb(a)||\"hidden\"===a.type)return!0;a=a.parentNode}return!1}n.expr.filters.hidden=function(a){return l.reliableHiddenOffsets()?a.offsetWidth<=0&&a.offsetHeight<=0&&!a.getClientRects().length:Zb(a)},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var $b=/%20/g,_b=/\\[\\]$/,ac=/\\r?\\n/g,bc=/^(?:submit|button|image|reset|file)$/i,cc=/^(?:input|select|textarea|keygen)/i;function dc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||_b.test(a)?d(a,e):dc(a+\"[\"+(\"object\"==typeof e&&null!=e?b:\"\")+\"]\",e,c,d)});else if(c||\"object\"!==n.type(b))d(a,b);else for(e in b)dc(a+\"[\"+e+\"]\",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?\"\":b,d[d.length]=encodeURIComponent(a)+\"=\"+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)dc(c,a[c],b,e);return d.join(\"&\").replace($b,\"+\")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,\"elements\");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(\":disabled\")&&cc.test(this.nodeName)&&!bc.test(a)&&(this.checked||!Z.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(ac,\"\\r\\n\")}}):{name:b.name,value:c.replace(ac,\"\\r\\n\")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return this.isLocal?ic():d.documentMode>8?hc():/^(get|post|head|put|delete|options)$/i.test(this.type)&&hc()||ic()}:hc;var ec=0,fc={},gc=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent(\"onunload\",function(){for(var a in fc)fc[a](void 0,!0)}),l.cors=!!gc&&\"withCredentials\"in gc,gc=l.ajax=!!gc,gc&&n.ajaxTransport(function(b){if(!b.crossDomain||l.cors){var c;return{send:function(d,e){var f,g=b.xhr(),h=++ec;if(g.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(f in b.xhrFields)g[f]=b.xhrFields[f];b.mimeType&&g.overrideMimeType&&g.overrideMimeType(b.mimeType),b.crossDomain||d[\"X-Requested-With\"]||(d[\"X-Requested-With\"]=\"XMLHttpRequest\");for(f in d)void 0!==d[f]&&g.setRequestHeader(f,d[f]+\"\");g.send(b.hasContent&&b.data||null),c=function(a,d){var f,i,j;if(c&&(d||4===g.readyState))if(delete fc[h],c=void 0,g.onreadystatechange=n.noop,d)4!==g.readyState&&g.abort();else{j={},f=g.status,\"string\"==typeof g.responseText&&(j.text=g.responseText);try{i=g.statusText}catch(k){i=\"\"}f||!b.isLocal||b.crossDomain?1223===f&&(f=204):f=j.text?200:404}j&&e(f,i,j,g.getAllResponseHeaders())},b.async?4===g.readyState?a.setTimeout(c):g.onreadystatechange=fc[h]=c:c()},abort:function(){c&&c(void 0,!0)}}}});function hc(){try{return new a.XMLHttpRequest}catch(b){}}function ic(){try{return new a.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}}n.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter(\"script\",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type=\"GET\",a.global=!1)}),n.ajaxTransport(\"script\",function(a){if(a.crossDomain){var b,c=d.head||n(\"head\")[0]||d.documentElement;return{send:function(e,f){b=d.createElement(\"script\"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||f(200,\"success\"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var jc=[],kc=/(=)\\?(?=&|$)|\\?\\?/;n.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var a=jc.pop()||n.expando+\"_\"+Eb++;return this[a]=!0,a}}),n.ajaxPrefilter(\"json jsonp\",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(kc.test(b.url)?\"url\":\"string\"==typeof b.data&&0===(b.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&kc.test(b.data)&&\"data\");return h||\"jsonp\"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(kc,\"$1\"+e):b.jsonp!==!1&&(b.url+=(Fb.test(b.url)?\"&\":\"?\")+b.jsonp+\"=\"+e),b.converters[\"script json\"]=function(){return g||n.error(e+\" was not called\"),g[0]},b.dataTypes[0]=\"json\",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?n(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,jc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),\"script\"):void 0}),n.parseHTML=function(a,b,c){if(!a||\"string\"!=typeof a)return null;\"boolean\"==typeof b&&(c=b,b=!1),b=b||d;var e=x.exec(a),f=!c&&[];return e?[b.createElement(e[1])]:(e=ja([a],b,f),f&&f.length&&n(f).remove(),n.merge([],e.childNodes))};var lc=n.fn.load;n.fn.load=function(a,b,c){if(\"string\"!=typeof a&&lc)return lc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(\" \");return h>-1&&(d=n.trim(a.slice(h,a.length)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&\"object\"==typeof b&&(e=\"POST\"),g.length>0&&n.ajax({url:a,type:e||\"GET\",dataType:\"html\",data:b}).done(function(a){f=arguments,g.html(d?n(\"<div>\").append(n.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},n.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};function mc(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,\"position\"),l=n(a),m={};\"static\"===k&&(a.style.position=\"relative\"),h=l.offset(),f=n.css(a,\"top\"),i=n.css(a,\"left\"),j=(\"absolute\"===k||\"fixed\"===k)&&n.inArray(\"auto\",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,n.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),\"using\"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(\"undefined\"!=typeof e.getBoundingClientRect&&(d=e.getBoundingClientRect()),c=mc(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return\"fixed\"===n.css(d,\"position\")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],\"html\")||(c=a.offset()),c.top+=n.css(a[0],\"borderTopWidth\",!0),c.left+=n.css(a[0],\"borderLeftWidth\",!0)),{top:b.top-c.top-n.css(d,\"marginTop\",!0),left:b.left-c.left-n.css(d,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&!n.nodeName(a,\"html\")&&\"static\"===n.css(a,\"position\"))a=a.offsetParent;return a||Qa})}}),n.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return Y(this,function(a,d,e){var f=mc(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each([\"top\",\"left\"],function(a,b){n.cssHooks[b]=Ua(l.pixelPosition,function(a,c){return c?(c=Sa(a,b),Oa.test(c)?n(a).position()[b]+\"px\":c):void 0})}),n.each({Height:\"height\",Width:\"width\"},function(a,b){n.each({\npadding:\"inner\"+a,content:b,\"\":\"outer\"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||\"boolean\"!=typeof d),g=c||(d===!0||e===!0?\"margin\":\"border\");return Y(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement[\"client\"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body[\"scroll\"+a],e[\"scroll\"+a],b.body[\"offset\"+a],e[\"offset\"+a],e[\"client\"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,\"**\"):this.off(b,a||\"**\",c)}}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return n});var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n});\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/js/jquery.treetable.js",
    "content": "/*\n * jQuery treetable Plugin 3.2.0\n * http://ludo.cubicphuse.nl/jquery-treetable\n *\n * Copyright 2013, Ludo van den Boom\n * Dual licensed under the MIT or GPL Version 2 licenses.\n */\n(function($) {\n  var Node, Tree, methods;\n\n  Node = (function() {\n    function Node(row, tree, settings) {\n      var parentId;\n\n      this.row = row;\n      this.tree = tree;\n      this.settings = settings;\n\n      // TODO Ensure id/parentId is always a string (not int)\n      this.id = this.row.data(this.settings.nodeIdAttr);\n\n      // TODO Move this to a setParentId function?\n      parentId = this.row.data(this.settings.parentIdAttr);\n      if (parentId != null && parentId !== \"\") {\n        this.parentId = parentId;\n      }\n\n      this.treeCell = $(this.row.children(this.settings.columnElType)[this.settings.column]);\n      this.expander = $(this.settings.expanderTemplate);\n      this.indenter = $(this.settings.indenterTemplate);\n      this.children = [];\n      this.initialized = false;\n      this.treeCell.prepend(this.indenter);\n    }\n\n    Node.prototype.addChild = function(child) {\n      return this.children.push(child);\n    };\n\n    Node.prototype.ancestors = function() {\n      var ancestors, node;\n      node = this;\n      ancestors = [];\n      while (node = node.parentNode()) {\n        ancestors.push(node);\n      }\n      return ancestors;\n    };\n\n    Node.prototype.collapse = function() {\n      if (this.collapsed()) {\n        return this;\n      }\n\n      this.row.removeClass(\"expanded\").addClass(\"collapsed\");\n\n      this._hideChildren();\n      this.expander.attr(\"title\", this.settings.stringExpand);\n\n      if (this.initialized && this.settings.onNodeCollapse != null) {\n        this.settings.onNodeCollapse.apply(this);\n      }\n\n      return this;\n    };\n\n    Node.prototype.collapsed = function() {\n      return this.row.hasClass(\"collapsed\");\n    };\n\n    // TODO destroy: remove event handlers, expander, indenter, etc.\n\n    Node.prototype.expand = function() {\n      if (this.expanded()) {\n        return this;\n      }\n\n      this.row.removeClass(\"collapsed\").addClass(\"expanded\");\n\n      if (this.initialized && this.settings.onNodeExpand != null) {\n        this.settings.onNodeExpand.apply(this);\n      }\n\n      if ($(this.row).is(\":visible\")) {\n        this._showChildren();\n      }\n\n      this.expander.attr(\"title\", this.settings.stringCollapse);\n\n      return this;\n    };\n\n    Node.prototype.expanded = function() {\n      return this.row.hasClass(\"expanded\");\n    };\n\n    Node.prototype.hide = function() {\n      this._hideChildren();\n      this.row.hide();\n      return this;\n    };\n\n    Node.prototype.isBranchNode = function() {\n      if(this.children.length > 0 || this.row.data(this.settings.branchAttr) === true) {\n        return true;\n      } else {\n        return false;\n      }\n    };\n\n    Node.prototype.updateBranchLeafClass = function(){\n      this.row.removeClass('branch');\n      this.row.removeClass('leaf');\n      this.row.addClass(this.isBranchNode() ? 'branch' : 'leaf');\n    };\n\n    Node.prototype.level = function() {\n      return this.ancestors().length;\n    };\n\n    Node.prototype.parentNode = function() {\n      if (this.parentId != null) {\n        return this.tree[this.parentId];\n      } else {\n        return null;\n      }\n    };\n\n    Node.prototype.removeChild = function(child) {\n      var i = $.inArray(child, this.children);\n      return this.children.splice(i, 1)\n    };\n\n    Node.prototype.render = function() {\n      var handler,\n          settings = this.settings,\n          target;\n\n      if (settings.expandable === true && this.isBranchNode()) {\n        handler = function(e) {\n          $(this).parents(\"table\").treetable(\"node\", $(this).parents(\"tr\").data(settings.nodeIdAttr)).toggle();\n          return e.preventDefault();\n        };\n\n        this.indenter.html(this.expander);\n        target = settings.clickableNodeNames === true ? this.treeCell : this.expander;\n\n        target.off(\"click.treetable\").on(\"click.treetable\", handler);\n        target.off(\"keydown.treetable\").on(\"keydown.treetable\", function(e) {\n          if (e.keyCode == 13) {\n            handler.apply(this, [e]);\n          }\n        });\n      }\n\n      this.indenter[0].style.paddingLeft = \"\" + (this.level() * settings.indent) + \"px\";\n\n      return this;\n    };\n\n    Node.prototype.reveal = function() {\n      if (this.parentId != null) {\n        this.parentNode().reveal();\n      }\n      return this.expand();\n    };\n\n    Node.prototype.setParent = function(node) {\n      if (this.parentId != null) {\n        this.tree[this.parentId].removeChild(this);\n      }\n      this.parentId = node.id;\n      this.row.data(this.settings.parentIdAttr, node.id);\n      return node.addChild(this);\n    };\n\n    Node.prototype.show = function() {\n      if (!this.initialized) {\n        this._initialize();\n      }\n      this.row.show();\n      if (this.expanded()) {\n        this._showChildren();\n      }\n      return this;\n    };\n\n    Node.prototype.toggle = function() {\n      if (this.expanded()) {\n        this.collapse();\n      } else {\n        this.expand();\n      }\n      return this;\n    };\n\n    Node.prototype._hideChildren = function() {\n      var child, _i, _len, _ref, _results;\n      _ref = this.children;\n      _results = [];\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        child = _ref[_i];\n        _results.push(child.hide());\n      }\n      return _results;\n    };\n\n    Node.prototype._initialize = function() {\n      var settings = this.settings;\n\n      this.render();\n\n      if (settings.expandable === true && settings.initialState === \"collapsed\") {\n        this.collapse();\n      } else {\n        this.expand();\n      }\n\n      if (settings.onNodeInitialized != null) {\n        settings.onNodeInitialized.apply(this);\n      }\n\n      return this.initialized = true;\n    };\n\n    Node.prototype._showChildren = function() {\n      var child, _i, _len, _ref, _results;\n      _ref = this.children;\n      _results = [];\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        child = _ref[_i];\n        _results.push(child.show());\n      }\n      return _results;\n    };\n\n    return Node;\n  })();\n\n  Tree = (function() {\n    function Tree(table, settings) {\n      this.table = table;\n      this.settings = settings;\n      this.tree = {};\n\n      // Cache the nodes and roots in simple arrays for quick access/iteration\n      this.nodes = [];\n      this.roots = [];\n    }\n\n    Tree.prototype.collapseAll = function() {\n      var node, _i, _len, _ref, _results;\n      _ref = this.nodes;\n      _results = [];\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        node = _ref[_i];\n        _results.push(node.collapse());\n      }\n      return _results;\n    };\n\n    Tree.prototype.expandAll = function() {\n      var node, _i, _len, _ref, _results;\n      _ref = this.nodes;\n      _results = [];\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        node = _ref[_i];\n        _results.push(node.expand());\n      }\n      return _results;\n    };\n\n    Tree.prototype.findLastNode = function (node) {\n      if (node.children.length > 0) {\n        return this.findLastNode(node.children[node.children.length - 1]);\n      } else {\n        return node;\n      }\n    };\n\n    Tree.prototype.loadRows = function(rows) {\n      var node, row, i;\n\n      if (rows != null) {\n        for (i = 0; i < rows.length; i++) {\n          row = $(rows[i]);\n\n          if (row.data(this.settings.nodeIdAttr) != null) {\n            node = new Node(row, this.tree, this.settings);\n            this.nodes.push(node);\n            this.tree[node.id] = node;\n\n            if (node.parentId != null && this.tree[node.parentId]) {\n              this.tree[node.parentId].addChild(node);\n            } else {\n              this.roots.push(node);\n            }\n          }\n        }\n      }\n\n      for (i = 0; i < this.nodes.length; i++) {\n        node = this.nodes[i].updateBranchLeafClass();\n      }\n\n      return this;\n    };\n\n    Tree.prototype.move = function(node, destination) {\n      // Conditions:\n      // 1: +node+ should not be inserted as a child of +node+ itself.\n      // 2: +destination+ should not be the same as +node+'s current parent (this\n      //    prevents +node+ from being moved to the same location where it already\n      //    is).\n      // 3: +node+ should not be inserted in a location in a branch if this would\n      //    result in +node+ being an ancestor of itself.\n      var nodeParent = node.parentNode();\n      if (node !== destination && destination.id !== node.parentId && $.inArray(node, destination.ancestors()) === -1) {\n        node.setParent(destination);\n        this._moveRows(node, destination);\n\n        // Re-render parentNode if this is its first child node, and therefore\n        // doesn't have the expander yet.\n        if (node.parentNode().children.length === 1) {\n          node.parentNode().render();\n        }\n      }\n\n      if(nodeParent){\n        nodeParent.updateBranchLeafClass();\n      }\n      if(node.parentNode()){\n        node.parentNode().updateBranchLeafClass();\n      }\n      node.updateBranchLeafClass();\n      return this;\n    };\n\n    Tree.prototype.removeNode = function(node) {\n      // Recursively remove all descendants of +node+\n      this.unloadBranch(node);\n\n      // Remove node from DOM (<tr>)\n      node.row.remove();\n\n      // Remove node from parent children list\n      if (node.parentId != null) {\n        node.parentNode().removeChild(node);\n      }\n\n      // Clean up Tree object (so Node objects are GC-ed)\n      delete this.tree[node.id];\n      this.nodes.splice($.inArray(node, this.nodes), 1);\n\n      return this;\n    }\n\n    Tree.prototype.render = function() {\n      var root, _i, _len, _ref;\n      _ref = this.roots;\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        root = _ref[_i];\n\n        // Naming is confusing (show/render). I do not call render on node from\n        // here.\n        root.show();\n      }\n      return this;\n    };\n\n    Tree.prototype.sortBranch = function(node, sortFun) {\n      // First sort internal array of children\n      node.children.sort(sortFun);\n\n      // Next render rows in correct order on page\n      this._sortChildRows(node);\n\n      return this;\n    };\n\n    Tree.prototype.unloadBranch = function(node) {\n      // Use a copy of the children array to not have other functions interfere\n      // with this function if they manipulate the children array\n      // (eg removeNode).\n      var children = node.children.slice(0),\n          i;\n\n      for (i = 0; i < children.length; i++) {\n        this.removeNode(children[i]);\n      }\n\n      // Reset node's collection of children\n      node.children = [];\n\n      node.updateBranchLeafClass();\n\n      return this;\n    };\n\n    Tree.prototype._moveRows = function(node, destination) {\n      var children = node.children, i;\n\n      node.row.insertAfter(destination.row);\n      node.render();\n\n      // Loop backwards through children to have them end up on UI in correct\n      // order (see #112)\n      for (i = children.length - 1; i >= 0; i--) {\n        this._moveRows(children[i], node);\n      }\n    };\n\n    // Special _moveRows case, move children to itself to force sorting\n    Tree.prototype._sortChildRows = function(parentNode) {\n      return this._moveRows(parentNode, parentNode);\n    };\n\n    return Tree;\n  })();\n\n  // jQuery Plugin\n  methods = {\n    init: function(options, force) {\n      var settings;\n\n      settings = $.extend({\n        branchAttr: \"ttBranch\",\n        clickableNodeNames: false,\n        column: 0,\n        columnElType: \"td\", // i.e. 'td', 'th' or 'td,th'\n        expandable: false,\n        expanderTemplate: \"<a href='#'>&nbsp;</a>\",\n        indent: 19,\n        indenterTemplate: \"<span class='indenter'></span>\",\n        initialState: \"collapsed\",\n        nodeIdAttr: \"ttId\", // maps to data-tt-id\n        parentIdAttr: \"ttParentId\", // maps to data-tt-parent-id\n        stringExpand: \"Expand\",\n        stringCollapse: \"Collapse\",\n\n        // Events\n        onInitialized: null,\n        onNodeCollapse: null,\n        onNodeExpand: null,\n        onNodeInitialized: null\n      }, options);\n\n      return this.each(function() {\n        var el = $(this), tree;\n\n        if (force || el.data(\"treetable\") === undefined) {\n          tree = new Tree(this, settings);\n          tree.loadRows(this.rows).render();\n\n          el.addClass(\"treetable\").data(\"treetable\", tree);\n\n          if (settings.onInitialized != null) {\n            settings.onInitialized.apply(tree);\n          }\n        }\n\n        return el;\n      });\n    },\n\n    destroy: function() {\n      return this.each(function() {\n        return $(this).removeData(\"treetable\").removeClass(\"treetable\");\n      });\n    },\n\n    collapseAll: function() {\n      this.data(\"treetable\").collapseAll();\n      return this;\n    },\n\n    collapseNode: function(id) {\n      var node = this.data(\"treetable\").tree[id];\n\n      if (node) {\n        node.collapse();\n      } else {\n        throw new Error(\"Unknown node '\" + id + \"'\");\n      }\n\n      return this;\n    },\n\n    expandAll: function() {\n      this.data(\"treetable\").expandAll();\n      return this;\n    },\n\n    expandNode: function(id) {\n      var node = this.data(\"treetable\").tree[id];\n\n      if (node) {\n        if (!node.initialized) {\n          node._initialize();\n        }\n\n        node.expand();\n      } else {\n        throw new Error(\"Unknown node '\" + id + \"'\");\n      }\n\n      return this;\n    },\n\n    loadBranch: function(node, rows) {\n      var settings = this.data(\"treetable\").settings,\n          tree = this.data(\"treetable\").tree;\n\n      // TODO Switch to $.parseHTML\n      rows = $(rows);\n\n      if (node == null) { // Inserting new root nodes\n        this.append(rows);\n      } else {\n        var lastNode = this.data(\"treetable\").findLastNode(node);\n        rows.insertAfter(lastNode.row);\n      }\n\n      this.data(\"treetable\").loadRows(rows);\n\n      // Make sure nodes are properly initialized\n      rows.filter(\"tr\").each(function() {\n        tree[$(this).data(settings.nodeIdAttr)].show();\n      });\n\n      if (node != null) {\n        // Re-render parent to ensure expander icon is shown (#79)\n        node.render().expand();\n      }\n\n      return this;\n    },\n\n    move: function(nodeId, destinationId) {\n      var destination, node;\n\n      node = this.data(\"treetable\").tree[nodeId];\n      destination = this.data(\"treetable\").tree[destinationId];\n      this.data(\"treetable\").move(node, destination);\n\n      return this;\n    },\n\n    node: function(id) {\n      return this.data(\"treetable\").tree[id];\n    },\n\n    removeNode: function(id) {\n      var node = this.data(\"treetable\").tree[id];\n\n      if (node) {\n        this.data(\"treetable\").removeNode(node);\n      } else {\n        throw new Error(\"Unknown node '\" + id + \"'\");\n      }\n\n      return this;\n    },\n\n    reveal: function(id) {\n      var node = this.data(\"treetable\").tree[id];\n\n      if (node) {\n        node.reveal();\n      } else {\n        throw new Error(\"Unknown node '\" + id + \"'\");\n      }\n\n      return this;\n    },\n\n    sortBranch: function(node, columnOrFunction) {\n      var settings = this.data(\"treetable\").settings,\n          prepValue,\n          sortFun;\n\n      columnOrFunction = columnOrFunction || settings.column;\n      sortFun = columnOrFunction;\n\n      if ($.isNumeric(columnOrFunction)) {\n        sortFun = function(a, b) {\n          var extractValue, valA, valB;\n\n          extractValue = function(node) {\n            var val = node.row.find(\"td:eq(\" + columnOrFunction + \")\").text();\n            // Ignore trailing/leading whitespace and use uppercase values for\n            // case insensitive ordering\n            return $.trim(val).toUpperCase();\n          }\n\n          valA = extractValue(a);\n          valB = extractValue(b);\n\n          if (valA < valB) return -1;\n          if (valA > valB) return 1;\n          return 0;\n        };\n      }\n\n      this.data(\"treetable\").sortBranch(node, sortFun);\n      return this;\n    },\n\n    unloadBranch: function(node) {\n      this.data(\"treetable\").unloadBranch(node);\n      return this;\n    }\n  };\n\n  $.fn.treetable = function(method) {\n    if (methods[method]) {\n      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n    } else if (typeof method === 'object' || !method) {\n      return methods.init.apply(this, arguments);\n    } else {\n      return $.error(\"Method \" + method + \" does not exist on jQuery.treetable\");\n    }\n  };\n\n  // Expose classes to world\n  this.TreeTable || (this.TreeTable = {});\n  this.TreeTable.Node = Node;\n  this.TreeTable.Tree = Tree;\n})(jQuery);\n"
  },
  {
    "path": "hiauth-server/src/main/resources/static/js/jquery.validate.min.js",
    "content": "/*! jQuery Validation Plugin - v1.19.5 - 7/1/2022\n * https://jqueryvalidation.org/\n * Copyright (c) 2022 Jörn Zaefferer; Licensed MIT */\n!function(a){\"function\"==typeof define&&define.amd?define([\"jquery\"],a):\"object\"==typeof module&&module.exports?module.exports=a(require(\"jquery\")):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn(\"Nothing selected, can't validate, returning nothing.\"));var c=a.data(this[0],\"validator\");return c?c:(this.attr(\"novalidate\",\"novalidate\"),c=new a.validator(b,this[0]),a.data(this[0],\"validator\",c),c.settings.onsubmit&&(this.on(\"click.validate\",\":submit\",function(b){c.submitButton=b.currentTarget,a(this).hasClass(\"cancel\")&&(c.cancelSubmit=!0),void 0!==a(this).attr(\"formnovalidate\")&&(c.cancelSubmit=!0)}),this.on(\"submit.validate\",function(b){function d(){var d,e;return c.submitButton&&(c.settings.submitHandler||c.formSubmitted)&&(d=a(\"<input type='hidden'/>\").attr(\"name\",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),!(c.settings.submitHandler&&!c.settings.debug)||(e=c.settings.submitHandler.call(c,c.currentForm,b),d&&d.remove(),void 0!==e&&e)}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c,d;return a(this[0]).is(\"form\")?b=this.validate().form():(d=[],b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b,b||(d=d.concat(c.errorList))}),c.errorList=d),b},rules:function(b,c){var d,e,f,g,h,i,j=this[0],k=\"undefined\"!=typeof this.attr(\"contenteditable\")&&\"false\"!==this.attr(\"contenteditable\");if(null!=j&&(!j.form&&k&&(j.form=this.closest(\"form\")[0],j.name=this.attr(\"name\")),null!=j.form)){if(b)switch(d=a.data(j.form,\"validator\").settings,e=d.rules,f=a.validator.staticRules(j),b){case\"add\":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case\"remove\":return c?(i={},a.each(c.split(/\\s/),function(a,b){i[b]=f[b],delete f[b]}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g)),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}});var b=function(a){return a.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\"\")};a.extend(a.expr.pseudos||a.expr[\":\"],{blank:function(c){return!b(\"\"+a(c).val())},filled:function(c){var d=a(c).val();return null!==d&&!!b(\"\"+d)},unchecked:function(b){return!a(b).prop(\"checked\")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:void 0===c?b:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp(\"\\\\{\"+a+\"\\\\}\",\"g\"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:\"error\",pendingClass:\"pending\",validClass:\"valid\",errorElement:\"label\",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:\":hidden\",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(b,c){var d=[16,17,18,20,35,36,37,38,39,40,45,144,225];9===c.which&&\"\"===this.elementValue(b)||a.inArray(c.keyCode,d)!==-1||(b.name in this.submitted||b.name in this.invalid)&&this.element(b)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){\"radio\"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){\"radio\"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:\"This field is required.\",remote:\"Please fix this field.\",email:\"Please enter a valid email address.\",url:\"Please enter a valid URL.\",date:\"Please enter a valid date.\",dateISO:\"Please enter a valid date (ISO).\",number:\"Please enter a valid number.\",digits:\"Please enter only digits.\",equalTo:\"Please enter the same value again.\",maxlength:a.validator.format(\"Please enter no more than {0} characters.\"),minlength:a.validator.format(\"Please enter at least {0} characters.\"),rangelength:a.validator.format(\"Please enter a value between {0} and {1} characters long.\"),range:a.validator.format(\"Please enter a value between {0} and {1}.\"),max:a.validator.format(\"Please enter a value less than or equal to {0}.\"),min:a.validator.format(\"Please enter a value greater than or equal to {0}.\"),step:a.validator.format(\"Please enter a multiple of {0}.\")},autoCreateRanges:!1,prototype:{init:function(){function b(b){var c=\"undefined\"!=typeof a(this).attr(\"contenteditable\")&&\"false\"!==a(this).attr(\"contenteditable\");if(!this.form&&c&&(this.form=a(this).closest(\"form\")[0],this.name=a(this).attr(\"name\")),d===this.form){var e=a.data(this.form,\"validator\"),f=\"on\"+b.type.replace(/^validate/,\"\"),g=e.settings;g[f]&&!a(this).is(g.ignore)&&g[f].call(e,this,b)}}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.currentForm,e=this.groups={};a.each(this.settings.groups,function(b,c){\"string\"==typeof c&&(c=c.split(/\\s/)),a.each(c,function(a,c){e[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).on(\"focusin.validate focusout.validate keyup.validate\",\":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], [type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox'], [contenteditable], [type='button']\",b).on(\"click.validate\",\"select, option, [type='radio'], [type='checkbox']\",b),this.settings.invalidHandler&&a(this.currentForm).on(\"invalid-form.validate\",this.settings.invalidHandler)},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler(\"invalid-form\",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c,d,e=this.clean(b),f=this.validationTargetFor(e),g=this,h=!0;return void 0===f?delete this.invalid[e.name]:(this.prepareElement(f),this.currentElements=a(f),d=this.groups[f.name],d&&a.each(this.groups,function(a,b){b===d&&a!==f.name&&(e=g.validationTargetFor(g.clean(g.findByName(a))),e&&e.name in g.invalid&&(g.currentElements.push(e),h=g.check(e)&&h))}),c=this.check(f)!==!1,h=h&&c,c?this.invalid[f.name]=!1:this.invalid[f.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),a(b).attr(\"aria-invalid\",!c)),h},showErrors:function(b){if(b){var c=this;a.extend(this.errorMap,b),this.errorList=a.map(this.errorMap,function(a,b){return{message:a,element:c.findByName(b)[0]}}),this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.invalid={},this.submitted={},this.prepareForm(),this.hideErrors();var b=this.elements().removeData(\"previousValue\").removeAttr(\"aria-invalid\");this.resetElements(b)},resetElements:function(a){var b;if(this.settings.unhighlight)for(b=0;a[b];b++)this.settings.unhighlight.call(this,a[b],this.settings.errorClass,\"\"),this.findByName(a[b].name).removeClass(this.settings.validClass);else a.removeClass(this.settings.errorClass).removeClass(this.settings.validClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)void 0!==a[b]&&null!==a[b]&&a[b]!==!1&&c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(\"\"),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(\":visible\").trigger(\"focus\").trigger(\"focusin\")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find(\"input, select, textarea, [contenteditable]\").not(\":submit, :reset, :image, :disabled\").not(this.settings.ignore).filter(function(){var d=this.name||a(this).attr(\"name\"),e=\"undefined\"!=typeof a(this).attr(\"contenteditable\")&&\"false\"!==a(this).attr(\"contenteditable\");return!d&&b.settings.debug&&window.console&&console.error(\"%o has no name assigned\",this),e&&(this.form=a(this).closest(\"form\")[0],this.name=d),this.form===b.currentForm&&(!(d in c||!b.objectLength(a(this).rules()))&&(c[d]=!0,!0))})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(\" \").join(\".\");return a(this.settings.errorElement+\".\"+b,this.errorContext)},resetInternals:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([])},reset:function(){this.resetInternals(),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d,e=a(b),f=b.type,g=\"undefined\"!=typeof e.attr(\"contenteditable\")&&\"false\"!==e.attr(\"contenteditable\");return\"radio\"===f||\"checkbox\"===f?this.findByName(b.name).filter(\":checked\").val():\"number\"===f&&\"undefined\"!=typeof b.validity?b.validity.badInput?\"NaN\":e.val():(c=g?e.text():e.val(),\"file\"===f?\"C:\\\\fakepath\\\\\"===c.substr(0,12)?c.substr(12):(d=c.lastIndexOf(\"/\"),d>=0?c.substr(d+1):(d=c.lastIndexOf(\"\\\\\"),d>=0?c.substr(d+1):c)):\"string\"==typeof c?c.replace(/\\r/g,\"\"):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f,g=a(b).rules(),h=a.map(g,function(a,b){return b}).length,i=!1,j=this.elementValue(b);\"function\"==typeof g.normalizer?f=g.normalizer:\"function\"==typeof this.settings.normalizer&&(f=this.settings.normalizer),f&&(j=f.call(b,j),delete g.normalizer);for(d in g){e={method:d,parameters:g[d]};try{if(c=a.validator.methods[d].call(this,j,b,e.parameters),\"dependency-mismatch\"===c&&1===h){i=!0;continue}if(i=!1,\"pending\"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(k){throw this.settings.debug&&window.console&&console.log(\"Exception occurred when checking element \"+b.id+\", check the '\"+e.method+\"' method.\",k),k instanceof TypeError&&(k.message+=\".  Exception occurred when checking element \"+b.id+\", check the '\"+e.method+\"' method.\"),k}}if(!i)return this.objectLength(g)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data(\"msg\"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data(\"msg\")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;a<arguments.length;a++)if(void 0!==arguments[a])return arguments[a]},defaultMessage:function(b,c){\"string\"==typeof c&&(c={method:c});var d=this.findDefined(this.customMessage(b.name,c.method),this.customDataMessage(b,c.method),!this.settings.ignoreTitle&&b.title||void 0,a.validator.messages[c.method],\"<strong>Warning: No message defined for \"+b.name+\"</strong>\"),e=/\\$?\\{(\\d+)\\}/g;return\"function\"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,\"{$1}\"),c.parameters)),d},formatAndAdd:function(a,b){var c=this.defaultMessage(a,b);this.errorList.push({message:c,element:a,method:b.method}),this.errorMap[a.name]=c,this.submitted[a.name]=c},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g,h=this.errorsFor(b),i=this.idOrName(b),j=a(b).attr(\"aria-describedby\");h.length?(h.removeClass(this.settings.validClass).addClass(this.settings.errorClass),h.html(c)):(h=a(\"<\"+this.settings.errorElement+\">\").attr(\"id\",i+\"-error\").addClass(this.settings.errorClass).html(c||\"\"),d=h,this.settings.wrapper&&(d=h.hide().show().wrap(\"<\"+this.settings.wrapper+\"/>\").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement.call(this,d,a(b)):d.insertAfter(b),h.is(\"label\")?h.attr(\"for\",i):0===h.parents(\"label[for='\"+this.escapeCssMeta(i)+\"']\").length&&(f=h.attr(\"id\"),j?j.match(new RegExp(\"\\\\b\"+this.escapeCssMeta(f)+\"\\\\b\"))||(j+=\" \"+f):j=f,a(b).attr(\"aria-describedby\",j),e=this.groups[b.name],e&&(g=this,a.each(g.groups,function(b,c){c===e&&a(\"[name='\"+g.escapeCssMeta(b)+\"']\",g.currentForm).attr(\"aria-describedby\",h.attr(\"id\"))})))),!c&&this.settings.success&&(h.text(\"\"),\"string\"==typeof this.settings.success?h.addClass(this.settings.success):this.settings.success(h,b)),this.toShow=this.toShow.add(h)},errorsFor:function(b){var c=this.escapeCssMeta(this.idOrName(b)),d=a(b).attr(\"aria-describedby\"),e=\"label[for='\"+c+\"'], label[for='\"+c+\"'] *\";return d&&(e=e+\", #\"+this.escapeCssMeta(d).replace(/\\s+/g,\", #\")),this.errors().filter(e)},escapeCssMeta:function(a){return void 0===a?\"\":a.replace(/([\\\\!\"#$%&'()*+,./:;<=>?@\\[\\]^`{|}~])/g,\"\\\\$1\")},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find(\"[name='\"+this.escapeCssMeta(b)+\"']\")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case\"select\":return a(\"option:selected\",c).length;case\"input\":if(this.checkable(c))return this.findByName(c.name).filter(\":checked\").length}return b.length},depend:function(a,b){return!this.dependTypes[typeof a]||this.dependTypes[typeof a](a,b)},dependTypes:{\"boolean\":function(a){return a},string:function(b,c){return!!a(b,c.form).length},\"function\":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&\"dependency-mismatch\"},startRequest:function(b){this.pending[b.name]||(this.pendingRequest++,a(b).addClass(this.settings.pendingClass),this.pending[b.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],a(b).removeClass(this.settings.pendingClass),c&&0===this.pendingRequest&&this.formSubmitted&&this.form()&&0===this.pendingRequest?(a(this.currentForm).trigger(\"submit\"),this.submitButton&&a(\"input:hidden[name='\"+this.submitButton.name+\"']\",this.currentForm).remove(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler(\"invalid-form\",[this]),this.formSubmitted=!1)},previousValue:function(b,c){return c=\"string\"==typeof c&&c||\"remote\",a.data(b,\"previousValue\")||a.data(b,\"previousValue\",{old:null,valid:!0,message:this.defaultMessage(b,{method:c})})},destroy:function(){this.resetForm(),a(this.currentForm).off(\".validate\").removeData(\"validator\").find(\".validate-equalTo-blur\").off(\".validate-equalTo\").removeClass(\"validate-equalTo-blur\").find(\".validate-lessThan-blur\").off(\".validate-lessThan\").removeClass(\"validate-lessThan-blur\").find(\".validate-lessThanEqual-blur\").off(\".validate-lessThanEqual\").removeClass(\"validate-lessThanEqual-blur\").find(\".validate-greaterThanEqual-blur\").off(\".validate-greaterThanEqual\").removeClass(\"validate-greaterThanEqual-blur\").find(\".validate-greaterThan-blur\").off(\".validate-greaterThan\").removeClass(\"validate-greaterThan-blur\")}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr(\"class\");return d&&a.each(d.split(\" \"),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},normalizeAttributeRule:function(a,b,c,d){/min|max|step/.test(c)&&(null===b||/number|range|text/.test(b))&&(d=Number(d),isNaN(d)&&(d=void 0)),d||0===d?a[c]=d:b===c&&\"range\"!==b&&(a[\"date\"===b?\"dateISO\":c]=!0)},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute(\"type\");for(c in a.validator.methods)\"required\"===c?(d=b.getAttribute(c),\"\"===d&&(d=!0),d=!!d):d=f.attr(c),this.normalizeAttributeRule(e,g,c,d);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute(\"type\");for(c in a.validator.methods)d=f.data(\"rule\"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),\"\"===d&&(d=!0),this.normalizeAttributeRule(e,g,c,d);return e},staticRules:function(b){var c={},d=a.data(b.form,\"validator\");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case\"string\":f=!!a(e.depends,c.form).length;break;case\"function\":f=e.depends.call(c,c)}f?b[d]=void 0===e.param||e.param:(a.data(c.form,\"validator\").resetElements(a(c)),delete b[d])}}),a.each(b,function(a,d){b[a]=\"function\"==typeof d&&\"normalizer\"!==a?d(c):d}),a.each([\"minlength\",\"maxlength\"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each([\"rangelength\",\"range\"],function(){var a;b[this]&&(Array.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:\"string\"==typeof b[this]&&(a=b[this].replace(/[\\[\\]]/g,\"\").split(/[\\s,]+/),b[this]=[Number(a[0]),Number(a[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if(\"string\"==typeof b){var c={};a.each(b.split(/\\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return\"dependency-mismatch\";if(\"select\"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:void 0!==b&&null!==b&&b.length>0},email:function(a,b){return this.optional(b)||/^[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])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(?:(?:(?:https?|ftp):)?\\/\\/)(?:(?:[^\\]\\[?\\/<~#`!@$^&*()+=}|:\";',>{ ]|%[0-9A-Fa-f]{2})+(?::(?:[^\\]\\[?\\/<~#`!@$^&*()+=}|:\";',>{ ]|%[0-9A-Fa-f]{2})*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z0-9\\u00a1-\\uffff][a-z0-9\\u00a1-\\uffff_-]{0,62})?[a-z0-9\\u00a1-\\uffff]\\.)+(?:[a-z\\u00a1-\\uffff]{2,}\\.?))(?::\\d{2,5})?(?:[/?#]\\S*)?$/i.test(a)},date:function(){var a=!1;return function(b,c){return a||(a=!0,this.settings.debug&&window.console&&console.warn(\"The `date` method is deprecated and will be removed in version '2.0.0'.\\nPlease don't use it, since it relies on the Date constructor, which\\nbehaves very differently across browsers and locales. Use `dateISO`\\ninstead or one of the locale specific methods in `localizations/`\\nand `additional-methods.js`.\")),this.optional(c)||!/Invalid|NaN/.test(new Date(b).toString())}}(),dateISO:function(a,b){return this.optional(b)||/^\\d{4}[\\/\\-](0?[1-9]|1[012])[\\/\\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^(?:-?\\d+|-?\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\\d+$/.test(a)},minlength:function(a,b,c){var d=Array.isArray(a)?a.length:this.getLength(a,b);return this.optional(b)||d>=c},maxlength:function(a,b,c){var d=Array.isArray(a)?a.length:this.getLength(a,b);return this.optional(b)||d<=c},rangelength:function(a,b,c){var d=Array.isArray(a)?a.length:this.getLength(a,b);return this.optional(b)||d>=c[0]&&d<=c[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||a<=c},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},step:function(b,c,d){var e,f=a(c).attr(\"type\"),g=\"Step attribute on input type \"+f+\" is not supported.\",h=[\"text\",\"number\",\"range\"],i=new RegExp(\"\\\\b\"+f+\"\\\\b\"),j=f&&!i.test(h.join()),k=function(a){var b=(\"\"+a).match(/(?:\\.(\\d+))?$/);return b&&b[1]?b[1].length:0},l=function(a){return Math.round(a*Math.pow(10,e))},m=!0;if(j)throw new Error(g);return e=k(d),(k(b)>e||l(b)%l(d)!==0)&&(m=!1),this.optional(c)||m},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.not(\".validate-equalTo-blur\").length&&e.addClass(\"validate-equalTo-blur\").on(\"blur.validate-equalTo\",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d,e){if(this.optional(c))return\"dependency-mismatch\";e=\"string\"==typeof e&&e||\"remote\";var f,g,h,i=this.previousValue(c,e);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),i.originalMessage=i.originalMessage||this.settings.messages[c.name][e],this.settings.messages[c.name][e]=i.message,d=\"string\"==typeof d&&{url:d}||d,h=a.param(a.extend({data:b},d.data)),i.old===h?i.valid:(i.old=h,f=this,this.startRequest(c),g={},g[c.name]=b,a.ajax(a.extend(!0,{mode:\"abort\",port:\"validate\"+c.name,dataType:\"json\",data:g,context:f.currentForm,success:function(a){var d,g,h,j=a===!0||\"true\"===a;f.settings.messages[c.name][e]=i.originalMessage,j?(h=f.formSubmitted,f.resetInternals(),f.toHide=f.errorsFor(c),f.formSubmitted=h,f.successList.push(c),f.invalid[c.name]=!1,f.showErrors()):(d={},g=a||f.defaultMessage(c,{method:e,parameters:b}),d[c.name]=i.message=g,f.invalid[c.name]=!0,f.showErrors(d)),i.valid=j,f.stopRequest(c,j)}},d)),\"pending\")}}});var c,d={};return a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,c){var e=a.port;\"abort\"===a.mode&&(d[e]&&d[e].abort(),d[e]=c)}):(c=a.ajax,a.ajax=function(b){var e=(\"mode\"in b?b:a.ajaxSettings).mode,f=(\"port\"in b?b:a.ajaxSettings).port;return\"abort\"===e?(d[f]&&d[f].abort(),d[f]=c.apply(this,arguments),d[f]):c.apply(this,arguments)}),a});"
  },
  {
    "path": "hiauth-server/src/main/resources/static/js/login.js",
    "content": "$(function () {\n\n    const contentPath = \"\";\n    const imgUrl = contentPath + \"/auth/code/image\";\n    const smsUrl = contentPath + \"/auth/code/sms\";\n\n    const $accountForm = $('#accountForm');\n    const $telForm = $('#telForm');\n\n    // 提示图标\n    const errorIcon = '<i aria-hidden=\"true\" class=\"fa fa-exclamation-triangle\"></i>';\n    $accountForm.validate({\n        debug: false,\n        errorPlacement: function (error, element) {\n            error.addClass(\"input-invalid\")\n            $(element).parent().after(error);\n        },\n        rules: {\n            account: {\n                required: true,\n                rangelength: [3, 10]\n            },\n            password: {\n                required: true,\n                rangelength: [3, 10]\n            },\n            captcha: {\n                required: true,\n                rangelength: [4, 6]\n            }\n        },\n        messages: {\n            account: {\n                required: errorIcon + \"请输入账号\",\n                rangelength: errorIcon + \"账号长度为{0}-{1}个字符\"\n            },\n            password: {\n                required: errorIcon + \"请输入密码\",\n                rangelength: errorIcon + \"密码长度为{0}-{1}个字符\"\n            },\n            captcha: {\n                required: errorIcon + \"请输入图形验证码\",\n                rangelength: errorIcon + \"图形验证码长度为{0}-{1}个字符\"\n            }\n        },\n        // 使用div标签，包裹提示信息，而后插入DOM\n        wrapper: \"div\",\n        showErrors: function (errorMap, errorList) {\n            for (var obj in errorMap) {\n                $(\"[name='\" + obj + \"']\").parent(\".input-group\").removeClass(\"input-group-valid\").addClass(\"input-group-invalid\")\n                $(\"[name='\" + obj + \"']\").addClass('is-invalid');\n            }\n            this.defaultShowErrors();\n        },\n        success: function (label) {\n            const id = $(label).attr(\"for\")\n            $(\"#\" + id).parent(\".input-group\").removeClass(\"input-group-invalid\").addClass(\"input-group-valid\")\n            $(\"#\" + id).removeClass('is-invalid').addClass(\"is-valid\");\n            $(label).parent(\".input-invalid\").remove();\n        }\n    });\n\n    $telForm.validate({\n        debug: false,\n        errorPlacement: function (error, element) {\n            error.addClass(\"input-invalid\")\n            $(element).parent().after(error);\n        },\n        rules: {\n            account: {\n                required: true,\n                rangelength: [11, 11]\n            },\n            smsCode: {\n                required: true,\n                rangelength: [4, 6]\n            },\n            captcha: {\n                required: true,\n                rangelength: [4, 6]\n            }\n        },\n        messages: {\n            account: {\n                required: errorIcon + \"请输入手机号码\",\n                rangelength: errorIcon + \"手机号码长度为{0}-{1}个字符\"\n            },\n            smsCode: {\n                required: errorIcon + \"请输入短信验证码\",\n                rangelength: errorIcon + \"短信验证码长度为{0}-{1}个字符\"\n            },\n            captcha: {\n                required: errorIcon + \"请输入图形验证码\",\n                rangelength: errorIcon + \"图形验证码长度为{0}-{1}个字符\"\n            }\n        },\n        // 使用div标签，包裹提示信息，而后插入DOM\n        wrapper: \"div\",\n        showErrors: function (errorMap, errorList) {\n            for (var obj in errorMap) {\n                $(\"[name='\" + obj + \"']\").parent(\".input-group\").removeClass(\"input-group-valid\").addClass(\"input-group-invalid\")\n                $(\"[name='\" + obj + \"']\").addClass('is-invalid');\n            }\n            this.defaultShowErrors();\n        },\n        success: function (label) {\n            const id = $(label).attr(\"for\")\n            $(\"#\" + id).parent(\".input-group\").removeClass(\"input-group-invalid\").addClass(\"input-group-valid\")\n            $(\"#\" + id).removeClass('is-invalid').addClass(\"is-valid\");\n            $(label).parent(\".input-invalid\").remove();\n        }\n    });\n\n    //获取图形验证码\n    function getCaptcha(formToken) {\n        const $this = $(\".captcha-img\");\n        const url = imgUrl + \"?formToken=\" + formToken + \"&r=\" + Math.random();\n        $this.attr('src', url);\n    }\n\n    //点击更新图形验证码\n    $('.captcha-img').click(function () {\n        const formToken = $(\"#formToken\").val();\n        getCaptcha(formToken);\n    });\n    getCaptcha($(\"#formToken\").val());\n\n    //获取短信验证码\n    function getSmsCaptcha(formToken, telNo, imgCode) {\n        const url = smsUrl + \"?telNo=\" + telNo + \"&formToken=\" + formToken + \"&imgCode=\" + imgCode + \"&r=\" + Math.random();\n        $.get(url, function (data) {\n            $(\"#smsCode\").val(data.data);\n        });\n    }\n\n    //点击获取短信验证码\n    $('.sms-code-btu').click(function (e) {\n        const $this = $(e.target);\n        if (!$this.hasClass(\"disabled\")) {\n            $telForm.validate({\n                ignore: \"#smsCode\",\n            });\n            const isValid = $telForm.valid();\n            // $telForm.addClass('was-validated')\n            if (isValid) {\n                const formToken = $(\"#formToken2\").val();\n                const telNo = $(\"#telNo\").val();\n                const imgCode = $(\"#captcha1\").val()\n                getSmsCaptcha(formToken, telNo, imgCode);\n                setTime($this, 60);\n            }\n            // $telForm.bootstrapValidator(\"addField\", \"smsCode\", smsCodeValidators);\n            $(\"#smsCode\").val(smsCodeValidators)\n        }\n    });\n\n    //发送完短信后倒计时数秒，如果需要支持页面刷新，可以使用cooke\n    function setTime($el, countdown) {\n        if (countdown == 0) {\n            $el.removeClass(\"disabled\");\n            $el.text(\"获取验证码\");\n            return false;\n        } else {\n            $el.addClass(\"disabled\");\n            $el.text(\"重新发送(\" + countdown + \")\");\n            countdown--;\n        }\n        setTimeout(function () {\n            setTime($el, countdown);\n        }, 1000);\n    }\n\n});"
  },
  {
    "path": "hiauth-server/src/main/resources/static/js/particle.js",
    "content": "!(function () {\n    let a;\n    let c;\n    let u;\n    let m = document.createElement(\"canvas\");\n    let d = t();\n    let r = m.getContext(\"2d\");\n    let x =\n        window.requestAnimationFrame ||\n        window.webkitRequestAnimationFrame ||\n        window.mozRequestAnimationFrame ||\n        window.oRequestAnimationFrame ||\n        window.msRequestAnimationFrame ||\n        function (n) {\n            window.setTimeout(n, 1e3 / 45);\n        };\n\n    let y = {x: null, y: null, max: 15e3};\n\n    function n(n, e, t) {\n        return n.getAttribute(e) || t;\n    }\n\n    function e(n) {\n        return document.getElementsByTagName(n);\n    }\n\n    function t() {\n        const t = e(\"script\"), o = t.length, i = t[o - 1];\n        return {\n            l: o,\n            z: n(i, \"zIndex\", -1),\n            o: n(i, \"opacity\", 0.3),\n            c: n(i, \"color\", \"255,255,255\"),\n            n: n(i, \"count\", 66)\n        };\n    }\n\n    function o() {\n        (a = m.width =\n            window.innerWidth ||\n            document.documentElement.clientWidth ||\n            document.body.clientWidth),\n            (c = m.height =\n                window.innerHeight ||\n                document.documentElement.clientHeight ||\n                document.body.clientHeight);\n    }\n\n    function i() {\n        r.clearRect(0, 0, a, c);\n        let n, e, t, o, m, l;\n        s.forEach(function (i, x) {\n            for (\n                i.x += i.xa,\n                    i.y += i.ya,\n                    i.xa *= i.x > a || i.x < 0 ? -1 : 1,\n                    i.ya *= i.y > c || i.y < 0 ? -1 : 1,\n                    r.fillRect(i.x - 0.5, i.y - 0.5, 1, 1),\n                    e = x + 1;\n                e < u.length;\n                e++\n            )\n                (n = u[e]),\n                null !== n.x &&\n                null !== n.y &&\n                ((o = i.x - n.x),\n                    (m = i.y - n.y),\n                    (l = o * o + m * m),\n                l < n.max &&\n                (n === y &&\n                l >= n.max / 2 &&\n                ((i.x -= 0.03 * o), (i.y -= 0.03 * m)),\n                    (t = (n.max - l) / n.max),\n                    r.beginPath(),\n                    (r.lineWidth = t / 2),\n                    (r.strokeStyle = \"rgba(\" + d.c + \",\" + (t + 0.2) + \")\"),\n                    r.moveTo(i.x, i.y),\n                    r.lineTo(n.x, n.y),\n                    r.stroke()));\n        }), x(i);\n    }\n\n    let l = \"c_n\" + d.l, w = Math.random;\n    (m.id = l),\n        (m.style.cssText = \"position:fixed;top:0;left:0;z-index:\" + d.z + \";opacity:\" + d.o),\n        e(\"body\")[0].appendChild(m),\n        o(),\n        (window.onresize = o),\n        (window.onmousemove = function(n) {\n            // 添加鼠标移动时间戳记录\n            (n = n || window.event), (y.x = n.clientX), (y.y = n.clientY);\n            // 新增闲置检测逻辑\n            clearTimeout(y.timeout);\n            y.timeout = setTimeout(() => {\n                y.x = null;\n                y.y = null;\n            }, 3000); // 3秒无操作后清空坐标\n        }),\n        (window.onmouseout = function () {\n            (y.x = null), (y.y = null);\n        });\n\n    for (var s = [], f = 0; d.n > f; f++) {\n        const h = w() * a,\n            g = w() * c,\n            v = 2 * w() - 1,\n            p = 2 * w() - 1;\n        s.push({x: h, y: g, xa: v, ya: p, max: 5e4});\n    }\n\n    (u = s.concat([y])),\n        setTimeout(function () {\n            i();\n        }, 100);\n})();"
  },
  {
    "path": "hiauth-server/src/main/resources/static/js/sliderCaptcha.js",
    "content": "(function ($) {\n    // 滑块验证码插件\n    $.fn.sliderCaptcha = function (options) {\n\n        if (typeof options === 'string') {\n            const methodName = options;\n            const args = Array.prototype.slice.call(arguments, 1);\n\n            // 如果是 reset 方法\n            if (methodName === 'reset') {\n                return this.each(function() {\n                    const $sliderTrack = $(this);\n                    const sliderInstance = $sliderTrack.data('sliderCaptcha');\n                    if (sliderInstance && typeof sliderInstance.reset === 'function') {\n                        sliderInstance.reset.apply(sliderInstance, args);\n                    }\n                });\n            }\n        }\n\n        // 默认配置\n        const defaults = {\n            token: null,\n            successCallback: null,\n            errorCallback: null\n        };\n\n        // 合并配置\n        const settings = $.extend({}, defaults, options);\n\n        // 遍历每个元素\n        return this.each(function () {\n            const $sliderTrack = $(this);\n            const $sliderThumb = $sliderTrack.find('.slider-thumb');\n            const $thumbTrack = $sliderTrack.find('.slider-track');\n            const $sliderTitle = $sliderTrack.find('.slider-title');\n            const $captchaInput = $sliderTrack.find('[name=\"captcha\"]');\n\n            let isDragging = false;\n            let isVerified = false;  // 添加验证状态变量\n            let startX = 0;\n            let endX = 0;\n            let startTime = 0;\n            let endTime = 0;\n            let startLeft = 0;\n\n            // 重置方法\n            function reset() {\n                $sliderThumb.animate({left: 0}, 300);\n                $thumbTrack.animate({width: 0}, 300);\n                $sliderTrack.removeClass('success');\n                $sliderThumb.removeClass('success');\n                $sliderTitle.removeClass('success');\n                $sliderTitle.text('按住滑块，拖动到最右边');\n                $sliderThumb.html('<img src=\"../static/img/chevron-right-light.png\" alt=\"\">');\n                isVerified = false;\n                $captchaInput.val('');\n            }\n\n            // 将 reset 方法暴露给元素\n            $sliderTrack.data('sliderCaptcha', {\n                reset: reset\n            });\n\n            // 鼠标按下事件\n            $sliderThumb.on('mousedown', function (e) {\n                // 如果已经验证成功，则不再允许拖动\n                if (isVerified) return;\n                isDragging = true;\n                startX = e.clientX;\n                startTime = new Date().getTime();\n                startLeft = parseInt($sliderThumb.css('left')) || 0;\n                e.preventDefault();\n            });\n\n            // 鼠标移动事件\n            $(document).on('mousemove', function (e) {\n                if (!isDragging) return;\n\n                const diffX = e.clientX - startX;\n                const newLeft = startLeft + diffX;\n\n                // 限制滑块移动范围\n                const maxLeft = $sliderTrack.width() - $sliderThumb.width();\n                const boundedLeft = Math.max(0, Math.min(newLeft, maxLeft));\n\n                $sliderThumb.css('left', boundedLeft);\n                $thumbTrack.css('width', boundedLeft);\n            });\n\n            // 鼠标释放事件\n            $(document).on('mouseup', function (e) {\n                if (!isDragging) return;\n                isDragging = false;\n                endX = e.clientX;\n                endTime = new Date().getTime();\n\n                // 检查是否拖动到最右边\n                const maxLeft = $sliderTrack.width() - $sliderThumb.width();\n                const currentLeft = parseInt($sliderThumb.css('left')) || 0;\n\n                // 如果拖动到最右边，验证成功\n                if (currentLeft >= maxLeft - 5) { // 允许5px的误差\n\n                    // 构建数据对象\n                    const data = {\n                        token: settings.token,\n                        startX: startX,\n                        endX: endX,\n                        startTime: startTime,\n                        endTime: endTime\n                    };\n\n                    // 执行成功回调\n                    if (typeof settings.successCallback === 'function') {\n                        settings.successCallback.call($sliderTrack, data);\n                    }\n\n                    // 调用后台接口\n                    $.ajax({\n                        url: '/auth/code/captcha',\n                        type: 'POST',\n                        data: JSON.stringify(data),\n                        contentType: 'application/json',\n                        success: function(response) {\n                            if(response.code === 10000){\n                                $sliderThumb.css('left', maxLeft);\n                                $sliderTrack.addClass('success');\n                                $sliderThumb.addClass('success');\n                                $sliderTitle.addClass('success');\n                                $sliderTitle.text('验证成功');\n                                // 修改滑块内容为绿色对号\n                                $sliderThumb.html('<img src=\"../static/img/chevron-success.png\" alt=\"\">');\n                                // 设置验证状态为已验证\n                                isVerified = true;\n                                $captchaInput.val(response.data)\n                            } else {\n                                // 验证失败时重置\n                                reset();\n                            }\n                        },\n                        error: function() {\n                            // 请求失败时重置\n                            reset();\n                        }\n                    });\n\n                } else {\n                    // 如果没有拖动到最右边，回到初始位置\n                    $sliderThumb.animate({left: 0}, 300);\n                    $thumbTrack.animate({width: 0}, 300);\n\n                    // 执行错误回调\n                    if (typeof settings.errorCallback === 'function') {\n                        settings.errorCallback.call($sliderTrack);\n                    }\n                }\n            });\n        });\n    };\n})(jQuery);"
  },
  {
    "path": "hiauth-server/src/main/resources/static/js/wxLogin.js",
    "content": "!function(e,t){e.WxLogin=function(o){var n=\"default\";!0===o.self_redirect?n=\"true\":!1===o.self_redirect&&(n=\"false\");var r=t.createElement(\"iframe\"),s=(new Date).getTime(),a=\"https://open.weixin.qq.com/connect/qrconnect?appid=\"+o.appid+\"&scope=\"+o.scope+\"&redirect_uri=\"+o.redirect_uri+\"&state=\"+o.state+\"&login_type=jssdk&self_redirect=\"+n+\"&styletype=\"+(o.styletype||\"\")+\"&sizetype=\"+(o.sizetype||\"\")+\"&bgcolor=\"+(o.bgcolor||\"\")+\"&rst=\"+(o.rst||\"\")+\"&ts=\"+s;a+=o.style?\"&style=\"+o.style:\"\",a+=o.href?\"&href=\"+o.href:\"\",a+=\"en\"===o.lang?\"&lang=en\":\"\",a+=1===o.stylelite?\"&stylelite=1\":\"\",a+=0===o.fast_login?\"&fast_login=0\":\"\",\"auto\"===o.color_scheme?a+=\"&color_scheme=auto\":\"dark\"===o.color_scheme?a+=\"&color_scheme=dark\":\"light\"===o.color_scheme&&(a+=\"&color_scheme=light\"),r.src=a,r.frameBorder=\"0\",r.allowTransparency=\"true\",r.scrolling=\"no\",r.width=\"300px\",r.height=\"400px\";var i=t.getElementById(o.id);if(i.innerHTML=\"\",i.appendChild(r),e.addEventListener&&e.JSON){var c=function(t){if(\"https://open.weixin.qq.com\"===t.origin)try{var n=JSON.parse(t.data);if(n&&\"status\"===n.type){var r=\"wxReady\"===n.status;r&&o.onReady&&\"function\"==typeof o.onReady&&o.onReady(r),\"wxQRcodeReady\"===n.status&&o.onQRcodeReady&&\"function\"==typeof o.onQRcodeReady&&o.onQRcodeReady()}}catch(t){e.console&&\"function\"==typeof e.console.log&&e.console.log(\"wxLogin postMessage error\",t)}};e.addEventListener(\"message\",c,!1);var l=!1;o.onCleanup=function(){!l&&e.removeEventListener&&(e.removeEventListener(\"message\",c,!1),l=!0)}}}}(window,document);"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/common/include.html",
    "content": "<!-- 公共head -->\n<head th:fragment=\"header(title)\">\n    <meta charset=\"utf-8\">\n    <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\">\n    <meta content=\"IE=edge\" http-equiv=\"X-UA-Compatible\">\n    <meta content=\"\" name=\"keywords\">\n    <meta content=\"\" name=\"description\">\n    <meta content=\"Mark Otto, Jacob Thornton, and Bootstrap contributors\" name=\"author\">\n    <title th:text=\"${title}\"></title>\n    <link rel=\"stylesheet\" th:href=\"@{/css/font-awesome.min.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/static/bootstrap-5.3.0/css/bootstrap.min.css}\"/>\n    <link rel=\"stylesheet\" th:href=\"@{/static/css/common.css}\"/>\n    <link href=\"http://cdn.datatables.net/2.1.2/css/dataTables.dataTables.min.css\" rel=\"stylesheet\"/>\n    <link href=\"https://cdn.datatables.net/2.1.2/css/dataTables.dataTables.css\" rel=\"stylesheet\"/>\n    <link href=\"https://cdn.datatables.net/buttons/3.1.0/css/buttons.dataTables.css\" rel=\"stylesheet\"/>\n    <!--    <link th:href=\"@{/webjars/bootstrap/5.3.0/css/bootstrap.min.css}\" rel=\"stylesheet\">-->\n</head>\n\n<!-- 公共JS -->\n<div th:fragment=\"commonjs\">\n    <script th:src=\"@{/webjars/jquery/3.7.1/jquery.min.js}\"></script>\n    <script th:src=\"@{/static/js/jquery.validate.min.js}\"></script>\n    <script th:src=\"@{/static/bootstrap-5.3.0/js/bootstrap.bundle.min.js}\"></script>\n    <script src=\"http://cdn.datatables.net/2.1.2/js/dataTables.min.js\"></script>\n    <script src=\"https://cdn.datatables.net/buttons/3.1.0/js/dataTables.buttons.js\"></script>\n    <script src=\"https://cdn.datatables.net/buttons/3.1.0/js/buttons.dataTables.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js\"></script>\n    <!--    <script th:src=\"@{/webjars/bootstrap/5.3.0/js/bootstrap.min.js}\"></script>-->\n</div>\n\n<!-- 公共导航 -->\n<div th:fragment=\"navbar(active, item)\">\n    <nav class=\"navbar navbar-expand-lg bg-body-tertiary fixed-top\">\n        <div class=\"container-fluid\">\n            <a class=\"navbar-brand\" href=\"/\">\n                <img alt=\"Logo\" class=\"d-inline-block align-text-top\" height=\"22\" th:src=\"@{/static/favicon.ico}\" width=\"22\">HiAuth\n            </a>\n            <button aria-controls=\"navbar\" aria-expanded=\"false\" aria-label=\"Toggle navigation\" class=\"navbar-toggler\" data-bs-target=\"#navbar\" data-bs-toggle=\"collapse\" type=\"button\">\n                <span class=\"navbar-toggler-icon\"></span>\n            </button>\n            <div class=\"collapse navbar-collapse\" id=\"navbar\">\n                <ul class=\"navbar-nav me-auto mb-2 mb-lg-0\">\n\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'corpMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='corpMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"@{/corpMgr}\">租户管理</a>\n                    </li>\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'myCorpMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='myCorpMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"@{/myCorpMgr}\">我的租户</a>\n                    </li>\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'userMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='userMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"@{/userMgr}\">用户管理</a>\n                    </li>\n\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'orgMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='orgMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"${'/' + corpId + '/orgMgr'}\">组织管理</a>\n                    </li>\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'empMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='empMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"${'/' + corpId + '/empMgr'}\">员工管理</a>\n                    </li>\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'roleMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='roleMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"${'/' + corpId + '/roleMgr'}\">角色管理</a>\n                    </li>\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'corpAppClientMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='corpAppClientMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"${'/' + corpId + '/corpAppClientMgr'}\">应用管理</a>\n                    </li>\n\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'appMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='appMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"@{/appMgr}\">应用管理</a>\n                    </li>\n                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'appResourceMgr')}\">\n                        <a aria-current=\"page\" th:class=\"${active=='appResourceMgr'}? 'nav-link active' : 'nav-link'\" th:href=\"${'/' + appId + '/appResourceMgr'}\">菜单管理</a>\n                    </li>\n\n<!--                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'index')}\">-->\n<!--                        <a th:class=\"${active=='index'}? 'nav-link active' : 'nav-link'\" aria-current=\"page\" href=\"/index\">首页</a>-->\n<!--                    </li>-->\n<!--                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'appMgr')}\"><a th:class=\"${active=='appMgr'}? 'nav-link active' : 'nav-link'\" href=\"/appMgr\">应用管理</a></li>-->\n<!--                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'orgMgr')}\"><a th:class=\"${active=='orgMgr'}? 'nav-link active' : 'nav-link'\" href=\"/orgMgr\">组织管理</a></li>-->\n<!--                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'empMgr')}\"><a th:class=\"${active=='empMgr'}? 'nav-link active' : 'nav-link'\" href=\"/empMgr\">用户管理</a></li>-->\n<!--                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'roleMgr')}\"><a th:class=\"${active=='roleMgr'}? 'nav-link active' : 'nav-link'\" href=\"/roleMgr\">角色管理</a></li>-->\n<!--                    <li class=\"nav-item\" th:if=\"${#arrays.contains(item, 'appResourceMgr')}\"><a th:class=\"${active=='appResourceMgr'}? 'nav-link active' : 'nav-link'\" href=\"/appResourceMgr\">权限管理</a></li>-->\n\n\n<!--                    <li class=\"nav-item dropdown\">-->\n<!--                        <a class=\"nav-link dropdown-toggle\" href=\"#\" role=\"button\" data-bs-toggle=\"dropdown\" aria-expanded=\"false\">Dropdown</a>-->\n<!--                        <ul class=\"dropdown-menu\">-->\n<!--                            <li><a class=\"dropdown-item\" href=\"#\">Action</a></li>-->\n<!--                            <li><a class=\"dropdown-item\" href=\"#\">Another action</a></li>-->\n<!--                            <li><hr class=\"dropdown-divider\"></li>-->\n<!--                            <li><a class=\"dropdown-item\" href=\"#\">Something else here</a></li>-->\n<!--                        </ul>-->\n<!--                    </li>-->\n<!--                    <li class=\"nav-item\"><a class=\"nav-link disabled\">Disabled</a></li>-->\n                </ul>\n<!--                <form class=\"d-flex\" role=\"search\">-->\n<!--                    <input class=\"form-control me-2\" type=\"search\" placeholder=\"Search\" aria-label=\"Search\">-->\n<!--                    <button class=\"btn btn-outline-success\" type=\"submit\">Search</button>-->\n<!--                </form>-->\n                <div class=\"dropdown text-end\">\n                    <a aria-expanded=\"false\" class=\"d-block text-decoration-none dropdown-toggle\" data-bs-toggle=\"dropdown\" href=\"#\">\n                        <img alt=\"mdo\" class=\"rounded-circle\" height=\"32\" src=\"https://foruda.gitee.com/avatar/1676910173490791781/395097_bestaone_1602213346.png\" width=\"32\">\n                    </a>\n                    <ul class=\"dropdown-menu dropdown-menu-end\">\n                        <li><a class=\"dropdown-item\" href=\"/profile\">个人信息</a></li>\n                        <li><a class=\"dropdown-item\" href=\"/setting\">设置</a></li>\n                        <li><hr class=\"dropdown-divider\"></li>\n                        <li><a class=\"dropdown-item\" href=\"/logout\">退出</a></li>\n                    </ul>\n                </div>\n            </div>\n        </div>\n    </nav>\n</div>\n\n<!-- 公共footer -->\n<div th:fragment=\"footer\">\n    <footer class=\"d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top\">\n        <div class=\"col-md-4 d-flex align-items-center\">\n            <a class=\"mb-3 me-2 mb-md-0 text-muted text-decoration-none lh-1\" href=\"/\">\n                <svg class=\"bi\" height=\"24\" width=\"30\">\n                    <use xlink:href=\"#bootstrap\"/>\n                </svg>\n            </a>\n            <span class=\"mb-3 mb-md-0 text-muted\">&copy; 2025 HiAuth, Inc</span>\n        </div>\n        <ul class=\"nav col-md-4 justify-content-end list-unstyled d-flex\">\n            <li class=\"ms-3\"><a class=\"text-muted\" href=\"#\">\n                <svg class=\"bi\" height=\"24\" width=\"24\">\n                    <use xlink:href=\"#twitter\"/>\n                </svg>\n            </a></li>\n            <li class=\"ms-3\"><a class=\"text-muted\" href=\"#\">\n                <svg class=\"bi\" height=\"24\" width=\"24\">\n                    <use xlink:href=\"#instagram\"/>\n                </svg>\n            </a></li>\n            <li class=\"ms-3\"><a class=\"text-muted\" href=\"#\">\n                <svg class=\"bi\" height=\"24\" width=\"24\">\n                    <use xlink:href=\"#facebook\"/>\n                </svg>\n            </a></li>\n        </ul>\n    </footer>\n    <svg style=\"display: none;\" xmlns=\"http://www.w3.org/2000/svg\">\n        <symbol id=\"facebook\" viewBox=\"0 0 16 16\">\n            <path d=\"M16 8.049c0-4.446-3.582-8.05-8-8.05C3.58 0-.002 3.603-.002 8.05c0 4.017 2.926 7.347 6.75 7.951v-5.625h-2.03V8.05H6.75V6.275c0-2.017 1.195-3.131 3.022-3.131.876 0 1.791.157 1.791.157v1.98h-1.009c-.993 0-1.303.621-1.303 1.258v1.51h2.218l-.354 2.326H9.25V16c3.824-.604 6.75-3.934 6.75-7.951z\"/>\n        </symbol>\n        <symbol id=\"instagram\" viewBox=\"0 0 16 16\">\n            <path d=\"M8 0C5.829 0 5.556.01 4.703.048 3.85.088 3.269.222 2.76.42a3.917 3.917 0 0 0-1.417.923A3.927 3.927 0 0 0 .42 2.76C.222 3.268.087 3.85.048 4.7.01 5.555 0 5.827 0 8.001c0 2.172.01 2.444.048 3.297.04.852.174 1.433.372 1.942.205.526.478.972.923 1.417.444.445.89.719 1.416.923.51.198 1.09.333 1.942.372C5.555 15.99 5.827 16 8 16s2.444-.01 3.298-.048c.851-.04 1.434-.174 1.943-.372a3.916 3.916 0 0 0 1.416-.923c.445-.445.718-.891.923-1.417.197-.509.332-1.09.372-1.942C15.99 10.445 16 10.173 16 8s-.01-2.445-.048-3.299c-.04-.851-.175-1.433-.372-1.941a3.926 3.926 0 0 0-.923-1.417A3.911 3.911 0 0 0 13.24.42c-.51-.198-1.092-.333-1.943-.372C10.443.01 10.172 0 7.998 0h.003zm-.717 1.442h.718c2.136 0 2.389.007 3.232.046.78.035 1.204.166 1.486.275.373.145.64.319.92.599.28.28.453.546.598.92.11.281.24.705.275 1.485.039.843.047 1.096.047 3.231s-.008 2.389-.047 3.232c-.035.78-.166 1.203-.275 1.485a2.47 2.47 0 0 1-.599.919c-.28.28-.546.453-.92.598-.28.11-.704.24-1.485.276-.843.038-1.096.047-3.232.047s-2.39-.009-3.233-.047c-.78-.036-1.203-.166-1.485-.276a2.478 2.478 0 0 1-.92-.598 2.48 2.48 0 0 1-.6-.92c-.109-.281-.24-.705-.275-1.485-.038-.843-.046-1.096-.046-3.233 0-2.136.008-2.388.046-3.231.036-.78.166-1.204.276-1.486.145-.373.319-.64.599-.92.28-.28.546-.453.92-.598.282-.11.705-.24 1.485-.276.738-.034 1.024-.044 2.515-.045v.002zm4.988 1.328a.96.96 0 1 0 0 1.92.96.96 0 0 0 0-1.92zm-4.27 1.122a4.109 4.109 0 1 0 0 8.217 4.109 4.109 0 0 0 0-8.217zm0 1.441a2.667 2.667 0 1 1 0 5.334 2.667 2.667 0 0 1 0-5.334z\"/>\n        </symbol>\n        <symbol id=\"twitter\" viewBox=\"0 0 16 16\">\n            <path d=\"M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z\"/>\n        </symbol>\n    </svg>\n</div>\n\n<!-- 公共svg -->\n<div th:fragment=\"svg\">\n    <svg style=\"display: none;\" xmlns=\"http://www.w3.org/2000/svg\">\n        <symbol id=\"bootstrap\" viewBox=\"0 0 118 94\">\n            <title>Bootstrap</title>\n            <path clip-rule=\"evenodd\" d=\"M24.509 0c-6.733 0-11.715 5.893-11.492 12.284.214 6.14-.064 14.092-2.066 20.577C8.943 39.365 5.547 43.485 0 44.014v5.972c5.547.529 8.943 4.649 10.951 11.153 2.002 6.485 2.28 14.437 2.066 20.577C12.794 88.106 17.776 94 24.51 94H93.5c6.733 0 11.714-5.893 11.491-12.284-.214-6.14.064-14.092 2.066-20.577 2.009-6.504 5.396-10.624 10.943-11.153v-5.972c-5.547-.529-8.934-4.649-10.943-11.153-2.002-6.484-2.28-14.437-2.066-20.577C105.214 5.894 100.233 0 93.5 0H24.508zM80 57.863C80 66.663 73.436 72 62.543 72H44a2 2 0 01-2-2V24a2 2 0 012-2h18.437c9.083 0 15.044 4.92 15.044 12.474 0 5.302-4.01 10.049-9.119 10.88v.277C75.317 46.394 80 51.21 80 57.863zM60.521 28.34H49.948v14.934h8.905c6.884 0 10.68-2.772 10.68-7.727 0-4.643-3.264-7.207-9.012-7.207zM49.948 49.2v16.458H60.91c7.167 0 10.964-2.876 10.964-8.281 0-5.406-3.903-8.178-11.425-8.178H49.948z\" fill-rule=\"evenodd\"></path>\n        </symbol>\n        <symbol id=\"home\" viewBox=\"0 0 16 16\">\n            <path d=\"M8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4.5a.5.5 0 0 0 .5-.5v-4h2v4a.5.5 0 0 0 .5.5H14a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146zM2.5 14V7.707l5.5-5.5 5.5 5.5V14H10v-4a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v4H2.5z\"/>\n        </symbol>\n        <symbol id=\"speedometer2\" viewBox=\"0 0 16 16\">\n            <path d=\"M8 4a.5.5 0 0 1 .5.5V6a.5.5 0 0 1-1 0V4.5A.5.5 0 0 1 8 4zM3.732 5.732a.5.5 0 0 1 .707 0l.915.914a.5.5 0 1 1-.708.708l-.914-.915a.5.5 0 0 1 0-.707zM2 10a.5.5 0 0 1 .5-.5h1.586a.5.5 0 0 1 0 1H2.5A.5.5 0 0 1 2 10zm9.5 0a.5.5 0 0 1 .5-.5h1.5a.5.5 0 0 1 0 1H12a.5.5 0 0 1-.5-.5zm.754-4.246a.389.389 0 0 0-.527-.02L7.547 9.31a.91.91 0 1 0 1.302 1.258l3.434-4.297a.389.389 0 0 0-.029-.518z\"/>\n            <path d=\"M0 10a8 8 0 1 1 15.547 2.661c-.442 1.253-1.845 1.602-2.932 1.25C11.309 13.488 9.475 13 8 13c-1.474 0-3.31.488-4.615.911-1.087.352-2.49.003-2.932-1.25A7.988 7.988 0 0 1 0 10zm8-7a7 7 0 0 0-6.603 9.329c.203.575.923.876 1.68.63C4.397 12.533 6.358 12 8 12s3.604.532 4.923.96c.757.245 1.477-.056 1.68-.631A7 7 0 0 0 8 3z\" fill-rule=\"evenodd\"/>\n        </symbol>\n        <symbol id=\"table\" viewBox=\"0 0 16 16\">\n            <path d=\"M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm15 2h-4v3h4V4zm0 4h-4v3h4V8zm0 4h-4v3h3a1 1 0 0 0 1-1v-2zm-5 3v-3H6v3h4zm-5 0v-3H1v2a1 1 0 0 0 1 1h3zm-4-4h4V8H1v3zm0-4h4V4H1v3zm5-3v3h4V4H6zm4 4H6v3h4V8z\"/>\n        </symbol>\n        <symbol id=\"people-circle\" viewBox=\"0 0 16 16\">\n            <path d=\"M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z\"/>\n            <path d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z\" fill-rule=\"evenodd\"/>\n        </symbol>\n        <symbol id=\"grid\" viewBox=\"0 0 16 16\">\n            <path d=\"M1 2.5A1.5 1.5 0 0 1 2.5 1h3A1.5 1.5 0 0 1 7 2.5v3A1.5 1.5 0 0 1 5.5 7h-3A1.5 1.5 0 0 1 1 5.5v-3zM2.5 2a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zm6.5.5A1.5 1.5 0 0 1 10.5 1h3A1.5 1.5 0 0 1 15 2.5v3A1.5 1.5 0 0 1 13.5 7h-3A1.5 1.5 0 0 1 9 5.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zM1 10.5A1.5 1.5 0 0 1 2.5 9h3A1.5 1.5 0 0 1 7 10.5v3A1.5 1.5 0 0 1 5.5 15h-3A1.5 1.5 0 0 1 1 13.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zm6.5.5A1.5 1.5 0 0 1 10.5 9h3a1.5 1.5 0 0 1 1.5 1.5v3a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 13.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3z\"/>\n        </symbol>\n        <symbol id=\"check\" viewBox=\"0 0 16 16\">\n            <title>Check</title>\n            <path d=\"M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z\"/>\n        </symbol>\n        <symbol id=\"facebook\" viewBox=\"0 0 16 16\">\n            <path d=\"M16 8.049c0-4.446-3.582-8.05-8-8.05C3.58 0-.002 3.603-.002 8.05c0 4.017 2.926 7.347 6.75 7.951v-5.625h-2.03V8.05H6.75V6.275c0-2.017 1.195-3.131 3.022-3.131.876 0 1.791.157 1.791.157v1.98h-1.009c-.993 0-1.303.621-1.303 1.258v1.51h2.218l-.354 2.326H9.25V16c3.824-.604 6.75-3.934 6.75-7.951z\"/>\n        </symbol>\n        <symbol id=\"instagram\" viewBox=\"0 0 16 16\">\n            <path d=\"M8 0C5.829 0 5.556.01 4.703.048 3.85.088 3.269.222 2.76.42a3.917 3.917 0 0 0-1.417.923A3.927 3.927 0 0 0 .42 2.76C.222 3.268.087 3.85.048 4.7.01 5.555 0 5.827 0 8.001c0 2.172.01 2.444.048 3.297.04.852.174 1.433.372 1.942.205.526.478.972.923 1.417.444.445.89.719 1.416.923.51.198 1.09.333 1.942.372C5.555 15.99 5.827 16 8 16s2.444-.01 3.298-.048c.851-.04 1.434-.174 1.943-.372a3.916 3.916 0 0 0 1.416-.923c.445-.445.718-.891.923-1.417.197-.509.332-1.09.372-1.942C15.99 10.445 16 10.173 16 8s-.01-2.445-.048-3.299c-.04-.851-.175-1.433-.372-1.941a3.926 3.926 0 0 0-.923-1.417A3.911 3.911 0 0 0 13.24.42c-.51-.198-1.092-.333-1.943-.372C10.443.01 10.172 0 7.998 0h.003zm-.717 1.442h.718c2.136 0 2.389.007 3.232.046.78.035 1.204.166 1.486.275.373.145.64.319.92.599.28.28.453.546.598.92.11.281.24.705.275 1.485.039.843.047 1.096.047 3.231s-.008 2.389-.047 3.232c-.035.78-.166 1.203-.275 1.485a2.47 2.47 0 0 1-.599.919c-.28.28-.546.453-.92.598-.28.11-.704.24-1.485.276-.843.038-1.096.047-3.232.047s-2.39-.009-3.233-.047c-.78-.036-1.203-.166-1.485-.276a2.478 2.478 0 0 1-.92-.598 2.48 2.48 0 0 1-.6-.92c-.109-.281-.24-.705-.275-1.485-.038-.843-.046-1.096-.046-3.233 0-2.136.008-2.388.046-3.231.036-.78.166-1.204.276-1.486.145-.373.319-.64.599-.92.28-.28.546-.453.92-.598.282-.11.705-.24 1.485-.276.738-.034 1.024-.044 2.515-.045v.002zm4.988 1.328a.96.96 0 1 0 0 1.92.96.96 0 0 0 0-1.92zm-4.27 1.122a4.109 4.109 0 1 0 0 8.217 4.109 4.109 0 0 0 0-8.217zm0 1.441a2.667 2.667 0 1 1 0 5.334 2.667 2.667 0 0 1 0-5.334z\"/>\n        </symbol>\n        <symbol id=\"twitter\" viewBox=\"0 0 16 16\">\n            <path d=\"M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z\"/>\n        </symbol>\n    </svg>\n</div>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/consent.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\">\n    <meta content=\"IE=edge\" http-equiv=\"X-UA-Compatible\">\n    <meta content=\"\" name=\"keywords\">\n    <meta content=\"\" name=\"description\">\n    <meta content=\"Mark Otto, Jacob Thornton, and Bootstrap contributors\" name=\"author\">\n    <title>统一认证中心</title>\n    <link rel=\"stylesheet\" th:href=\"@{/static/fontawesome-5.15.4/css/all.min.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/static/bootstrap-5.3.0/css/bootstrap.min.css}\"/>\n    <link rel=\"stylesheet\" th:href=\"@{/static/css/common.css}\"/>\n    <style>\n        body {\n            background-color: aliceblue;\n        }\n    </style>\n    <script>\n        function cancelConsent() {\n            document.consent_form.reset();\n            document.consent_form.submit();\n        }\n    </script>\n</head>\n<body>\n<div class=\"container\">\n    <div class=\"py-5\"><h1 class=\"text-center text-primary\">应用授权确认</h1></div>\n    <div class=\"row\">\n        <div class=\"col text-center\">\n            <p class=\"lead\">\n                应用 <span class=\"fw-bold text-primary\" th:text=\"${clientId}\"></span>\n                请求访问您的账户\n                <span class=\"fw-bold\" th:text=\"${principalName}\"></span>\n            </p>\n        </div>\n    </div>\n\n    <div class=\"row pb-3\">\n        <div class=\"col text-center\">\n            <p class=\"lead mb-0\">以下权限需要您的授权，请仔细审阅后确认</p>\n        </div>\n    </div>\n\n    <div class=\"row justify-content-center\">\n        <div class=\"col-md-5\">\n            <form method=\"post\" name=\"consent_form\" th:action=\"@{/oauth2/authorize}\">\n                <input name=\"client_id\" th:value=\"${clientId}\" type=\"hidden\">\n                <input name=\"state\" th:value=\"${state}\" type=\"hidden\">\n                <!-- 新增权限授权区域 -->\n                <div class=\"card mb-4\">\n                    <div class=\"card-header bg-primary text-white\">请求的权限范围</div>\n                    <div class=\"card-body\">\n                        <div class=\"form-check py-2\" th:each=\"scope: ${scopes}\">\n                            <div class=\"d-flex align-items-center gap-2\">\n                                <input checked class=\"form-check-input\" name=\"scope\" th:id=\"${scope.scope}\" th:value=\"${scope.scope}\" type=\"checkbox\">\n                                <label class=\"form-check-label fw-bold m-0\" th:for=\"${scope.scope}\" th:text=\"${scope.scope}\"></label>\n                                <span class=\"text-muted\" th:text=\"${scope.description}\"></span>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n\n                <!-- 已授权权限显示区域 -->\n                <div class=\"card mb-4 border-success\" th:if=\"${not #lists.isEmpty(previouslyApprovedScopes)}\">\n                    <div class=\"card-header bg-success text-white\">已授权的权限</div>\n                    <div class=\"card-body\">\n                        <div class=\"form-check py-2\" th:each=\"scope: ${previouslyApprovedScopes}\">\n                            <input checked class=\"form-check-input\" disabled th:id=\"${scope.scope}\" type=\"checkbox\">\n                            <label class=\"form-check-label fw-bold text-success\" th:for=\"${scope.scope}\" th:text=\"${scope.scope}\"></label>\n                            <p class=\"text-success\" th:text=\"${scope.description}\"></p>\n                        </div>\n                    </div>\n                </div>\n\n                <!-- 操作按钮组 -->\n                <div class=\"d-grid gap-3\">\n                    <button id=\"submit-consent\" class=\"btn btn-primary btn-lg\" type=\"submit\">确认授权</button>\n                    <!--                    <button class=\"btn btn-outline-danger\" type=\"button\" onclick=\"cancelConsent()\">-->\n                    <!--                        <i class=\"fa fa-times-circle\"></i> 取消授权-->\n                    <!--                    </button>-->\n                </div>\n            </form>\n        </div>\n    </div>\n\n    <!-- 底部说明 -->\n    <div class=\"row pt-4\">\n        <div class=\"col text-center text-muted\">\n            <p class=\"small\">请注意：本次授权仅会在您明确同意后生效。</p>\n        </div>\n    </div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/consent_bak.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\">\n    <meta content=\"IE=edge\" http-equiv=\"X-UA-Compatible\">\n    <meta content=\"\" name=\"keywords\">\n    <meta content=\"\" name=\"description\">\n    <meta content=\"Mark Otto, Jacob Thornton, and Bootstrap contributors\" name=\"author\">\n    <title>AUTH</title>\n    <link rel=\"stylesheet\" th:href=\"@{/css/font-awesome.min.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/static/bootstrap-5.3.0/css/bootstrap.min.css}\"/>\n    <link rel=\"stylesheet\" th:href=\"@{/static/css/common.css}\"/>\n    <style>\n        body {\n            background-color: aliceblue;\n        }\n    </style>\n    <script>\n        function cancelConsent() {\n            document.consent_form.reset();\n            document.consent_form.submit();\n        }\n    </script>\n</head>\n<body>\n<div class=\"container\">\n    <div class=\"py-5\"><h1 class=\"text-center text-primary\">App permissions</h1></div>\n    <div class=\"row\">\n        <div class=\"col text-center\">\n            <p>\n                The application\n                <span class=\"font-weight-bold text-primary\" th:text=\"${clientId}\"></span>\n                wants to access your account\n                <span class=\"font-weight-bold\" th:text=\"${principalName}\"></span>\n            </p>\n        </div>\n    </div>\n    <div class=\"row pb-3\">\n        <div class=\"col text-center\"><p>The following permissions are requested by the above app.<br/>Please review these and consent if you approve.</p></div>\n    </div>\n    <div class=\"row\">\n        <div class=\"col text-center\">\n            <form method=\"post\" name=\"consent_form\" th:action=\"@{/oauth2/authorize}\">\n                <input name=\"client_id\" th:value=\"${clientId}\" type=\"hidden\">\n                <input name=\"state\" th:value=\"${state}\" type=\"hidden\">\n                <div class=\"form-group form-check py-1\" th:each=\"scope: ${scopes}\">\n                    <input name=\"scope\" th:id=\"${scope.scope}\" th:value=\"${scope.scope}\" type=\"checkbox\">\n                    <label class=\"form-check-label font-weight-bold\" th:for=\"${scope.scope}\" th:text=\"${scope.scope}\"></label>\n                    <span class=\"text-primary\" th:text=\"${scope.description}\"></span>\n                </div>\n                <p th:if=\"${not #lists.isEmpty(previouslyApprovedScopes)}\">You have already granted the following\n                    permissions to the above app:</p>\n                <div class=\"form-group form-check py-1\" th:each=\"scope: ${previouslyApprovedScopes}\">\n                    <input checked class=\"form-check-input\" disabled th:id=\"${scope.scope}\" type=\"checkbox\">\n                    <label class=\"form-check-label font-weight-bold\" th:for=\"${scope.scope}\" th:text=\"${scope.scope}\"></label>\n                    <p class=\"text-primary\" th:text=\"${scope.description}\"></p>\n                </div>\n                <div class=\"form-group pt-3\">\n                    <button class=\"btn btn-primary btn-lg\" id=\"submit-consent\" type=\"submit\">Submit Consent</button>\n                </div>\n                <div class=\"form-group\">\n                    <button class=\"btn btn-link regular\" id=\"cancel-consent\" onclick=\"cancelConsent();\" type=\"button\">Cancel</button>\n                </div>\n            </form>\n        </div>\n    </div>\n    <div class=\"row pt-4\">\n        <div class=\"col text-center\">\n            <p><small>Your consent to provide access is required.<br/>If you do not approve, click Cancel, in which case no information will be shared with the app.</small></p>\n        </div>\n    </div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/error/401.html",
    "content": "<!DOCTYPE HTML>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\"/>\n</head>\n\n<body>\n    <h1>401</h1>\n</body>\n\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/error/403.html",
    "content": "<!DOCTYPE HTML>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\"/>\n</head>\n\n<body>\n    <h1>403</h1>\n    <div>没有权限</div>\n</body>\n\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/error/404.html",
    "content": "<!DOCTYPE HTML>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\"/>\n</head>\n\n<body>\n    <h1>404</h1>\n</body>\n\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/error/500.html",
    "content": "<!DOCTYPE HTML>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\"/>\n</head>\n\n<body>\n    <h1>500</h1>\n</body>\n\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/error/unconsent.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <th:block th:insert=\"~{common/include :: header('HiAuth')}\"/>\n</head>\n<body>\n\n<div class=\"container\">\n    <h2 class=\"form-signin-heading\">Login with OAuth 2.0</h2>\n    <div class=\"alert alert-danger\" role=\"alert\">[access_denied] OAuth 2.0 Parameter: client_id</div>\n    <table class=\"table table-striped\">\n        <tbody>\n        <tr>\n            <td><a href=\"/oauth2/authorization/authorization-code\">himallxx</a></td>\n        </tr>\n        </tbody>\n    </table>\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/index.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <th:block th:insert=\"~{common/include :: header('HiAuth')}\"/>\n    <style>\n        .corp-name {\n            margin: 20px 0;\n            padding: 5px;\n            font-size: 24px;\n            border-bottom: 1px solid #ced4da;\n        }\n    </style>\n</head>\n<body>\n<div class=\"container\">\n\n    <header th:with=\"item=${#strings.arraySplit('index',',')}\">\n        <th:block th:insert=\"~{common/include :: navbar('appMgr',${item})}\"/>\n    </header>\n\n    <main>\n\n        <div class=\"corp\" th:each=\"corpApp : ${corpApps}\">\n            <div class=\"corp-name\" th:text=\"${corpApp.corpName}\"></div>\n            <div class=\"row row-cols-1 row-cols-md-3 mb-3 text-center\">\n                <div class=\"col\" th:each=\"app : ${corpApp.apps}\">\n                    <div class=\"card mb-4 rounded-3 shadow-sm\">\n                        <div class=\"card-header py-3 d-flex justify-content-between align-items-center\">\n                            <h5 class=\"my-0 fw-normal\" th:text=\"${app.appName}\"></h5>\n                        </div>\n                        <div class=\"card-body\">\n                            <ul class=\"list-unstyled mt-3 mb-4\">\n                                <li th:text=\"${app.appRemark}\"></li>\n                            </ul>\n                            <a class=\"w-100 btn btn-lg btn-outline-primary\" th:href=\"@{/openApp(cid=${app.corpId},appId=${app.appId})}\" type=\"button\">打开</a>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n    </main>\n\n    <th:block th:insert=\"~{common/include :: footer}\"/>\n\n</div>\n<th:block th:insert=\"~{common/include :: commonjs}\"/>\n<script>\n    $(function () {\n        console.log(\"xx\")\n    })\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/login.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\">\n    <meta content=\"\" name=\"description\">\n    <title id=\"titleName\"></title>\n    <script th:src=\"@{webjars/jquery/3.7.1/jquery.min.js}\"></script>\n    <script th:src=\"@{static/js/jquery.validate.min.js}\"></script>\n    <script src=\"../static/js/sliderCaptcha.js\"></script>\n    <style>\n        :root {\n            --primary-border-color: rgb(61 33 68);\n            --primary-text-color: rgb(61 33 68);\n            --primary-but-color: rgb(61 33 68);\n            --error-color: #a94442;\n        }\n\n        html, body {\n            height: 100vh;\n            width: 100%;\n            margin: 0;\n            padding: 0;\n        }\n\n        .text-center {\n            height: 100%;\n            width: 100%;\n            background: url(\"static/img/login-bg.jpg\") 100% 100% no-repeat;\n            background-size: 100% 100%;\n        }\n\n        .form-signIn {\n            float: right;\n            width: 720px;\n            height: 100%;\n            background: rgba(255, 255, 255, 0.6);\n            position: relative;\n        }\n\n        .tab-content {\n            box-sizing: border-box;\n            position: absolute;\n            left: 50%;\n            top: 45%;\n            transform: translate(-50%, -50%);\n            width: 420px;\n            height: 480px;\n            border: 1px solid var(--primary-border-color);\n            border-radius: 8px;\n            padding: 48px 30px 0 30px;\n        }\n\n        .title {\n            font-size: 28px;\n            font-weight: bold;\n            line-height: 32px;\n            text-align: center;\n            color: var(--primary-text-color);\n            margin-bottom: 40px;\n            margin-top: 0;\n        }\n\n        form {\n            width: 360px;\n        }\n\n        .input-group {\n            box-sizing: border-box;\n            height: 40px;\n            border: 1px solid var(--primary-border-color);\n            border-radius: 2px;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n        }\n\n        .input-group input {\n            height: 100%;\n            background: transparent;\n            border: none;\n            width: calc(100% - 40px);\n            box-sizing: border-box;\n            color: var(--primary-text-color);\n        }\n\n        .input-group input:focus-visible {\n            outline: none;\n        }\n\n        .input-group input::placeholder {\n            color: var(--primary-text-color);\n            font-size: 14px;\n        }\n\n        .focus-group {\n            border: 1px solid var(--primary-border-color) !important;\n        }\n\n        .fill-value-group {\n            border: 1px solid var(--primary-border-color);\n        }\n\n        .input-group-icon {\n            display: inline-block;\n            width: 16px;\n            height: 16px;\n            margin: 0 12px;\n        }\n\n        .btn-login {\n            margin-top: 16px;\n            height: 40px;\n            width: 100%;\n            background: var(--primary-but-color);\n            border: none;\n            font-size: 16px;\n            color: #fff;\n            border-radius: 2px;\n            text-align: center;\n            font-weight: 700;\n            letter-spacing: 4px;\n        }\n\n        .btn-login:disabled {\n            background-color: rgb(61 33 68 / 70%);\n            cursor: not-allowed;\n\n            &:hover {\n                opacity: 1;\n            }\n        }\n\n        .logo {\n            height: 50px;\n            position: absolute;\n            top: 37px;\n            left: 37px;\n            display: flex;\n            align-items: center;\n        }\n\n        .input-invalid {\n            height: 24px;\n            font-size: 10px;\n            color: var(--error-color);\n            margin-top: 2px;\n        }\n\n        input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {\n            -webkit-text-fill-color: #D0E1EF !important;\n            -webkit-box-shadow: 0 0 0 5.20833rem transparent inset !important;\n            background-color: transparent !important;\n            -webkit-transition: background-color 50000s ease-in-out 0s;\n            transition: background-color 50000s ease-in-out 0s\n        }\n\n        .showPassword {\n            display: none;\n        }\n\n        .slider-captcha {\n            width: 100%;\n            display: flex;\n            font-size: 14px;\n            color: var(--text-black-color);\n            overflow: hidden;\n        }\n\n        .slider-track {\n            width: 0;\n            z-index: 1;\n            background-color: #ddd;\n        }\n\n        .slider-captcha.success {\n            background-color: var(--input-bgcolor) !important;\n        }\n\n        .slider-thumb {\n            width: 46px;\n            height: 38px;\n            left: 0;\n            cursor: move;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            transition: left 0.3s;\n            z-index: 2;\n            background-color: var(--primary-but-color);\n        }\n\n        .slider-thumb.success {\n            color: rgba(70, 182, 91, 1);\n        }\n\n        .slider-title {\n            position: absolute;\n            line-height: 38px;\n            left: 0;\n            width: 100%;\n            text-align: center;\n            z-index: 1;\n            transition: opacity 0.3s;\n            color: rgb(61, 33, 68, 0.8);\n        }\n\n        .slider-title.success {\n            z-index: 1;\n            background-color: transparent;\n            color: rgba(70, 182, 91);\n        }\n    </style>\n</head>\n<body class=\"text-center\">\n<div class=\"logo\"></div>\n<div class=\"form-signIn\">\n    <div class=\"tab-content\">\n        <p class=\"title\" th:text=\"${title}\">用户登录</p>\n        <form id=\"accountForm\" method=\"post\" th:action=\"@{account/doLogin}\">\n            <input name=\"_csrf\" th:value=\"${_csrf.token}\" type=\"hidden\">\n            <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n            <input id=\"formToken\" name=\"formToken\" th:value=\"${formToken}\" type=\"hidden\">\n            <input name=\"loginType\" th:value=\"pwd\" type=\"hidden\">\n            <div class=\"form-item input-group\">\n                <span class=\"input-group-icon\"><img alt=\"\" th:src=\"@{static/img/yhm_fill.png}\"></span>\n                <input aria-label=\"Account\" class=\"login-input form-control\" id=\"username\" name=\"username\" th:placeholder=\"${usernamePlaceholder}\" th:value=\"${username}\" type=\"text\">\n            </div>\n            <div class=\"input-invalid\">\n                <label class=\"error\" for=\"username\" id=\"username-error\" style=\"display: none\"><i aria-hidden=\"true\" class=\"fa fa-exclamation-triangle\"></i>请输入账号</label>\n            </div>\n            <div class=\"form-item input-group\">\n                <span class=\"input-group-icon\"><img alt=\"\" th:src=\"@{static/img/sd_fill.png}\"></span>\n                <input aria-label=\"Password\" class=\"login-input form-control\" id=\"password\" name=\"password\" th:placeholder=\"${passwordPlaceholder}\" th:value=\"${password}\" type=\"password\">\n                <span class=\"input-group-icon\">\n                    <img alt=\"\" class=\"hiddenPassword\" th:src=\"@{static/img/gbck_fill.png}\">\n                    <img alt=\"\" class=\"showPassword\" th:src=\"@{static/img/ck_line.png}\">\n                </span>\n            </div>\n            <div class=\"input-invalid\">\n                <label class=\"error\" for=\"password\" id=\"password-error\" style=\"display: none\"><i aria-hidden=\"true\" class=\"fa fa-exclamation-triangle\"></i>请输入密码</label>\n            </div>\n            <div class=\"form-item input-group\">\n                <div class=\"slider-captcha\" id=\"slider-captcha-account\">\n                    <div class=\"slider-track\"></div>\n                    <div class=\"slider-thumb\"><img alt=\"\" class=\"slider-thumb-icon\" src=\"../static/img/chevron-right.png\"></div>\n                    <div class=\"slider-title\">按住滑块，拖动到最右边</div>\n                    <input name=\"captcha\" type=\"hidden\">\n                </div>\n            </div>\n            <div class=\"input-invalid\" style=\"text-align: center;\">\n                <label th:if=\"${param.error}\" th:text=\"${session.SPRING_SECURITY_LAST_EXCEPTION} ? ${session.SPRING_SECURITY_LAST_EXCEPTION.message}\"></label>\n            </div>\n            <button class=\"submit btn-login\" disabled type=\"submit\">登录</button>\n        </form>\n    </div>\n</div>\n\n<script>\n    document.getElementById(\"titleName\").innerHTML = '统一授权平台'\n    const inputs = document.querySelectorAll('.login-input');\n    inputs.forEach(function (input) {\n        let parentElement = input.parentNode\n        let classList = parentElement.classList\n        if (input.value) {\n            parentElement.classList.add('fill-value-group');\n        }\n        input.addEventListener('focus', function () {\n            parentElement.classList.add('focus-group');\n        });\n        input.addEventListener('blur', function () {\n            classList.remove('focus-group');\n            if (input.value) {\n                classList.add('fill-value-group');\n            } else {\n                // classList.remove('fill-value-group');\n            }\n        });\n    });\n\n    $(function () {\n        const contentPath = \"\";\n        const imgUrl = contentPath + \"auth/code/image\";\n        const $accountForm = $('#accountForm');\n        // 提示图标\n        const errorIcon = '<i aria-hidden=\"true\" class=\"fa fa-exclamation-triangle\"></i>';\n        $accountForm.validate({\n            debug: false,\n            errorPlacement: function (error, element) {},\n            rules: {\n                username: {\n                    required: true,\n                    rangelength: [3, 10]\n                },\n                password: {\n                    required: true,\n                    rangelength: [3, 10]\n                },\n                captcha: {\n                    required: true,\n                    rangelength: [4, 6]\n                }\n            },\n            messages: {\n                username: {\n                    required: errorIcon + \"请输入账号\",\n                    rangelength: errorIcon + \"账号长度为{0}-{1}个字符\"\n                },\n                password: {\n                    required: errorIcon + \"请输入密码\",\n                    rangelength: errorIcon + \"密码长度为{0}-{1}个字符\"\n                },\n                captcha: {\n                    required: errorIcon + \"请输入图形验证码\",\n                    rangelength: errorIcon + \"图形验证码长度为{0}-{1}个字符\"\n                }\n            },\n            // 使用div标签，包裹提示信息，而后插入DOM\n            wrapper: \"div\",\n            showErrors: function (errorMap, errorList) {\n                this.defaultShowErrors();\n            },\n            success: function (label) {}\n        });\n\n        //获取图形验证码\n        function getCaptcha(formToken) {\n            const $this = $(\".captcha-img\");\n            const url = imgUrl + \"?formToken=\" + formToken + \"&r=\" + Math.random();\n            $this.attr('src', url);\n        }\n\n        //点击更新图形验证码\n        $('.captcha-img').click(function () {\n            const formToken = $(\"#formToken\").val();\n            getCaptcha(formToken);\n        });\n        getCaptcha($(\"#formToken\").val());\n\n        //点击切换密码显示\n        $('.hiddenPassword').click(function () {\n            let password = document.getElementById('password');\n            password.setAttribute('type', 'text');\n            $('.hiddenPassword').hide()\n            $('.showPassword').show()\n        });\n\n        //点击切换密码显示\n        $('.showPassword').click(function () {\n            let password = document.getElementById('password');\n            password.setAttribute('type', 'password');\n            $('.showPassword').hide()\n            $('.hiddenPassword').show()\n        });\n\n        // 构建滑动验证码\n        $('#slider-captcha-account').sliderCaptcha({\n            token: $('#formToken').val(),\n            successCallback: function (data) {\n                $('#accountForm > .btn-login').removeAttr('disabled');\n                console.log('滑块验证成功');\n            },\n            errorCallback: function () {\n                console.log('滑块验证失败');\n            }\n        });\n\n    });\n\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/login1.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\">\n    <meta content=\"\" name=\"description\">\n    <title id=\"titleName\"></title>\n    <script src=\"../static/js/jquery.min.js\"></script>\n    <script src=\"../static/js/jquery.validate.min.js\"></script>\n    <script src=\"../static/js/wxLogin.js\"></script>\n    <script src=\"../static/js/sliderCaptcha.js\"></script>\n    <link href=\"../static/fontawesome-5.15.4/css/all.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/css/login1.css\" rel=\"stylesheet\">\n</head>\n\n<body>\n<!-- 登录失败提示 -->\n<div class=\"error-alert\" onclick=\"this.style.display='none'\" th:if=\"${param.error}\">\n    <span th:text=\"${session.SPRING_SECURITY_LAST_EXCEPTION} ? ${session.SPRING_SECURITY_LAST_EXCEPTION.message}\"></span>\n    <svg class=\"close-icon\" viewBox=\"0 0 24 24\">\n        <path d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\" fill=\"currentColor\"/>\n    </svg>\n</div>\n<div class=\"login-page-container\">\n    <div class=\"lft-container\">\n        <img alt=\"\" class=\"gb\" src=\"../static/img/login3-bg.png\">\n        <img alt=\"\" class=\"logo\" src=\"../static/img/lhkj-logo_1.png\">\n        <!--<p>汇聚海量用户，提供专业服务</p>-->\n    </div>\n    <div class=\"rgt-container dark-box\" id=\"right-box\">\n        <div class=\"switch-container dark-switch\" id=\"switch\">\n            <div class=\"switch-inner light-inner\">\n                <div class=\"inner-box\">\n                    <div class=\"switch-item\" onclick=\"handleSwitch(1)\"><img alt=\"\" src=\"../static/img/light_sun.png\"></div>\n                    <div class=\"switch-item\" onclick=\"handleSwitch(2)\"><img alt=\"\" src=\"../static/img/light_moon.png\"></div>\n                </div>\n            </div>\n            <div class=\"switch-inner dark-inner\">\n                <div class=\"inner-box\">\n                    <div class=\"switch-item\" onclick=\"handleSwitch(1)\"><img alt=\"\" src=\"../static/img/dark_sun.png\"></div>\n                    <div class=\"switch-item\" onclick=\"handleSwitch(2)\"><img alt=\"\" src=\"../static/img/dark_moon.png\"></div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"login-container\">\n            <div class=\"login-title\" th:with=\"isEmpty=${#strings.isEmpty(appName)}\">\n                <span th:if=\"${!isEmpty}\" th:text=\"${appName}\"></span>\n                <span th:if=\"${isEmpty}\">认证中心</span>\n            </div>\n            <div class=\"tabs\">\n                <div class=\"tab\" id=\"phone\" onclick=\"switchTab('phone')\" th:if=\"${loginTypes.contains('phone')}\">验证码登录</div>\n                <div class=\"tab\" id=\"account\" onclick=\"switchTab('account')\" th:if=\"${loginTypes.contains('account')}\">账户登录</div>\n                <div class=\"tab\" id=\"wechat\" onclick=\"switchTab('wechat')\" th:if=\"${loginTypes.contains('wechat')}\">扫码登录</div>\n            </div>\n            <!-- 账户登录表单 -->\n            <form class=\"form\" id=\"accountForm\" method=\"post\" style=\"display: none;\" th:action=\"@{account/doLogin}\">\n                <input name=\"_csrf\" th:value=\"${_csrf.token}\" type=\"hidden\">\n                <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n                <input id=\"formToken\" name=\"formToken\" th:value=\"${formToken}\" type=\"hidden\">\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <input class=\"input\" name=\"username\" placeholder=\"请输入您的账号\" type=\"text\">\n                    </div>\n                </div>\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <div class=\"slider-captcha\" id=\"slider-captcha-account\">\n                            <div class=\"slider-track\"></div>\n                            <div class=\"slider-thumb\"><img alt=\"\" class=\"slider-thumb-icon\" src=\"../static/img/chevron-right.png\"></div>\n                            <div class=\"slider-title\">按住滑块，拖动到最右边</div>\n                            <input name=\"captcha\" type=\"hidden\">\n                        </div>\n                    </div>\n                </div>\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <input class=\"input password\" id=\"passwordInput\" name=\"password\" placeholder=\"请输入密码\" style=\"padding-right: 34px;\" type=\"password\">\n                        <!-- 新增右侧眼睛图标 -->\n                        <svg class=\"icon input-icon\" height=\"32\" id=\"eyeIcon\" onclick=\"togglePasswordVisibility()\" style=\"right:10px; left:auto; cursor:pointer;\" viewBox=\"0 0 1024 1024\" width=\"32\">\n                            <path d=\"M97.834667 97.834667a42.666667 42.666667 0 0 1 60.373333 0l155.221333 155.264c2.517333 1.962667 4.778667 4.266667 6.826667 6.826666l443.349333 443.306667c2.901333 2.261333 5.546667 4.864 7.850667 7.893333l154.752 154.709334a42.666667 42.666667 0 0 1-60.373333 60.330666l-134.528-134.570666C669.653333 827.733333 596.138667 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.661333 14.848-32.597333l1.066667-1.621334c25.685333-40.661333 77.866667-114.176 154.453333-176.682666L97.834667 158.165333a42.666667 42.666667 0 0 1 0-60.330666z m184.533333 244.906666C212.48 397.866667 163.584 465.92 139.392 504.234667a388.565333 388.565333 0 0 0-4.693333 7.68V512a409.941333 409.941333 0 0 0 4.693333 7.594667c22.656 36.010667 67.626667 98.986667 131.925333 152.661333C335.488 725.845333 416.298667 768 512 768c57.728 0 109.994667-15.317333 156.458667-39.210667l-69.76-69.76a170.666667 170.666667 0 0 1-233.728-233.728L282.368 342.698667z m147.2 147.157334a85.333333 85.333333 0 0 0 104.533333 104.533333l-104.533333-104.533333zM512 256c-16.256 0-32.085333 1.194667-47.36 3.498667a42.666667 42.666667 0 0 1-12.501333-84.437334A409.045333 409.045333 0 0 1 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512 2.645333 11.605333 2.645333 26.538667 0 38.144-3.285333 14.378667-9.813333 24.661333-14.890667 32.597333l-1.024 1.664a788.778667 788.778667 0 0 1-61.525333 84.138667 42.666667 42.666667 0 1 1-65.408-54.784 704.853333 704.853333 0 0 0 59.52-82.645333V512v-0.042667a62.336 62.336 0 0 0-1.28-2.090666l-3.413334-5.546667c-22.698667-35.968-67.712-98.986667-131.968-152.618667C688.554667 298.154667 607.744 256 512 256z\" fill=\"currentColor\"></path>\n                        </svg>\n                    </div>\n                </div>\n                <button class=\"submit-btn\" disabled type=\"submit\">立即登录</button>\n            </form>\n            <!-- 手机登录表单 -->\n            <form class=\"form\" id=\"phoneForm\" method=\"post\" th:action=\"@{phone/doLogin}\">\n                <input name=\"_csrf\" th:value=\"${_csrf.token}\" type=\"hidden\">\n                <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n                <input name=\"formToken\" th:value=\"${formToken}\" type=\"hidden\">\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <input autocomplete=\"on\" class=\"input\" name=\"phone\" oninput=\"this.value = this.value.replace(/\\D/g,'')\" placeholder=\"请输入您的手机号码\" type=\"tel\">\n                    </div>\n                    <div class=\"error-message\">请输入有效的手机号码</div>\n                </div>\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <div class=\"slider-captcha\" id=\"slider-captcha-phone\">\n                            <div class=\"slider-track\"></div>\n                            <div class=\"slider-thumb\"><img alt=\"\" class=\"slider-thumb-icon\" src=\"../static/img/chevron-right.png\"></div>\n                            <div class=\"slider-title\">按住滑块，拖动到最右边</div>\n                            <input name=\"captcha\" type=\"hidden\">\n                        </div>\n                    </div>\n                </div>\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper sms-code-row\">\n                        <div class=\"input-sub-wrapper\">\n                            <input class=\"input\" name=\"smsCode\" placeholder=\"请输入验证码\" style=\"flex:1\" type=\"text\">\n                        </div>\n                        <button class=\"get-code-btn\" disabled id=\"smsCodeBtn\" type=\"button\">获取验证码</button>\n                    </div>\n                </div>\n                <button class=\"submit-btn\" disabled type=\"submit\">立即登录</button>\n            </form>\n            <!-- 手机登录表单 -->\n            <form class=\"form\" id=\"wechatForm\" method=\"post\" style=\"width: 330px\" th:action=\"@{wechat/qrcode/doLogin}\">\n                <div id=\"wechat_qrcode\"></div>\n                <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n            </form>\n        </div>\n        <p class=\"record-text\">登录即表示您同意HiAuth的&nbsp;<span>用户协议</span>&nbsp;和&nbsp;<span>隐私协议</span></p>\n    </div>\n</div>\n</body>\n<script>\n    // 新增初始化登录方式\n    document.addEventListener('DOMContentLoaded', function () {\n        // 新增URL参数清除逻辑\n        const url = new URL(window.location.href);\n        if (url.searchParams.has('error')) {\n            url.searchParams.delete('error');\n            window.history.replaceState({}, '', url);\n        }\n        const lastLoginType = localStorage.getItem('hiauth_last_loginType') || 'phone';\n        const screenModel = localStorage.getItem('hiauth_screen_model') || 1;\n        switchTab(lastLoginType);\n        handleSwitch(screenModel)\n    });\n\n    function handleSwitch(type) {\n        if (type == 1) {\n            //切换白色模式\n            $('#switch').attr('class', 'switch-container light-switch')\n            $('#right-box').attr('class', 'rgt-container light-box')\n            $('.slider-thumb-icon').attr('src', '../static/img/chevron-right-light.png');\n        }\n        if (type == 2) {\n            //切换黑色模式\n            $('#switch').attr('class', 'switch-container dark-switch')\n            $('#right-box').attr('class', 'rgt-container dark-box')\n            $('.slider-thumb-icon').attr('src', '../static/img/chevron-right.png');\n        }\n        localStorage.setItem('hiauth_screen_model', type);\n    }\n\n    // 切换登录方式\n    function switchTab(type) {\n        document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));\n        document.querySelectorAll('.form').forEach(form => form.style.display = 'none');\n        let tab = document.querySelector(`.tab#` + type);\n        if (tab == null) {\n            tab = document.querySelector('.tabs > .tab:first-child');\n        }\n        tab.classList.add('active');\n        type = tab.id;\n        document.getElementById(type + 'Form').style.display = 'block';\n        localStorage.setItem('hiauth_last_loginType', type);\n    }\n\n    // 切换密码可见性\n    function togglePasswordVisibility() {\n        const passwordField = document.getElementById('passwordInput');\n        const eyeIcon = document.getElementById('eyeIcon');\n        const isPassword = passwordField.type === 'password';\n        // 切换输入框类型\n        passwordField.type = isPassword ? 'text' : 'password';\n        // 切换图标路径\n        if (isPassword) {\n            // 睁眼图标（明文状态）\n            eyeIcon.innerHTML = '<path fill=\"currentColor\" d=\"M341.333333 512a170.666667 170.666667 0 1 1 341.333334 0 170.666667 170.666667 0 0 1-341.333334 0z m170.666667-85.333333a85.333333 85.333333 0 1 0 0 170.666666 85.333333 85.333333 0 0 0 0-170.666666z\"></path><path fill=\"currentColor\" d=\"M216.618667 286.165333C290.389333 224.64 389.973333 170.666667 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512a92.16 92.16 0 0 1 0 38.144c-3.285333 14.378667-9.813333 24.618667-14.848 32.512l-1.024 1.621333c-25.301333 40.064-75.776 111.146667-149.418667 172.629334C733.653333 799.36 634.112 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.618667 14.848-32.512l1.024-1.621333c25.258667-40.064 75.776-111.146667 149.418667-172.629334zM271.36 351.701333C207.018667 405.333333 162.090667 468.352 139.349333 504.32a409.173333 409.173333 0 0 0-4.693333 7.594667V512l1.237333 2.090667 3.413334 5.546666c22.741333 35.968 67.712 98.986667 132.010666 152.618667C335.488 725.845333 416.298667 768 512 768c95.744 0 176.554667-42.154667 240.725333-95.701333 64.256-53.632 109.226667-116.650667 131.968-152.661334a445.610667 445.610667 0 0 0 4.693334-7.594666V512a445.610667 445.610667 0 0 0-4.693334-7.594667c-22.741333-36.010667-67.712-98.986667-131.968-152.661333C688.554667 298.154667 607.744 256 512 256c-95.701333 0-176.512 42.154667-240.682667 95.701333z\"></path>';\n        } else {\n            // 闭眼图标（密文状态）\n            eyeIcon.innerHTML = '<path fill=\"currentColor\" d=\"M97.834667 97.834667a42.666667 42.666667 0 0 1 60.373333 0l155.221333 155.264c2.517333 1.962667 4.778667 4.266667 6.826667 6.826666l443.349333 443.306667c2.901333 2.261333 5.546667 4.864 7.850667 7.893333l154.752 154.709334a42.666667 42.666667 0 0 1-60.373333 60.330666l-134.528-134.570666C669.653333 827.733333 596.138667 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.661333 14.848-32.597333l1.066667-1.621334c25.685333-40.661333 77.866667-114.176 154.453333-176.682666L97.834667 158.165333a42.666667 42.666667 0 0 1 0-60.330666z m184.533333 244.906666C212.48 397.866667 163.584 465.92 139.392 504.234667a388.565333 388.565333 0 0 0-4.693333 7.68V512a409.941333 409.941333 0 0 0 4.693333 7.594667c22.656 36.010667 67.626667 98.986667 131.925333 152.661333C335.488 725.845333 416.298667 768 512 768c57.728 0 109.994667-15.317333 156.458667-39.210667l-69.76-69.76a170.666667 170.666667 0 0 1-233.728-233.728L282.368 342.698667z m147.2 147.157334a85.333333 85.333333 0 0 0 104.533333 104.533333l-104.533333-104.533333zM512 256c-16.256 0-32.085333 1.194667-47.36 3.498667a42.666667 42.666667 0 0 1-12.501333-84.437334A409.045333 409.045333 0 0 1 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512 2.645333 11.605333 2.645333 26.538667 0 38.144-3.285333 14.378667-9.813333 24.661333-14.890667 32.597333l-1.024 1.664a788.778667 788.778667 0 0 1-61.525333 84.138667 42.666667 42.666667 0 1 1-65.408-54.784 704.853333 704.853333 0 0 0 59.52-82.645333V512v-0.042667a62.336 62.336 0 0 0-1.28-2.090666l-3.413334-5.546667c-22.698667-35.968-67.712-98.986667-131.968-152.618667C688.554667 298.154667 607.744 256 512 256z\"/>';\n        }\n    }\n\n    const errorIcon = '<i aria-hidden=\"true\" class=\"fa fa-exclamation-circle\"></i>';\n\n    // 初始化账号登录表单验证\n    $(\"#accountForm\").validate({\n        rules: {\n            username: {\n                required: true,\n                minlength: 3,\n                maxlength: 20\n            },\n            password: {\n                required: true,\n                minlength: 5,\n                maxlength: 20\n            },\n            captcha: {\n                required: true,\n                minlength: 4,\n                maxlength: 4\n            }\n        },\n        messages: {\n            username: {\n                required: errorIcon + \" 用户名不能为空\",\n                minlength: errorIcon + \" 用户名至少3个字符\",\n                maxlength: errorIcon + \" 用户名不能超过20个字符\"\n            },\n            password: {\n                required: errorIcon + \" 密码不能为空\",\n                minlength: errorIcon + \" 密码至少5个字符\",\n                maxlength: errorIcon + \" 密码不能超过20个字符\"\n            },\n            captcha: {\n                required: errorIcon + \" 图形验证码不能为空\",\n                minlength: errorIcon + \" 图形验证为4个字符\",\n                maxlength: errorIcon + \" 图形验证为4个字符\"\n            }\n        },\n        errorPlacement: function (error, element) {\n            error.appendTo(element.closest('.input-wrapper').parent());\n        },\n        submitHandler: function (form) {\n            // 存储登录信息\n            const username = form.querySelector('#accountForm input[name=\"username\"]').value;\n            localStorage.setItem('hiauth_last_loginType', \"account\");\n            localStorage.setItem('hiauth_last_username', username);\n            form.submit();\n        }\n    });\n\n    // 添加自定义验证方法\n    $.validator.addMethod(\"chineseMobile\", function (value, element) {\n        return this.optional(element) || /^1[3-9]\\d{9}$/.test(value);\n    }, errorIcon + \" 请输入正确的11位手机号码\");\n\n    // 初始化手机号登录表单验证\n    $(\"#phoneForm\").validate({\n        rules: {\n            phone: {\n                required: true,\n                minlength: 11,\n                maxlength: 11,\n                chineseMobile: true\n            },\n            captcha: {\n                required: true,\n                minlength: 4,\n                maxlength: 4\n            },\n            smsCode: {\n                required: true,\n                minlength: 6,\n                maxlength: 6\n            }\n        },\n        messages: {\n            phone: {\n                required: errorIcon + \" 手机号不能为空\",\n                minlength: errorIcon + \" 请输入正确的11位手机号码\",\n                maxlength: errorIcon + \" 请输入正确的11位手机号码\"\n            },\n            captcha: {\n                required: errorIcon + \" 图形验证码不能为空\",\n                minlength: errorIcon + \" 验证码必须为4位\",\n                maxlength: errorIcon + \" 验证码必须为4位\"\n            },\n            smsCode: {\n                required: errorIcon + \" 短信验证码不能为空\",\n                minlength: errorIcon + \" 验证码必须为6位\",\n                maxlength: errorIcon + \" 验证码必须为6位\"\n            }\n        },\n        errorPlacement: function (error, element) {\n            error.appendTo(element.closest('.input-wrapper').parent());\n        },\n        submitHandler: function (form) {\n            // 存储登录信息\n            const phone = form.querySelector('#phoneForm input[name=\"phone\"]').value;\n            localStorage.setItem('hiauth_last_loginType', \"phone\");\n            localStorage.setItem('hiauth_last_phone', phone);\n            form.submit();\n        }\n    });\n\n    // 短信验证码倒计时功能\n    let countdown = 60;\n    let timer = null;\n\n    function startCountdown() {\n        const btn = $(\"#smsCodeBtn\");\n        btn.prop(\"disabled\", true).text(`${countdown}秒后重发`);\n        timer = setInterval(() => {\n            countdown--;\n            if (countdown <= 0) {\n                clearInterval(timer);\n                btn.prop(\"disabled\", false).text(\"获取验证码\");\n                countdown = 60;\n                return;\n            }\n            btn.text(`${countdown}秒后重发`);\n        }, 1000);\n    }\n\n    // 绑定获取验证码按钮点击事件\n    $(\"#smsCodeBtn\").click(function () {\n\n        const phoneEl = $(\"#phoneForm input[name='phone']\");\n        const imgCodeEl = $(\"#phoneForm input[name='captcha']\");\n        const formTokenEl = $(\"#phoneForm input[name='formToken']\");\n\n        const phoneIsValid = phoneEl.valid();\n        const imgCodeIsValid = imgCodeEl.valid();\n        if (!phoneIsValid || !imgCodeIsValid) {\n            return;\n        }\n\n        const phone = phoneEl.val();\n        const imgCode = imgCodeEl.val();\n        const formToken = formTokenEl.val();\n\n        $(this).prop(\"disabled\", true)\n\n        // 发送短信验证码请求\n        $.ajax({\n            url: \"auth/code/sms?telNo=\" + phone + \"&formToken=\" + formToken + \"&imgCode=\" + imgCode + \"&r=\" + Math.random(),\n            type: \"GET\",\n            success: function (data) {\n                $(\".error-alert\").remove();\n                if (data.code !== 10000) {\n                    let message = data.message;\n                    if(data.code===20102){\n                        message = \"验证码已失效，请重试！\";\n                    } else if(data.code===20103){\n                        message = \"手机号未注册！\";\n                    }\n                    $(\"body\").prepend(`\n                            <div class=\"error-alert\" onclick=\"this.remove()\">\n                                ${message}\n                                <svg viewBox=\"0 0 24 24\" class=\"close-icon\">\n                                    <path fill=\"currentColor\" d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\"/>\n                                </svg>\n                            </div>\n                        `);\n                    $('#slider-captcha-phone').sliderCaptcha('reset');\n                } else {\n                    startCountdown();\n                }\n            }\n        });\n    });\n\n    // 在页面加载时读取存储的登录信息\n    document.addEventListener('DOMContentLoaded', function () {\n        const lastUsername = localStorage.getItem('hiauth_last_username');\n        if (lastUsername) {\n            document.querySelector(`#accountForm input[name=\"username\"]`).value = lastUsername;\n        }\n        const lastPhone = localStorage.getItem('hiauth_last_phone');\n        if (lastPhone) {\n            document.querySelector(`#phoneForm input[name=\"phone\"]`).value = lastPhone;\n        }\n    });\n\n    // 微信登录二维码\n    new WxLogin({\n        id: \"wechat_qrcode\",\n        appid: \"[[${wechatAppid}]]\",\n        scope: \"snsapi_login\",\n        redirect_uri: encodeURI(\"[[${wechatRedirectUri}]]\"),\n        state: \"[[${wechaState}]]\",\n        style: \"[[${wechatStyle}]]\",\n        href: \"[[${wechatHref}]]\"\n    });\n\n    $('#slider-captcha-phone').sliderCaptcha({\n        token: $('#formToken').val(),\n        successCallback: function (data) {\n            $('#phoneForm > .submit-btn').removeAttr('disabled');\n            $('#smsCodeBtn').removeAttr('disabled');\n            console.log('滑块验证成功');\n        },\n        errorCallback: function () {\n            console.log('滑块验证失败');\n        }\n    });\n\n    $('#slider-captcha-account').sliderCaptcha({\n        token: $('#formToken').val(),\n        successCallback: function (data) {\n            $('#accountForm > .submit-btn').removeAttr('disabled');\n            console.log('滑块验证成功');\n        },\n        errorCallback: function () {\n            console.log('滑块验证失败');\n        }\n    });\n\n</script>\n\n</html>"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/login2.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\">\n    <meta content=\"\" name=\"description\">\n    <title id=\"titleName\"></title>\n    <script th:src=\"@{webjars/jquery/3.7.1/jquery.min.js}\"></script>\n    <script th:src=\"@{static/js/jquery.validate.min.js}\"></script>\n    <script th:src=\"@{static/js/wxLogin.js}\"></script>\n    <link rel=\"stylesheet\" th:href=\"@{/static/fontawesome-5.15.4/css/all.min.css}\">\n    <style>\n        :root {\n            --primary-color: #1890ff;\n            --error-color: #ff4d4f;\n            --text-color: rgba(0, 0, 0, 0.85);\n        }\n\n        body {\n            margin: 0;\n            min-height: 100vh;\n            font-family: 'Orbitron', sans-serif;\n            color: var(--text-color);\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            background-color: #1a1a2e;\n            background-image: linear-gradient(rgba(0, 209, 255, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 209, 255, 0.1) 1px, transparent 1px);\n            background-size: 20px 20px;\n        }\n\n        .login-container {\n            background: white;\n            padding: 40px;\n            border-radius: 8px;\n            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n            width: 100%;\n            max-width: 320px;\n            margin-top: -10%;\n        }\n\n        .tabs {\n            display: flex;\n            margin-bottom: 26px;\n            border-bottom: 1px solid #eee;\n        }\n\n        .tab {\n            padding: 12px 20px;\n            cursor: pointer;\n            color: var(--text-color);\n            border-bottom: 2px solid transparent;\n            transition: all 0.3s;\n        }\n\n        .tab.active {\n            color: var(--primary-color);\n            border-bottom-color: var(--primary-color);\n        }\n\n        .form-group label {\n            display: block;\n            margin-bottom: 8px;\n            color: var(--text-color);\n            font-weight: 500;\n        }\n\n        .input {\n            width: calc(100% - 42px);\n            padding: 10px 0px 10px 40px; /* 增加左侧padding */\n            border: 1px solid #d9d9d9;\n            border-radius: 4px;\n            font-size: 14px;\n            transition: border-color 0.3s;\n        }\n\n        .password {\n            width: calc(100% - 76px);\n        }\n\n        /* 新增图标容器样式 */\n        .input-wrapper {\n            position: relative;\n            margin-bottom: 4px;\n        }\n\n        .input-sub-wrapper {\n            width: 200px;\n        }\n\n        /* 修改错误提示定位方式 */\n        .form-group > .error {\n            color: #ff4d4f;\n            font-size: 10px;\n        }\n\n        /* 增加表单组最小高度 */\n        .form-group {\n            position: relative;\n            min-height: 62px; /* 保持固定高度避免跳动 */\n        }\n\n        .input-icon {\n            position: absolute;\n            left: 15px;\n            top: 50%;\n            transform: translateY(-50%);\n            color: var(--primary-color);\n            width: 16px;\n            height: 16px;\n        }\n\n        input:focus {\n            outline: none;\n            border-color: var(--primary-color);\n            box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);\n        }\n\n        .captcha-row {\n            display: flex;\n            gap: 10px;\n        }\n\n        .captcha-img {\n            border: 1px solid #d9d9d9;\n            border-radius: 4px;\n            cursor: pointer;\n            width: 110px;\n            height: 36px;\n        }\n\n        .sms-code-row {\n            display: flex;\n            gap: 10px;\n        }\n\n        .get-code-btn {\n            background: white;\n            color: var(--primary-color);\n            border: 1px solid var(--primary-color);\n            padding: 0 15px;\n            border-radius: 4px;\n            cursor: pointer;\n            transition: opacity 0.3s;\n            width: 110px;\n            height: 38px;\n        }\n\n        .get-code-btn:disabled {\n            background: #ccc;\n            cursor: not-allowed;\n        }\n\n        .submit-btn {\n            width: 100%;\n            background: var(--primary-color);\n            color: white;\n            padding: 12px;\n            margin-bottom: 10px;\n            border: none;\n            border-radius: 4px;\n            font-size: 16px;\n            cursor: pointer;\n            transition: opacity 0.3s;\n        }\n\n        .submit-btn:hover {\n            opacity: 0.9;\n        }\n\n        .error-message {\n            color: var(--error-color);\n            font-size: 12px;\n            margin-top: 2px;\n            display: none;\n            height: 20px; /* 固定错误信息高度 */\n        }\n\n        input.invalid {\n            border-color: var(--error-color);\n        }\n\n        input.invalid + .error-message {\n            display: block;\n        }\n\n        /* 新增错误提示样式 */\n        .error-alert {\n            position: fixed;\n            top: 20px;\n            background: #ff4444;\n            color: white;\n            padding: 12px 20px;\n            border-radius: 6px;\n            display: flex;\n            align-items: center;\n            gap: 10px;\n            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n            cursor: pointer;\n            transition: 0.3s all;\n            z-index: 1000;\n        }\n\n        .error-alert:hover {\n            transform: translateY(-2px);\n            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n        }\n\n        .close-icon {\n            width: 18px;\n            height: 18px;\n            opacity: 0.8;\n        }\n\n        .close-icon:hover {\n            opacity: 1;\n        }\n\n        #wechat_qrcode {\n            text-align: center;\n            height: 330px;\n        }\n    </style>\n</head>\n<body>\n<!-- 登录失败提示 -->\n<div class=\"error-alert\" onclick=\"this.style.display='none'\" th:if=\"${param.error}\">\n    <span th:text=\"${session.SPRING_SECURITY_LAST_EXCEPTION} ? ${session.SPRING_SECURITY_LAST_EXCEPTION.message}\"></span>\n    <svg class=\"close-icon\" viewBox=\"0 0 24 24\">\n        <path d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\" fill=\"currentColor\"/>\n    </svg>\n</div>\n\n<div class=\"login-container\">\n    <div class=\"tabs\">\n        <div class=\"tab phone\" onclick=\"switchTab('phone')\" th:if=\"${loginTypes.contains('phone')}\">手机登录</div>\n        <div class=\"tab account\" onclick=\"switchTab('account')\" th:if=\"${loginTypes.contains('account')}\">账户登录</div>\n        <div class=\"tab wechat\" onclick=\"switchTab('wechat')\" th:if=\"${loginTypes.contains('wechat')}\">微信登录</div>\n    </div>\n    <!-- 账户登录表单 -->\n    <form class=\"form\" id=\"accountForm\" method=\"post\" style=\"display: none;\" th:action=\"@{account/doLogin}\">\n        <input name=\"_csrf\" th:value=\"${_csrf.token}\" type=\"hidden\">\n        <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n        <input id=\"formToken1\" name=\"formToken\" th:value=\"${formToken}\" type=\"hidden\">\n        <div class=\"form-group\">\n            <div class=\"input-wrapper\">\n                <svg class=\"icon input-icon\" height=\"20\" viewBox=\"0 0 1024 1024\" width=\"20\">\n                    <path d=\"M634.784 540.544c94.976-45.888 160.864-142.912 160.864-255.328 0-156.384-127.264-283.616-283.648-283.616s-283.648 127.232-283.648 283.616c0 112.416 65.856 209.44 160.864 255.296-195.84 55.36-340.32 239.072-340.32 457.248l0 24.608 46.304 0 0-24.608c0-236.192 186.976-428.384 416.8-428.384 229.792 0 416.8 192.16 416.8 428.384l0 24.608 46.304 0 0-24.608c0-218.144-144.48-401.888-340.32-457.216zM274.656 285.248c0-130.848 106.464-237.312 237.344-237.312s237.344 106.464 237.344 237.312c0 130.88-106.464 237.344-237.344 237.344s-237.344-106.464-237.344-237.344z\" fill=\"currentColor\"></path>\n                </svg>\n                <input class=\"input\" name=\"username\" placeholder=\"用户名\" type=\"text\">\n            </div>\n        </div>\n\n        <div class=\"form-group\">\n            <div class=\"input-wrapper\">\n                <svg class=\"icon input-icon\" height=\"32\" viewBox=\"0 0 1024 1024\" width=\"32\">\n                    <path d=\"M884.224 448.512c-17.92-17.92-41.472-28.16-66.56-28.16H273.408V296.96c0-64 24.576-123.904 69.632-168.96s104.96-69.632 168.96-69.632c62.976 0 122.88 24.576 168.96 69.632 45.056 45.056 69.632 104.96 69.632 168.96 0 16.384 12.8 28.672 28.672 28.672 16.384 0 29.696-12.8 29.696-28.672 0-78.848-30.72-153.6-87.04-209.92S591.36 0 512 0C433.152 0 358.4 31.232 302.08 87.04 245.76 143.36 215.04 218.112 215.04 296.96v123.392h-8.704c-25.088 0-48.64 9.728-66.56 28.16-17.92 17.92-28.16 41.472-28.16 66.56v415.232c0 25.088 9.728 48.64 28.16 66.56 17.408 17.408 41.472 27.136 66.56 27.136h611.328c24.576 0 48.128-9.728 66.56-27.136 17.92-17.92 28.16-41.984 28.16-66.56v-415.232c0-24.576-10.24-48.64-28.16-66.56z m-713.728 66.56c0-9.216 4.096-19.456 10.24-25.6 6.656-6.656 15.872-10.24 25.6-10.24h611.328c9.216 0 17.92 3.584 25.6 10.24 6.656 6.656 10.24 16.384 10.24 25.6v415.232c0 9.216-3.584 17.92-10.24 24.576-7.68 7.168-16.896 10.752-25.6 10.752H206.336c-9.728 0-18.944-4.096-25.6-10.24-6.656-6.656-10.24-15.36-10.24-24.576v-415.744z\" fill=\"currentColor\"></path>\n                </svg>\n                <input class=\"input password\" id=\"passwordInput\" name=\"password\" placeholder=\"密码\" style=\"padding-right: 34px;\" type=\"password\">\n                <!-- 新增右侧眼睛图标 -->\n                <svg class=\"icon input-icon\" height=\"32\" id=\"eyeIcon\" onclick=\"togglePasswordVisibility()\" style=\"right:10px; left:auto; cursor:pointer;\" viewBox=\"0 0 1024 1024\" width=\"32\">\n                    <path d=\"M97.834667 97.834667a42.666667 42.666667 0 0 1 60.373333 0l155.221333 155.264c2.517333 1.962667 4.778667 4.266667 6.826667 6.826666l443.349333 443.306667c2.901333 2.261333 5.546667 4.864 7.850667 7.893333l154.752 154.709334a42.666667 42.666667 0 0 1-60.373333 60.330666l-134.528-134.570666C669.653333 827.733333 596.138667 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.661333 14.848-32.597333l1.066667-1.621334c25.685333-40.661333 77.866667-114.176 154.453333-176.682666L97.834667 158.165333a42.666667 42.666667 0 0 1 0-60.330666z m184.533333 244.906666C212.48 397.866667 163.584 465.92 139.392 504.234667a388.565333 388.565333 0 0 0-4.693333 7.68V512a409.941333 409.941333 0 0 0 4.693333 7.594667c22.656 36.010667 67.626667 98.986667 131.925333 152.661333C335.488 725.845333 416.298667 768 512 768c57.728 0 109.994667-15.317333 156.458667-39.210667l-69.76-69.76a170.666667 170.666667 0 0 1-233.728-233.728L282.368 342.698667z m147.2 147.157334a85.333333 85.333333 0 0 0 104.533333 104.533333l-104.533333-104.533333zM512 256c-16.256 0-32.085333 1.194667-47.36 3.498667a42.666667 42.666667 0 0 1-12.501333-84.437334A409.045333 409.045333 0 0 1 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512 2.645333 11.605333 2.645333 26.538667 0 38.144-3.285333 14.378667-9.813333 24.661333-14.890667 32.597333l-1.024 1.664a788.778667 788.778667 0 0 1-61.525333 84.138667 42.666667 42.666667 0 1 1-65.408-54.784 704.853333 704.853333 0 0 0 59.52-82.645333V512v-0.042667a62.336 62.336 0 0 0-1.28-2.090666l-3.413334-5.546667c-22.698667-35.968-67.712-98.986667-131.968-152.618667C688.554667 298.154667 607.744 256 512 256z\" fill=\"currentColor\"></path>\n                </svg>\n            </div>\n        </div>\n        <div class=\"form-group\">\n            <div class=\"input-wrapper captcha-row\">\n                <div class=\"input-sub-wrapper\">\n                    <svg class=\"icon input-icon\" height=\"32\" viewBox=\"0 0 1024 1024\" width=\"32\">\n                        <path d=\"M791.8 512.2c0 34.5 28 62.4 62.5 62.4s62.4-28 62.4-62.4c0-34.5-27.9-62.4-62.4-62.4-34.5-0.1-62.5 27.9-62.5 62.4z m-228.3 0c0 34.5 28 62.4 62.4 62.4 34.5 0 62.4-28 62.4-62.4 0-34.5-28-62.4-62.4-62.4-34.4-0.1-62.4 27.9-62.4 62.4z m-228.2 0c0 34.5 28 62.4 62.4 62.4 34.5 0 62.4-28 62.4-62.4 0-34.5-28-62.4-62.4-62.4-34.5-0.1-62.4 27.9-62.4 62.4z m-228.3 0c0 34.5 28 62.4 62.4 62.4 34.5 0 62.4-28 62.4-62.4 0-34.5-28-62.4-62.4-62.4-34.4-0.1-62.4 27.9-62.4 62.4z m916.4 346.9c0-0.8-0.5-2-0.5-2.8v-89.2c0-22.4-4.3-40.5-26.7-40.5s-24.2 18.2-24.2 40.5v89.2c0 0.8 0.6 1.7 0.7 2.5 0 0.8 0.2 2.2 0.2 3.1 0 10.9-28.7 50.6-39.6 50.6H93.1c-10.9 0-39.9-39.7-39.9-50.6 0-0.8-0.6-2-0.7-2.8 0.1-0.8-0.5-2-0.5-2.8v-89.2c0-22.4-1.4-40.5-23.7-40.5C5.8 726.6 1.1 744.7 1.1 767.1v89.2c0 0.8 0.6 1.7 0.7 2.5 0 0.8 0.2 2.2 0.2 3.1 0 55.6 35.4 101.4 91 101.4h840.3c55.6 0 90.7-45.8 90.7-101.4 0.1-0.8-0.5-1.9-0.6-2.8zM27.1 291.3c22.4 0 23.7-18.2 23.7-40.5v-89.2c0-10.9 30.3-50 41.1-50h840.3c10.9 0 38.7 39.2 38.7 50v89.2c0 22.4 2.4 40.5 24.8 40.5 22.4 0 26-18.2 26-40.5v-89.2c0-0.7 0.6-1.4 0.6-2.1-1.1-54.6-35.2-98.7-90.1-98.7H92C37.1 60.8 1.8 104.9 0.7 159.5c0 0.7-0.7 1.4-0.7 2.1v89.2c0 22.3 4.7 40.5 27.1 40.5z\" fill=\"currentColor\"></path>\n                    </svg>\n                    <input class=\"input\" name=\"captcha\" placeholder=\"图形验证码\" style=\"flex:1\" type=\"text\">\n                </div>\n                <img alt=\"图形验证码\" class=\"captcha-img\">\n            </div>\n        </div>\n        <button class=\"submit-btn\" type=\"submit\">立即登录</button>\n    </form>\n    <!-- 手机登录表单 -->\n    <form class=\"form\" id=\"phoneForm\" method=\"post\" th:action=\"@{phone/doLogin}\">\n        <input name=\"_csrf\" th:value=\"${_csrf.token}\" type=\"hidden\">\n        <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n        <input name=\"formToken\" th:value=\"${formToken}\" type=\"hidden\">\n        <div class=\"form-group\">\n            <div class=\"input-wrapper\">\n                <svg class=\"icon input-icon\" height=\"32\" viewBox=\"0 0 1024 1024\" width=\"32\">\n                    <path d=\"M470.34769 884.839747h81.800292c16.459815 0 29.926936-13.467121 29.926937-29.926936s-13.467121-29.926936-29.926937-29.926937h-81.800292c-16.459815 0-29.926936 13.467121-29.926936 29.926937s13.467121 29.926936 29.926936 29.926936z\" fill=\"currentColor\"></path>\n                    <path d=\"M835.210911 2.493911H188.789089c-32.91963 0-59.853872 26.934243-59.853872 59.853873v901.798344c0 32.91963 26.934243 59.853872 59.853872 59.853872h646.421822c32.91963 0 59.853872-26.934243 59.853872-59.853872v-901.798344c0-32.91963-26.934243-59.853872-59.853872-59.853873z m0 961.652217H188.789089V763.136873h646.421822v201.009255z m0-260.863128H188.789089V62.347784h646.421822V703.283z\" fill=\"currentColor\"></path>\n                </svg>\n                <input class=\"input\" name=\"phone\" oninput=\"this.value = this.value.replace(/\\D/g,'')\" placeholder=\"手机号\" type=\"tel\">\n            </div>\n            <div class=\"error-message\">请输入有效的手机号码</div>\n        </div>\n        <div class=\"form-group\">\n            <div class=\"input-wrapper captcha-row\">\n                <div class=\"input-sub-wrapper\">\n                    <svg class=\"icon input-icon\" height=\"32\" viewBox=\"0 0 1024 1024\" width=\"32\">\n                        <path d=\"M791.8 512.2c0 34.5 28 62.4 62.5 62.4s62.4-28 62.4-62.4c0-34.5-27.9-62.4-62.4-62.4-34.5-0.1-62.5 27.9-62.5 62.4z m-228.3 0c0 34.5 28 62.4 62.4 62.4 34.5 0 62.4-28 62.4-62.4 0-34.5-28-62.4-62.4-62.4-34.4-0.1-62.4 27.9-62.4 62.4z m-228.2 0c0 34.5 28 62.4 62.4 62.4 34.5 0 62.4-28 62.4-62.4 0-34.5-28-62.4-62.4-62.4-34.5-0.1-62.4 27.9-62.4 62.4z m-228.3 0c0 34.5 28 62.4 62.4 62.4 34.5 0 62.4-28 62.4-62.4 0-34.5-28-62.4-62.4-62.4-34.4-0.1-62.4 27.9-62.4 62.4z m916.4 346.9c0-0.8-0.5-2-0.5-2.8v-89.2c0-22.4-4.3-40.5-26.7-40.5s-24.2 18.2-24.2 40.5v89.2c0 0.8 0.6 1.7 0.7 2.5 0 0.8 0.2 2.2 0.2 3.1 0 10.9-28.7 50.6-39.6 50.6H93.1c-10.9 0-39.9-39.7-39.9-50.6 0-0.8-0.6-2-0.7-2.8 0.1-0.8-0.5-2-0.5-2.8v-89.2c0-22.4-1.4-40.5-23.7-40.5C5.8 726.6 1.1 744.7 1.1 767.1v89.2c0 0.8 0.6 1.7 0.7 2.5 0 0.8 0.2 2.2 0.2 3.1 0 55.6 35.4 101.4 91 101.4h840.3c55.6 0 90.7-45.8 90.7-101.4 0.1-0.8-0.5-1.9-0.6-2.8zM27.1 291.3c22.4 0 23.7-18.2 23.7-40.5v-89.2c0-10.9 30.3-50 41.1-50h840.3c10.9 0 38.7 39.2 38.7 50v89.2c0 22.4 2.4 40.5 24.8 40.5 22.4 0 26-18.2 26-40.5v-89.2c0-0.7 0.6-1.4 0.6-2.1-1.1-54.6-35.2-98.7-90.1-98.7H92C37.1 60.8 1.8 104.9 0.7 159.5c0 0.7-0.7 1.4-0.7 2.1v89.2c0 22.3 4.7 40.5 27.1 40.5z\" fill=\"currentColor\"></path>\n                    </svg>\n                    <input class=\"input\" name=\"captcha\" placeholder=\"图形验证码\" style=\"flex:1\" type=\"text\">\n                </div>\n                <img alt=\"图形验证码\" class=\"captcha-img\">\n            </div>\n        </div>\n        <div class=\"form-group\">\n            <div class=\"input-wrapper sms-code-row\">\n                <div class=\"input-sub-wrapper\">\n                    <svg class=\"icon input-icon\" height=\"32\" viewBox=\"0 0 1250 1024\" width=\"32\">\n                        <path d=\"M283.177 715.07V285.095H233.87a248.452 248.452 0 0 1-52.438 42.53 240.88 240.88 0 0 1-60.758 25.238v64.964a233.403 233.403 0 0 0 97.586-54.215v351.46h64.87z m304.256-191.152a552.053 552.053 0 0 0-95.904 78.517 165.541 165.541 0 0 0-42.063 112.636h292.852v-57.954H529.807a207.137 207.137 0 0 1 82.163-81.321 614.587 614.587 0 0 0 88.005-69.17 151.053 151.053 0 0 0 41.642-101.887 120.347 120.347 0 0 0-38.651-92.538 142.547 142.547 0 0 0-100.67-35.987A138.387 138.387 0 0 0 492.79 322.95a168.252 168.252 0 0 0-41.081 115.44h64.917a133.527 133.527 0 0 1 22.574-78.985 70.853 70.853 0 0 1 60.757-27.575 82.303 82.303 0 0 1 57.767 18.228 69.45 69.45 0 0 1 19.63 54.214 104.13 104.13 0 0 1-29.164 70.105 423.247 423.247 0 0 1-60.758 49.54z m366.742 143.949a85.107 85.107 0 0 1-60.757-21.5 89.968 89.968 0 0 1-28.042-66.833h-65.431a151.894 151.894 0 0 0 50.054 110.299 157.129 157.129 0 0 0 104.737 33.65 161.662 161.662 0 0 0 111.327-38.791 127.17 127.17 0 0 0 40.52-97.212 92.352 92.352 0 0 0-21.451-63.095 121.515 121.515 0 0 0-57.206-35.52 92.211 92.211 0 0 0 70.105-94.408 106.513 106.513 0 0 0-38.137-86.462 158.204 158.204 0 0 0-103.055-31.781A144.183 144.183 0 0 0 855.047 312.2a141.472 141.472 0 0 0-46.737 100.016h63.656a89.174 89.174 0 0 1 25.658-59.823 85.855 85.855 0 0 1 60.15-19.63 83.004 83.004 0 0 1 57.767 17.294 64.73 64.73 0 0 1 18.694 49.54 61.88 61.88 0 0 1-20.19 49.541 87.398 87.398 0 0 1-58.888 17.76H924.73v49.074h30.987a96.044 96.044 0 0 1 63.655 18.227 67.067 67.067 0 0 1 23.368 56.084 73.283 73.283 0 0 1-22.013 53.28 91.79 91.79 0 0 1-66.179 24.303zM1072.092 0H179.048A179.562 179.562 0 0 0 0.421 180.403v90.67H60.01v-90.67A119.552 119.552 0 0 1 179.048 60.29h893.044a119.552 119.552 0 0 1 118.992 120.113v90.67h59.589v-90.67A179.609 179.609 0 0 0 1072.092 0z m118.992 842.662a119.646 119.646 0 0 1-118.992 120.58H179.048A119.646 119.646 0 0 1 60.01 842.662V752.46H0.42v90.202a179.656 179.656 0 0 0 178.628 180.87h893.044a179.656 179.656 0 0 0 178.58-180.87V752.46h-59.588v90.202z\" fill=\"currentColor\"></path>\n                    </svg>\n                    <input class=\"input\" name=\"smsCode\" placeholder=\"短信验证码\" style=\"flex:1\" type=\"text\">\n                </div>\n                <button class=\"get-code-btn\" id=\"smsCodeBtn\" type=\"button\">获取验证码</button>\n            </div>\n        </div>\n        <button class=\"submit-btn\" type=\"submit\">立即登录</button>\n    </form>\n    <!-- 手机登录表单 -->\n    <form class=\"form\" id=\"wechatForm\" method=\"post\" th:action=\"@{wechat/qrcode/doLogin}\">\n        <div id=\"wechat_qrcode\"></div>\n        <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n    </form>\n</div>\n\n<script>\n    // 新增初始化登录方式\n    document.addEventListener('DOMContentLoaded', function () {\n        // 新增URL参数清除逻辑\n        const url = new URL(window.location.href);\n        if (url.searchParams.has('error')) {\n            url.searchParams.delete('error');\n            window.history.replaceState({}, '', url);\n        }\n        const lastLoginType = localStorage.getItem('hiauth_last_loginType') || 'phone';\n        switchTab(lastLoginType);\n    });\n\n    // 切换登录方式\n    function switchTab(type) {\n        document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));\n        document.querySelectorAll('.form').forEach(form => form.style.display = 'none');\n        if (type === 'phone') {\n            document.querySelector(`.tab.phone`).classList.add('active');\n        } else if (type === 'account') {\n            document.querySelector(`.tab.account`).classList.add('active');\n        } else if (type === 'wechat') {\n            document.querySelector(`.tab.wechat`).classList.add('active');\n        }\n        document.getElementById(type + 'Form').style.display = 'block';\n        localStorage.setItem('hiauth_last_loginType', type);\n    }\n\n    // 切换密码可见性\n    function togglePasswordVisibility() {\n        const passwordField = document.getElementById('passwordInput');\n        const eyeIcon = document.getElementById('eyeIcon');\n        const isPassword = passwordField.type === 'password';\n        // 切换输入框类型\n        passwordField.type = isPassword ? 'text' : 'password';\n        // 切换图标路径\n        if (isPassword) {\n            // 睁眼图标（明文状态）\n            eyeIcon.innerHTML = '<path fill=\"currentColor\" d=\"M341.333333 512a170.666667 170.666667 0 1 1 341.333334 0 170.666667 170.666667 0 0 1-341.333334 0z m170.666667-85.333333a85.333333 85.333333 0 1 0 0 170.666666 85.333333 85.333333 0 0 0 0-170.666666z\"></path><path fill=\"currentColor\" d=\"M216.618667 286.165333C290.389333 224.64 389.973333 170.666667 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512a92.16 92.16 0 0 1 0 38.144c-3.285333 14.378667-9.813333 24.618667-14.848 32.512l-1.024 1.621333c-25.301333 40.064-75.776 111.146667-149.418667 172.629334C733.653333 799.36 634.112 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.618667 14.848-32.512l1.024-1.621333c25.258667-40.064 75.776-111.146667 149.418667-172.629334zM271.36 351.701333C207.018667 405.333333 162.090667 468.352 139.349333 504.32a409.173333 409.173333 0 0 0-4.693333 7.594667V512l1.237333 2.090667 3.413334 5.546666c22.741333 35.968 67.712 98.986667 132.010666 152.618667C335.488 725.845333 416.298667 768 512 768c95.744 0 176.554667-42.154667 240.725333-95.701333 64.256-53.632 109.226667-116.650667 131.968-152.661334a445.610667 445.610667 0 0 0 4.693334-7.594666V512a445.610667 445.610667 0 0 0-4.693334-7.594667c-22.741333-36.010667-67.712-98.986667-131.968-152.661333C688.554667 298.154667 607.744 256 512 256c-95.701333 0-176.512 42.154667-240.682667 95.701333z\"></path>';\n        } else {\n            // 闭眼图标（密文状态）\n            eyeIcon.innerHTML = '<path fill=\"currentColor\" d=\"M97.834667 97.834667a42.666667 42.666667 0 0 1 60.373333 0l155.221333 155.264c2.517333 1.962667 4.778667 4.266667 6.826667 6.826666l443.349333 443.306667c2.901333 2.261333 5.546667 4.864 7.850667 7.893333l154.752 154.709334a42.666667 42.666667 0 0 1-60.373333 60.330666l-134.528-134.570666C669.653333 827.733333 596.138667 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.661333 14.848-32.597333l1.066667-1.621334c25.685333-40.661333 77.866667-114.176 154.453333-176.682666L97.834667 158.165333a42.666667 42.666667 0 0 1 0-60.330666z m184.533333 244.906666C212.48 397.866667 163.584 465.92 139.392 504.234667a388.565333 388.565333 0 0 0-4.693333 7.68V512a409.941333 409.941333 0 0 0 4.693333 7.594667c22.656 36.010667 67.626667 98.986667 131.925333 152.661333C335.488 725.845333 416.298667 768 512 768c57.728 0 109.994667-15.317333 156.458667-39.210667l-69.76-69.76a170.666667 170.666667 0 0 1-233.728-233.728L282.368 342.698667z m147.2 147.157334a85.333333 85.333333 0 0 0 104.533333 104.533333l-104.533333-104.533333zM512 256c-16.256 0-32.085333 1.194667-47.36 3.498667a42.666667 42.666667 0 0 1-12.501333-84.437334A409.045333 409.045333 0 0 1 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512 2.645333 11.605333 2.645333 26.538667 0 38.144-3.285333 14.378667-9.813333 24.661333-14.890667 32.597333l-1.024 1.664a788.778667 788.778667 0 0 1-61.525333 84.138667 42.666667 42.666667 0 1 1-65.408-54.784 704.853333 704.853333 0 0 0 59.52-82.645333V512v-0.042667a62.336 62.336 0 0 0-1.28-2.090666l-3.413334-5.546667c-22.698667-35.968-67.712-98.986667-131.968-152.618667C688.554667 298.154667 607.744 256 512 256z\"/>';\n        }\n    }\n\n    const errorIcon = '<i aria-hidden=\"true\" class=\"fa fa-exclamation-circle\"></i>';\n\n    // 初始化账号登录表单验证\n    $(\"#accountForm\").validate({\n        rules: {\n            username: {\n                required: true,\n                minlength: 3,\n                maxlength: 20\n            },\n            password: {\n                required: true,\n                minlength: 5,\n                maxlength: 20\n            },\n            captcha: {\n                required: true,\n                minlength: 4,\n                maxlength: 4\n            }\n        },\n        messages: {\n            username: {\n                required: errorIcon + \" 用户名不能为空\",\n                minlength: errorIcon + \" 用户名至少3个字符\",\n                maxlength: errorIcon + \" 用户名不能超过20个字符\"\n            },\n            password: {\n                required: errorIcon + \" 密码不能为空\",\n                minlength: errorIcon + \" 密码至少5个字符\",\n                maxlength: errorIcon + \" 密码不能超过20个字符\"\n            },\n            captcha: {\n                required: errorIcon + \" 图形验证码不能为空\",\n                minlength: errorIcon + \" 图形验证为4个字符\",\n                maxlength: errorIcon + \" 图形验证为4个字符\"\n            }\n        },\n        errorPlacement: function (error, element) {\n            error.appendTo(element.closest('.input-wrapper').parent());\n        },\n        submitHandler: function (form) {\n            // 存储登录信息\n            const username = form.querySelector('#accountForm input[name=\"username\"]').value;\n            localStorage.setItem('hiauth_last_loginType', \"account\");\n            localStorage.setItem('hiauth_last_username', username);\n            form.submit();\n        }\n    });\n\n    // 添加自定义验证方法\n    $.validator.addMethod(\"chineseMobile\", function (value, element) {\n        return this.optional(element) || /^1[3-9]\\d{9}$/.test(value);\n    }, errorIcon + \" 请输入正确的11位手机号码\");\n\n    // 初始化手机号登录表单验证\n    $(\"#phoneForm\").validate({\n        rules: {\n            phone: {\n                required: true,\n                minlength: 11,\n                maxlength: 11,\n                chineseMobile: true\n            },\n            captcha: {\n                required: true,\n                minlength: 4,\n                maxlength: 4\n            },\n            smsCode: {\n                required: true,\n                minlength: 6,\n                maxlength: 6\n            }\n        },\n        messages: {\n            phone: {\n                required: errorIcon + \" 手机号不能为空\",\n                minlength: errorIcon + \" 请输入正确的11位手机号码\",\n                maxlength: errorIcon + \" 请输入正确的11位手机号码\"\n            },\n            captcha: {\n                required: errorIcon + \" 图形验证码不能为空\",\n                minlength: errorIcon + \" 验证码必须为4位\",\n                maxlength: errorIcon + \" 验证码必须为4位\"\n            },\n            smsCode: {\n                required: errorIcon + \" 短信验证码不能为空\",\n                minlength: errorIcon + \" 验证码必须为6位\",\n                maxlength: errorIcon + \" 验证码必须为6位\"\n            }\n        },\n        errorPlacement: function (error, element) {\n            error.appendTo(element.closest('.input-wrapper').parent());\n        },\n        submitHandler: function (form) {\n            // 存储登录信息\n            const phone = form.querySelector('#phoneForm input[name=\"phone\"]').value;\n            localStorage.setItem('hiauth_last_loginType', \"phone\");\n            localStorage.setItem('hiauth_last_phone', phone);\n            form.submit();\n        }\n    });\n\n    // 获取图像验证码配置\n    const contentPath = \"\";\n    const imgUrl = contentPath + \"auth/code/image\";\n\n    // 获取图形验证码\n    function getCaptcha(formToken) {\n        const $this = $(\".captcha-img\");\n        const url = imgUrl + \"?formToken=\" + formToken + \"&r=\" + Math.random();\n        $this.attr('src', url);\n    }\n\n    //点击更新图形验证码\n    $('.captcha-img').click(function () {\n        const formToken = $(\"#formToken1\").val();\n        getCaptcha(formToken);\n    });\n    getCaptcha($(\"#formToken1\").val());\n\n    // 短信验证码倒计时功能\n    let countdown = 60;\n    let timer = null;\n\n    function startCountdown() {\n        const btn = $(\"#smsCodeBtn\");\n        btn.prop(\"disabled\", true).text(`${countdown}秒后重发`);\n        timer = setInterval(() => {\n            countdown--;\n            if (countdown <= 0) {\n                clearInterval(timer);\n                btn.prop(\"disabled\", false).text(\"获取验证码\");\n                countdown = 60;\n                return;\n            }\n            btn.text(`${countdown}秒后重发`);\n        }, 1000);\n    }\n\n    // 绑定获取验证码按钮点击事件\n    $(\"#smsCodeBtn\").click(function () {\n\n        const phoneEl = $(\"#phoneForm input[name='phone']\");\n        const imgCodeEl = $(\"#phoneForm input[name='captcha']\");\n        const formTokenEl = $(\"#phoneForm input[name='formToken']\");\n\n        const phoneIsValid = phoneEl.valid();\n        const imgCodeIsValid = imgCodeEl.valid();\n        if (!phoneIsValid || !imgCodeIsValid) {\n            return;\n        }\n\n        const phone = phoneEl.val();\n        const imgCode = imgCodeEl.val();\n        const formToken = formTokenEl.val();\n\n        // 发送短信验证码请求\n        $.ajax({\n            url: \"auth/code/sms?telNo=\" + phone + \"&formToken=\" + formToken + \"&imgCode=\" + imgCode + \"&r=\" + Math.random(),\n            type: \"GET\",\n            success: function (data) {\n                $(\".error-alert\").remove();\n                if (data.code !== 10000) {\n                    $(\"body\").prepend(`\n                            <div class=\"error-alert\" onclick=\"this.remove()\">\n                                ${data.message}\n                                <svg viewBox=\"0 0 24 24\" class=\"close-icon\">\n                                    <path fill=\"currentColor\" d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\"/>\n                                </svg>\n                            </div>\n                        `);\n                    const formToken = $(\"#formToken1\").val();\n                    getCaptcha(formToken);\n                } else {\n                    startCountdown();\n                }\n            }\n        });\n    });\n\n    // 在页面加载时读取存储的登录信息\n    document.addEventListener('DOMContentLoaded', function () {\n        const lastLoginType = localStorage.getItem('hiauth_last_loginType') || 'account';\n        const lastUsername = localStorage.getItem('hiauth_last_username');\n        if (lastUsername) {\n            document.querySelector(`#accountForm input[name=\"username\"]`).value = lastUsername;\n        }\n        const lastPhone = localStorage.getItem('hiauth_last_phone');\n        if (lastPhone) {\n            document.querySelector(`#phoneForm input[name=\"phone\"]`).value = lastPhone;\n        }\n    });\n\n    // 微信登录二维码\n    new WxLogin({\n        id: \"wechat_qrcode\",\n        appid: \"[[${wechatAppid}]]\",\n        scope: \"snsapi_login\",\n        redirect_uri: encodeURI(\"[[${wechatRedirectUri}]]\"),\n        state: \"[[${wechaState}]]\",\n        style: \"[[${wechatStyle}]]\",\n        href: \"[[${wechatHref}]]\"\n    });\n\n</script>\n<script th:src=\"@{static/js/particle.js}\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/login3.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\">\n    <meta content=\"\" name=\"description\">\n    <title id=\"titleName\"></title>\n    <script src=\"../static/js/jquery.min.js\"></script>\n    <script src=\"../static/js/jquery.validate.min.js\"></script>\n    <script src=\"../static/js/wxLogin.js\"></script>\n    <script src=\"../static/js/sliderCaptcha.js\"></script>\n    <link href=\"../static/fontawesome-5.15.4/css/all.min.css\" rel=\"stylesheet\">\n    <link href=\"../static/css/login3.css\" rel=\"stylesheet\">\n</head>\n\n<body>\n<!-- 登录失败提示 -->\n<div class=\"error-alert\" onclick=\"this.style.display='none'\" th:if=\"${param.error}\">\n    <span th:text=\"${session.SPRING_SECURITY_LAST_EXCEPTION} ? ${session.SPRING_SECURITY_LAST_EXCEPTION.message}\"></span>\n    <svg class=\"close-icon\" viewBox=\"0 0 24 24\">\n        <path d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\" fill=\"currentColor\"/>\n    </svg>\n</div>\n<div class=\"login-page-container\">\n    <div class=\"lft-container\">\n        <img alt=\"\" class=\"gb\" src=\"../static/img/login3-bg.png\">\n        <img alt=\"\" class=\"logo\" src=\"http://uavs-common-oss.mayizhifei.com/wxmp/images/myzf_logo_1.png\">\n        <!--<p>汇聚海量用户，提供专业服务</p>-->\n    </div>\n    <div class=\"rgt-container dark-box\" id=\"right-box\">\n        <div class=\"switch-container dark-switch\" id=\"switch\">\n            <div class=\"switch-inner light-inner\">\n                <div class=\"inner-box\">\n                    <div class=\"switch-item\" onclick=\"handleSwitch(1)\"><img alt=\"\" src=\"../static/img/light_sun.png\"></div>\n                    <div class=\"switch-item\" onclick=\"handleSwitch(2)\"><img alt=\"\" src=\"../static/img/light_moon.png\"></div>\n                </div>\n            </div>\n            <div class=\"switch-inner dark-inner\">\n                <div class=\"inner-box\">\n                    <div class=\"switch-item\" onclick=\"handleSwitch(1)\"><img alt=\"\" src=\"../static/img/dark_sun.png\"></div>\n                    <div class=\"switch-item\" onclick=\"handleSwitch(2)\"><img alt=\"\" src=\"../static/img/dark_moon.png\"></div>\n                </div>\n            </div>\n        </div>\n        <div class=\"login-container\">\n            <div class=\"login-title\" th:with=\"isEmpty=${#strings.isEmpty(appName)}\">\n                <span th:if=\"${!isEmpty}\" th:text=\"${appName}\"></span>\n                <span th:if=\"${isEmpty}\">认证中心</span>\n            </div>\n            <div class=\"tabs\">\n                <div class=\"tab\" id=\"phone\" onclick=\"switchTab('phone')\" th:if=\"${loginTypes.contains('phone')}\">验证码登录</div>\n                <div class=\"tab\" id=\"account\" onclick=\"switchTab('account')\" th:if=\"${loginTypes.contains('account')}\">账户登录</div>\n                <div class=\"tab\" id=\"wechat\" onclick=\"switchTab('wechat')\" th:if=\"${loginTypes.contains('wechat')}\">扫码登录</div>\n            </div>\n            <!-- 账户登录表单 -->\n            <form class=\"form\" id=\"accountForm\" method=\"post\" style=\"display: none;\" th:action=\"@{account/doLogin}\">\n                <input name=\"_csrf\" th:value=\"${_csrf.token}\" type=\"hidden\">\n                <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n                <input id=\"formToken\" name=\"formToken\" th:value=\"${formToken}\" type=\"hidden\">\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <input class=\"input\" name=\"username\" placeholder=\"请输入您的账号\" type=\"text\">\n                    </div>\n                </div>\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <div class=\"slider-captcha\" id=\"slider-captcha-account\">\n                            <div class=\"slider-track\"></div>\n                            <div class=\"slider-thumb\"><img alt=\"\" class=\"slider-thumb-icon\" src=\"../static/img/chevron-right.png\"></div>\n                            <div class=\"slider-title\">按住滑块，拖动到最右边</div>\n                            <input name=\"captcha\" type=\"hidden\">\n                        </div>\n                    </div>\n                </div>\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <input class=\"input password\" id=\"passwordInput\" name=\"password\" placeholder=\"请输入密码\" style=\"padding-right: 34px;\" type=\"password\">\n                        <!-- 新增右侧眼睛图标 -->\n                        <svg class=\"icon input-icon\" height=\"32\" id=\"eyeIcon\" onclick=\"togglePasswordVisibility()\" style=\"right:10px; left:auto; cursor:pointer;\" viewBox=\"0 0 1024 1024\" width=\"32\">\n                            <path d=\"M97.834667 97.834667a42.666667 42.666667 0 0 1 60.373333 0l155.221333 155.264c2.517333 1.962667 4.778667 4.266667 6.826667 6.826666l443.349333 443.306667c2.901333 2.261333 5.546667 4.864 7.850667 7.893333l154.752 154.709334a42.666667 42.666667 0 0 1-60.373333 60.330666l-134.528-134.570666C669.653333 827.733333 596.138667 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.661333 14.848-32.597333l1.066667-1.621334c25.685333-40.661333 77.866667-114.176 154.453333-176.682666L97.834667 158.165333a42.666667 42.666667 0 0 1 0-60.330666z m184.533333 244.906666C212.48 397.866667 163.584 465.92 139.392 504.234667a388.565333 388.565333 0 0 0-4.693333 7.68V512a409.941333 409.941333 0 0 0 4.693333 7.594667c22.656 36.010667 67.626667 98.986667 131.925333 152.661333C335.488 725.845333 416.298667 768 512 768c57.728 0 109.994667-15.317333 156.458667-39.210667l-69.76-69.76a170.666667 170.666667 0 0 1-233.728-233.728L282.368 342.698667z m147.2 147.157334a85.333333 85.333333 0 0 0 104.533333 104.533333l-104.533333-104.533333zM512 256c-16.256 0-32.085333 1.194667-47.36 3.498667a42.666667 42.666667 0 0 1-12.501333-84.437334A409.045333 409.045333 0 0 1 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512 2.645333 11.605333 2.645333 26.538667 0 38.144-3.285333 14.378667-9.813333 24.661333-14.890667 32.597333l-1.024 1.664a788.778667 788.778667 0 0 1-61.525333 84.138667 42.666667 42.666667 0 1 1-65.408-54.784 704.853333 704.853333 0 0 0 59.52-82.645333V512v-0.042667a62.336 62.336 0 0 0-1.28-2.090666l-3.413334-5.546667c-22.698667-35.968-67.712-98.986667-131.968-152.618667C688.554667 298.154667 607.744 256 512 256z\" fill=\"currentColor\"></path>\n                        </svg>\n                    </div>\n                </div>\n                <button class=\"submit-btn\" disabled type=\"submit\">立即登录</button>\n                <div class=\"wechat_register\">还没注册 <span class=\"link\" onclick=\"onShowRegisterQRcode()\">点击注册</span></div>\n            </form>\n            <!-- 手机登录表单 -->\n            <form class=\"form\" id=\"phoneForm\" method=\"post\" th:action=\"@{phone/doLogin}\">\n                <input name=\"_csrf\" th:value=\"${_csrf.token}\" type=\"hidden\">\n                <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n                <input name=\"formToken\" th:value=\"${formToken}\" type=\"hidden\">\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <input autocomplete=\"on\" class=\"input\" name=\"phone\" oninput=\"this.value = this.value.replace(/\\D/g,'')\" placeholder=\"请输入您的手机号码\" type=\"tel\">\n                    </div>\n                    <div class=\"error-message\">请输入有效的手机号码</div>\n                </div>\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper\">\n                        <div class=\"slider-captcha\" id=\"slider-captcha-phone\">\n                            <div class=\"slider-track\"></div>\n                            <div class=\"slider-thumb\"><img alt=\"\" class=\"slider-thumb-icon\" src=\"../static/img/chevron-right.png\"></div>\n                            <div class=\"slider-title\">按住滑块，拖动到最右边</div>\n                            <input name=\"captcha\" type=\"hidden\">\n                        </div>\n                    </div>\n                </div>\n                <div class=\"form-group\">\n                    <div class=\"input-wrapper sms-code-row\">\n                        <div class=\"input-sub-wrapper\">\n                            <input class=\"input\" name=\"smsCode\" placeholder=\"请输入验证码\" style=\"flex:1\" type=\"text\">\n                        </div>\n                        <button class=\"get-code-btn\" disabled id=\"smsCodeBtn\" type=\"button\">获取验证码</button>\n                    </div>\n                </div>\n                <button class=\"submit-btn\" disabled type=\"submit\">立即登录</button>\n                <div class=\"wechat_register\">还没注册 <span class=\"link\" onclick=\"onShowRegisterQRcode()\">点击注册</span></div>\n            </form>\n            <!-- 手机登录表单 -->\n            <form class=\"form\" id=\"wechatForm\" method=\"post\" style=\"width: 330px;position: relative;\"\n                  th:action=\"@{wechat/qrcode/doLogin}\">\n                <div id=\"wechat_qrcode\"></div>\n                <input name=\"clientId\" th:value=\"${clientId}\" type=\"hidden\">\n                <div class=\"wechat_register\">还没注册 <span class=\"link\" onclick=\"onShowRegisterQRcode()\">点击注册</span></div>\n            </form>\n        </div>\n        <p class=\"record-text\">登录即表示您同意蚂蚁智飞的&nbsp;<span>用户协议</span>&nbsp;和&nbsp;<span>隐私协议</span></p>\n    </div>\n</div>\n<div class=\"wechat_modal\">\n    <div class=\"box\">\n        <div class=\"title\">使用微信扫一扫</div>\n        <img alt=\"二维码\" class=\"QRcode\" src=\"http://uavs-common-oss.mayizhifei.com/wxmp/images/QRCode.png\">\n    </div>\n    <img class=\"close\" onclick=\"onCloseRegisterQRcode()\" src=\"../static/img/close.png\">\n</div>\n</body>\n<script>\n    // 新增初始化登录方式\n    document.addEventListener('DOMContentLoaded', function () {\n        // 新增URL参数清除逻辑\n        const url = new URL(window.location.href);\n        if (url.searchParams.has('error')) {\n            url.searchParams.delete('error');\n            window.history.replaceState({}, '', url);\n        }\n        const lastLoginType = localStorage.getItem('hiauth_last_loginType') || 'phone';\n        const screenModel = localStorage.getItem('hiauth_screen_model') || 1;\n        switchTab(lastLoginType);\n        handleSwitch(screenModel)\n    });\n\n    function handleSwitch(type) {\n        if (type == 1) {\n            //切换白色模式\n            $('#switch').attr('class', 'switch-container light-switch')\n            $('#right-box').attr('class', 'rgt-container light-box')\n            $('.slider-thumb-icon').attr('src', '../static/img/chevron-right-light.png');\n        }\n        if (type == 2) {\n            //切换黑色模式\n            $('#switch').attr('class', 'switch-container dark-switch')\n            $('#right-box').attr('class', 'rgt-container dark-box')\n            $('.slider-thumb-icon').attr('src', '../static/img/chevron-right.png');\n        }\n        localStorage.setItem('hiauth_screen_model', type);\n    }\n\n    // 切换登录方式\n    function switchTab(type) {\n        document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));\n        document.querySelectorAll('.form').forEach(form => form.style.display = 'none');\n        let tab = document.querySelector(`.tab#` + type);\n        if (tab == null) {\n            tab = document.querySelector('.tabs > .tab:first-child');\n        }\n        tab.classList.add('active');\n        type = tab.id;\n        document.getElementById(type + 'Form').style.display = 'block';\n        localStorage.setItem('hiauth_last_loginType', type);\n    }\n\n    // 切换密码可见性\n    function togglePasswordVisibility() {\n        const passwordField = document.getElementById('passwordInput');\n        const eyeIcon = document.getElementById('eyeIcon');\n        const isPassword = passwordField.type === 'password';\n        // 切换输入框类型\n        passwordField.type = isPassword ? 'text' : 'password';\n        // 切换图标路径\n        if (isPassword) {\n            // 睁眼图标（明文状态）\n            eyeIcon.innerHTML = '<path fill=\"currentColor\" d=\"M341.333333 512a170.666667 170.666667 0 1 1 341.333334 0 170.666667 170.666667 0 0 1-341.333334 0z m170.666667-85.333333a85.333333 85.333333 0 1 0 0 170.666666 85.333333 85.333333 0 0 0 0-170.666666z\"></path><path fill=\"currentColor\" d=\"M216.618667 286.165333C290.389333 224.64 389.973333 170.666667 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512a92.16 92.16 0 0 1 0 38.144c-3.285333 14.378667-9.813333 24.618667-14.848 32.512l-1.024 1.621333c-25.301333 40.064-75.776 111.146667-149.418667 172.629334C733.653333 799.36 634.112 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.618667 14.848-32.512l1.024-1.621333c25.258667-40.064 75.776-111.146667 149.418667-172.629334zM271.36 351.701333C207.018667 405.333333 162.090667 468.352 139.349333 504.32a409.173333 409.173333 0 0 0-4.693333 7.594667V512l1.237333 2.090667 3.413334 5.546666c22.741333 35.968 67.712 98.986667 132.010666 152.618667C335.488 725.845333 416.298667 768 512 768c95.744 0 176.554667-42.154667 240.725333-95.701333 64.256-53.632 109.226667-116.650667 131.968-152.661334a445.610667 445.610667 0 0 0 4.693334-7.594666V512a445.610667 445.610667 0 0 0-4.693334-7.594667c-22.741333-36.010667-67.712-98.986667-131.968-152.661333C688.554667 298.154667 607.744 256 512 256c-95.701333 0-176.512 42.154667-240.682667 95.701333z\"></path>';\n        } else {\n            // 闭眼图标（密文状态）\n            eyeIcon.innerHTML = '<path fill=\"currentColor\" d=\"M97.834667 97.834667a42.666667 42.666667 0 0 1 60.373333 0l155.221333 155.264c2.517333 1.962667 4.778667 4.266667 6.826667 6.826666l443.349333 443.306667c2.901333 2.261333 5.546667 4.864 7.850667 7.893333l154.752 154.709334a42.666667 42.666667 0 0 1-60.373333 60.330666l-134.528-134.570666C669.653333 827.733333 596.138667 853.333333 512 853.333333c-122.069333 0-221.610667-53.973333-295.381333-115.498666-73.642667-61.482667-124.16-132.565333-149.418667-172.629334a539.477333 539.477333 0 0 0-1.024-1.621333c-5.034667-7.893333-11.52-18.133333-14.848-32.512a92.117333 92.117333 0 0 1 0-38.144c3.285333-14.378667 9.813333-24.661333 14.848-32.597333l1.066667-1.621334c25.685333-40.661333 77.866667-114.176 154.453333-176.682666L97.834667 158.165333a42.666667 42.666667 0 0 1 0-60.330666z m184.533333 244.906666C212.48 397.866667 163.584 465.92 139.392 504.234667a388.565333 388.565333 0 0 0-4.693333 7.68V512a409.941333 409.941333 0 0 0 4.693333 7.594667c22.656 36.010667 67.626667 98.986667 131.925333 152.661333C335.488 725.845333 416.298667 768 512 768c57.728 0 109.994667-15.317333 156.458667-39.210667l-69.76-69.76a170.666667 170.666667 0 0 1-233.728-233.728L282.368 342.698667z m147.2 147.157334a85.333333 85.333333 0 0 0 104.533333 104.533333l-104.533333-104.533333zM512 256c-16.256 0-32.085333 1.194667-47.36 3.498667a42.666667 42.666667 0 0 1-12.501333-84.437334A409.045333 409.045333 0 0 1 512 170.666667c122.112 0 221.653333 53.973333 295.424 115.498666 73.642667 61.482667 124.16 132.565333 149.418667 172.629334l1.024 1.621333c5.034667 7.893333 11.52 18.133333 14.848 32.512 2.645333 11.605333 2.645333 26.538667 0 38.144-3.285333 14.378667-9.813333 24.661333-14.890667 32.597333l-1.024 1.664a788.778667 788.778667 0 0 1-61.525333 84.138667 42.666667 42.666667 0 1 1-65.408-54.784 704.853333 704.853333 0 0 0 59.52-82.645333V512v-0.042667a62.336 62.336 0 0 0-1.28-2.090666l-3.413334-5.546667c-22.698667-35.968-67.712-98.986667-131.968-152.618667C688.554667 298.154667 607.744 256 512 256z\"/>';\n        }\n    }\n\n    const errorIcon = '<i aria-hidden=\"true\" class=\"fa fa-exclamation-circle\"></i>';\n\n    // 初始化账号登录表单验证\n    $(\"#accountForm\").validate({\n        rules: {\n            username: {\n                required: true,\n                minlength: 3,\n                maxlength: 20\n            },\n            password: {\n                required: true,\n                minlength: 5,\n                maxlength: 20\n            },\n            captcha: {\n                required: true,\n                minlength: 4,\n                maxlength: 4\n            }\n        },\n        messages: {\n            username: {\n                required: errorIcon + \" 用户名不能为空\",\n                minlength: errorIcon + \" 用户名至少3个字符\",\n                maxlength: errorIcon + \" 用户名不能超过20个字符\"\n            },\n            password: {\n                required: errorIcon + \" 密码不能为空\",\n                minlength: errorIcon + \" 密码至少5个字符\",\n                maxlength: errorIcon + \" 密码不能超过20个字符\"\n            },\n            captcha: {\n                required: errorIcon + \" 图形验证码不能为空\",\n                minlength: errorIcon + \" 图形验证为4个字符\",\n                maxlength: errorIcon + \" 图形验证为4个字符\"\n            }\n        },\n        errorPlacement: function (error, element) {\n            error.appendTo(element.closest('.input-wrapper').parent());\n        },\n        submitHandler: function (form) {\n            // 存储登录信息\n            const username = form.querySelector('#accountForm input[name=\"username\"]').value;\n            localStorage.setItem('hiauth_last_loginType', \"account\");\n            localStorage.setItem('hiauth_last_username', username);\n            form.submit();\n        }\n    });\n\n    // 添加自定义验证方法\n    $.validator.addMethod(\"chineseMobile\", function (value, element) {\n        return this.optional(element) || /^1[3-9]\\d{9}$/.test(value);\n    }, errorIcon + \" 请输入正确的11位手机号码\");\n\n    // 初始化手机号登录表单验证\n    $(\"#phoneForm\").validate({\n        rules: {\n            phone: {\n                required: true,\n                minlength: 11,\n                maxlength: 11,\n                chineseMobile: true\n            },\n            captcha: {\n                required: true,\n                minlength: 4,\n                maxlength: 4\n            },\n            smsCode: {\n                required: true,\n                minlength: 6,\n                maxlength: 6\n            }\n        },\n        messages: {\n            phone: {\n                required: errorIcon + \" 手机号不能为空\",\n                minlength: errorIcon + \" 请输入正确的11位手机号码\",\n                maxlength: errorIcon + \" 请输入正确的11位手机号码\"\n            },\n            captcha: {\n                required: errorIcon + \" 图形验证码不能为空\",\n                minlength: errorIcon + \" 验证码必须为4位\",\n                maxlength: errorIcon + \" 验证码必须为4位\"\n            },\n            smsCode: {\n                required: errorIcon + \" 短信验证码不能为空\",\n                minlength: errorIcon + \" 验证码必须为6位\",\n                maxlength: errorIcon + \" 验证码必须为6位\"\n            }\n        },\n        errorPlacement: function (error, element) {\n            error.appendTo(element.closest('.input-wrapper').parent());\n        },\n        submitHandler: function (form) {\n            // 存储登录信息\n            const phone = form.querySelector('#phoneForm input[name=\"phone\"]').value;\n            localStorage.setItem('hiauth_last_loginType', \"phone\");\n            localStorage.setItem('hiauth_last_phone', phone);\n            form.submit();\n        }\n    });\n\n    // 短信验证码倒计时功能\n    let countdown = 60;\n    let timer = null;\n\n    function startCountdown() {\n        const btn = $(\"#smsCodeBtn\");\n        btn.prop(\"disabled\", true).text(`${countdown}秒后重发`);\n        timer = setInterval(() => {\n            countdown--;\n            if (countdown <= 0) {\n                clearInterval(timer);\n                btn.prop(\"disabled\", false).text(\"获取验证码\");\n                countdown = 60;\n                return;\n            }\n            btn.text(`${countdown}秒后重发`);\n        }, 1000);\n    }\n\n    // 绑定获取验证码按钮点击事件\n    $(\"#smsCodeBtn\").click(function () {\n\n        const phoneEl = $(\"#phoneForm input[name='phone']\");\n        const imgCodeEl = $(\"#phoneForm input[name='captcha']\");\n        const formTokenEl = $(\"#phoneForm input[name='formToken']\");\n\n        const phoneIsValid = phoneEl.valid();\n        const imgCodeIsValid = imgCodeEl.valid();\n        if (!phoneIsValid || !imgCodeIsValid) {\n            return;\n        }\n\n        const phone = phoneEl.val();\n        const imgCode = imgCodeEl.val();\n        const formToken = formTokenEl.val();\n\n        $(this).prop(\"disabled\", true)\n\n        // 发送短信验证码请求\n        $.ajax({\n            url: \"auth/code/sms?telNo=\" + phone + \"&formToken=\" + formToken + \"&imgCode=\" + imgCode + \"&r=\" + Math.random(),\n            type: \"GET\",\n            success: function (data) {\n                $(\".error-alert\").remove();\n                if (data.code !== 10000) {\n                    let message = data.message;\n                    if(data.code===20101){\n                        message = \"验证码已失效，请重试！\";\n                    } else\n                    if(data.code===20102){\n                        message = \"验证码已失效，请重试！\";\n                    } else if(data.code===20103){\n                        message = \"手机号未注册！\";\n                    }\n                    $(\"body\").prepend(`\n                            <div class=\"error-alert\" onclick=\"this.remove()\">\n                                ${message}\n                                <svg viewBox=\"0 0 24 24\" class=\"close-icon\">\n                                    <path fill=\"currentColor\" d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\"/>\n                                </svg>\n                            </div>\n                        `);\n                    $('#slider-captcha-phone').sliderCaptcha('reset');\n                } else {\n                    startCountdown();\n                }\n            }\n        });\n    });\n\n    // 在页面加载时读取存储的登录信息\n    document.addEventListener('DOMContentLoaded', function () {\n        const lastUsername = localStorage.getItem('hiauth_last_username');\n        if (lastUsername) {\n            document.querySelector(`#accountForm input[name=\"username\"]`).value = lastUsername;\n        }\n        const lastPhone = localStorage.getItem('hiauth_last_phone');\n        if (lastPhone) {\n            document.querySelector(`#phoneForm input[name=\"phone\"]`).value = lastPhone;\n        }\n    });\n\n    // 微信登录二维码\n    new WxLogin({\n        id: \"wechat_qrcode\",\n        appid: \"[[${wechatAppid}]]\",\n        scope: \"snsapi_login\",\n        redirect_uri: encodeURI(\"[[${wechatRedirectUri}]]\"),\n        state: \"[[${wechaState}]]\",\n        style: \"[[${wechatStyle}]]\",\n        href: \"[[${wechatHref}]]\"\n    });\n\n    $('#slider-captcha-phone').sliderCaptcha({\n        token: $('#formToken').val(),\n        successCallback: function (data) {\n            $('#phoneForm > .submit-btn').removeAttr('disabled');\n            $('#smsCodeBtn').removeAttr('disabled');\n            console.log('滑块验证成功');\n        },\n        errorCallback: function () {\n            console.log('滑块验证失败');\n        }\n    });\n\n    $('#slider-captcha-account').sliderCaptcha({\n        token: $('#formToken').val(),\n        successCallback: function (data) {\n            $('#accountForm > .submit-btn').removeAttr('disabled');\n            console.log('滑块验证成功');\n        },\n        errorCallback: function () {\n            console.log('滑块验证失败');\n        }\n    });\n\n    function onShowRegisterQRcode() {\n        const QRcode = document.querySelector('.wechat_modal')\n        QRcode.style.display = 'flex';\n    }\n\n    function onCloseRegisterQRcode() {\n        const QRcode = document.querySelector('.wechat_modal')\n        QRcode.style.display = 'none';\n    }\n\n</script>\n\n</html>"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/oauth/oauth_approval.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n\n<head>\n    <title>HiAuth</title>\n    <meta charset=\"utf-8\">\n    <meta content=\"IE=edge\" http-equiv=\"X-UA-Compatible\">\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\">\n    <meta content=\"\" name=\"description\">\n    <meta content=\"\" name=\"author\">\n    <link rel=\"icon\" th:href=\"@{/static/favicon.ico}\">\n\n    <link rel=\"stylesheet\" th:href=\"@{/static/bootstrap/css/bootstrap.min.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/css/font-awesome.min.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/static/bootstrap/css/bootstrapValidator.min.css}\">\n\n    <script th:src=\"@{/static/js/jquery.min.js}\"></script>\n    <script th:src=\"@{/static/bootstrap/js/bootstrap.min.js}\"></script>\n    <script th:src=\"@{/static/bootstrap/js/bootstrapValidator.min.js}\"></script>\n\n</head>\n\n<body>\n\n<div class=\"container\">\n\n    <div class=\"row\" style=\"margin-top: 100px;\">\n\n        <div class=\"col-md-4 col-md-offset-4\">\n\n            <form id='confirmationForm' method='post' name='confirmationForm' th:action=\"@{/oauth/authorize}\">\n                <input name='user_oauth_approval' type='hidden' value='true'/>\n\n                <div class=\"panel panel-default\">\n                    <div class=\"panel-heading\">\n                        <div>\n                            <img class=\"img-circle\" style=\"width: 50px;height: 50px;\" th:src=\"@{/static/img/app.png}\">\n                            <span style=\"margin-left: 10px;\">应用：<span th:text=\"${appName}\"/>，申请接入HiAuth</span>\n                        </div>\n                    </div>\n                    <div class=\"alert-warning\" style=\"height: 30px;padding: 5px;margin-bottom: 15px;\">\n                        <span class=\"glyphicon glyphicon-exclamation-sign\" style=\"margin-right: 2px;\"></span>同意后将获取如下权限\n                    </div>\n                    <div class=\"panel-body\">\n                        <ul class=\"list-group\">\n                            <div th:each=\"scope,scopeStat:${scopeList}\">\n                                <li class=\"list-group-item\" style=\"border-width: 0px;\">\n                                    <span class=\"fa fa-check-circle-o fa-fw\" style=\"color: #3c763d;\"></span>\n                                    <span style=\"margin-left: 10px;\" th:text=\"${scope.text}\"/>\n                                    <input th:name=\"${scope.name}\" type=\"hidden\" value=\"true\"/>\n                                </li>\n                            </div>\n                        </ul>\n                    </div>\n\n                    <div class=\"panel-footer\" style=\"text-align: right;\">\n                        <button class=\"btn btn-default\" name='authorize' type=\"submit\">同意</button>\n                        <button class=\"btn btn-default\" name='deny' type=\"submit\">拒绝</button>\n                    </div>\n\n                </div>\n\n            </form>\n\n        </div>\n\n    </div>\n\n</div>\n\n    <!--<h3>应用：<span th:text=\"${session.authorizationRequest.clientId}\" />，申请接入HiAuth</h3>-->\n    <!--<h5>申请权限 :</h5>-->\n    <!--<form id='confirmationForm' name='confirmationForm' th:action=\"@{/oauth/authorize}\" method='post'>-->\n        <!--<input name='user_oauth_approval' value='true' type='hidden'/>-->\n        <!--<div th:each=\"scope,scopeStat:${scopeList}\">-->\n            <!--<input value=\"true\" type=\"hidden\" th:name=\"${scope.name}\" />-->\n            <!--<span th:text=\"${scopeStat.index + 1} + ':' + ${scope.text}\" />-->\n        <!--</div>-->\n        <!--<br/>-->\n        <!--<label><input name='authorize' value='同意' type='submit'/></label>-->\n        <!--<label><input name='deny' value='拒绝' type='submit'/></label>-->\n    <!--</form>-->\n\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/oauth/oauth_error.html",
    "content": "<!DOCTYPE HTML>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>error</title>\n    <meta charset=\"utf-8\"/>\n</head>\n<body>\n<div class=\"container\">\n    <div class=\"row\">\n        <div class=\"col-md-12 well\">\n            <h3>错误</h3>\n            <p style=\"color:red;\">出错了！不能继续授权操作！</p>\n            <p th:utext=\"${errorSummary}\">errorSummary\n        </div>\n    </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/profile.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <th:block th:insert=\"~{common/include :: header('HiAuth')}\"/>\n    <style>\n\n    </style>\n</head>\n<body>\n<div class=\"container\">\n\n    <header th:with=\"item=${#strings.arraySplit('corpMgr,myCorpMgr,appMgr,userMgr',',')}\">\n        <th:block th:insert=\"~{common/include :: navbar('profile',${item})}\"/>\n    </header>\n\n    <main>\n        个人信息\n    </main>\n\n    <th:block th:insert=\"~{common/include :: footer}\"/>\n\n</div>\n<th:block th:insert=\"~{common/include :: commonjs}\"/>\n<script>\n    $(function () {\n        console.log(\"xx\")\n    })\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/setting.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <th:block th:insert=\"~{common/include :: header('HiAuth')}\"/>\n    <style>\n\n    </style>\n</head>\n<body>\n<div class=\"container\">\n\n    <header th:with=\"item=${#strings.arraySplit('corpMgr,myCorpMgr,appMgr,userMgr',',')}\">\n        <th:block th:insert=\"~{common/include :: navbar('profile',${item})}\"/>\n    </header>\n\n    <main>\n        设置\n    </main>\n\n    <th:block th:insert=\"~{common/include :: footer}\"/>\n\n</div>\n<th:block th:insert=\"~{common/include :: commonjs}\"/>\n<script>\n    $(function () {\n        console.log(\"xx\")\n    })\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/user/detail.html",
    "content": "<!DOCTYPE HTML>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\"/>\n</head>\n\n<body>\n    <h1>用户详细</h1>\n    <span th:text=\"${auth.principal.username}\"></span>\n</body>\n\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/user/list.html",
    "content": "<!DOCTYPE HTML>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\"/>\n</head>\n\n<body>\n    <h1>用户列表</h1>\n    <span th:text=\"${auth.principal.username}\"></span>\n</body>\n\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/user/me.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>HiAuth</title>\n    <meta charset=\"utf-8\">\n    <meta content=\"IE=edge\" http-equiv=\"X-UA-Compatible\">\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\">\n    <meta content=\"\" name=\"description\">\n    <meta content=\"\" name=\"author\">\n    <link rel=\"icon\" th:href=\"@{/static/favicon.ico}\">\n\n    <link rel=\"stylesheet\" th:href=\"@{/static/bootstrap/css/bootstrap.min.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/css/font-awesome.min.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/static/bootstrap/css/bootstrapValidator.min.css}\">\n\n    <script th:src=\"@{/static/js/jquery.min.js}\"></script>\n    <script th:src=\"@{/static/bootstrap/js/bootstrap.min.js}\"></script>\n    <script th:src=\"@{/static/bootstrap/js/bootstrapValidator.min.js}\"></script>\n\n    <link rel=\"stylesheet\" th:href=\"@{/static/css/index.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/static/css/user_me.css}\">\n\n</head>\n<body>\n\n<div class=\"site-wrapper\">\n\n    <div class=\"site-wrapper-inner\">\n\n        <div class=\"cover-container\">\n\n            <div class=\"masthead clearfix\">\n                <div class=\"inner\">\n                    <h3 class=\"masthead-brand\">HIAUTH</h3>\n                    <nav>\n                        <ul class=\"nav masthead-nav\">\n                            <li><a th:href=\"@{/index}\">首页</a></li>\n                            <li class=\"active\"><a th:href=\"@{/user/me}\">个人信息</a></li>\n                            <li><a th:href=\"@{/logout}\">退出</a></li>\n                        </ul>\n                    </nav>\n                </div>\n            </div>\n\n            <div class=\"user-info\">\n\n                <div class=\"row\">\n                    <div class=\"col-md-3 title\">用户姓名：</div>\n                    <div class=\"col-md-9 text\"><span th:text=\"${user.username}\"></span></div>\n                </div>\n\n                <div class=\"row\" th:each=\"consent:${authorizationConsentList}\">\n                    <div class=\"col-md-3\" th:text=\"${consent.clientName}\"/>\n                    <div class=\"col-md-9\" th:text=\"${consent.authorities}\"/>\n                </div>\n\n            </div>\n\n            <div class=\"mastfoot\">\n                <div class=\"inner\">\n                    <p>HiAuth system for <a href=\"https://github.com/bestaone\">hiauth.com</a>, by <a href=\"https://github.com/bestaone\">@earven</a>.</p>\n                </div>\n            </div>\n\n        </div>\n\n    </div>\n\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "hiauth-server/src/main/resources/templates/user/user.html",
    "content": "<!DOCTYPE HTML>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta content=\"width=device-width, initial-scale=1\" name=\"viewport\"/>\n</head>\n\n<body>\n\n<div class=\"container\" style=\"margin-top: 60px\">\n    <img src=\"http://upload.jianshu.io/users/upload_avatars/3424642/fb55f16faaf6.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240\"/>\n    <p th:text=\"${username}\">Anoy</p>\n    <form method=\"post\" th:action=\"@{/logout}\">\n        <button style=\"margin-top: 20px\">退出登录</button>\n    </form>\n</div>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/AuthServerTests.java",
    "content": "package cn.hiauth.server;\n\nimport cn.hutool.core.codec.Base64;\nimport com.jayway.jsonpath.JsonPath;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.utils.URIBuilder;\nimport org.htmlunit.WebClient;\nimport org.htmlunit.WebResponse;\nimport org.htmlunit.html.DomElement;\nimport org.htmlunit.html.HtmlCheckBoxInput;\nimport org.htmlunit.html.HtmlPage;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;\nimport org.springframework.security.test.context.support.WithMockUser;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.MvcResult;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.when;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n@Slf4j\n@Transactional\n@AutoConfigureMockMvc\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\npublic class AuthServerTests {\n\n    public static final String redirectUri = \"http://127.0.0.1:8080/login/oauth2/code/hiauth-code\";\n    public static final String clientId = \"himall\", scope = \"openid profile\", authorization = \"Basic \" + Base64.encode(\"himall:secret\".getBytes());\n    private final String authorizationRequestUri = UriComponentsBuilder\n            .fromPath(\"/oauth2/authorize\")\n            .queryParam(\"response_type\", \"code\")\n            .queryParam(\"client_id\", clientId)\n            .queryParam(\"scope\", scope)\n            .queryParam(\"state\", \"state\")\n            .queryParam(\"redirect_uri\", this.redirectUri)\n            .toUriString();\n    @Autowired\n    MockMvc mvc;\n    @Autowired\n    private WebClient webClient;\n    @MockitoBean\n    private OAuth2AuthorizationConsentService authorizationConsentService;\n\n    @BeforeEach\n    public void setUp() {\n        this.webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);\n        this.webClient.getOptions().setRedirectEnabled(true);\n        this.webClient.getCookieManager().clearCookies();\n        when(this.authorizationConsentService.findById(any(), any())).thenReturn(null);\n    }\n\n    @Test\n    public void whenClientCredentialsSuccess() throws Exception {\n        String accessToken = getAccessTokenWithClientCredentia();\n        assertThat(accessToken).isNotBlank();\n    }\n\n    @Test\n    @WithMockUser(\"corpadmin\")\n    public void whenAuthorizationCodeSuccess() throws Exception {\n        String code = getCode();\n        assertThat(code).isNotBlank();\n        log.info(\"code：{}\", code);\n        String at = getAccessTokenWithCode(code);\n        assertThat(at).isNotBlank();\n        log.info(\"accessToken：{}\", at);\n    }\n\n    private String getCode() throws Exception {\n        final HtmlPage consentPage = this.webClient.getPage(this.authorizationRequestUri);\n        assertThat(consentPage.getTitleText()).isEqualTo(\"统一认证中心\");\n\n        List<HtmlCheckBoxInput> scopes = new ArrayList<>();\n        consentPage.querySelectorAll(\"input[name='scope']\").forEach(scope -> scopes.add((HtmlCheckBoxInput) scope));\n        for (HtmlCheckBoxInput scope : scopes) {\n            // 默认勾选，点两次依然勾选\n            scope.click();\n            scope.click();\n        }\n\n        List<String> scopeIds = new ArrayList<>();\n        scopes.forEach(scope -> {\n            assertThat(scope.isChecked()).isTrue();\n            scopeIds.add(scope.getId());\n        });\n        assertThat(scopeIds).containsExactlyInAnyOrder(\"profile\");\n\n        DomElement submitConsentButton = consentPage.querySelector(\"button[id='submit-consent']\");\n        this.webClient.getOptions().setRedirectEnabled(false);\n\n        WebResponse approveConsentResponse = submitConsentButton.click().getWebResponse();\n        assertThat(approveConsentResponse.getStatusCode()).isEqualTo(HttpStatus.MOVED_PERMANENTLY.value());\n        String location = approveConsentResponse.getResponseHeaderValue(\"location\");\n        assertThat(location).startsWith(this.redirectUri);\n        assertThat(location).contains(\"code=\");\n\n        URIBuilder builder = new URIBuilder(location);\n        List<NameValuePair> params = builder.getQueryParams();\n        Optional<NameValuePair> opt = params.stream().filter(e -> e.getName().equals(\"code\")).findFirst();\n        return opt.get().getValue();\n    }\n\n    private String getAccessTokenWithCode(String code) throws Exception {\n        MvcResult result = mvc.perform(\n                        post(\"/oauth2/token\")\n                                .param(\"grant_type\", \"authorization_code\")\n                                .param(\"code\", code)\n                                .param(\"redirect_uri\", redirectUri)\n                                .header(\"Authorization\", authorization)\n                                .contentType(MediaType.APPLICATION_FORM_URLENCODED)\n                                .accept(MediaType.APPLICATION_JSON)\n                )\n                .andExpect(status().isOk())\n                .andReturn();\n        String content = result.getResponse().getContentAsString();\n        log.debug(\"返回结果：{}\", content);\n        String at = JsonPath.read(content, \"$.access_token\");\n        assertThat(at).isNotBlank();\n        return at;\n    }\n\n    private String getAccessTokenWithClientCredentia() throws Exception {\n        MvcResult result = mvc.perform(\n                        post(\"/oauth2/token\")\n                                .param(\"grant_type\", \"client_credentials\")\n                                .param(\"scope\", \"profile\")\n                                .header(\"Authorization\", authorization)\n                                .contentType(MediaType.APPLICATION_JSON)\n                )\n                .andExpect(status().isOk())\n                .andReturn();\n        String content = result.getResponse().getContentAsString();\n        log.debug(\"返回结果：{}\", content);\n        String at = JsonPath.read(content, \"$.access_token\");\n        assertThat(at).isNotBlank();\n        return at;\n    }\n\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/CustomJdbcRegisteredClientRepositoryTests.java",
    "content": "package cn.hiauth.server;\n\nimport cn.hiauth.server.config.web.auth.CustomJdbcRegisteredClientRepository;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 应用\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass CustomJdbcRegisteredClientRepositoryTests {\n\n    @Resource\n    private CustomJdbcRegisteredClientRepository repository;\n\n    @Test\n    public void test() throws JsonProcessingException {\n        Set<String> clientIds = new HashSet<>();\n        clientIds.add(\"himall\");\n        List<RegisteredClient> list = repository.findByClientIds(clientIds);\n        Assert.isTrue(!list.isEmpty(), \"查询失败\");\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/DefaultAuthorizationServerApplicationTests.java",
    "content": "package cn.hiauth.server;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.htmlunit.WebClient;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.util.UriComponentsBuilder;\n\n@Slf4j\n@Transactional\n@AutoConfigureMockMvc\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\npublic class DefaultAuthorizationServerApplicationTests {\n\n    private static final String AUTHORIZATION_REQUEST = UriComponentsBuilder\n            .fromPath(\"/oauth2/authorize\")\n            .queryParam(\"response_type\", \"code\")\n            .queryParam(\"client_id\", AuthServerTests.clientId)\n            .queryParam(\"scope\", AuthServerTests.scope)\n            .queryParam(\"state\", \"some-state\")\n            .queryParam(\"redirect_uri\", AuthServerTests.redirectUri)\n            .toUriString();\n\n    @Autowired\n    private WebClient webClient;\n\n    @BeforeEach\n    public void setUp() {\n        this.webClient.getOptions().setThrowExceptionOnScriptError(false);\n        this.webClient.getOptions().setThrowExceptionOnFailingStatusCode(true);\n        this.webClient.getOptions().setRedirectEnabled(true);\n        this.webClient.getCookieManager().clearCookies();    // log out\n    }\n\n//    @Test\n//    public void whenLoginSuccessfulThenDisplayOk() throws IOException {\n//        HtmlPage page = this.webClient.getPage(\"/\");\n//        assertLoginPage(page);\n//        this.webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);\n//        WebResponse signInResponse = signIn(page, \"corpadmin\", \"123456\").getWebResponse();\n//        assertThat(signInResponse.getStatusCode()).isEqualTo(HttpStatus.OK.value());\t// there is no \"default\" index page\n//    }\n\n//    @Test\n//    public void whenLoginFailsThenDisplayBadCredentials() throws IOException {\n//        this.webClient.getOptions().setRedirectEnabled(true);\n//        HtmlPage page = this.webClient.getPage(\"/\");\n//        HtmlPage loginErrorPage = signIn(page, \"corpadmin\", \"111111\");\n//        HtmlElement alert = loginErrorPage.querySelector(\".error-box\");\n//        assertThat(alert.getTextContent()).isNotBlank();\n//    }\n\n//    @Test\n//    public void whenNotLoggedInAndRequestingTokenThenRedirectsToLogin() throws IOException {\n//        HtmlPage page = this.webClient.getPage(AUTHORIZATION_REQUEST);\n//        assertLoginPage(page);\n//    }\n\n//    @Test\n//    public void whenLoggingInAndRequestingTokenThenRedirectsToClientApplication() throws IOException {\n//        // Log in\n//        this.webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);\n//        this.webClient.getOptions().setRedirectEnabled(false);\n//        HtmlPage page = this.webClient.getPage(\"/\");\n//        signIn(page, \"corpadmin\", \"111111\");\n//\n//        // Request token\n//        WebResponse response = this.webClient.getPage(AUTHORIZATION_REQUEST).getWebResponse();\n//\n//        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.MOVED_PERMANENTLY.value());\n//        String location = response.getResponseHeaderValue(\"location\");\n////        assertThat(location).startsWith(AuthServerTests.redirectUri);\n////        assertThat(location).contains(\"code=\");\n//    }\n\n//    private static <P extends Page> P signIn(HtmlPage page, String username, String password) throws IOException {\n//        HtmlInput usernameInput = page.querySelector(\"input[name=\\\"username\\\"]\");\n//        HtmlInput passwordInput = page.querySelector(\"input[name=\\\"password\\\"]\");\n//        HtmlButton signInButton = page.querySelector(\"button.submit\");\n//        usernameInput.type(username);\n//        passwordInput.type(password);\n//        return signInButton.click();\n//    }\n//\n//    private static void assertLoginPage(HtmlPage page) {\n//        assertThat(page.getUrl().toString()).contains(\"/login\");\n//        HtmlInput csrfInput = page.querySelector(\"input[name=\\\"_csrf\\\"]\");\n//        HtmlInput clientIdInput = page.querySelector(\"input[name=\\\"clientId\\\"]\");\n//        HtmlInput formTokenInput = page.querySelector(\"input[name=\\\"formToken\\\"]\");\n//        HtmlInput usernameInput = page.querySelector(\"input[name=\\\"username\\\"]\");\n//        HtmlInput passwordInput = page.querySelector(\"input[name=\\\"password\\\"]\");\n//        HtmlButton signInButton = page.querySelector(\"button.submit\");\n//        assertThat(csrfInput).isNotNull();\n//        assertThat(clientIdInput).isNotNull();\n//        assertThat(formTokenInput).isNotNull();\n//        assertThat(usernameInput).isNotNull();\n//        assertThat(passwordInput).isNotNull();\n//        assertThat(signInButton.getTextContent()).isEqualTo(\"登录\");\n//    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/DefaultAuthorizationServerConsentTests.java",
    "content": "package cn.hiauth.server;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.htmlunit.WebClient;\nimport org.htmlunit.WebResponse;\nimport org.htmlunit.html.DomElement;\nimport org.htmlunit.html.HtmlCheckBoxInput;\nimport org.htmlunit.html.HtmlPage;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;\nimport org.springframework.security.test.context.support.WithMockUser;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.when;\n\n@Slf4j\n@Transactional\n@AutoConfigureMockMvc\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\npublic class DefaultAuthorizationServerConsentTests {\n\n    private final String authorizationRequestUri = UriComponentsBuilder\n            .fromPath(\"/oauth2/authorize\")\n            .queryParam(\"response_type\", \"code\")\n            .queryParam(\"client_id\", AuthServerTests.clientId)\n            .queryParam(\"scope\", AuthServerTests.scope)\n            .queryParam(\"state\", \"state\")\n            .queryParam(\"redirect_uri\", AuthServerTests.redirectUri)\n            .toUriString();\n    @Autowired\n    private WebClient webClient;\n    @MockitoBean\n    private OAuth2AuthorizationConsentService authorizationConsentService;\n\n    @BeforeEach\n    public void setUp() {\n        this.webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);\n        this.webClient.getOptions().setRedirectEnabled(true);\n        this.webClient.getCookieManager().clearCookies();\n        when(this.authorizationConsentService.findById(any(), any())).thenReturn(null);\n    }\n\n    @Test\n    @WithMockUser(\"corpadmin\")\n    public void whenUserConsentsToAllScopesThenReturnAuthorizationCode() throws IOException {\n        final HtmlPage consentPage = this.webClient.getPage(this.authorizationRequestUri);\n        assertThat(consentPage.getTitleText()).isEqualTo(\"统一认证中心\");\n        List<HtmlCheckBoxInput> scopes = new ArrayList<>();\n        consentPage.querySelectorAll(\"input[name='scope']\").forEach(scope -> scopes.add((HtmlCheckBoxInput) scope));\n        for (HtmlCheckBoxInput scope : scopes) {\n            scope.click();\n            scope.click();\n        }\n        List<String> scopeIds = new ArrayList<>();\n        scopes.forEach(scope -> {\n            assertThat(scope.isChecked()).isTrue();\n            scopeIds.add(scope.getId());\n        });\n        assertThat(scopeIds).containsExactlyInAnyOrder(\"profile\");\n        DomElement submitConsentButton = consentPage.querySelector(\"button[id='submit-consent']\");\n        this.webClient.getOptions().setRedirectEnabled(false);\n        WebResponse approveConsentResponse = submitConsentButton.click().getWebResponse();\n        assertThat(approveConsentResponse.getStatusCode()).isEqualTo(HttpStatus.MOVED_PERMANENTLY.value());\n        String location = approveConsentResponse.getResponseHeaderValue(\"location\");\n        assertThat(location).startsWith(AuthServerTests.redirectUri);\n        assertThat(location).contains(\"code=\");\n    }\n\n//    @Test\n//    @WithMockUser(\"corpadmin\")\n//    public void whenUserCancelsConsentThenReturnAccessDeniedError() throws IOException {\n//        final HtmlPage consentPage = this.webClient.getPage(this.authorizationRequestUri);\n//        assertThat(consentPage.getTitleText()).isEqualTo(\"统一认证中心\");\n//        DomElement cancelConsentButton = consentPage.querySelector(\"button[id='cancel-consent']\");\n//        this.webClient.getOptions().setRedirectEnabled(false);\n//        //以后处理\n//        WebResponse cancelConsentResponse = cancelConsentButton.click().getWebResponse();\n//        assertThat(cancelConsentResponse.getStatusCode()).isEqualTo(HttpStatus.MOVED_PERMANENTLY.value());\n//        String location = cancelConsentResponse.getResponseHeaderValue(\"location\");\n//        assertThat(location).startsWith(AuthServerTests.redirectUri);\n//        assertThat(location).contains(\"error=access_denied\");\n//    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/AppResourceServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.AppResource;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\n/**\n * 系统资源\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass AppResourceServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private AppResourceService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        AppResource o = new AppResource();\n        o.setPid(1L);\n        o.setAppId(1L);\n        o.setCode(txt);\n        o.setUrl(txt);\n        o.setName(txt);\n        o.setType(1);\n        o.setRemark(txt);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setCode(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getCode()), \"更新失败\");\n\n        //page\n        Page<AppResource> page = new Page<>(1, 2, true);\n        IPage<AppResource> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n    }\n\n   /* @Test\n    public void findTreeTest() {\n        AppResourceWithKeywordDto dto = new AppResourceWithKeywordDto();\n        dto.setCorpId(1L);\n        List<AppResourceVo> list = service.findListWithKeyword(dto);\n        Assert.isTrue(list.size() > 0,\"查询失败\");\n    }*/\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/AppServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.App;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 应用\n */\n@Slf4j\n//@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass AppServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private AppService service;\n\n    @Test\n    public void CRUDTest() {\n\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"loginTypes\", \"phone,account\");\n\n        //add\n        App o = new App();\n        o.setName(txt);\n        o.setIcon(txt);\n        o.setCreateTime(LocalDateTime.now());\n        o.setCreator(1L);\n        o.setRemark(txt);\n        o.setExtend(map);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setName(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getName()), \"更新失败\");\n\n        //page\n        Page<App> page = new Page<>(1, 2, true);\n        IPage<App> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/CorpServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.Corp;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\n\n/**\n * 租户\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass CorpServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private CorpService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        Corp o = new Corp();\n        o.setName(txt);\n        o.setStatus(1);\n        o.setCreator(1L);\n        o.setUpdater(1L);\n        o.setDeleter(1L);\n        o.setCreateTime(LocalDateTime.now());\n        o.setUpdateTime(LocalDateTime.now());\n        o.setDeleteTime(LocalDateTime.now());\n        o.setIsDeleted(false);\n        o.setAppCount(1);\n        o.setDepCount(1);\n        o.setEmpCount(1);\n        o.setIcon(txt);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setName(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getName()), \"更新失败\");\n\n        //page\n        Page<Corp> page = new Page<>(1, 2, true);\n        IPage<Corp> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/DepartmentServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.Department;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\n\n/**\n * 部门\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass DepartmentServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private DepartmentService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        Department o = new Department();\n        o.setCid(1L);\n        o.setPid(1L);\n        o.setSort(1);\n        o.setNo(txt);\n        o.setName(txt);\n        o.setCreator(1L);\n        o.setUpdater(1L);\n        o.setCreateTime(LocalDateTime.now());\n        o.setUpdateTime(LocalDateTime.now());\n        o.setStatus(1);\n        o.setRemark(txt);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setNo(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getNo()), \"更新失败\");\n\n        //page\n        Page<Department> page = new Page<>(1, 2, true);\n        IPage<Department> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/DictServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.api.dto.dict.DictPageDto;\nimport cn.hiauth.server.entity.Dict;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\n\n/**\n * 字典\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass DictServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private DictService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        Dict o = new Dict();\n        o.setCid(1L);\n        o.setSort(1);\n        o.setCode(txt);\n        o.setPCode(txt);\n        o.setName(txt);\n        o.setValue(txt);\n        o.setIsEnable(false);\n        o.setCreateTime(LocalDateTime.now());\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setCode(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getCode()), \"更新失败\");\n\n        //page\n        Page<Dict> page = new Page<>(1, 2, true);\n        IPage<Dict> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //find root\n        DictPageDto dto = new DictPageDto();\n        dto.setCid(1L);\n        oPage = service.pageByPcode(page, null, txt, false);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/EmployeeServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.Employee;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\n\n/**\n * 员工\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass EmployeeServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private EmployeeService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        Employee o = new Employee();\n        o.setCid(1342L);\n        o.setUserId(2131L);\n        o.setNo(txt);\n        o.setName(txt);\n        o.setEmail(txt);\n        o.setCreator(1L);\n        o.setUpdater(1L);\n        o.setDeleter(1L);\n        o.setCreateTime(LocalDateTime.now());\n        o.setUpdateTime(LocalDateTime.now());\n        o.setDeleteTime(LocalDateTime.now());\n        o.setIsDeleted(false);\n        o.setIsCorpAdmin(false);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setNo(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getNo()), \"更新失败\");\n\n        //page\n        Page<Employee> page = new Page<>(1, 2, true);\n        IPage<Employee> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/FileServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.File;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\n\n/**\n * 文件\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass FileServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private FileService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        File o = new File();\n        o.setCode(txt);\n        o.setOriginName(txt);\n        o.setName(txt);\n        o.setExt(txt);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setCode(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getCode()), \"更新失败\");\n\n        //page\n        Page<File> page = new Page<>(1, 2, true);\n        IPage<File> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/Oauth2AuthorizationConsentServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.Oauth2AuthorizationConsent;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\n/**\n * oauth2认证授权\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass Oauth2AuthorizationConsentServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 10);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private Oauth2AuthorizationConsentService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        Oauth2AuthorizationConsent o = new Oauth2AuthorizationConsent();\n        o.setRegisteredClientId(txt);\n        o.setPrincipalName(txt);\n        o.setAuthorities(txt);\n        service.save(o);\n//\t\tAssert.notNull(o.getId(), \"添加失败\");\n\n        //update\n//\t\t//o.setName(txtNew);\n//\t\tservice.updateById(o);\n//\n//\t\t//get\n//\t\to = service.getById(o.getId());\n//\t\tAssert.notNull(o.getId(), \"主键查询失败\");\n//\t\t//Assert.isTrue(txtNew.equals(o.getName()), \"更新失败\");\n//\n        //page\n        Page<Oauth2AuthorizationConsent> page = new Page<>(1, 2, true);\n        IPage<Oauth2AuthorizationConsent> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n//\n//\t\t//delete\n//\t\tservice.removeById(o.getId());\n//\t\to = service.getById(o.getId());\n//\t\tAssert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/Oauth2AuthorizationServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.Oauth2Authorization;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\n\n/**\n * oauth2认证\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass Oauth2AuthorizationServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private Oauth2AuthorizationService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        Oauth2Authorization o = new Oauth2Authorization();\n        o.setRegisteredClientId(txt);\n        o.setPrincipalName(txt);\n        o.setAuthorizationGrantType(txt);\n        o.setAuthorizedScopes(txt);\n        o.setAttributes(txt);\n        o.setState(txt);\n        o.setAuthorizationCodeValue(txt);\n        o.setAuthorizationCodeIssuedAt(LocalDateTime.now());\n        o.setAuthorizationCodeExpiresAt(LocalDateTime.now());\n        o.setAuthorizationCodeMetadata(txt);\n        o.setAccessTokenValue(txt);\n        o.setAccessTokenIssuedAt(LocalDateTime.now());\n        o.setAccessTokenExpiresAt(LocalDateTime.now());\n        o.setAccessTokenMetadata(txt);\n        o.setAccessTokenType(txt);\n        o.setAccessTokenScopes(txt);\n        o.setOidcIdTokenValue(txt);\n        o.setOidcIdTokenIssuedAt(LocalDateTime.now());\n        o.setOidcIdTokenExpiresAt(LocalDateTime.now());\n        o.setOidcIdTokenMetadata(txt);\n        o.setRefreshTokenValue(txt);\n        o.setRefreshTokenIssuedAt(LocalDateTime.now());\n        o.setRefreshTokenExpiresAt(LocalDateTime.now());\n        o.setRefreshTokenMetadata(txt);\n        o.setUserCodeValue(txt);\n        o.setUserCodeIssuedAt(LocalDateTime.now());\n        o.setUserCodeExpiresAt(LocalDateTime.now());\n        o.setUserCodeMetadata(txt);\n        o.setDeviceCodeValue(txt);\n        o.setDeviceCodeIssuedAt(LocalDateTime.now());\n        o.setDeviceCodeExpiresAt(LocalDateTime.now());\n        o.setDeviceCodeMetadata(txt);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setRegisteredClientId(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getRegisteredClientId()), \"更新失败\");\n\n        //page\n        Page<Oauth2Authorization> page = new Page<>(1, 2, true);\n        IPage<Oauth2Authorization> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/Oauth2RegisteredClientServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.Oauth2RegisteredClient;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\n\n/**\n * oauth2客户端\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass Oauth2RegisteredClientServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private Oauth2RegisteredClientService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        Oauth2RegisteredClient o = new Oauth2RegisteredClient();\n        o.setClientId(txt);\n        o.setClientIdIssuedAt(LocalDateTime.now());\n        o.setClientSecret(txt);\n        o.setClientSecretExpiresAt(LocalDateTime.now());\n        o.setClientName(txt);\n        o.setClientAuthenticationMethods(txt);\n        o.setAuthorizationGrantTypes(txt);\n        o.setRedirectUris(txt);\n        o.setPostLogoutRedirectUris(txt);\n        o.setScopes(txt);\n        o.setClientSettings(txt);\n        o.setTokenSettings(txt);\n        o.setAppId(1L);\n        o.setCid(1L);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setClientId(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getClientId()), \"更新失败\");\n\n        //page\n        Page<Oauth2RegisteredClient> page = new Page<>(1, 2, true);\n        IPage<Oauth2RegisteredClient> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/RoleServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.Role;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\n\n/**\n * 角色\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass RoleServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private RoleService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        Role o = new Role();\n        o.setCid(1L);\n        o.setName(txt);\n        o.setRemark(txt);\n        o.setCreator(1L);\n        o.setUpdater(1L);\n        o.setCreateTime(LocalDateTime.now());\n        o.setUpdateTime(LocalDateTime.now());\n        o.setIsEnable(false);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setName(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getName()), \"更新失败\");\n\n        //page\n        Page<Role> page = new Page<>(1, 2, true);\n        IPage<Role> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/SysLogServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.SysLog;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\n\n/**\n * 系统日志\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass SysLogServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private SysLogService service;\n\n    @Test\n    public void CRUDTest() {\n\n        //add\n        SysLog o = new SysLog();\n        o.setActor(txt);\n        o.setActorIp(txt);\n        o.setActorType(1);\n        o.setEventTime(LocalDateTime.now());\n        o.setEventType(txt);\n        o.setEventLevel(1);\n        o.setEventResult(txt);\n        o.setEventDesc(txt);\n        o.setSourceSys(txt);\n        o.setSourceModule(txt);\n        o.setCreateTime(LocalDateTime.now());\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setActor(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getActor()), \"更新失败\");\n\n        //page\n        Page<SysLog> page = new Page<>(1, 2, true);\n        IPage<SysLog> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "hiauth-server/src/test/java/cn/hiauth/server/service/UserServiceTests.java",
    "content": "package cn.hiauth.server.service;\n\nimport cn.hiauth.server.ServerStarter;\nimport cn.hiauth.server.entity.User;\nimport cn.hutool.core.util.RandomUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport jakarta.annotation.Resource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\nimport java.time.LocalDateTime;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 用户\n */\n@Slf4j\n@Transactional\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = ServerStarter.class)\nclass UserServiceTests {\n\n    private static final String txt = RandomUtil.randomString(\"abcdefghigklmn\", 5);\n\n    private static final String txtNew = txt + \"new\";\n\n    @Resource\n    private UserService service;\n\n    @Test\n    public void CRUDTest() {\n\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"pwdStatus\", 0);\n\n        //add\n        User o = new User();\n        o.setName(txt);\n        o.setGender(1);\n        o.setAvatarUrl(txt);\n        o.setPhoneNum(txt);\n        o.setUsername(txt);\n        o.setPwd(txt);\n        o.setStatus(1);\n        o.setRegtime(LocalDateTime.now());\n        o.setLastLoginTime(LocalDateTime.now());\n        o.setCreator(1L);\n        o.setUpdater(1L);\n        o.setDeleter(1L);\n        o.setCreateTime(LocalDateTime.now());\n        o.setUpdateTime(LocalDateTime.now());\n        o.setDeleteTime(LocalDateTime.now());\n        o.setIsDeleted(false);\n        o.setIsSysAdmin(false);\n        o.setExtend(map);\n        service.save(o);\n        Assert.notNull(o.getId(), \"添加失败\");\n\n        //update\n        o.setName(txtNew);\n        service.updateById(o);\n\n        //get\n        o = service.getById(o.getId());\n        Assert.notNull(o.getId(), \"主键查询失败\");\n        Assert.isTrue(txtNew.equals(o.getName()), \"更新失败\");\n\n        //page\n        Page<User> page = new Page<>(1, 2, true);\n        IPage<User> oPage = service.page(page);\n        Assert.isTrue(oPage.getTotal() > 0, \"分页查询失败\");\n\n        //delete\n        service.removeById(o.getId());\n        o = service.getById(o.getId());\n        Assert.isNull(o, \"删除失败\");\n\n    }\n\n}\n"
  },
  {
    "path": "other/hiauth.sql",
    "content": "\n-- ----------------------------\n-- Table structure for oauth2_authorization\n-- ----------------------------\nDROP TABLE IF EXISTS \"oauth2_authorization\";\nCREATE TABLE \"oauth2_authorization\" (\n  \"id\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"registered_client_id\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"principal_name\" varchar(200) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"authorization_grant_type\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"authorized_scopes\" varchar(1000) COLLATE \"pg_catalog\".\"default\" DEFAULT NULL::character varying,\n  \"attributes\" text COLLATE \"pg_catalog\".\"default\",\n  \"state\" varchar(500) COLLATE \"pg_catalog\".\"default\" DEFAULT NULL::character varying,\n  \"authorization_code_value\" text COLLATE \"pg_catalog\".\"default\",\n  \"authorization_code_issued_at\" timestamp(0),\n  \"authorization_code_expires_at\" timestamp(0),\n  \"authorization_code_metadata\" text COLLATE \"pg_catalog\".\"default\",\n  \"access_token_value\" text COLLATE \"pg_catalog\".\"default\",\n  \"access_token_issued_at\" timestamp(0),\n  \"access_token_expires_at\" timestamp(0),\n  \"access_token_metadata\" text COLLATE \"pg_catalog\".\"default\",\n  \"access_token_type\" varchar(100) COLLATE \"pg_catalog\".\"default\" DEFAULT NULL::character varying,\n  \"access_token_scopes\" varchar(1000) COLLATE \"pg_catalog\".\"default\" DEFAULT NULL::character varying,\n  \"oidc_id_token_value\" text COLLATE \"pg_catalog\".\"default\",\n  \"oidc_id_token_issued_at\" timestamp(0),\n  \"oidc_id_token_expires_at\" timestamp(0),\n  \"oidc_id_token_metadata\" text COLLATE \"pg_catalog\".\"default\",\n  \"refresh_token_value\" text COLLATE \"pg_catalog\".\"default\",\n  \"refresh_token_issued_at\" timestamp(0),\n  \"refresh_token_expires_at\" timestamp(0),\n  \"refresh_token_metadata\" text COLLATE \"pg_catalog\".\"default\",\n  \"user_code_value\" text COLLATE \"pg_catalog\".\"default\",\n  \"user_code_issued_at\" timestamp(0),\n  \"user_code_expires_at\" timestamp(0),\n  \"user_code_metadata\" text COLLATE \"pg_catalog\".\"default\",\n  \"device_code_value\" text COLLATE \"pg_catalog\".\"default\",\n  \"device_code_issued_at\" timestamp(0),\n  \"device_code_expires_at\" timestamp(0),\n  \"device_code_metadata\" text COLLATE \"pg_catalog\".\"default\"\n)\n;\nCOMMENT ON TABLE \"oauth2_authorization\" IS 'oauth2认证';\n\n-- ----------------------------\n-- Table structure for oauth2_authorization_consent\n-- ----------------------------\nDROP TABLE IF EXISTS \"oauth2_authorization_consent\";\nCREATE TABLE \"oauth2_authorization_consent\" (\n  \"registered_client_id\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"principal_name\" varchar(200) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"authorities\" varchar(1000) COLLATE \"pg_catalog\".\"default\" NOT NULL\n)\n;\nCOMMENT ON TABLE \"oauth2_authorization_consent\" IS 'oauth2认证授权';\n\n-- ----------------------------\n-- Table structure for oauth2_registered_client\n-- ----------------------------\nDROP TABLE IF EXISTS \"oauth2_registered_client\";\nCREATE TABLE \"oauth2_registered_client\" (\n  \"id\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"client_id\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"client_id_issued_at\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"client_secret\" varchar(200) COLLATE \"pg_catalog\".\"default\" DEFAULT NULL::character varying,\n  \"client_secret_expires_at\" timestamp(0),\n  \"client_name\" varchar(200) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"client_authentication_methods\" varchar(1000) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"authorization_grant_types\" varchar(1000) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"redirect_uris\" varchar(1000) COLLATE \"pg_catalog\".\"default\" DEFAULT NULL::character varying,\n  \"post_logout_redirect_uris\" varchar(1000) COLLATE \"pg_catalog\".\"default\" DEFAULT NULL::character varying,\n  \"scopes\" varchar(1000) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"client_settings\" varchar(2000) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"token_settings\" varchar(2000) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"app_id\" int8 NOT NULL,\n  \"cid\" int8 NOT NULL\n)\n;\nCOMMENT ON COLUMN \"oauth2_registered_client\".\"app_id\" IS '应用id（自定义扩展字段）';\nCOMMENT ON COLUMN \"oauth2_registered_client\".\"cid\" IS '租户id（自定义扩展字段）';\nCOMMENT ON TABLE \"oauth2_registered_client\" IS 'oauth2客户端';\n\n-- ----------------------------\n-- Records of oauth2_registered_client\n-- ----------------------------\nBEGIN;\nINSERT INTO \"oauth2_registered_client\" (\"id\", \"client_id\", \"client_id_issued_at\", \"client_secret\", \"client_secret_expires_at\", \"client_name\", \"client_authentication_methods\", \"authorization_grant_types\", \"redirect_uris\", \"post_logout_redirect_uris\", \"scopes\", \"client_settings\", \"token_settings\", \"app_id\", \"cid\") VALUES ('abcd-12', 'zhiyuan-admin', '2025-01-01 00:00:00', '{bcrypt}$2a$10$L/QEiqOTG3V8ktKMbBLR0..oaeGXHqAdT5aZ3tRdrMFqS87zCT.yu', NULL, '志远管理系统', 'client_secret_basic,client_secret_post', 'refresh_token,authorization_code,client_credentials,password', 'http://dcss-dev.vking.fun:31080/apisvc-admin/oauth2/token/redirect,http://127.0.0.1:9002/oauth2/token/redirect', 'http://127.0.0.1:8080/', 'openid,profile,user', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-authorization-consent\":true,\"settings.client.require-proof-key\":false,\"cid\":\"1\",\"appId\":\"12\"}', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",36000],\"settings.token.access-token-format\":{\"@class\":\"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat\",\"value\":\"self-contained\"},\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",2592000],\"settings.token.authorization-code-time-to-live\":[\"java.time.Duration\",600],\"settings.token.device-code-time-to-live\":[\"java.time.Duration\",300]}', 12, 1);\nINSERT INTO \"oauth2_registered_client\" (\"id\", \"client_id\", \"client_id_issued_at\", \"client_secret\", \"client_secret_expires_at\", \"client_name\", \"client_authentication_methods\", \"authorization_grant_types\", \"redirect_uris\", \"post_logout_redirect_uris\", \"scopes\", \"client_settings\", \"token_settings\", \"app_id\", \"cid\") VALUES ('abcd-11', 'zhiyuan', '2025-01-01 00:00:00', '{bcrypt}$2a$10$L/QEiqOTG3V8ktKMbBLR0..oaeGXHqAdT5aZ3tRdrMFqS87zCT.yu', NULL, '志远业务系统', 'client_secret_basic,client_secret_post', 'refresh_token,authorization_code,client_credentials,password', 'http://dcss-dev.vking.fun:31080/apisvc-dcss/oauth2/token/redirect,http://127.0.0.1:9001/oauth2/token/redirect', 'http://127.0.0.1:8080/', 'openid,profile,user', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-authorization-consent\":true,\"settings.client.require-proof-key\":false,\"cid\":\"1\",\"appId\":\"11\"}', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",36000],\"settings.token.access-token-format\":{\"@class\":\"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat\",\"value\":\"self-contained\"},\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",2592000],\"settings.token.authorization-code-time-to-live\":[\"java.time.Duration\",600],\"settings.token.device-code-time-to-live\":[\"java.time.Duration\",300]}', 11, 1);\nINSERT INTO \"oauth2_registered_client\" (\"id\", \"client_id\", \"client_id_issued_at\", \"client_secret\", \"client_secret_expires_at\", \"client_name\", \"client_authentication_methods\", \"authorization_grant_types\", \"redirect_uris\", \"post_logout_redirect_uris\", \"scopes\", \"client_settings\", \"token_settings\", \"app_id\", \"cid\") VALUES ('abcd-13', 'zhiyuan-oms', '2025-01-01 00:00:00', '{bcrypt}$2a$10$L/QEiqOTG3V8ktKMbBLR0..oaeGXHqAdT5aZ3tRdrMFqS87zCT.yu', NULL, '志远运营系统', 'client_secret_basic,client_secret_post', 'refresh_token,authorization_code,client_credentials,password', 'http://dcss-dev.vking.fun:31080/apisvc-oms/oauth2/token/redirect,http://127.0.0.1:4000/oauth2/token/redirect', 'http://127.0.0.1:8080/', 'openid,profile,user', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-authorization-consent\":true,\"settings.client.require-proof-key\":false,\"cid\":\"1\",\"appId\":\"13\"}', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",36000],\"settings.token.access-token-format\":{\"@class\":\"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat\",\"value\":\"self-contained\"},\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",2592000],\"settings.token.authorization-code-time-to-live\":[\"java.time.Duration\",600],\"settings.token.device-code-time-to-live\":[\"java.time.Duration\",300]}', 13, 1);\nINSERT INTO \"oauth2_registered_client\" (\"id\", \"client_id\", \"client_id_issued_at\", \"client_secret\", \"client_secret_expires_at\", \"client_name\", \"client_authentication_methods\", \"authorization_grant_types\", \"redirect_uris\", \"post_logout_redirect_uris\", \"scopes\", \"client_settings\", \"token_settings\", \"app_id\", \"cid\") VALUES ('abcd-91', 'himall', '2025-01-01 00:00:00', '{bcrypt}$2a$10$L/QEiqOTG3V8ktKMbBLR0..oaeGXHqAdT5aZ3tRdrMFqS87zCT.yu', NULL, 'HIMALL', 'client_secret_basic,client_secret_post', 'refresh_token,authorization_code,client_credentials,password', 'http://himall.hiauth.com/login/oauth2/code/hiauth-code,http://127.0.0.1:9000/login/oauth2/code/hiauth-code,http://127.0.0.1:9000/oauth2/token/redirect,http://127.0.0.1:9000/home', 'http://127.0.0.1:8080/', 'openid,profile,user', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-authorization-consent\":true,\"settings.client.require-proof-key\":false,\"cid\":\"1\",\"appId\":\"91\"}', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",36000],\"settings.token.access-token-format\":{\"@class\":\"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat\",\"value\":\"self-contained\"},\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",2592000],\"settings.token.authorization-code-time-to-live\":[\"java.time.Duration\",600],\"settings.token.device-code-time-to-live\":[\"java.time.Duration\",300]}', 91, 1);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_app\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_app\";\nCREATE TABLE \"t_app\" (\n  \"id\" int8 NOT NULL,\n  \"cid\" int8,\n  \"name\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"icon\" varchar(200) COLLATE \"pg_catalog\".\"default\",\n  \"create_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"creator\" int8,\n  \"remark\" varchar(200) COLLATE \"pg_catalog\".\"default\",\n  \"home\" varchar(100) COLLATE \"pg_catalog\".\"default\",\n  \"extend\" jsonb\n)\n;\nCOMMENT ON COLUMN \"t_app\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_app\".\"cid\" IS '创建应用的企业CID';\nCOMMENT ON COLUMN \"t_app\".\"name\" IS '名称';\nCOMMENT ON COLUMN \"t_app\".\"icon\" IS '图标';\nCOMMENT ON COLUMN \"t_app\".\"create_time\" IS '创建时间';\nCOMMENT ON COLUMN \"t_app\".\"creator\" IS '创建人';\nCOMMENT ON COLUMN \"t_app\".\"remark\" IS '说明';\nCOMMENT ON COLUMN \"t_app\".\"home\" IS '主页地址';\nCOMMENT ON COLUMN \"t_app\".\"extend\" IS '扩展字段';\nCOMMENT ON TABLE \"t_app\" IS '应用';\n\n-- ----------------------------\n-- Records of t_app\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_app\" (\"id\", \"cid\", \"name\", \"icon\", \"create_time\", \"creator\", \"remark\", \"home\", \"extend\") VALUES (11, NULL, '志远业务系统', '/unpapi/image/7af4deea5db94394b46690c1f14f9a0d.jpg', '2025-01-01 00:00:00', 1, '志远业务系统', NULL, NULL);\nINSERT INTO \"t_app\" (\"id\", \"cid\", \"name\", \"icon\", \"create_time\", \"creator\", \"remark\", \"home\", \"extend\") VALUES (12, NULL, '志远管理系统', '/unpapi/image/ded337a3c4064cff8f7e6a2d607aac2e.jpeg', '2025-01-01 00:00:00', 1, '志远管理系统', NULL, NULL);\nINSERT INTO \"t_app\" (\"id\", \"cid\", \"name\", \"icon\", \"create_time\", \"creator\", \"remark\", \"home\", \"extend\") VALUES (13, NULL, '志远运营系统', '/unpapi/image/de58d213858240ce83681e8194e6ece3.jpeg', '2025-01-01 00:00:00', 1, '志远运营系统', NULL, NULL);\nINSERT INTO \"t_app\" (\"id\", \"cid\", \"name\", \"icon\", \"create_time\", \"creator\", \"remark\", \"home\", \"extend\") VALUES (91, NULL, 'HiMall', '/unpapi/image/f91626c1876c4ff293056efda7fef04c.jpg', '2025-01-01 00:00:00', 1, 'HiMall', NULL, NULL);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_app_resource\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_app_resource\";\nCREATE TABLE \"t_app_resource\" (\n  \"id\" int8 NOT NULL,\n  \"pid\" int8,\n  \"app_id\" int8 NOT NULL,\n  \"code\" varchar(50) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"url\" varchar(50) COLLATE \"pg_catalog\".\"default\",\n  \"name\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"type\" int4 NOT NULL,\n  \"remark\" varchar(50) COLLATE \"pg_catalog\".\"default\",\n  \"extend\" jsonb,\n  \"sort\" int2 NOT NULL DEFAULT 1,\n  \"api\" varchar(50) COLLATE \"pg_catalog\".\"default\"\n)\n;\nCOMMENT ON COLUMN \"t_app_resource\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_app_resource\".\"pid\" IS '父节点';\nCOMMENT ON COLUMN \"t_app_resource\".\"app_id\" IS '应用id';\nCOMMENT ON COLUMN \"t_app_resource\".\"code\" IS '编码';\nCOMMENT ON COLUMN \"t_app_resource\".\"url\" IS '前端地址';\nCOMMENT ON COLUMN \"t_app_resource\".\"name\" IS '名称';\nCOMMENT ON COLUMN \"t_app_resource\".\"type\" IS '资源类型，1：目录、菜单，2：页面，3：功能、接口';\nCOMMENT ON COLUMN \"t_app_resource\".\"remark\" IS '备注';\nCOMMENT ON COLUMN \"t_app_resource\".\"extend\" IS '扩展字段';\nCOMMENT ON COLUMN \"t_app_resource\".\"sort\" IS '排序';\nCOMMENT ON COLUMN \"t_app_resource\".\"api\" IS '接口地址';\nCOMMENT ON TABLE \"t_app_resource\" IS '系统资源';\n\n-- ----------------------------\n-- Records of t_app_resource\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_app_resource\" (\"id\", \"pid\", \"app_id\", \"code\", \"url\", \"name\", \"type\", \"remark\", \"extend\", \"sort\", \"api\") VALUES (12110000, NULL, 12, 'xtgl', '/xtgl', '系统管理', 1, NULL, NULL, 1, '/api/xtgl/*');\nINSERT INTO \"t_app_resource\" (\"id\", \"pid\", \"app_id\", \"code\", \"url\", \"name\", \"type\", \"remark\", \"extend\", \"sort\", \"api\") VALUES (12120000, NULL, 12, 'rzgl', '/rzgl', '日志管理', 1, NULL, NULL, 2, '/api/rzgl/*');\nINSERT INTO \"t_app_resource\" (\"id\", \"pid\", \"app_id\", \"code\", \"url\", \"name\", \"type\", \"remark\", \"extend\", \"sort\", \"api\") VALUES (13140000, NULL, 13, 'xtpz', '/xtpz', '系统配置', 1, NULL, NULL, 4, '/api/xtpz/*');\nINSERT INTO \"t_app_resource\" (\"id\", \"pid\", \"app_id\", \"code\", \"url\", \"name\", \"type\", \"remark\", \"extend\", \"sort\", \"api\") VALUES (13130000, NULL, 13, 'yjsbgl', '/yjsbgl', '硬件设备管理', 1, NULL, NULL, 3, '/api/yjsbgl/*');\nINSERT INTO \"t_app_resource\" (\"id\", \"pid\", \"app_id\", \"code\", \"url\", \"name\", \"type\", \"remark\", \"extend\", \"sort\", \"api\") VALUES (13120000, NULL, 13, 'zxtgl', '/zxtgl', '子系统管理', 1, NULL, NULL, 2, '/api/zxtgl/*');\nINSERT INTO \"t_app_resource\" (\"id\", \"pid\", \"app_id\", \"code\", \"url\", \"name\", \"type\", \"remark\", \"extend\", \"sort\", \"api\") VALUES (13110000, NULL, 13, 'zsgl', '/zsgl', ' 站所管理', 1, NULL, NULL, 1, '/api/zsgl/*');\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_area\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_area\";\nCREATE TABLE \"t_area\" (\n  \"id\" int8 NOT NULL,\n  \"type\" int4 NOT NULL,\n  \"code\" varchar(10) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"p_code\" varchar(10) COLLATE \"pg_catalog\".\"default\",\n  \"name\" varchar(50) COLLATE \"pg_catalog\".\"default\" NOT NULL\n)\n;\nCOMMENT ON COLUMN \"t_area\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_area\".\"type\" IS '类型：1-省，2-市，3-区';\nCOMMENT ON COLUMN \"t_area\".\"code\" IS '区域编码';\nCOMMENT ON COLUMN \"t_area\".\"p_code\" IS '父级区域编码';\nCOMMENT ON COLUMN \"t_area\".\"name\" IS '区域名称';\nCOMMENT ON TABLE \"t_area\" IS '行政区域';\n\n-- ----------------------------\n-- Records of t_area\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_area\" (\"id\", \"type\", \"code\", \"p_code\", \"name\") VALUES (220000, 1, '220000', NULL, '吉林省');\nINSERT INTO \"t_area\" (\"id\", \"type\", \"code\", \"p_code\", \"name\") VALUES (410000, 1, '410000', NULL, '河南省');\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_config\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_config\";\nCREATE TABLE \"t_config\" (\n  \"id\" int8 NOT NULL,\n  \"cid\" int8 NOT NULL,\n  \"sort\" int4 NOT NULL DEFAULT 0,\n  \"code\" varchar(50) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"value\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"create_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP\n)\n;\nCOMMENT ON COLUMN \"t_config\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_config\".\"cid\" IS 'cid';\nCOMMENT ON COLUMN \"t_config\".\"sort\" IS '排序';\nCOMMENT ON COLUMN \"t_config\".\"code\" IS '编码';\nCOMMENT ON COLUMN \"t_config\".\"value\" IS '值';\nCOMMENT ON COLUMN \"t_config\".\"create_time\" IS '创建时间';\nCOMMENT ON TABLE \"t_config\" IS '配置';\n\n-- ----------------------------\n-- Records of t_config\n-- ----------------------------\nBEGIN;\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_corp\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_corp\";\nCREATE TABLE \"t_corp\" (\n  \"id\" int8 NOT NULL,\n  \"name\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"status\" int4 NOT NULL,\n  \"creator\" int8,\n  \"updater\" int8,\n  \"deleter\" int8,\n  \"create_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"update_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"delete_time\" timestamp(0),\n  \"is_deleted\" bool NOT NULL DEFAULT false,\n  \"app_count\" int4 NOT NULL DEFAULT 0,\n  \"dep_count\" int4 NOT NULL DEFAULT 1,\n  \"emp_count\" int4 NOT NULL DEFAULT 1,\n  \"icon\" varchar(200) COLLATE \"pg_catalog\".\"default\"\n)\n;\nCOMMENT ON COLUMN \"t_corp\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_corp\".\"name\" IS '名称';\nCOMMENT ON COLUMN \"t_corp\".\"status\" IS '状态，1：正常';\nCOMMENT ON COLUMN \"t_corp\".\"creator\" IS '创建人';\nCOMMENT ON COLUMN \"t_corp\".\"updater\" IS '更新人';\nCOMMENT ON COLUMN \"t_corp\".\"deleter\" IS '删除人';\nCOMMENT ON COLUMN \"t_corp\".\"create_time\" IS '创建时间';\nCOMMENT ON COLUMN \"t_corp\".\"update_time\" IS '更新时间';\nCOMMENT ON COLUMN \"t_corp\".\"delete_time\" IS '删除时间';\nCOMMENT ON COLUMN \"t_corp\".\"is_deleted\" IS '是否已删除';\nCOMMENT ON COLUMN \"t_corp\".\"app_count\" IS '应用数';\nCOMMENT ON COLUMN \"t_corp\".\"dep_count\" IS '部门数';\nCOMMENT ON COLUMN \"t_corp\".\"emp_count\" IS '员工数';\nCOMMENT ON COLUMN \"t_corp\".\"icon\" IS '图标';\nCOMMENT ON TABLE \"t_corp\" IS '租户';\n\n-- ----------------------------\n-- Records of t_corp\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_corp\" (\"id\", \"name\", \"status\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"app_count\", \"dep_count\", \"emp_count\", \"icon\") VALUES (2, '星途科技', 1, NULL, NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 0, 1, 1, 'https://foruda.gitee.com/avatar/1676910173490791781/395097_bestaone_1602213346.png');\nINSERT INTO \"t_corp\" (\"id\", \"name\", \"status\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"app_count\", \"dep_count\", \"emp_count\", \"icon\") VALUES (3, '天辉智能', 1, NULL, NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 0, 0, 0, NULL);\nINSERT INTO \"t_corp\" (\"id\", \"name\", \"status\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"app_count\", \"dep_count\", \"emp_count\", \"icon\") VALUES (1, '上海志远科技', 1, NULL, NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 0, 1, 1, 'https://foruda.gitee.com/avatar/1676910173490791781/395097_bestaone_1602213346.png');\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_corp_app\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_corp_app\";\nCREATE TABLE \"t_corp_app\" (\n  \"id\" int8 NOT NULL,\n  \"corp_id\" int8 NOT NULL,\n  \"app_id\" int8 NOT NULL\n)\n;\nCOMMENT ON COLUMN \"t_corp_app\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_corp_app\".\"corp_id\" IS '租户id';\nCOMMENT ON COLUMN \"t_corp_app\".\"app_id\" IS '应用id';\nCOMMENT ON TABLE \"t_corp_app\" IS '租户添加的应用';\n\n-- ----------------------------\n-- Records of t_corp_app\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_corp_app\" (\"id\", \"corp_id\", \"app_id\") VALUES (11, 1, 11);\nINSERT INTO \"t_corp_app\" (\"id\", \"corp_id\", \"app_id\") VALUES (12, 1, 12);\nINSERT INTO \"t_corp_app\" (\"id\", \"corp_id\", \"app_id\") VALUES (13, 1, 13);\nINSERT INTO \"t_corp_app\" (\"id\", \"corp_id\", \"app_id\") VALUES (91, 1, 91);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_dep_emp\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_dep_emp\";\nCREATE TABLE \"t_dep_emp\" (\n  \"id\" int8 NOT NULL,\n  \"cid\" int8 NOT NULL,\n  \"emp_id\" int8 NOT NULL,\n  \"dep_id\" int8 NOT NULL\n)\n;\nCOMMENT ON COLUMN \"t_dep_emp\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_dep_emp\".\"cid\" IS '租户id';\nCOMMENT ON COLUMN \"t_dep_emp\".\"emp_id\" IS '员工';\nCOMMENT ON COLUMN \"t_dep_emp\".\"dep_id\" IS '部门';\nCOMMENT ON TABLE \"t_dep_emp\" IS '部门员工关系';\n\n-- ----------------------------\n-- Records of t_dep_emp\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_dep_emp\" (\"id\", \"cid\", \"emp_id\", \"dep_id\") VALUES (1, 1, 1, 21);\nINSERT INTO \"t_dep_emp\" (\"id\", \"cid\", \"emp_id\", \"dep_id\") VALUES (2, 1, 2, 21);\nINSERT INTO \"t_dep_emp\" (\"id\", \"cid\", \"emp_id\", \"dep_id\") VALUES (3, 1, 3, 21);\nINSERT INTO \"t_dep_emp\" (\"id\", \"cid\", \"emp_id\", \"dep_id\") VALUES (4, 1, 4, 21);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_department\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_department\";\nCREATE TABLE \"t_department\" (\n  \"id\" int8 NOT NULL,\n  \"cid\" int8 NOT NULL,\n  \"pid\" int8,\n  \"sort\" int4 NOT NULL DEFAULT 0,\n  \"no\" varchar(10) COLLATE \"pg_catalog\".\"default\",\n  \"name\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"creator\" int8,\n  \"updater\" int8,\n  \"create_time\" timestamp(0),\n  \"update_time\" timestamp(0),\n  \"status\" int4 NOT NULL DEFAULT 1,\n  \"remark\" varchar(100) COLLATE \"pg_catalog\".\"default\"\n)\n;\nCOMMENT ON COLUMN \"t_department\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_department\".\"cid\" IS '租户id';\nCOMMENT ON COLUMN \"t_department\".\"pid\" IS '父部门';\nCOMMENT ON COLUMN \"t_department\".\"sort\" IS '排序号';\nCOMMENT ON COLUMN \"t_department\".\"no\" IS '部门编码';\nCOMMENT ON COLUMN \"t_department\".\"name\" IS '部门名称';\nCOMMENT ON COLUMN \"t_department\".\"creator\" IS '创建人';\nCOMMENT ON COLUMN \"t_department\".\"updater\" IS '更新人';\nCOMMENT ON COLUMN \"t_department\".\"create_time\" IS '创建时间';\nCOMMENT ON COLUMN \"t_department\".\"update_time\" IS '更新时间';\nCOMMENT ON COLUMN \"t_department\".\"status\" IS '状态，0：禁用，1：启用';\nCOMMENT ON COLUMN \"t_department\".\"remark\" IS '备注';\nCOMMENT ON TABLE \"t_department\" IS '部门';\n\n-- ----------------------------\n-- Records of t_department\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_department\" (\"id\", \"cid\", \"pid\", \"sort\", \"no\", \"name\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"status\", \"remark\") VALUES (2, 1, 1, 1, 'NO02', '华东分公司', NULL, NULL, '2024-12-01 00:00:00', '2024-12-01 00:00:00', 1, NULL);\nINSERT INTO \"t_department\" (\"id\", \"cid\", \"pid\", \"sort\", \"no\", \"name\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"status\", \"remark\") VALUES (3, 1, 1, 1, 'NO03', '华北分公司', NULL, NULL, '2024-12-01 00:00:00', '2024-12-01 00:00:00', 1, NULL);\nINSERT INTO \"t_department\" (\"id\", \"cid\", \"pid\", \"sort\", \"no\", \"name\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"status\", \"remark\") VALUES (21, 1, 2, 1, 'NO0201', '研发部', NULL, NULL, '2024-12-01 00:00:00', '2024-12-01 00:00:00', 1, NULL);\nINSERT INTO \"t_department\" (\"id\", \"cid\", \"pid\", \"sort\", \"no\", \"name\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"status\", \"remark\") VALUES (22, 1, 2, 1, 'NO0202', '产品部', NULL, NULL, '2024-12-01 00:00:00', '2024-12-01 00:00:00', 1, NULL);\nINSERT INTO \"t_department\" (\"id\", \"cid\", \"pid\", \"sort\", \"no\", \"name\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"status\", \"remark\") VALUES (1, 1, NULL, 1, 'NO01', '上海志远科技', NULL, NULL, '2024-12-01 00:00:00', '2024-12-01 00:00:00', 1, NULL);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_dict\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_dict\";\nCREATE TABLE \"t_dict\" (\n  \"id\" int8 NOT NULL,\n  \"code\" varchar(50) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"name\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"p_code\" varchar(50) COLLATE \"pg_catalog\".\"default\",\n  \"value\" varchar(50) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"sort\" int4 NOT NULL DEFAULT 1,\n  \"is_enable\" bool DEFAULT false,\n  \"cid\" int8,\n  \"create_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"has_child\" bool NOT NULL DEFAULT false\n)\n;\nCOMMENT ON COLUMN \"t_dict\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_dict\".\"code\" IS '编码';\nCOMMENT ON COLUMN \"t_dict\".\"name\" IS '名称';\nCOMMENT ON COLUMN \"t_dict\".\"p_code\" IS '父编码';\nCOMMENT ON COLUMN \"t_dict\".\"value\" IS '值';\nCOMMENT ON COLUMN \"t_dict\".\"sort\" IS '排序字段';\nCOMMENT ON COLUMN \"t_dict\".\"is_enable\" IS '是否启用';\nCOMMENT ON COLUMN \"t_dict\".\"create_time\" IS '创建时间';\nCOMMENT ON COLUMN \"t_dict\".\"has_child\" IS '是否有子节点';\nCOMMENT ON TABLE \"t_dict\" IS '数据字典表';\n\n-- ----------------------------\n-- Records of t_dict\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_dict\" (\"id\", \"code\", \"name\", \"p_code\", \"value\", \"sort\", \"is_enable\", \"cid\", \"create_time\", \"has_child\") VALUES (10000000002, 'pilot_ability', '飞手能力', NULL, '10200', 0, 't', 1, '2025-01-20 11:25:54', 'f');\nINSERT INTO \"t_dict\" (\"id\", \"code\", \"name\", \"p_code\", \"value\", \"sort\", \"is_enable\", \"cid\", \"create_time\", \"has_child\") VALUES (10000000003, 'drone_license_type', '执照类型', NULL, '10300', 0, 't', 1, '2025-01-20 11:25:54', 'f');\nINSERT INTO \"t_dict\" (\"id\", \"code\", \"name\", \"p_code\", \"value\", \"sort\", \"is_enable\", \"cid\", \"create_time\", \"has_child\") VALUES (10000000004, 'drone_license_level', '执照等级', NULL, '10400', 0, 't', 1, '2025-01-20 11:25:54', 'f');\nINSERT INTO \"t_dict\" (\"id\", \"code\", \"name\", \"p_code\", \"value\", \"sort\", \"is_enable\", \"cid\", \"create_time\", \"has_child\") VALUES (10000000005, 'drone_license_model', '执照机型', NULL, '10500', 0, 't', 1, '2025-01-20 11:25:54', 'f');\nINSERT INTO \"t_dict\" (\"id\", \"code\", \"name\", \"p_code\", \"value\", \"sort\", \"is_enable\", \"cid\", \"create_time\", \"has_child\") VALUES (10000000006, 'uav_type', '无人机类别', NULL, '10600', 0, 't', 1, '2025-01-20 11:25:54', 'f');\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_emp_role\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_emp_role\";\nCREATE TABLE \"t_emp_role\" (\n  \"id\" int8 NOT NULL,\n  \"cid\" int8 NOT NULL,\n  \"role_id\" int8 NOT NULL,\n  \"emp_id\" int8 NOT NULL\n)\n;\nCOMMENT ON COLUMN \"t_emp_role\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_emp_role\".\"cid\" IS '租户id';\nCOMMENT ON COLUMN \"t_emp_role\".\"role_id\" IS '角色';\nCOMMENT ON COLUMN \"t_emp_role\".\"emp_id\" IS '员工';\nCOMMENT ON TABLE \"t_emp_role\" IS '员工角色关系';\n\n-- ----------------------------\n-- Records of t_emp_role\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_emp_role\" (\"id\", \"cid\", \"role_id\", \"emp_id\") VALUES (1, 1, 1, 1);\nINSERT INTO \"t_emp_role\" (\"id\", \"cid\", \"role_id\", \"emp_id\") VALUES (2, 1, 2, 2);\nINSERT INTO \"t_emp_role\" (\"id\", \"cid\", \"role_id\", \"emp_id\") VALUES (3, 1, 3, 3);\nINSERT INTO \"t_emp_role\" (\"id\", \"cid\", \"role_id\", \"emp_id\") VALUES (4, 1, 4, 4);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_employee\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_employee\";\nCREATE TABLE \"t_employee\" (\n  \"id\" int8 NOT NULL,\n  \"cid\" int8 NOT NULL,\n  \"user_id\" int8 NOT NULL,\n  \"no\" varchar(10) COLLATE \"pg_catalog\".\"default\",\n  \"name\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"email\" varchar(50) COLLATE \"pg_catalog\".\"default\",\n  \"creator\" int8,\n  \"updater\" int8,\n  \"deleter\" int8,\n  \"create_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"update_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"delete_time\" timestamp(0),\n  \"is_deleted\" bool NOT NULL DEFAULT false,\n  \"is_corp_admin\" bool NOT NULL DEFAULT false,\n  \"last_login_time\" timestamp(0),\n  \"extend\" jsonb\n)\n;\nCOMMENT ON COLUMN \"t_employee\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_employee\".\"cid\" IS '租户ID';\nCOMMENT ON COLUMN \"t_employee\".\"user_id\" IS '用户id';\nCOMMENT ON COLUMN \"t_employee\".\"no\" IS '员工号';\nCOMMENT ON COLUMN \"t_employee\".\"name\" IS '姓名';\nCOMMENT ON COLUMN \"t_employee\".\"email\" IS '邮箱';\nCOMMENT ON COLUMN \"t_employee\".\"creator\" IS '创建人';\nCOMMENT ON COLUMN \"t_employee\".\"updater\" IS '更新人';\nCOMMENT ON COLUMN \"t_employee\".\"deleter\" IS '删除人';\nCOMMENT ON COLUMN \"t_employee\".\"create_time\" IS '创建时间';\nCOMMENT ON COLUMN \"t_employee\".\"update_time\" IS '更新时间';\nCOMMENT ON COLUMN \"t_employee\".\"delete_time\" IS '删除时间';\nCOMMENT ON COLUMN \"t_employee\".\"is_deleted\" IS '是否已删除';\nCOMMENT ON COLUMN \"t_employee\".\"is_corp_admin\" IS '是否为租户管理员';\nCOMMENT ON COLUMN \"t_employee\".\"last_login_time\" IS '最近一次登录时间';\nCOMMENT ON COLUMN \"t_employee\".\"extend\" IS '扩展字段';\nCOMMENT ON TABLE \"t_employee\" IS '员工';\n\n-- ----------------------------\n-- Records of t_employee\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_employee\" (\"id\", \"cid\", \"user_id\", \"no\", \"name\", \"email\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_corp_admin\", \"last_login_time\", \"extend\") VALUES (2, 1, 12, 'E002', '业务员', 'yw@163.com', NULL, NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 't', NULL, NULL);\nINSERT INTO \"t_employee\" (\"id\", \"cid\", \"user_id\", \"no\", \"name\", \"email\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_corp_admin\", \"last_login_time\", \"extend\") VALUES (3, 1, 13, 'E003', '运营', 'yy@163.com', NULL, NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 't', NULL, NULL);\nINSERT INTO \"t_employee\" (\"id\", \"cid\", \"user_id\", \"no\", \"name\", \"email\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_corp_admin\", \"last_login_time\", \"extend\") VALUES (4, 1, 14, 'E004', '审计员', 'sj@163.com', NULL, NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 't', NULL, NULL);\nINSERT INTO \"t_employee\" (\"id\", \"cid\", \"user_id\", \"no\", \"name\", \"email\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_corp_admin\", \"last_login_time\", \"extend\") VALUES (1, 1, 11, 'E001', '管理员', 'admin@163.com', NULL, NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 't', '2025-07-22 18:49:32', NULL);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_file\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_file\";\nCREATE TABLE \"t_file\" (\n  \"id\" int8 NOT NULL,\n  \"code\" varchar(50) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"name\" varchar(50) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"ext\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"data\" bytea,\n  \"origin_name\" varchar(50) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"create_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP\n)\n;\nCOMMENT ON COLUMN \"t_file\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_file\".\"code\" IS '编码';\nCOMMENT ON COLUMN \"t_file\".\"name\" IS '名称';\nCOMMENT ON COLUMN \"t_file\".\"ext\" IS '扩展名';\nCOMMENT ON COLUMN \"t_file\".\"data\" IS '数据';\nCOMMENT ON COLUMN \"t_file\".\"origin_name\" IS '原始名称';\nCOMMENT ON COLUMN \"t_file\".\"create_time\" IS '创建时间';\nCOMMENT ON TABLE \"t_file\" IS '文件';\n\n-- ----------------------------\n-- Records of t_file\n-- ----------------------------\n\n\n-- ----------------------------\n-- Table structure for t_role\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_role\";\nCREATE TABLE \"t_role\" (\n  \"id\" int8 NOT NULL,\n  \"cid\" int8 NOT NULL,\n  \"name\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"remark\" varchar(100) COLLATE \"pg_catalog\".\"default\",\n  \"creator\" int8,\n  \"updater\" int8,\n  \"create_time\" timestamp(0) NOT NULL,\n  \"update_time\" timestamp(0) NOT NULL,\n  \"is_enable\" bool DEFAULT true,\n  \"status\" varchar COLLATE \"pg_catalog\".\"default\" DEFAULT 1\n)\n;\nCOMMENT ON COLUMN \"t_role\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_role\".\"cid\" IS 'cid';\nCOMMENT ON COLUMN \"t_role\".\"name\" IS '名称';\nCOMMENT ON COLUMN \"t_role\".\"remark\" IS '备注';\nCOMMENT ON COLUMN \"t_role\".\"creator\" IS '创建人';\nCOMMENT ON COLUMN \"t_role\".\"updater\" IS '更新人';\nCOMMENT ON COLUMN \"t_role\".\"create_time\" IS '创建时间';\nCOMMENT ON COLUMN \"t_role\".\"update_time\" IS '更新时间';\nCOMMENT ON COLUMN \"t_role\".\"is_enable\" IS '是否可用';\nCOMMENT ON COLUMN \"t_role\".\"status\" IS '启用状态，0：禁用，1：启用';\nCOMMENT ON TABLE \"t_role\" IS '角色';\n\n-- ----------------------------\n-- Records of t_role\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_role\" (\"id\", \"cid\", \"name\", \"remark\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"is_enable\", \"status\") VALUES (1, 1, '企业管理员', '企业管理员', NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', 't', '1');\nINSERT INTO \"t_role\" (\"id\", \"cid\", \"name\", \"remark\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"is_enable\", \"status\") VALUES (2, 1, '业务员', '业务员', NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', 't', '1');\nINSERT INTO \"t_role\" (\"id\", \"cid\", \"name\", \"remark\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"is_enable\", \"status\") VALUES (3, 1, '运营', '运营', NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', 't', '1');\nINSERT INTO \"t_role\" (\"id\", \"cid\", \"name\", \"remark\", \"creator\", \"updater\", \"create_time\", \"update_time\", \"is_enable\", \"status\") VALUES (4, 1, '审计员', '审计员', NULL, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', 't', '1');\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_role_app_resource\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_role_app_resource\";\nCREATE TABLE \"t_role_app_resource\" (\n  \"id\" int8 NOT NULL,\n  \"cid\" int8 NOT NULL,\n  \"role_id\" int8 NOT NULL,\n  \"app_resource_id\" int8 NOT NULL,\n  \"app_id\" int8 NOT NULL\n)\n;\nCOMMENT ON COLUMN \"t_role_app_resource\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_role_app_resource\".\"cid\" IS '租户';\nCOMMENT ON COLUMN \"t_role_app_resource\".\"role_id\" IS '角色';\nCOMMENT ON COLUMN \"t_role_app_resource\".\"app_resource_id\" IS '资源';\nCOMMENT ON COLUMN \"t_role_app_resource\".\"app_id\" IS '应用id';\nCOMMENT ON TABLE \"t_role_app_resource\" IS '角色和应用资源关系';\n\n-- ----------------------------\n-- Records of t_role_app_resource\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119424, 1, 3, 10111512, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119425, 1, 3, 10131800, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119426, 1, 3, 10111513, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119427, 1, 3, 10121311, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119428, 1, 3, 10131100, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119429, 1, 3, 10130000, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119430, 1, 3, 10131600, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119431, 1, 3, 10170000, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119432, 1, 3, 10210000, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119433, 1, 3, 10111511, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119434, 1, 3, 10121111, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119435, 1, 3, 10111700, 11);\nINSERT INTO \"t_role_app_resource\" (\"id\", \"cid\", \"role_id\", \"app_resource_id\", \"app_id\") VALUES (1856297430726119436, 1, 3, 10121300, 11);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_sys_log\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_sys_log\";\nCREATE TABLE \"t_sys_log\" (\n  \"id\" int8 NOT NULL,\n  \"actor\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"actor_ip\" varchar(20) COLLATE \"pg_catalog\".\"default\",\n  \"actor_type\" int4 NOT NULL,\n  \"event_time\" timestamp(0) NOT NULL,\n  \"event_desc\" varchar(200) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"create_time\" timestamp(0) NOT NULL,\n  \"actor_user_id\" int8,\n  \"event_type\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"event_level\" int4 NOT NULL DEFAULT 1,\n  \"event_result\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"source_sys\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"username\" varchar(20) COLLATE \"pg_catalog\".\"default\",\n  \"cid\" int8,\n  \"actor_emp_id\" int8,\n  \"source_module\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL\n)\n;\nCOMMENT ON COLUMN \"t_sys_log\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_sys_log\".\"actor\" IS '事件触发者';\nCOMMENT ON COLUMN \"t_sys_log\".\"actor_ip\" IS '触发者ip';\nCOMMENT ON COLUMN \"t_sys_log\".\"actor_type\" IS '触发者类型，1：系统，2：员工';\nCOMMENT ON COLUMN \"t_sys_log\".\"event_time\" IS '事件产生时间';\nCOMMENT ON COLUMN \"t_sys_log\".\"event_desc\" IS '事件描述';\nCOMMENT ON COLUMN \"t_sys_log\".\"create_time\" IS '创建时间';\nCOMMENT ON COLUMN \"t_sys_log\".\"actor_user_id\" IS '事件触发者用户id';\nCOMMENT ON COLUMN \"t_sys_log\".\"event_type\" IS '事件分类';\nCOMMENT ON COLUMN \"t_sys_log\".\"event_level\" IS '事件等级';\nCOMMENT ON COLUMN \"t_sys_log\".\"event_result\" IS '事件结果';\nCOMMENT ON COLUMN \"t_sys_log\".\"source_sys\" IS '事件产生的系统';\nCOMMENT ON COLUMN \"t_sys_log\".\"username\" IS '触发者的用户名';\nCOMMENT ON COLUMN \"t_sys_log\".\"cid\" IS '租户id';\nCOMMENT ON COLUMN \"t_sys_log\".\"actor_emp_id\" IS '触发者员工id';\nCOMMENT ON COLUMN \"t_sys_log\".\"source_module\" IS '事件产生的模块';\nCOMMENT ON TABLE \"t_sys_log\" IS '系统日志';\n\n-- ----------------------------\n-- Records of t_sys_log\n-- ----------------------------\nBEGIN;\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for t_user\n-- ----------------------------\nDROP TABLE IF EXISTS \"t_user\";\nCREATE TABLE \"t_user\" (\n  \"id\" int8 NOT NULL,\n  \"name\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"gender\" int4 NOT NULL DEFAULT 0,\n  \"avatar_url\" varchar(100) COLLATE \"pg_catalog\".\"default\",\n  \"phone_num\" varchar(20) COLLATE \"pg_catalog\".\"default\",\n  \"username\" varchar(20) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"pwd\" varchar(100) COLLATE \"pg_catalog\".\"default\" NOT NULL,\n  \"status\" int4 NOT NULL DEFAULT 1,\n  \"regtime\" timestamp(0) NOT NULL,\n  \"last_login_time\" timestamp(0),\n  \"creator\" int8,\n  \"updater\" int8,\n  \"deleter\" int8,\n  \"create_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"update_time\" timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  \"delete_time\" timestamp(0),\n  \"is_deleted\" bool NOT NULL DEFAULT false,\n  \"is_sys_admin\" bool NOT NULL DEFAULT false,\n  \"registe_channel\" varchar(50) COLLATE \"pg_catalog\".\"default\",\n  \"wx_openid\" varchar(50) COLLATE \"pg_catalog\".\"default\",\n  \"wx_unionid\" varchar(50) COLLATE \"pg_catalog\".\"default\",\n  \"wxmp_openid\" varchar(50) COLLATE \"pg_catalog\".\"default\",\n  \"extend\" jsonb\n)\n;\nCOMMENT ON COLUMN \"t_user\".\"id\" IS '主键';\nCOMMENT ON COLUMN \"t_user\".\"name\" IS '名称';\nCOMMENT ON COLUMN \"t_user\".\"gender\" IS '性别，0：未知，1：男，2：女';\nCOMMENT ON COLUMN \"t_user\".\"avatar_url\" IS '头像';\nCOMMENT ON COLUMN \"t_user\".\"phone_num\" IS '手机号码';\nCOMMENT ON COLUMN \"t_user\".\"username\" IS '用户名';\nCOMMENT ON COLUMN \"t_user\".\"pwd\" IS '密码';\nCOMMENT ON COLUMN \"t_user\".\"status\" IS '状态，0：禁用，1：启用';\nCOMMENT ON COLUMN \"t_user\".\"regtime\" IS '注册时间';\nCOMMENT ON COLUMN \"t_user\".\"last_login_time\" IS '最后登录时间';\nCOMMENT ON COLUMN \"t_user\".\"creator\" IS '创建人';\nCOMMENT ON COLUMN \"t_user\".\"updater\" IS '更新人';\nCOMMENT ON COLUMN \"t_user\".\"deleter\" IS '删除人';\nCOMMENT ON COLUMN \"t_user\".\"create_time\" IS '创建时间';\nCOMMENT ON COLUMN \"t_user\".\"update_time\" IS '更新时间';\nCOMMENT ON COLUMN \"t_user\".\"delete_time\" IS '删除时间';\nCOMMENT ON COLUMN \"t_user\".\"is_deleted\" IS '是否已删除';\nCOMMENT ON COLUMN \"t_user\".\"is_sys_admin\" IS '是否为系统管理员';\nCOMMENT ON COLUMN \"t_user\".\"registe_channel\" IS '注册去渠道';\nCOMMENT ON COLUMN \"t_user\".\"wx_openid\" IS '微信openid';\nCOMMENT ON COLUMN \"t_user\".\"wx_unionid\" IS '微信unionid';\nCOMMENT ON COLUMN \"t_user\".\"wxmp_openid\" IS '微信小程序openid';\nCOMMENT ON COLUMN \"t_user\".\"extend\" IS '扩展字段';\nCOMMENT ON TABLE \"t_user\" IS '用户';\n\n-- ----------------------------\n-- Records of t_user\n-- ----------------------------\nBEGIN;\nINSERT INTO \"t_user\" (\"id\", \"name\", \"gender\", \"avatar_url\", \"phone_num\", \"username\", \"pwd\", \"status\", \"regtime\", \"last_login_time\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_sys_admin\", \"registe_channel\", \"wx_openid\", \"wx_unionid\", \"wxmp_openid\", \"extend\") VALUES (14, '审计员', 0, '/unpapi/image/f0531da94c93447a9f7398dabba6474c.jpg', '13400000004', 'usersj', '{bcrypt}$2a$10$YtvFLcaEdnv4kWM62eHpm.8C2xm9CSLUzsN53JzenyxcroaqeblWy', 1, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 1, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 'f', NULL, NULL, NULL, NULL, NULL);\nINSERT INTO \"t_user\" (\"id\", \"name\", \"gender\", \"avatar_url\", \"phone_num\", \"username\", \"pwd\", \"status\", \"regtime\", \"last_login_time\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_sys_admin\", \"registe_channel\", \"wx_openid\", \"wx_unionid\", \"wxmp_openid\", \"extend\") VALUES (2, '系统管理员', 1, '/unpapi/image/090003179b164eeca6b7dae3bf619379.jpeg', '13488888888', 'admin', '{bcrypt}$2a$10$YtvFLcaEdnv4kWM62eHpm.8C2xm9CSLUzsN53JzenyxcroaqeblWy', 1, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 1, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 't', NULL, NULL, NULL, NULL, NULL);\nINSERT INTO \"t_user\" (\"id\", \"name\", \"gender\", \"avatar_url\", \"phone_num\", \"username\", \"pwd\", \"status\", \"regtime\", \"last_login_time\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_sys_admin\", \"registe_channel\", \"wx_openid\", \"wx_unionid\", \"wxmp_openid\", \"extend\") VALUES (1, '超级管理员', 1, '/unpapi/image/090003179b164eeca6b7dae3bf619379.jpeg', '13466666666', 'superadmin', '{bcrypt}$2a$10$YtvFLcaEdnv4kWM62eHpm.8C2xm9CSLUzsN53JzenyxcroaqeblWy', 1, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 1, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 't', NULL, NULL, NULL, NULL, NULL);\nINSERT INTO \"t_user\" (\"id\", \"name\", \"gender\", \"avatar_url\", \"phone_num\", \"username\", \"pwd\", \"status\", \"regtime\", \"last_login_time\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_sys_admin\", \"registe_channel\", \"wx_openid\", \"wx_unionid\", \"wxmp_openid\", \"extend\") VALUES (12, '业务员', 1, '/unpapi/image/23cc6f77dd9d490182be03ba393e672b.jpeg', '13400000002', 'useryw', '{bcrypt}$2a$10$YtvFLcaEdnv4kWM62eHpm.8C2xm9CSLUzsN53JzenyxcroaqeblWy', 1, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 1, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 'f', NULL, NULL, NULL, NULL, NULL);\nINSERT INTO \"t_user\" (\"id\", \"name\", \"gender\", \"avatar_url\", \"phone_num\", \"username\", \"pwd\", \"status\", \"regtime\", \"last_login_time\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_sys_admin\", \"registe_channel\", \"wx_openid\", \"wx_unionid\", \"wxmp_openid\", \"extend\") VALUES (11, '企业管理员', 1, '/unpapi/image/2c924149ddfe4bd181959ee9bede10c0.jpeg', '13400000001', 'corpadmin', '{bcrypt}$2a$10$YtvFLcaEdnv4kWM62eHpm.8C2xm9CSLUzsN53JzenyxcroaqeblWy', 1, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 1, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 'f', NULL, NULL, NULL, NULL, NULL);\nINSERT INTO \"t_user\" (\"id\", \"name\", \"gender\", \"avatar_url\", \"phone_num\", \"username\", \"pwd\", \"status\", \"regtime\", \"last_login_time\", \"creator\", \"updater\", \"deleter\", \"create_time\", \"update_time\", \"delete_time\", \"is_deleted\", \"is_sys_admin\", \"registe_channel\", \"wx_openid\", \"wx_unionid\", \"wxmp_openid\", \"extend\") VALUES (13, '运营', 1, '/unpapi/image/23cc6f77dd9d490182be03ba393e672b.jpeg', '13400000003', 'useryy', '{bcrypt}$2a$10$YtvFLcaEdnv4kWM62eHpm.8C2xm9CSLUzsN53JzenyxcroaqeblWy', 1, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 1, NULL, '2025-01-01 00:00:00', '2025-01-01 00:00:00', NULL, 'f', 'f', NULL, NULL, NULL, NULL, NULL);\nCOMMIT;\n\n-- ----------------------------\n-- Primary Key structure for table oauth2_authorization\n-- ----------------------------\nALTER TABLE \"oauth2_authorization\" ADD CONSTRAINT \"oauth2_authorization_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Primary Key structure for table oauth2_authorization_consent\n-- ----------------------------\nALTER TABLE \"oauth2_authorization_consent\" ADD CONSTRAINT \"oauth2_authorization_consent_pkey\" PRIMARY KEY (\"registered_client_id\", \"principal_name\");\n\n-- ----------------------------\n-- Primary Key structure for table oauth2_registered_client\n-- ----------------------------\nALTER TABLE \"oauth2_registered_client\" ADD CONSTRAINT \"oauth2_registered_client_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Primary Key structure for table t_app\n-- ----------------------------\nALTER TABLE \"t_app\" ADD CONSTRAINT \"t_app_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_app_resource\n-- ----------------------------\nALTER TABLE \"t_app_resource\" ADD CONSTRAINT \"uk_app_id_code\" UNIQUE (\"app_id\", \"code\");\nCOMMENT ON CONSTRAINT \"uk_app_id_code\" ON \"t_app_resource\" IS '资源编码唯一';\n\n-- ----------------------------\n-- Primary Key structure for table t_app_resource\n-- ----------------------------\nALTER TABLE \"t_app_resource\" ADD CONSTRAINT \"t_resource_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Indexes structure for table t_area\n-- ----------------------------\nCREATE INDEX \"area_idx_p_code\" ON \"t_area\" USING btree (\n  \"p_code\" COLLATE \"pg_catalog\".\"default\" \"pg_catalog\".\"text_ops\" ASC NULLS LAST\n);\n\n-- ----------------------------\n-- Uniques structure for table t_area\n-- ----------------------------\nALTER TABLE \"t_area\" ADD CONSTRAINT \"area_uk_code\" UNIQUE (\"code\");\n\n-- ----------------------------\n-- Primary Key structure for table t_area\n-- ----------------------------\nALTER TABLE \"t_area\" ADD CONSTRAINT \"t_area_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_config\n-- ----------------------------\nALTER TABLE \"t_config\" ADD CONSTRAINT \"config_uk_cid_code\" UNIQUE (\"cid\", \"code\");\n\n-- ----------------------------\n-- Primary Key structure for table t_config\n-- ----------------------------\nALTER TABLE \"t_config\" ADD CONSTRAINT \"t_config_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Primary Key structure for table t_corp\n-- ----------------------------\nALTER TABLE \"t_corp\" ADD CONSTRAINT \"t_corp_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Primary Key structure for table t_corp_app\n-- ----------------------------\nALTER TABLE \"t_corp_app\" ADD CONSTRAINT \"t_corp_app_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_dep_emp\n-- ----------------------------\nALTER TABLE \"t_dep_emp\" ADD CONSTRAINT \"uk_dep_emp_ed\" UNIQUE (\"emp_id\", \"dep_id\");\n\n-- ----------------------------\n-- Primary Key structure for table t_dep_emp\n-- ----------------------------\nALTER TABLE \"t_dep_emp\" ADD CONSTRAINT \"t_emp_dep_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_department\n-- ----------------------------\nALTER TABLE \"t_department\" ADD CONSTRAINT \"uk_dep_cn\" UNIQUE (\"cid\", \"no\");\nCOMMENT ON CONSTRAINT \"uk_dep_cn\" ON \"t_department\" IS '企业内部门编号唯一';\n\n-- ----------------------------\n-- Primary Key structure for table t_department\n-- ----------------------------\nALTER TABLE \"t_department\" ADD CONSTRAINT \"t_department_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_dict\n-- ----------------------------\nALTER TABLE \"t_dict\" ADD CONSTRAINT \"uk_t_dict_code\" UNIQUE (\"code\", \"p_code\");\n\n-- ----------------------------\n-- Primary Key structure for table t_dict\n-- ----------------------------\nALTER TABLE \"t_dict\" ADD CONSTRAINT \"t_dict_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_emp_role\n-- ----------------------------\nALTER TABLE \"t_emp_role\" ADD CONSTRAINT \"uk_emp_role_re\" UNIQUE (\"role_id\", \"emp_id\");\n\n-- ----------------------------\n-- Primary Key structure for table t_emp_role\n-- ----------------------------\nALTER TABLE \"t_emp_role\" ADD CONSTRAINT \"t_role_emp_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_employee\n-- ----------------------------\nALTER TABLE \"t_employee\" ADD CONSTRAINT \"uk_emp_cu\" UNIQUE (\"cid\", \"user_id\");\nCOMMENT ON CONSTRAINT \"uk_emp_cu\" ON \"t_employee\" IS '企业下员工唯一';\n\n-- ----------------------------\n-- Primary Key structure for table t_employee\n-- ----------------------------\nALTER TABLE \"t_employee\" ADD CONSTRAINT \"t_employee_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_file\n-- ----------------------------\nALTER TABLE \"t_file\" ADD CONSTRAINT \"uk_code\" UNIQUE (\"code\");\n\n-- ----------------------------\n-- Primary Key structure for table t_file\n-- ----------------------------\nALTER TABLE \"t_file\" ADD CONSTRAINT \"t_file_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Primary Key structure for table t_role\n-- ----------------------------\nALTER TABLE \"t_role\" ADD CONSTRAINT \"t_role_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_role_app_resource\n-- ----------------------------\nALTER TABLE \"t_role_app_resource\" ADD CONSTRAINT \"uk_role_app_resource_ra\" UNIQUE (\"role_id\", \"app_resource_id\");\nCOMMENT ON CONSTRAINT \"uk_role_app_resource_ra\" ON \"t_role_app_resource\" IS '角色与资源关系绑定唯一';\n\n-- ----------------------------\n-- Primary Key structure for table t_role_app_resource\n-- ----------------------------\nALTER TABLE \"t_role_app_resource\" ADD CONSTRAINT \"t_role_app_resource_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Primary Key structure for table t_sys_log\n-- ----------------------------\nALTER TABLE \"t_sys_log\" ADD CONSTRAINT \"t_sys_log_pkey\" PRIMARY KEY (\"id\");\n\n-- ----------------------------\n-- Uniques structure for table t_user\n-- ----------------------------\nALTER TABLE \"t_user\" ADD CONSTRAINT \"uk_user_username\" UNIQUE (\"username\", \"is_deleted\");\nALTER TABLE \"t_user\" ADD CONSTRAINT \"uk_user_phone_num\" UNIQUE (\"phone_num\", \"is_deleted\");\nALTER TABLE \"t_user\" ADD CONSTRAINT \"uk_wx_unionid\" UNIQUE (\"wx_unionid\");\nALTER TABLE \"t_user\" ADD CONSTRAINT \"uk_wx_openid\" UNIQUE (\"wx_openid\");\nCOMMENT ON CONSTRAINT \"uk_user_username\" ON \"t_user\" IS '用户名唯一';\nCOMMENT ON CONSTRAINT \"uk_user_phone_num\" ON \"t_user\" IS '手机号唯一';\nCOMMENT ON CONSTRAINT \"uk_wx_unionid\" ON \"t_user\" IS '微信unionid';\nCOMMENT ON CONSTRAINT \"uk_wx_openid\" ON \"t_user\" IS '微信openid';\n\n-- ----------------------------\n-- Primary Key structure for table t_user\n-- ----------------------------\nALTER TABLE \"t_user\" ADD CONSTRAINT \"t_user_pkey\" PRIMARY KEY (\"id\");\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.hiauth</groupId>\n    <artifactId>HiAuth</artifactId>\n    <version>3.0.0-SNAPSHOT</version>\n    <packaging>pom</packaging>\n\n    <modules>\n<!--        <module>hiauth-client-starter</module>-->\n        <module>hiauth-server</module>\n        <module>example/hiauth-server-exp</module>\n        <module>example/hiauth-client-exp</module>\n        <module>example/demo</module>\n        <module>example/himall</module>\n        <module>example/hiauth-client</module>\n        <module>example/spring-cloud</module>\n        <module>example/spring-cloud-with-hiauth-client</module>\n        <module>example/wechat-login</module>\n        <module>example/resource</module>\n    </modules>\n\n</project>\n"
  }
]