立即开始!
无需部署,立刻体验。我们为客户提供了强大稳健的 Saas 平台,通过访问 FinClip Clou 即可快速体验。
diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml deleted file mode 100644 index 08f2ad0..0000000 --- a/.github/workflows/documentation.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: documentation - -on: - pull_request: - branches: [main] - push: - branches: [main] - -jobs: - checks: - if: github.event_name != 'push' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Test Build - run: | - if [ -e yarn.lock ]; then - yarn install --frozen-lockfile - elif [ -e package-lock.json ]; then - npm ci - else - npm i - fi - npm run build - gh-release: - if: github.event_name != 'pull_request' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - uses: webfactory/ssh-agent@v0.5.0 - with: - ssh-private-key: ${{ secrets.GH_PAGES_DEPLOY }} - - name: Release to GitHub Pages - env: - USE_SSH: true - GIT_USER: xulis - run: | - git config --global user.email "xulishan@finogeeks.com" - git config --global user.name "xulis" - if [ -e yarn.lock ]; then - yarn install --frozen-lockfile - elif [ -e package-lock.json ]; then - npm ci - else - npm i - fi - npm run deploy diff --git a/README.md b/README.md deleted file mode 100644 index 0798fa7..0000000 --- a/README.md +++ /dev/null @@ -1,44 +0,0 @@ -
-
-
-
-
- FinClip 运维文档项目 -
-
- 👉 https://devops.finclip.com/ 👈 -
- ---- -## FinClip 是什么? -[FinClip](https://www.finclip.com/) 是基于自研、领先的小程序容器技术,让任何企业的 APP 均获得嵌入该容器而瞬间运行小程序的能力,轻松实现移动应用的动态发布,与业务内容的跨端投放。 - -FinClip提供私有化解决方案,本项目旨在提供FinClip私有化的运行维护的文档支持,由FinClip运维团队提供。当然,如果您有意与我们一同完善这个文档项目,也欢迎提交内容到本仓库。 - -## 安装 -本文档项目采用 [Docusaurus 2](https://docusaurus.io/) 构建,仓库已配置GitHub Actions,当你提交内容到本仓库之后,可以直接访问 https://devops.finclip.com/ 查看新的内容。 - -当然,你也可以在自己的电脑中运行此文档网站,通过以下命令可以进行安装,需要依赖Node运行环境: - -```console -yarn install -``` - -## 本地开发 - -```console -yarn start -``` - -这个命令将在你的本地环境启动一个Web服务器,你可以通过访问这个服务实时查看更改。 - -## 编译 - -```console -yarn build -``` - -该命令将文档构建生成静态网页,内容默认回报存在项目目录下的`build`目录。 - diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index e00595d..0000000 --- a/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')], -}; diff --git a/blog/2021-08-30-frp.md b/blog/2021-08-30-frp.md deleted file mode 100644 index b75ebaf..0000000 --- a/blog/2021-08-30-frp.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -slug: frp -title: frp实现内网穿透 -author: yangyehong@finogeeks.com -author_title: yehong -author_url: https://github.com/yangyehong -author_image_url: https://avatars.githubusercontent.com/u/31943904?v=4 -tags: [frp, ops] ---- - -**项目地址:** - -https://github.com/fatedier/frp - -### 功能 - -通过frp,使处于内网或无固定公网ip的机器,对外网环境提供 tcp 和 udp 服务,例如在家里通过 ssh 访问处于公司内网环境内的主机 - -### 准备 - - **1. 公网服务器1台 (服务端)** - - **2. 内网电脑 1 台 (客户端)** - - -### 安装 - -### 1. 下载安装包。 - -**https://github.com/fatedier/frp/releases** - - -**都执行** - -```shell -mkdir -p /opt/frp - -cd /opt/frp - -wget https://github.com/fatedier/frp/releases/download/v0.25.0/frp_0.25.0_linux_amd64.tar.gz - -tar -zxvf frp_0.25.0_linux_amd64.tar.gz -``` - -### 2.服务端配置 - -```shell -chmod +x ./frps -vi ./frps.ini - -[common] -bind_port = 7000 #与客户端绑定的进行通信的端口 - -#启动 -nohup ./frps -c ./frps.ini & -``` - -### 3.客户端配置 - -```shell -chmod +x ./frpc -vi ./frpc.ini - -[common] -server_addr = 192.168.1.1 #服务端地址 -server_port = 7000 #对应端口 - -[ssh] -type = tcp #协议 -local_ip = 127.0.0.1 #本机ip -local_port = 22 #ssh默认端口号 -remote_port = 6000 #连接客户端端口,注意多个客户端时不能相同 - -#启动 -nohup ./frpc -c ./frpc.ini & -``` - - -### 4.验证 - -当客户端成功连上服务端时,服务端会监听客户端上自定义的端口。访问 -服务端地址 192.168.1.1 + 自定义端口 6000 即可 diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 0000000..bd3d304 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,28 @@ + + + + + +FinClip 运维文档项目
FinClip 是基于自研、领先的小程序容器技术,让任何企业的 APP 均获得嵌入该容器而瞬间运行小程序的能力,轻松实现移动应用的动态发布,与业务内容的跨端投放。
FinClip提供私有化解决方案,本项目旨在提供FinClip私有化的运行维护的文档支持,由FinClip运维团队提供。当然,如果您有意与我们一同完善这个文档项目,也欢迎提交内容到本仓库。
',7)]))}const d=e(p,[["render",r]]);export{h as __pageData,d as default}; diff --git a/docs/assets/README.md.B-u3jNj9.lean.js b/docs/assets/README.md.B-u3jNj9.lean.js new file mode 100644 index 0000000..9bdbeaf --- /dev/null +++ b/docs/assets/README.md.B-u3jNj9.lean.js @@ -0,0 +1 @@ +import{_ as e,c as i,a9 as a,o as n}from"./chunks/framework.BjXht68r.js";const h=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"README.md","filePath":"README.md"}'),p={name:"README.md"};function r(o,t,l,s,c,f){return n(),i("div",null,t[0]||(t[0]=[a('FinClip 运维文档项目
FinClip 是基于自研、领先的小程序容器技术,让任何企业的 APP 均获得嵌入该容器而瞬间运行小程序的能力,轻松实现移动应用的动态发布,与业务内容的跨端投放。
FinClip提供私有化解决方案,本项目旨在提供FinClip私有化的运行维护的文档支持,由FinClip运维团队提供。当然,如果您有意与我们一同完善这个文档项目,也欢迎提交内容到本仓库。
',7)]))}const d=e(p,[["render",r]]);export{h as __pageData,d as default}; diff --git a/docs/assets/app.Dv3XxakT.js b/docs/assets/app.Dv3XxakT.js new file mode 100644 index 0000000..4e52ca5 --- /dev/null +++ b/docs/assets/app.Dv3XxakT.js @@ -0,0 +1 @@ +import{R as p}from"./chunks/theme.CF0q4NFF.js";import{R as o,aa as u,ab as l,ac as c,ad as f,ae as d,af as m,ag as h,ah as g,ai as A,aj as v,d as P,u as R,v as w,s as y,ak as C,al as b,am as E,a8 as S}from"./chunks/framework.BjXht68r.js";function i(e){if(e.extends){const a=i(e.extends);return{...a,...e,async enhanceApp(t){a.enhanceApp&&await a.enhanceApp(t),e.enhanceApp&&await e.enhanceApp(t)}}}return e}const s=i(p),T=P({name:"VitePressApp",setup(){const{site:e,lang:a,dir:t}=R();return w(()=>{y(()=>{document.documentElement.lang=a.value,document.documentElement.dir=t.value})}),e.value.router.prefetchLinks&&C(),b(),E(),s.setup&&s.setup(),()=>S(s.Layout)}});async function j(){globalThis.__VITEPRESS__=!0;const e=_(),a=D();a.provide(l,e);const t=c(e.route);return a.provide(f,t),a.component("Content",d),a.component("ClientOnly",m),Object.defineProperties(a.config.globalProperties,{$frontmatter:{get(){return t.frontmatter.value}},$params:{get(){return t.page.value.params}}}),s.enhanceApp&&await s.enhanceApp({app:a,router:e,siteData:h}),{app:a,router:e,data:t}}function D(){return g(T)}function _(){let e=o,a;return A(t=>{let n=v(t),r=null;return n&&(e&&(a=n),(e||a===n)&&(n=n.replace(/\.js$/,".lean.js")),r=import(n)),o&&(e=!1),r},s.NotFound)}o&&j().then(({app:e,router:a,data:t})=>{a.go().then(()=>{u(a.route,t.site),e.mount("#app")})});export{j as createApp}; diff --git a/docs/assets/chunks/VPAlgoliaSearchBox.COXLzJlP.js b/docs/assets/chunks/VPAlgoliaSearchBox.COXLzJlP.js new file mode 100644 index 0000000..92f2e0d --- /dev/null +++ b/docs/assets/chunks/VPAlgoliaSearchBox.COXLzJlP.js @@ -0,0 +1,12 @@ +import{d as pi,an as vi,J as hi,v as di,q as yi,P as _i,o as gi,c as bi}from"./framework.BjXht68r.js";import{u as Si}from"./theme.CF0q4NFF.js";/*! @docsearch/js 3.8.0 | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */function Un(){return Un=Object.assign?Object.assign.bind():function(t){for(var e=1;e本章节主要介绍 FinClip 数字化管理平台的配置文件内容。
FinClip 私有化部署中,业务系统相关的配置通过挂载形式提供给 quark 服务读取管理,其他服务统一从配置中心中获取。在 docker compose 部署的环境中,我们采用文件挂载的方式挂载配置文件,在 Kubernetes 或容器平台环境中,采用 ConfigMap 的方式挂载给容器。
FinClip 的配置主要分为两个部分:
数据库相关配置,填写 MySQL 连接和认证信息
DB_MODE: mysql
+MYSQL_URL: user_name:password@tcp(mysql_host:3306)/db_name?charset=utf8mb4
+driverName: mysql
+dataSourceName: user_name:password@tcp(mysql:3306)/
+dbName: db_name
Redis 配置,支持 single 和 cluster模式
REDIS_MODE: single
+REDIS_ADDR: redis:6379
+REDIS_PASSWORD: redis_pass
对象存储配置,用于存储静态文件,支持minio、tencent_cos、ali_oss、aws_s3、disk。
STORAGE_MODE: minio
+STORAGE_ENDPOINT: minio:9000
+STORAGE_ACCESS_KEY: access_key
+STORAGE_SECRET_KEY: secret_key
+STORAGE_BUCKET_NAME: bucket_name
+STORAGE_S3_USE_SSL: false
业务相关的通用配置,包括服务开启的默认端口、日志模式等。
ENV: fc-private
+EDITION: private
+LOG_MODE: warn
+HTTP_PORT: '8080'
+...
services 是一个数组类型的字段,里面包含了每个服务的相关配置。大部分时候不需要更改,其中需要留意的是 License 配置,当您购买且部署了 FinClip之后,需要更新 License 配置,此配置设置在服务 finclip-cloud-license-manager:
- SERVER_NAME: finclip-cloud-license-manager
+ LICENSE_ENCRYPTION_STR: License_文件内容
本章节主要介绍 FinClip 数字化管理平台的配置文件内容。
FinClip 私有化部署中,业务系统相关的配置通过挂载形式提供给 quark 服务读取管理,其他服务统一从配置中心中获取。在 docker compose 部署的环境中,我们采用文件挂载的方式挂载配置文件,在 Kubernetes 或容器平台环境中,采用 ConfigMap 的方式挂载给容器。
FinClip 的配置主要分为两个部分:
数据库相关配置,填写 MySQL 连接和认证信息
DB_MODE: mysql
+MYSQL_URL: user_name:password@tcp(mysql_host:3306)/db_name?charset=utf8mb4
+driverName: mysql
+dataSourceName: user_name:password@tcp(mysql:3306)/
+dbName: db_name
Redis 配置,支持 single 和 cluster模式
REDIS_MODE: single
+REDIS_ADDR: redis:6379
+REDIS_PASSWORD: redis_pass
对象存储配置,用于存储静态文件,支持minio、tencent_cos、ali_oss、aws_s3、disk。
STORAGE_MODE: minio
+STORAGE_ENDPOINT: minio:9000
+STORAGE_ACCESS_KEY: access_key
+STORAGE_SECRET_KEY: secret_key
+STORAGE_BUCKET_NAME: bucket_name
+STORAGE_S3_USE_SSL: false
业务相关的通用配置,包括服务开启的默认端口、日志模式等。
ENV: fc-private
+EDITION: private
+LOG_MODE: warn
+HTTP_PORT: '8080'
+...
services 是一个数组类型的字段,里面包含了每个服务的相关配置。大部分时候不需要更改,其中需要留意的是 License 配置,当您购买且部署了 FinClip之后,需要更新 License 配置,此配置设置在服务 finclip-cloud-license-manager:
- SERVER_NAME: finclip-cloud-license-manager
+ LICENSE_ENCRYPTION_STR: License_文件内容
FinClip 数字化管理平台私有化部署中,运维配置主要围绕Docker 容器和 Kubernetes 相关的内容。我们采用业界常用的标准方式进行部署管理,因此您可以利用您的运维通用技能,对 FinClip 进行管理。以下是针对单机部署和集群部署的配置说明。
如前文所言,FinClip 采用 docker compose 进行单节点的部署和管理,因此,只需要根据 docker 官方的配置管理方式即可对 FinClip 系统进行运维管理。
1. 定位配置目录
通过查看任意一个正在运行的容器,可以定位到 Compose 配置所在的目录
docker ps
+docker inspect [container_id] | grep -i working_dir
2. Compose 目录文件
3. 自定义服务访问端口
可以通过修改 docker-compose.yaml中的 gateway 服务的 端口映射修改访问端口。
ports:
+ - "30001:8000" #例如30001
FinClip支持使用Kubernetes以及兼容的容器平台进行部署,通过容器编排平台,你可以实现服务都高可用、自动化伸缩扩展、资源优化和高效管理等运维内容。FinClip服务采用docker进行打包,支持helm chart进行配置管理。
在Kubernetes部署中,配置文件主要包括:
在Helm Chart配置中,主要配置内容都编写在 Values.yaml中,你可以根据实际情况进行修改以生成Kubernetes配置文件。
`,18)]))}const c=i(n,[["render",l]]);export{d as __pageData,c as default}; diff --git a/docs/assets/docs_config_ops-configuration.md.DmczDTxc.lean.js b/docs/assets/docs_config_ops-configuration.md.DmczDTxc.lean.js new file mode 100644 index 0000000..522cf32 --- /dev/null +++ b/docs/assets/docs_config_ops-configuration.md.DmczDTxc.lean.js @@ -0,0 +1,3 @@ +import{_ as i,c as e,a9 as a,o as t}from"./chunks/framework.BjXht68r.js";const d=JSON.parse('{"title":"运维配置","description":"运维配置管理","frontmatter":{"title":"运维配置","description":"运维配置管理"},"headers":[],"relativePath":"docs/config/ops-configuration.md","filePath":"docs/config/ops-configuration.md"}'),n={name:"docs/config/ops-configuration.md"};function l(o,s,r,p,h,g){return t(),e("div",null,s[0]||(s[0]=[a(`FinClip 数字化管理平台私有化部署中,运维配置主要围绕Docker 容器和 Kubernetes 相关的内容。我们采用业界常用的标准方式进行部署管理,因此您可以利用您的运维通用技能,对 FinClip 进行管理。以下是针对单机部署和集群部署的配置说明。
如前文所言,FinClip 采用 docker compose 进行单节点的部署和管理,因此,只需要根据 docker 官方的配置管理方式即可对 FinClip 系统进行运维管理。
1. 定位配置目录
通过查看任意一个正在运行的容器,可以定位到 Compose 配置所在的目录
docker ps
+docker inspect [container_id] | grep -i working_dir
2. Compose 目录文件
3. 自定义服务访问端口
可以通过修改 docker-compose.yaml中的 gateway 服务的 端口映射修改访问端口。
ports:
+ - "30001:8000" #例如30001
FinClip支持使用Kubernetes以及兼容的容器平台进行部署,通过容器编排平台,你可以实现服务都高可用、自动化伸缩扩展、资源优化和高效管理等运维内容。FinClip服务采用docker进行打包,支持helm chart进行配置管理。
在Kubernetes部署中,配置文件主要包括:
在Helm Chart配置中,主要配置内容都编写在 Values.yaml中,你可以根据实际情况进行修改以生成Kubernetes配置文件。
`,18)]))}const c=i(n,[["render",l]]);export{d as __pageData,c as default}; diff --git a/docs/assets/docs_config_update-and-restart.md.BnMtPxph.js b/docs/assets/docs_config_update-and-restart.md.BnMtPxph.js new file mode 100644 index 0000000..ce49a71 --- /dev/null +++ b/docs/assets/docs_config_update-and-restart.md.BnMtPxph.js @@ -0,0 +1 @@ +import{_ as a,c as i,a9 as t,o as s}from"./chunks/framework.BjXht68r.js";const k=JSON.parse('{"title":"更新操作","description":"更新操作","frontmatter":{"title":"更新操作","description":"更新操作"},"headers":[],"relativePath":"docs/config/update-and-restart.md","filePath":"docs/config/update-and-restart.md"}'),o={name:"docs/config/update-and-restart.md"};function l(r,e,n,d,c,p){return s(),i("div",null,e[0]||(e[0]=[t(' 如前面的章节所述,FinClip 私有化部署中,业务配置保存在一个配置文件中,在单节点部署中,配置文件为部署目录下的fc-private.yaml
,在 Kubernetes环境部署中为 ConfigMap 形式的 fc-private.yaml
, 保存在 quark-cm0
cm 中。
如果你需要更新配置并重新加载,只需要修改这个文件之后,重启 quark
服务,然后重启其他响应的运维服务即可。
kubectl edit configmap quark-cm0
对于运维配置,则涉及到各种环境的差异。我们采用业界常用的运维标准进行部署,因此,修改运维相关的配置文件可以参考大部分技术资料和文章进行修改,通常是修改配置文件,然后重启服务组件即可。这些配置包括但不限于:
如前面的章节所述,FinClip 私有化部署中,业务配置保存在一个配置文件中,在单节点部署中,配置文件为部署目录下的fc-private.yaml
,在 Kubernetes环境部署中为 ConfigMap 形式的 fc-private.yaml
, 保存在 quark-cm0
cm 中。
如果你需要更新配置并重新加载,只需要修改这个文件之后,重启 quark
服务,然后重启其他响应的运维服务即可。
kubectl edit configmap quark-cm0
对于运维配置,则涉及到各种环境的差异。我们采用业界常用的运维标准进行部署,因此,修改运维相关的配置文件可以参考大部分技术资料和文章进行修改,通常是修改配置文件,然后重启服务组件即可。这些配置包括但不限于:
FinClip 后端服务采用 Golang 语言编写,系统架构采用微服务架构,每个服务经过编译之后会被打包成容器,我 们采用业界主流的容器管理平台进行服务编排, 因此,我们大部分运维能力,包括服务的故障转移、动态扩容、资源管理等能力都是依赖于容器平台实现。此外,FinClip 还依赖部分成熟的开源组件作为基础设施,以实现业务系统中的数据存储、缓存等。
运维架构图:
架构部分:
基础服务部分:
容器: Docker
容器编排平台: Kubernetes、Rancher(可选)
日志系统:
监控系统: Prometheus
FinClip 采用典型的三层架构设计,接入层 - 服务层 - 基础服务层。因此,我们的平台架构兼顾运维可维护性、可扩展性和安全性。
提供多种部署模式,以满足不同业务场景和需求。
部署模式 | 适用环境 | 架构设计 | 优点 | 缺点 | 部署说明 |
---|---|---|---|---|---|
单节点 | POC、测试环境 | compose 部署所有服务 | 部署快、成本低 | 性能一般,单点故障 | 服单台务器部署所有服务 |
小集群 | 生产、高可用场景 | 使用Kubernetes ,4台服务器 | 高可用、资源利用高 | 资源竞争 | 服务均匀分布在4台服务器 |
中大规模集群 | 对扩展性、灾备有要求 | Kubernetes 集群,多服务器,业务与基础服务分离 | 高可用、性能较好、无资源竞争 | 成本较高 | 类似小规模,更多服务器且服务分离 |
双机房冷备集群 | 对业务连续性要求高 | 主机房工作,冷备机房待命接管 | 更高的容灾能力、切换灵活 | 成本高、维护复杂 | 主从机房都部署 Kubernetes 集群,主机房部署数据服务集群,冷备机房做单节点同步 |
在单节点部署模式中,所有服务将部署在一台服务器中
操作系统与容器平台:
容器与系统组件:
服务器:
用途 | CPU | 内存 | 储存空间 | 部署内容 | 数量 | 参考 TPS |
---|---|---|---|---|---|---|
最低配置 | 4 核 | 8 GB | 100 GB | 数据库、缓存和FinClip微服务 | 1 | 4000 |
推荐配置 | 8 核 | 16 GB | 200 GB | 数据库、缓存和FinClip微服务 | 1 | 6000 |
系统:
小规模集群的部署架构提供最小规模的高可用,需要使用四台服务器,其中四台服务器只能宕机一台,适合绝大部分的、对高可用与故障隔离具有较小要求的客户。
小规模集群将采用 Kubernetes 的方式部署,所需的配置可以参考下表▼:
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 4 台 | 2w |
运维管理(可选) | 8 核 | 16 GB | 500 GB | 1 台 | - |
角色分配可以参考下图▼:
系统:
部署说明: 所有服务将均匀部署在四台服务器中, 数据库和缓存系统使用docker compose部署在主机,业务服务使用Kubernetes进行部署,均匀分布在四台服务器。
集群模式部署能够提供一定程度的、软件层面的故障转移能力。大规模集群的部署架构适合对可扩展性、灾备等指标有要求的客户使用。该架构的集群设计上主要关注在于故障隔离、故障恢复、可拓展性等方面。
大规模集群的服务器数量没有上限,支持多活、多机房部署,可根据业务规模、灾备要求自定义。相比小规模集群,大规模集群可以提供更高的QPS,更好的性能以及更好的扩展性。
大规模集群将采用 Kubernetes 的方式部署,所需的配置可以参考下表(磁盘建议使用SSD)▼:
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 8 台 | 3w |
运维管理 | 8 核 | 16 GB | 500 GB | 1 台 | - |
角色分配可以参考下图▼:
系统:
部署说明: 与小规模部署类似,不过,大规模集群部署采用更多的服务器,业务服务与基础服务分离, 微服务采用更多的实例数部署,以承担更高的用户访问。
双机房部署架构提供更高的容灾能力,适用于对业务连续性要求较高的客户。双机房架构通常包含一个主机房和一个冷备机房,平时仅主机房提供服务,冷备机房处于待命状态,只有在主机房出现故障时才会启用。
部署架构
主机房:主机房承担所有的业务负载,所有业务服务、数据库和缓存系统都运行在主机房。通常部署的组件和资源配置与小规模集群类似,保证业务的正常运转。
冷备机房:冷备机房不承担日常业务,但部署有与主机房相同的服务架构和数据同步机制。通过数据库备份或实时同步的方式,确保数据的一致性。一旦主机房故障,冷备机房能够迅速接管业务。
所需的配置可以参考下表(磁盘建议使用SSD)▼:
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 12 台 | 3w |
运维管理 | 8 核 | 16 GB | 500 GB | 1 台 | - |
角色分配可以参考下图▼:
数据同步机制
数据库同步:通过主从复制和数据库同步工具保证主机房和冷备机房数据库的一致性。主机房负责写入,冷备机房保持数据同步。
缓存同步:Redis 等缓存服务可以通过持久化机制来同步缓存数据。冷备机房的缓存数据可以在主机房故障时恢复。
文件同步:通过对象存储的同步机制确保业务文件和数据的一致性。
部署说明
FinClip 后端服务采用 Golang 语言编写,系统架构采用微服务架构,每个服务经过编译之后会被打包成容器,我 们采用业界主流的容器管理平台进行服务编排, 因此,我们大部分运维能力,包括服务的故障转移、动态扩容、资源管理等能力都是依赖于容器平台实现。此外,FinClip 还依赖部分成熟的开源组件作为基础设施,以实现业务系统中的数据存储、缓存等。
运维架构图:
架构部分:
基础服务部分:
容器: Docker
容器编排平台: Kubernetes、Rancher(可选)
日志系统:
监控系统: Prometheus
FinClip 采用典型的三层架构设计,接入层 - 服务层 - 基础服务层。因此,我们的平台架构兼顾运维可维护性、可扩展性和安全性。
提供多种部署模式,以满足不同业务场景和需求。
部署模式 | 适用环境 | 架构设计 | 优点 | 缺点 | 部署说明 |
---|---|---|---|---|---|
单节点 | POC、测试环境 | compose 部署所有服务 | 部署快、成本低 | 性能一般,单点故障 | 服单台务器部署所有服务 |
小集群 | 生产、高可用场景 | 使用Kubernetes ,4台服务器 | 高可用、资源利用高 | 资源竞争 | 服务均匀分布在4台服务器 |
中大规模集群 | 对扩展性、灾备有要求 | Kubernetes 集群,多服务器,业务与基础服务分离 | 高可用、性能较好、无资源竞争 | 成本较高 | 类似小规模,更多服务器且服务分离 |
双机房冷备集群 | 对业务连续性要求高 | 主机房工作,冷备机房待命接管 | 更高的容灾能力、切换灵活 | 成本高、维护复杂 | 主从机房都部署 Kubernetes 集群,主机房部署数据服务集群,冷备机房做单节点同步 |
在单节点部署模式中,所有服务将部署在一台服务器中
操作系统与容器平台:
容器与系统组件:
服务器:
用途 | CPU | 内存 | 储存空间 | 部署内容 | 数量 | 参考 TPS |
---|---|---|---|---|---|---|
最低配置 | 4 核 | 8 GB | 100 GB | 数据库、缓存和FinClip微服务 | 1 | 4000 |
推荐配置 | 8 核 | 16 GB | 200 GB | 数据库、缓存和FinClip微服务 | 1 | 6000 |
系统:
小规模集群的部署架构提供最小规模的高可用,需要使用四台服务器,其中四台服务器只能宕机一台,适合绝大部分的、对高可用与故障隔离具有较小要求的客户。
小规模集群将采用 Kubernetes 的方式部署,所需的配置可以参考下表▼:
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 4 台 | 2w |
运维管理(可选) | 8 核 | 16 GB | 500 GB | 1 台 | - |
角色分配可以参考下图▼:
系统:
部署说明: 所有服务将均匀部署在四台服务器中, 数据库和缓存系统使用docker compose部署在主机,业务服务使用Kubernetes进行部署,均匀分布在四台服务器。
集群模式部署能够提供一定程度的、软件层面的故障转移能力。大规模集群的部署架构适合对可扩展性、灾备等指标有要求的客户使用。该架构的集群设计上主要关注在于故障隔离、故障恢复、可拓展性等方面。
大规模集群的服务器数量没有上限,支持多活、多机房部署,可根据业务规模、灾备要求自定义。相比小规模集群,大规模集群可以提供更高的QPS,更好的性能以及更好的扩展性。
大规模集群将采用 Kubernetes 的方式部署,所需的配置可以参考下表(磁盘建议使用SSD)▼:
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 8 台 | 3w |
运维管理 | 8 核 | 16 GB | 500 GB | 1 台 | - |
角色分配可以参考下图▼:
系统:
部署说明: 与小规模部署类似,不过,大规模集群部署采用更多的服务器,业务服务与基础服务分离, 微服务采用更多的实例数部署,以承担更高的用户访问。
双机房部署架构提供更高的容灾能力,适用于对业务连续性要求较高的客户。双机房架构通常包含一个主机房和一个冷备机房,平时仅主机房提供服务,冷备机房处于待命状态,只有在主机房出现故障时才会启用。
部署架构
主机房:主机房承担所有的业务负载,所有业务服务、数据库和缓存系统都运行在主机房。通常部署的组件和资源配置与小规模集群类似,保证业务的正常运转。
冷备机房:冷备机房不承担日常业务,但部署有与主机房相同的服务架构和数据同步机制。通过数据库备份或实时同步的方式,确保数据的一致性。一旦主机房故障,冷备机房能够迅速接管业务。
所需的配置可以参考下表(磁盘建议使用SSD)▼:
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 12 台 | 3w |
运维管理 | 8 核 | 16 GB | 500 GB | 1 台 | - |
角色分配可以参考下图▼:
数据同步机制
数据库同步:通过主从复制和数据库同步工具保证主机房和冷备机房数据库的一致性。主机房负责写入,冷备机房保持数据同步。
缓存同步:Redis 等缓存服务可以通过持久化机制来同步缓存数据。冷备机房的缓存数据可以在主机房故障时恢复。
文件同步:通过对象存储的同步机制确保业务文件和数据的一致性。
部署说明
进程 | 服务 | 端口(内部) | 备注 |
---|---|---|---|
app-manager | 小程序管理 | HTTP/8080 | 小程序管理主要提供小程序的整体管理和运营相关的能力,帮助管理员更好的管理和运营小程序。 |
user-system | 用户管理 | HTTP/8080 | 用户管理主要提供用户登录、注册、角色、权限等的管理和组织机构的管理。 |
data-center | 数据管理 | HTTP/8080 | 主要提供操作日志,小程序搜索,灰度统计,数据上报,数据统计的管理。 |
oper-ability | 运营小程序管理 | HTTP/8080 | 主要提供小程序平台运营相关的能力及一些通用功能,帮助运营人员更好的运营小程序管理平台。 |
integration-api | 统一平台 | HTTP/8080 | 将多个独立的API(应用程序接口)整合到一个统一平台的服务,以便于用户在一个集成的服务中访问和管理来自不同来源的数据和服务,为用户提供了一个统一、高效的访问和管理数据的途径。 |
access-api | RESTful API 服务 | HTTP/8080 | 为面向SDK提供服务的 RESTful API 服务,为运行时小程序提供相关服务支持。 |
open-api | 接口服务 | HTTP/8080 | 提供给开发者的接口服务,允许他们通过API(应用程序接口)与平台或服务进行交互。开放API服务的设计目的是为开发者提供可编程的接口,使能够自由地使用和集成功能或数据。 |
iam-manager | 身份识别和访问管理服务 | HTTP/8080 | 提供第三方OAuth登录功能,集成LDAP登录支持,提供了完善的审计日志系统。 |
cloud-frontend | 前端服务 | HTTP/8080 | 数字中心与开发中心前端服务 |
license-manager | License 校验中心 | HTTP/8080 | License 用于决定小程序平台的部分功能,例如小程序数量、应用数量、灰度发布数量等。 |
quark | 配置中心服务 | HTTP/8080 | 是一个面向服务端的配置管理工具,用于管理控制变量参数信息,并提供界面供用户操作。 |
miniprogram-preview | 小程序预览 | HTTP/8080 | 用于在小程序完全发布或上线之前提供预览,使开发人员能够在不正式部署小程序的情况下进行测试和审查。 |
delivery | 异步管理服务 | HTTP/8080 | 小程序异步通信组件,能够有效地解耦系统 |
registry | 服务管理中心 | HTTP/8080 | 小程序服务管理中心,动态跟踪服务的更新 |
进程 | 服务 | 端口(内部) | 备注 |
---|---|---|---|
gateway | 网关服务 | HTTP/8000、443 (对外) | 用户入口网关,提供路由和鉴权。 |
minio | 对象存储服务 | HTTP/9000 | 提供S3对象存储 |
mysql | 数据库服务 | TCP/3306 | SQL数据库,提供系统数据存储 |
redis | 缓存服务 | TCP/6379 | 高性能的key-value数据库,做缓存集群,用于加速服务读写速度。 |
名称 | 分类 | 端口 | 介绍 |
---|---|---|---|
CentOS 7.9/Ubuntu 22.04 | 操作系统 | - | 操作系统,可选大部分GNU/Linux,内核版本需要支持Docker |
Prometheus/Grafana | 监控系统 | 内部/多端口 | 可选,用于实现监控面板、告警等功能 |
ELK/PLG | 日志系统 | 内部/多端口 | 可选,用于管理应用程序日志 |
Kubernetes/Docker | 容器编排 | 内部/多端口 | 容器编排系统,用于管理容器服务 |
进程 | 服务 | 端口(内部) | 备注 |
---|---|---|---|
app-manager | 小程序管理 | HTTP/8080 | 小程序管理主要提供小程序的整体管理和运营相关的能力,帮助管理员更好的管理和运营小程序。 |
user-system | 用户管理 | HTTP/8080 | 用户管理主要提供用户登录、注册、角色、权限等的管理和组织机构的管理。 |
data-center | 数据管理 | HTTP/8080 | 主要提供操作日志,小程序搜索,灰度统计,数据上报,数据统计的管理。 |
oper-ability | 运营小程序管理 | HTTP/8080 | 主要提供小程序平台运营相关的能力及一些通用功能,帮助运营人员更好的运营小程序管理平台。 |
integration-api | 统一平台 | HTTP/8080 | 将多个独立的API(应用程序接口)整合到一个统一平台的服务,以便于用户在一个集成的服务中访问和管理来自不同来源的数据和服务,为用户提供了一个统一、高效的访问和管理数据的途径。 |
access-api | RESTful API 服务 | HTTP/8080 | 为面向SDK提供服务的 RESTful API 服务,为运行时小程序提供相关服务支持。 |
open-api | 接口服务 | HTTP/8080 | 提供给开发者的接口服务,允许他们通过API(应用程序接口)与平台或服务进行交互。开放API服务的设计目的是为开发者提供可编程的接口,使能够自由地使用和集成功能或数据。 |
iam-manager | 身份识别和访问管理服务 | HTTP/8080 | 提供第三方OAuth登录功能,集成LDAP登录支持,提供了完善的审计日志系统。 |
cloud-frontend | 前端服务 | HTTP/8080 | 数字中心与开发中心前端服务 |
license-manager | License 校验中心 | HTTP/8080 | License 用于决定小程序平台的部分功能,例如小程序数量、应用数量、灰度发布数量等。 |
quark | 配置中心服务 | HTTP/8080 | 是一个面向服务端的配置管理工具,用于管理控制变量参数信息,并提供界面供用户操作。 |
miniprogram-preview | 小程序预览 | HTTP/8080 | 用于在小程序完全发布或上线之前提供预览,使开发人员能够在不正式部署小程序的情况下进行测试和审查。 |
delivery | 异步管理服务 | HTTP/8080 | 小程序异步通信组件,能够有效地解耦系统 |
registry | 服务管理中心 | HTTP/8080 | 小程序服务管理中心,动态跟踪服务的更新 |
进程 | 服务 | 端口(内部) | 备注 |
---|---|---|---|
gateway | 网关服务 | HTTP/8000、443 (对外) | 用户入口网关,提供路由和鉴权。 |
minio | 对象存储服务 | HTTP/9000 | 提供S3对象存储 |
mysql | 数据库服务 | TCP/3306 | SQL数据库,提供系统数据存储 |
redis | 缓存服务 | TCP/6379 | 高性能的key-value数据库,做缓存集群,用于加速服务读写速度。 |
名称 | 分类 | 端口 | 介绍 |
---|---|---|---|
CentOS 7.9/Ubuntu 22.04 | 操作系统 | - | 操作系统,可选大部分GNU/Linux,内核版本需要支持Docker |
Prometheus/Grafana | 监控系统 | 内部/多端口 | 可选,用于实现监控面板、告警等功能 |
ELK/PLG | 日志系统 | 内部/多端口 | 可选,用于管理应用程序日志 |
Kubernetes/Docker | 容器编排 | 内部/多端口 | 容器编排系统,用于管理容器服务 |
在部署之前,需要准备以下资源:
中控机
安装包
Centos:https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/os/centos/ansible-centos-7-x86-1.0.1.tar.gz
+
+Ubuntu:https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/debian/ansible-ubuntu-x86-22.04.20240628.tar.gz
https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/finclip-deploy-ansible-master.tar.gz
https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/rke2/1.26.12-rke2r1.tar.gz
https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/images/rancher-images-x86-2.7.10.tar.gz
https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/images/stateful-images-x86-1.0.2.tar.gz
请向凡泰极客人员索取最新版本;
请向凡泰极客人员索取最新版本;
由凡泰极客人员颁发提供;
将凡泰极客提供的 Ansible Playbook、Rancher 镜像包、中间件镜像包、FinClip 组件镜像包、FinClip 编排 Helm 上传至中控机后,依次执行下列命令进行依赖安装:
# 创建部署目录
+mkdir -p /data/finclip-installation
+# 解压playbook
+tar xvf finclip-deploy-ansible-master.tar.gz -C /data/finclip-installation
+# Centos
+tar xvf ansible-centos-7-x86-1.0.1.tar.gz -C /data/finclip-installation/finclip-deploy-ansible-master/
+# Ubuntu
+tar xvf ansible-ubuntu-x86-22.04.20240628.tar.gz -C /data/finclip-installation/finclip-deploy-ansible-master/
+# 移动镜像包
+mv 1.26.12-rke2r1.tar.gz rancher-images-x86-2.7.10.tar.gz stateful-images-x86-1.0.1.tar.gz monitor-57.2.0.tar.gz log-image.tar.gz /data/finclip-installation/finclip-deploy-ansible-master/
cd /data/finclip-installation/finclip-deploy-ansible-master/
bash /data/finclip-installation/finclip-deploy-ansible-master/files/install_python3-with-pip.sh
bash /data/finclip-installation/finclip-deploy-ansible-master/files/install_ansible.sh
安装完成后,可以通过命令 pip3 -V
验证 pip3 是否安装成功。
Ansible 可以通过 ansible --version
验证是否安装成功。
在中控机上配置 Ansible Playbook
回到安装包目录,依次执行下列命令准备 Ansible Playbook
cd /data/finclip-installation/finclip-deploy-ansible-master/
cp inventory.example inventory
角色 | 说明 | 最小节点数 / 推荐节点数 |
---|---|---|
registry | 私有 Docker 镜像仓库 | 1 / 1 |
redis_cluster | Redis 集群 | 0 / 3 或更多 |
mysql | mysql 集群 | 0 / 2 或更多 |
minio | MinIO 集群+纠删码模式 | 0 / 4 或更多 |
rke_worker | Kubernetes 集群的 Worker 节点 | 0 / 3 或更多 |
rke_controlplane | Kubernetes 集群的控制节点 | 0 / 3 或更多 |
最小: 指的是该组件可以接受以该数量的节点运行;
推荐: 指的是该组件在标准化部署下,建议以该数量的节点进行部署;
registry: 部署过程中会用到的私有 Docker 镜像仓库。该组件属于临时组件,部署完成后,建议转移所有镜像至您自有的镜像仓库中;
更多: 代表该角色所指的服务,如果有特别的需要,可以分配该数量以上的、且尽可能多的节点。
准备 SSH 鉴权信息
依次执行下列命令准备 SSH 鉴权信息
中控机执行命令: ssh-keygen
,按照命令提示进行操作,如果不需要自定义配置,连续敲击 [ENTER] 即可按照默认进行设置。直到出现下列 randomart image 代表 SSH Public Key 已经生成完成。
执行命令:ssh-copy-id -i /root/.ssh/id_rsa.pub [用户]@[IP 地址]
所有机器都需要分发,请根据实际情况,替换 [用户] 与 [IP 地址] ,如 root@10.0.0.1 。
执行命令: cd /data/finclip-installation/finclip-deploy-ansible-master/
执行命令:ansible all -m ping
确认所有回显均为“[IP 地址] | SUCCESS” 与“ping: pong” 。
标准化基建部署
默认全部内容部署在 /data/finclip 目录下
如需修改: 编辑 /data/finclip-installation/finclip-deploy-ansible-master/roles/deploy/vars/default.yaml
文件,修改 persistent_dir_prefixe: "/data/finclip"
变量
确认 inventory 文件的角色分配无误后,执行下列命令通过 Ansible 自动部署中间件与基建服务
cd /data/finclip-installation/finclip-deploy-ansible-master/
ansible-playbook deploy.yaml | tee setup.log
部署通常需要 30-40 分钟左右,如果出现下列的信息,则表示部署完成:
部署完成后日志保存在当前目录 setup.log 文件中
获取 MySQL、Redis、Registry、MinIO 等中间件的鉴权、连接地址信息
cat /data/finclip-installation/finclip-deploy-ansible-master/note.txt
获取 Rancher、Grafana 等密钥信息;
cat /data/finclip-installation/finclip-deploy-ansible-master/.secret.yaml
获取 ElasticSearch 的鉴权信息,其中 "elastic" 用户为业务用户。
cat /root/esAuth
注意: Helm 部署 Finclip 只需要查看 note.txt 中的信息即可。
导入镜像
回到安装包目录,中控机执行以下命令,导入凡泰极客提供的 FinClip 组件镜像包并上传至 Registry 仓库:
for i in `docker load -i images.tgz |awk '{print $NF}'` ; do docker tag $i `echo $i|awk -F '/' '{print "registry.finogeeks.internal:5000/"$(NF-1)"/"$NF}'` ; docker push `echo $i|awk -F '/' '{print "registry.finogeeks.internal:5000/"$(NF-1)"/"$NF}'` ;done
创建 finclip namespace
中控机执行以下命令:
kubectl create namespace finclip
创建 imagePullSecrets
创建所需凭据,用于拉取 Registry 仓库中的容器镜像,中控机执行以下命令创建:
kubectl create secret generic finclipro --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson -n finclip
修改 Helm 部署文件
回到安装包目录,解压由凡泰极客人员提供 Helm chart 包。
需要修改连接接信息、鉴权以符合实际环境需要。
进入到 FinClip 编排 Helm chart 目录,修改 "凡泰极客-POC-F-01_20240513_license.txt" 文件为正确的 license 密钥
进入到 FinClip 编排 Helm chart 目录,编辑 values.yaml 文件,删除旧的数据服务信息,复制 /data/finclip-installation/finclip-deploy-ansible-master/note.txt 中的 redis、mysql、objectStorage、 elasticsearch 信息直接粘贴到 values.yaml 文件中。
使用sed命令修改仓库地址
sed -i 's@docker.finogeeks.club/mop@registry.finogeeks.internal:5000/mop@g' values.yaml\nsed -i 's@docker.finogeeks.club/infra@registry.finogeeks.internal:5000/infra@g' values.yaml
启动 finclip 服务
在部署机器上执行(中控机上)
使用 cd 命令切换到 FinClip 编排 Helm chart 目录 :finclip-chart(不同版本目录名不同)
执行命令启动服务:Helm install finclip . -n finclip
启动完成查看 pod 状态是否为 running:kubectl get pod -n finclip
其他命令参考:
配置修改后更新:Helm upgrade finclip . -n finclip
卸载:Helm uninstall finclip -n finclip
网站名称 | 访问链接 | 初始账户 | 说明 |
---|---|---|---|
数字中⼼ | http://IP:PORT/ops#/ | admin | PORT:端口号,默认 30001,IP:服务器所在ip地址,如: 172.217.163.46 |
开发中⼼ | http://IP:PORT/dev#/ | 自行注册 |
访问地址:集群版部署
',112)]))}const y=s(p,[["render",h]]);export{b as __pageData,y as default}; diff --git a/docs/assets/docs_deployment_installation-steps.md.Bvy7Q3jn.lean.js b/docs/assets/docs_deployment_installation-steps.md.Bvy7Q3jn.lean.js new file mode 100644 index 0000000..e3587dd --- /dev/null +++ b/docs/assets/docs_deployment_installation-steps.md.Bvy7Q3jn.lean.js @@ -0,0 +1,12 @@ +import{_ as s,c as a,a9 as t,o as e}from"./chunks/framework.BjXht68r.js";const l="/images/ssh-keygen.png",n="/images/ansible-done.jpeg",b=JSON.parse('{"title":"安装步骤","description":"A guide in my new Starlight docs site.","frontmatter":{"title":"安装步骤","description":"A guide in my new Starlight docs site."},"headers":[],"relativePath":"docs/deployment/installation-steps.md","filePath":"docs/deployment/installation-steps.md"}'),p={name:"docs/deployment/installation-steps.md"};function h(d,i,o,r,k,g){return e(),a("div",null,i[0]||(i[0]=[t(`在部署之前,需要准备以下资源:
中控机
安装包
Centos:https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/os/centos/ansible-centos-7-x86-1.0.1.tar.gz
+
+Ubuntu:https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/debian/ansible-ubuntu-x86-22.04.20240628.tar.gz
https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/finclip-deploy-ansible-master.tar.gz
https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/rke2/1.26.12-rke2r1.tar.gz
https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/images/rancher-images-x86-2.7.10.tar.gz
https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/download/ansible/images/stateful-images-x86-1.0.2.tar.gz
请向凡泰极客人员索取最新版本;
请向凡泰极客人员索取最新版本;
由凡泰极客人员颁发提供;
将凡泰极客提供的 Ansible Playbook、Rancher 镜像包、中间件镜像包、FinClip 组件镜像包、FinClip 编排 Helm 上传至中控机后,依次执行下列命令进行依赖安装:
# 创建部署目录
+mkdir -p /data/finclip-installation
+# 解压playbook
+tar xvf finclip-deploy-ansible-master.tar.gz -C /data/finclip-installation
+# Centos
+tar xvf ansible-centos-7-x86-1.0.1.tar.gz -C /data/finclip-installation/finclip-deploy-ansible-master/
+# Ubuntu
+tar xvf ansible-ubuntu-x86-22.04.20240628.tar.gz -C /data/finclip-installation/finclip-deploy-ansible-master/
+# 移动镜像包
+mv 1.26.12-rke2r1.tar.gz rancher-images-x86-2.7.10.tar.gz stateful-images-x86-1.0.1.tar.gz monitor-57.2.0.tar.gz log-image.tar.gz /data/finclip-installation/finclip-deploy-ansible-master/
cd /data/finclip-installation/finclip-deploy-ansible-master/
bash /data/finclip-installation/finclip-deploy-ansible-master/files/install_python3-with-pip.sh
bash /data/finclip-installation/finclip-deploy-ansible-master/files/install_ansible.sh
安装完成后,可以通过命令 pip3 -V
验证 pip3 是否安装成功。
Ansible 可以通过 ansible --version
验证是否安装成功。
在中控机上配置 Ansible Playbook
回到安装包目录,依次执行下列命令准备 Ansible Playbook
cd /data/finclip-installation/finclip-deploy-ansible-master/
cp inventory.example inventory
角色 | 说明 | 最小节点数 / 推荐节点数 |
---|---|---|
registry | 私有 Docker 镜像仓库 | 1 / 1 |
redis_cluster | Redis 集群 | 0 / 3 或更多 |
mysql | mysql 集群 | 0 / 2 或更多 |
minio | MinIO 集群+纠删码模式 | 0 / 4 或更多 |
rke_worker | Kubernetes 集群的 Worker 节点 | 0 / 3 或更多 |
rke_controlplane | Kubernetes 集群的控制节点 | 0 / 3 或更多 |
最小: 指的是该组件可以接受以该数量的节点运行;
推荐: 指的是该组件在标准化部署下,建议以该数量的节点进行部署;
registry: 部署过程中会用到的私有 Docker 镜像仓库。该组件属于临时组件,部署完成后,建议转移所有镜像至您自有的镜像仓库中;
更多: 代表该角色所指的服务,如果有特别的需要,可以分配该数量以上的、且尽可能多的节点。
准备 SSH 鉴权信息
依次执行下列命令准备 SSH 鉴权信息
中控机执行命令: ssh-keygen
,按照命令提示进行操作,如果不需要自定义配置,连续敲击 [ENTER] 即可按照默认进行设置。直到出现下列 randomart image 代表 SSH Public Key 已经生成完成。
执行命令:ssh-copy-id -i /root/.ssh/id_rsa.pub [用户]@[IP 地址]
所有机器都需要分发,请根据实际情况,替换 [用户] 与 [IP 地址] ,如 root@10.0.0.1 。
执行命令: cd /data/finclip-installation/finclip-deploy-ansible-master/
执行命令:ansible all -m ping
确认所有回显均为“[IP 地址] | SUCCESS” 与“ping: pong” 。
标准化基建部署
默认全部内容部署在 /data/finclip 目录下
如需修改: 编辑 /data/finclip-installation/finclip-deploy-ansible-master/roles/deploy/vars/default.yaml
文件,修改 persistent_dir_prefixe: "/data/finclip"
变量
确认 inventory 文件的角色分配无误后,执行下列命令通过 Ansible 自动部署中间件与基建服务
cd /data/finclip-installation/finclip-deploy-ansible-master/
ansible-playbook deploy.yaml | tee setup.log
部署通常需要 30-40 分钟左右,如果出现下列的信息,则表示部署完成:
部署完成后日志保存在当前目录 setup.log 文件中
获取 MySQL、Redis、Registry、MinIO 等中间件的鉴权、连接地址信息
cat /data/finclip-installation/finclip-deploy-ansible-master/note.txt
获取 Rancher、Grafana 等密钥信息;
cat /data/finclip-installation/finclip-deploy-ansible-master/.secret.yaml
获取 ElasticSearch 的鉴权信息,其中 "elastic" 用户为业务用户。
cat /root/esAuth
注意: Helm 部署 Finclip 只需要查看 note.txt 中的信息即可。
导入镜像
回到安装包目录,中控机执行以下命令,导入凡泰极客提供的 FinClip 组件镜像包并上传至 Registry 仓库:
for i in `docker load -i images.tgz |awk '{print $NF}'` ; do docker tag $i `echo $i|awk -F '/' '{print "registry.finogeeks.internal:5000/"$(NF-1)"/"$NF}'` ; docker push `echo $i|awk -F '/' '{print "registry.finogeeks.internal:5000/"$(NF-1)"/"$NF}'` ;done
创建 finclip namespace
中控机执行以下命令:
kubectl create namespace finclip
创建 imagePullSecrets
创建所需凭据,用于拉取 Registry 仓库中的容器镜像,中控机执行以下命令创建:
kubectl create secret generic finclipro --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson -n finclip
修改 Helm 部署文件
回到安装包目录,解压由凡泰极客人员提供 Helm chart 包。
需要修改连接接信息、鉴权以符合实际环境需要。
进入到 FinClip 编排 Helm chart 目录,修改 "凡泰极客-POC-F-01_20240513_license.txt" 文件为正确的 license 密钥
进入到 FinClip 编排 Helm chart 目录,编辑 values.yaml 文件,删除旧的数据服务信息,复制 /data/finclip-installation/finclip-deploy-ansible-master/note.txt 中的 redis、mysql、objectStorage、 elasticsearch 信息直接粘贴到 values.yaml 文件中。
使用sed命令修改仓库地址
sed -i 's@docker.finogeeks.club/mop@registry.finogeeks.internal:5000/mop@g' values.yaml\nsed -i 's@docker.finogeeks.club/infra@registry.finogeeks.internal:5000/infra@g' values.yaml
启动 finclip 服务
在部署机器上执行(中控机上)
使用 cd 命令切换到 FinClip 编排 Helm chart 目录 :finclip-chart(不同版本目录名不同)
执行命令启动服务:Helm install finclip . -n finclip
启动完成查看 pod 状态是否为 running:kubectl get pod -n finclip
其他命令参考:
配置修改后更新:Helm upgrade finclip . -n finclip
卸载:Helm uninstall finclip -n finclip
网站名称 | 访问链接 | 初始账户 | 说明 |
---|---|---|---|
数字中⼼ | http://IP:PORT/ops#/ | admin | PORT:端口号,默认 30001,IP:服务器所在ip地址,如: 172.217.163.46 |
开发中⼼ | http://IP:PORT/dev#/ | 自行注册 |
访问地址:集群版部署
',112)]))}const y=s(p,[["render",h]]);export{b as __pageData,y as default}; diff --git a/docs/assets/docs_deployment_rollback-and-backup.md.YcuMlt4j.js b/docs/assets/docs_deployment_rollback-and-backup.md.YcuMlt4j.js new file mode 100644 index 0000000..ce580ea --- /dev/null +++ b/docs/assets/docs_deployment_rollback-and-backup.md.YcuMlt4j.js @@ -0,0 +1,2 @@ +import{_ as s,c as a,a9 as t,o as h}from"./chunks/framework.BjXht68r.js";const l="/images/rollback.png",o=JSON.parse('{"title":"备份和回滚","description":"A guide in my new Starlight docs site.","frontmatter":{"title":"备份和回滚","description":"A guide in my new Starlight docs site."},"headers":[],"relativePath":"docs/deployment/rollback-and-backup.md","filePath":"docs/deployment/rollback-and-backup.md"}'),k={name:"docs/deployment/rollback-and-backup.md"};function p(e,i,n,d,r,g){return h(),a("div",null,i[0]||(i[0]=[t(`配置文件备份
备份 FinClip 配置文件,路径根据版本调整
cp /data/finclip-installation/<当前版本> /data/backup/
数据备份
对系统的数据库和存储服务(MySQL 和 MinIO)进行备份,执行以下操作:
MySQL 数据库备份
mysqldump -h <mysql_host> -u <user> -p<password> --all-databases > /data/backup/mysql-backup-$(date +%Y%m%d%H%M%S).sql
MinIO 数据备份
使用 MinIO 客户端 (mc) 备份存储数据:
mc alias set myminio http://<minio_host> <access_key> <secret_key>
+mc mirror myminio/<bucket_name> /data/backup/minio-backup-$(date +%Y%m%d%H%M%S)
查看历史版本
登录包含 kubectl
和 helm
工具的服务器,执行以下命令查看部署历史版本:
helm history finclip -n finclip
选择回滚版本
查看历史版本的输出,找到需要回滚到的版本号,通常是当前版本的前一个版本(deployed
状态之前的版本)。
执行回滚操作
使用以下命令执行回滚操作:
helm rollback finclip <version_number> -n finclip
注意:将
<version_number>
替换为要回滚到的版本号。
验证回滚结果
验证 Pod 状态
kubectl -n finclip get pod
确保所有 Pod 的 STATUS
均为 Running
。
配置文件备份
备份 FinClip 配置文件,路径根据版本调整
cp /data/finclip-installation/<当前版本> /data/backup/
数据备份
对系统的数据库和存储服务(MySQL 和 MinIO)进行备份,执行以下操作:
MySQL 数据库备份
mysqldump -h <mysql_host> -u <user> -p<password> --all-databases > /data/backup/mysql-backup-$(date +%Y%m%d%H%M%S).sql
MinIO 数据备份
使用 MinIO 客户端 (mc) 备份存储数据:
mc alias set myminio http://<minio_host> <access_key> <secret_key>
+mc mirror myminio/<bucket_name> /data/backup/minio-backup-$(date +%Y%m%d%H%M%S)
查看历史版本
登录包含 kubectl
和 helm
工具的服务器,执行以下命令查看部署历史版本:
helm history finclip -n finclip
选择回滚版本
查看历史版本的输出,找到需要回滚到的版本号,通常是当前版本的前一个版本(deployed
状态之前的版本)。
执行回滚操作
使用以下命令执行回滚操作:
helm rollback finclip <version_number> -n finclip
注意:将
<version_number>
替换为要回滚到的版本号。
验证回滚结果
验证 Pod 状态
kubectl -n finclip get pod
确保所有 Pod 的 STATUS
均为 Running
。
根据上一章的描述,我们可以根据实际业务需求,来准备和规划 FinClip 平台的部署:
在一般的场景里,我们会采用业务系统日活(DAU)来确定系统规模。然而在实际情况中,采用日活估计系统规模会存在一定偏差,影响因素包括用户使用频率、小程序包大小、是否开启 CDN、业务访问高峰期等因素。因此,我们采用 TPS、QPS 等指标来确定需求,会更加容易确定系统规模的需求。
根据我们的压力测试数据,可以作为参考:
1 台服务器
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
最低配置 | 4 核 | 8 GB | 100 GB | 1 | 4000 |
推荐配置 | 8 核 | 16 GB | 200 GB | 1 | 6000 |
4 台服务器
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 4 台 | 1.5w |
运维管理 | 8 核 | 16 GB | 500 GB | 1 台 | - |
8 台服务器
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 8 台 | 3w |
运维管理 | 8 核 | 16 GB | 500 GB | 1 台 | - |
网络和带宽
根据上一章的描述,我们可以根据实际业务需求,来准备和规划 FinClip 平台的部署:
在一般的场景里,我们会采用业务系统日活(DAU)来确定系统规模。然而在实际情况中,采用日活估计系统规模会存在一定偏差,影响因素包括用户使用频率、小程序包大小、是否开启 CDN、业务访问高峰期等因素。因此,我们采用 TPS、QPS 等指标来确定需求,会更加容易确定系统规模的需求。
根据我们的压力测试数据,可以作为参考:
1 台服务器
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
最低配置 | 4 核 | 8 GB | 100 GB | 1 | 4000 |
推荐配置 | 8 核 | 16 GB | 200 GB | 1 | 6000 |
4 台服务器
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 4 台 | 1.5w |
运维管理 | 8 核 | 16 GB | 500 GB | 1 台 | - |
8 台服务器
用途 | CPU | 内存 | 储存空间 | 数量 | 参考 TPS |
---|---|---|---|---|---|
业务服务 | 8 核 | 16 GB | 500 GB | 8 台 | 3w |
运维管理 | 8 核 | 16 GB | 500 GB | 1 台 | - |
网络和带宽
根据具体升级内容,调整版本或组件。例如:
下载并上传离线镜像包到部署服务器 镜像包下载链接由凡泰提供
导入离线镜像 使用以下命令导入镜像并推送至私有仓库:
for i in `docker load -i <离线镜像包文件名> |awk '{print $NF}'` ; do docker tag $i `echo $i|awk -F '/' '{print "registry.finogeeks.internal:5000/mop/"$NF}'` ; docker push `echo $i|awk -F '/' '{print "registry.finogeeks.internal:5000/mop/"$NF}'` ;done
备份配置文件
备份 FinClip 配置文件,路径根据版本调整(示例路径:/data/finclip-installation/1.12.0/values.yaml
)
cp /data/finclip-installation/1.12.0/values.yaml /data/finclip-installation/1.12.0/values-$(date +%Y%m%d%H%M%S).yaml
修改配置文件
编辑 FinClip 配置文件:
vim values.yaml
根据升级需求修改配置。例如:
apps:\n integration_api: registry.finogeeks.internal:5000/mop/integration-api:<目标版本号>
执行升级命令 使用 helm
工具进行升级,命令如下:
helm upgrade finclip -n finclip /data/finclip/<版本号>
检查 Pod 状态
升级完成后,确认所有组件运行正常:
kubectl get pod -n finclip
列应显示为 :Running
kubectl -n finclip logs
查看具体组件日志排查。根据具体升级内容,调整版本或组件。例如:
下载并上传离线镜像包到部署服务器 镜像包下载链接由凡泰提供
导入离线镜像 使用以下命令导入镜像并推送至私有仓库:
for i in `docker load -i <离线镜像包文件名> |awk '{print $NF}'` ; do docker tag $i `echo $i|awk -F '/' '{print "registry.finogeeks.internal:5000/mop/"$NF}'` ; docker push `echo $i|awk -F '/' '{print "registry.finogeeks.internal:5000/mop/"$NF}'` ;done
备份配置文件
备份 FinClip 配置文件,路径根据版本调整(示例路径:/data/finclip-installation/1.12.0/values.yaml
)
cp /data/finclip-installation/1.12.0/values.yaml /data/finclip-installation/1.12.0/values-$(date +%Y%m%d%H%M%S).yaml
修改配置文件
编辑 FinClip 配置文件:
vim values.yaml
根据升级需求修改配置。例如:
apps:\n integration_api: registry.finogeeks.internal:5000/mop/integration-api:<目标版本号>
执行升级命令 使用 helm
工具进行升级,命令如下:
helm upgrade finclip -n finclip /data/finclip/<版本号>
检查 Pod 状态
升级完成后,确认所有组件运行正常:
kubectl get pod -n finclip
列应显示为 :Running
kubectl -n finclip logs
查看具体组件日志排查。FinClip 小程序数字化管理系统 - 系统巡检
本手册通过ansible进行系统巡检并生成报告。 适用于通过部署文档安装的集群: https://devops-docs.finogeeks.club/deployment/03_installation_steps/
· 准备巡检ansible-playbook的包,上传服务器。
https://static.finogeeks.club/deploy/download/check-master.tar.gz
tar -zxvf check-master.tar.gz
+cd check-master
+
+# 复制部署集群的inventory文件或新建文件inventory添加所有节点ip
+cp /data/finclip-installation/finclip-deploy-ansible-master/inventory .
+
+# 执行巡检脚本
+ansible-playbook init.yml
执行完毕,无报错信息。
报告文件生成:服务器/tmp/report-%Y-%m-%d.html
下载文件到本地电脑用浏览器打开:
· 关注 服务器资源使用情况
正常指标: ok Total = Total
· 关注 Kubernetes集群及服务情况
正常指标: 集群正常,服务状态正常,对比上次巡检无重启pod
',18)]))}const f=e(l,[["render",o]]);export{b as __pageData,f as default}; diff --git a/docs/assets/docs_maintenance_patrol.md.Xz-WgIH8.lean.js b/docs/assets/docs_maintenance_patrol.md.Xz-WgIH8.lean.js new file mode 100644 index 0000000..278f85c --- /dev/null +++ b/docs/assets/docs_maintenance_patrol.md.Xz-WgIH8.lean.js @@ -0,0 +1,8 @@ +import{_ as e,c as s,a9 as n,o as t}from"./chunks/framework.BjXht68r.js";const p="/images/patrol.png",i="/images/patrol02.png",b=JSON.parse('{"title":"运维巡检","description":"A reference page in my new Starlight docs site.","frontmatter":{"title":"运维巡检","description":"A reference page in my new Starlight docs site."},"headers":[],"relativePath":"docs/maintenance/patrol.md","filePath":"docs/maintenance/patrol.md"}'),l={name:"docs/maintenance/patrol.md"};function o(r,a,c,d,h,m){return t(),s("div",null,a[0]||(a[0]=[n(`FinClip 小程序数字化管理系统 - 系统巡检
本手册通过ansible进行系统巡检并生成报告。 适用于通过部署文档安装的集群: https://devops-docs.finogeeks.club/deployment/03_installation_steps/
· 准备巡检ansible-playbook的包,上传服务器。
https://static.finogeeks.club/deploy/download/check-master.tar.gz
tar -zxvf check-master.tar.gz
+cd check-master
+
+# 复制部署集群的inventory文件或新建文件inventory添加所有节点ip
+cp /data/finclip-installation/finclip-deploy-ansible-master/inventory .
+
+# 执行巡检脚本
+ansible-playbook init.yml
执行完毕,无报错信息。
报告文件生成:服务器/tmp/report-%Y-%m-%d.html
下载文件到本地电脑用浏览器打开:
· 关注 服务器资源使用情况
正常指标: ok Total = Total
· 关注 Kubernetes集群及服务情况
正常指标: 集群正常,服务状态正常,对比上次巡检无重启pod
',18)]))}const f=e(l,[["render",o]]);export{b as __pageData,f as default}; diff --git a/docs/assets/docs_monitoring_logging.md.cvCCB2Uv.js b/docs/assets/docs_monitoring_logging.md.cvCCB2Uv.js new file mode 100644 index 0000000..426d5a1 --- /dev/null +++ b/docs/assets/docs_monitoring_logging.md.cvCCB2Uv.js @@ -0,0 +1 @@ +import{_ as o,c as i,a9 as r,o as t}from"./chunks/framework.BjXht68r.js";const e="/images/promtail-loki.png",g=JSON.parse('{"title":"日志系统","description":"A guide in my new Starlight docs site.","frontmatter":{"title":"日志系统","description":"A guide in my new Starlight docs site."},"headers":[],"relativePath":"docs/monitoring/logging.md","filePath":"docs/monitoring/logging.md"}'),n={name:"docs/monitoring/logging.md"};function l(s,a,h,d,c,m){return t(),i("div",null,a[0]||(a[0]=[r('在现代的软件系统运维中,日志收集与分析至关重要。我们的日志收集系统基于 Promtail、Loki 和 Grafana 构建,是一个高效且功能强大的解决方案。它能够从复杂的系统环境中收集日志,对其进行有效的存储和管理,并通过直观的可视化界面帮助运维人员和开发人员快速获取有价值的信息,用于系统监控、故障排查、性能分析、安全审计等多种场景,保障系统的稳定运行和持续优化。
我们的日志收集系统基于开源组件 Promtail、Loki 和 Grafana 构建了一个高效的日志收集和分析平台,能够实时收集、存储和展示应用服务的日志数据。
如下图所示,日志系统包含 Promtail、Loki 和 Grafana 三个核心组件。Promtail 作为日志收集工具,负责将日志从各个服务中提取并发送到 Loki,Loki 则负责存储日志数据,Grafana 提供强大的日志可视化和查询能力,帮助用户快速定位问题和监控服务健康状况。
配置日志收集规则,当应用日志中出现关键字(如 "ERROR" 或 "Exception")时,Loki 将该日志数据存储,并通过 Grafana 创建仪表盘,实时展示异常日志的数量和详细信息,帮助运维人员快速定位问题。
在 Grafana 中创建仪表盘,监控各服务的响应时间。当某个服务的响应时间超过 5 秒时,Loki 将记录该事件并将其展示在 Grafana 中。运维人员可在仪表盘中实时查看,快速发现响应慢的服务,并通过设置告警规则通知相关人员。
随着日志量的增加,需要定期清理不再需要的日志数据。可以在 Loki 中配置日志保留策略,按时间或日志级别进行自动清理,确保日志系统的高效运行并节省存储空间。
',20)]))}const p=o(n,[["render",l]]);export{g as __pageData,p as default}; diff --git a/docs/assets/docs_monitoring_logging.md.cvCCB2Uv.lean.js b/docs/assets/docs_monitoring_logging.md.cvCCB2Uv.lean.js new file mode 100644 index 0000000..426d5a1 --- /dev/null +++ b/docs/assets/docs_monitoring_logging.md.cvCCB2Uv.lean.js @@ -0,0 +1 @@ +import{_ as o,c as i,a9 as r,o as t}from"./chunks/framework.BjXht68r.js";const e="/images/promtail-loki.png",g=JSON.parse('{"title":"日志系统","description":"A guide in my new Starlight docs site.","frontmatter":{"title":"日志系统","description":"A guide in my new Starlight docs site."},"headers":[],"relativePath":"docs/monitoring/logging.md","filePath":"docs/monitoring/logging.md"}'),n={name:"docs/monitoring/logging.md"};function l(s,a,h,d,c,m){return t(),i("div",null,a[0]||(a[0]=[r('在现代的软件系统运维中,日志收集与分析至关重要。我们的日志收集系统基于 Promtail、Loki 和 Grafana 构建,是一个高效且功能强大的解决方案。它能够从复杂的系统环境中收集日志,对其进行有效的存储和管理,并通过直观的可视化界面帮助运维人员和开发人员快速获取有价值的信息,用于系统监控、故障排查、性能分析、安全审计等多种场景,保障系统的稳定运行和持续优化。
我们的日志收集系统基于开源组件 Promtail、Loki 和 Grafana 构建了一个高效的日志收集和分析平台,能够实时收集、存储和展示应用服务的日志数据。
如下图所示,日志系统包含 Promtail、Loki 和 Grafana 三个核心组件。Promtail 作为日志收集工具,负责将日志从各个服务中提取并发送到 Loki,Loki 则负责存储日志数据,Grafana 提供强大的日志可视化和查询能力,帮助用户快速定位问题和监控服务健康状况。
配置日志收集规则,当应用日志中出现关键字(如 "ERROR" 或 "Exception")时,Loki 将该日志数据存储,并通过 Grafana 创建仪表盘,实时展示异常日志的数量和详细信息,帮助运维人员快速定位问题。
在 Grafana 中创建仪表盘,监控各服务的响应时间。当某个服务的响应时间超过 5 秒时,Loki 将记录该事件并将其展示在 Grafana 中。运维人员可在仪表盘中实时查看,快速发现响应慢的服务,并通过设置告警规则通知相关人员。
随着日志量的增加,需要定期清理不再需要的日志数据。可以在 Loki 中配置日志保留策略,按时间或日志级别进行自动清理,确保日志系统的高效运行并节省存储空间。
',20)]))}const p=o(n,[["render",l]]);export{g as __pageData,p as default}; diff --git a/docs/assets/docs_monitoring_metrics.md.BpjmOyW2.js b/docs/assets/docs_monitoring_metrics.md.BpjmOyW2.js new file mode 100644 index 0000000..edd9c15 --- /dev/null +++ b/docs/assets/docs_monitoring_metrics.md.BpjmOyW2.js @@ -0,0 +1 @@ +import{_ as e,c as t,a9 as r,o as s}from"./chunks/framework.BjXht68r.js";const u=JSON.parse('{"title":"监控指标","description":"A guide in my new Starlight docs site.","frontmatter":{"title":"监控指标","description":"A guide in my new Starlight docs site."},"headers":[],"relativePath":"docs/monitoring/metrics.md","filePath":"docs/monitoring/metrics.md"}'),n={name:"docs/monitoring/metrics.md"};function i(l,o,a,_,g,d){return s(),t("div",null,o[0]||(o[0]=[r('container_cpu_usage_seconds_total: 容器的CPU使用时间(秒)。
container_memory_usage_bytes: 容器使用的内存(字节)。
container_memory_working_set_bytes: 容器正在使用的内存,不包括缓存。
container_fs_usage_bytes: 容器使用的磁盘空间(字节)。
container_last_seen: 容器最后一次被检查的时间。
container_start_time_seconds: 容器的启动时间戳(秒)。
kube_pod_status_phase: Pod的当前状态(Running、Pending、Succeeded、Failed、Unknown)。
kube_pod_container_status_restarts_total: Pod容器的重启次数。
kube_pod_container_status_running: Pod容器是否正在运行。
kube_pod_container_status_terminated: Pod容器是否已终止。
kube_pod_container_status_waiting: Pod容器是否处于等待状态。
used_cpu_sys: Redis进程在系统中使用的CPU时间(秒)。
used_cpu_user: Redis进程在用户空间中使用的CPU时间(秒)。
used_cpu_sys_children: 所有子进程在系统中使用的CPU时间(秒)。
used_cpu_user_children: 所有子进程在用户空间中使用的CPU时间(秒)。
used_memory_rss: 操作系统分配给Redis进程的内存量(RSS)。
used_memory_peak: Redis实例的最大内存使用量(字节)。
maxmemory: Redis配置的最大内存限制(字节)。
mem_fragmentation_ratio: 内存碎片率。计算为used_memory_rss / used_memory
,用于指示内存的浪费情况。
used_memory: Redis实例已使用的内存总量(字节)。
Cpu_usage
: CPU的使用率。Memory_usage
: 内存的使用率。Disk_space_usage
: 磁盘的使用情况。Threads_connected
: 当前连接的线程数。Threads_running
: 当前处于运行状态的线程数。Threads_created
: 自启动以来创建的线程数。Max_used_connections
: MySQL历史上最大并发连接数。Aborted_connects
: 尝试连接但失败的次数。Queries
: 每秒查询数。Slow_queries
: 慢查询的数量。Select_full_join
: 执行全表连接的查询数。Select_range_check
: 使用范围查询的次数。Sort_merge_passes
: 执行排序时需要的合并操作数。Com_select
, Com_insert
, Com_update
, Com_delete
: 分别表示SELECT、INSERT、UPDATE、DELETE命令的执行次数。Key_read_requests
: 从缓存中读取的请求数。Key_reads
: 从磁盘读取的键数。Key_write_requests
: 向缓存中写入的请求数。Key_writes
: 写入缓存的键数。InnoDB_buffer_pool_reads
: 从InnoDB缓存池读取的次数。InnoDB_buffer_pool_pages_dirty
: 缓存池中脏页的数量。Seconds_Behind_Master
: 从服务器与主服务器的延迟时间(秒)。Slave_IO_Running
: 复制IO线程的状态。Slave_SQL_Running
: 复制SQL线程的状态。Innodb_buffer_pool_size
: InnoDB缓冲池的大小。Innodb_buffer_pool_free
: 缓冲池中未使用的空间。Innodb_buffer_pool_wait_free
: 等待可用内存的次数。Innodb_row_lock_current_waits
: 当前等待行锁的次数。minio_memory_used_bytes
: 当前内存使用量(字节数)。minio_cpu_usage
: CPU使用率。minio_cpu_load
: CPU负载(1分钟、5分钟、15分钟平均负载minio_api_requests_total
: API 请求的总数。minio_api_request_duration_seconds
: API 请求的响应时间(秒)。minio_api_requests_rate
: API 请求速率(每秒请求数)。minio_api_errors_total
: API 请求中的错误总数。minio_api_success_total
: 成功处理的 API 请求总数。minio_api_latency_seconds
: API 请求的延迟时间(秒)。minio_network_received_bytes_total
: 从客户端接收的总字节数。minio_network_sent_bytes_total
: 向客户端发送的总字节数。minio_network_error_total
: 网络错误的总数。minio_network_requests_total
: 网络请求总数。minio_errors_total
: 总的错误次数。minio_error_rate
: 错误率(每秒发生的错误数)。minio_object_errs
: 对象存储中的错误数量。minio_request_errs
: API 请求中的错误数量。minio_health_check
: MinIO实例的健康检查状态。
minio_uptime_seconds
: MinIO实例的运行时间(秒)。
minio_heartbeat
: 用于检测节点心跳的状态。
minio_watchdog_timeouts
: 监控超时的次数。
minio_cluster_health
: MinIO集群的健康状况(用于集群部署)。
minio_cluster_nodes
: 集群中可用节点的数量。
container_cpu_usage_seconds_total: 容器的CPU使用时间(秒)。
container_memory_usage_bytes: 容器使用的内存(字节)。
container_memory_working_set_bytes: 容器正在使用的内存,不包括缓存。
container_fs_usage_bytes: 容器使用的磁盘空间(字节)。
container_last_seen: 容器最后一次被检查的时间。
container_start_time_seconds: 容器的启动时间戳(秒)。
kube_pod_status_phase: Pod的当前状态(Running、Pending、Succeeded、Failed、Unknown)。
kube_pod_container_status_restarts_total: Pod容器的重启次数。
kube_pod_container_status_running: Pod容器是否正在运行。
kube_pod_container_status_terminated: Pod容器是否已终止。
kube_pod_container_status_waiting: Pod容器是否处于等待状态。
used_cpu_sys: Redis进程在系统中使用的CPU时间(秒)。
used_cpu_user: Redis进程在用户空间中使用的CPU时间(秒)。
used_cpu_sys_children: 所有子进程在系统中使用的CPU时间(秒)。
used_cpu_user_children: 所有子进程在用户空间中使用的CPU时间(秒)。
used_memory_rss: 操作系统分配给Redis进程的内存量(RSS)。
used_memory_peak: Redis实例的最大内存使用量(字节)。
maxmemory: Redis配置的最大内存限制(字节)。
mem_fragmentation_ratio: 内存碎片率。计算为used_memory_rss / used_memory
,用于指示内存的浪费情况。
used_memory: Redis实例已使用的内存总量(字节)。
Cpu_usage
: CPU的使用率。Memory_usage
: 内存的使用率。Disk_space_usage
: 磁盘的使用情况。Threads_connected
: 当前连接的线程数。Threads_running
: 当前处于运行状态的线程数。Threads_created
: 自启动以来创建的线程数。Max_used_connections
: MySQL历史上最大并发连接数。Aborted_connects
: 尝试连接但失败的次数。Queries
: 每秒查询数。Slow_queries
: 慢查询的数量。Select_full_join
: 执行全表连接的查询数。Select_range_check
: 使用范围查询的次数。Sort_merge_passes
: 执行排序时需要的合并操作数。Com_select
, Com_insert
, Com_update
, Com_delete
: 分别表示SELECT、INSERT、UPDATE、DELETE命令的执行次数。Key_read_requests
: 从缓存中读取的请求数。Key_reads
: 从磁盘读取的键数。Key_write_requests
: 向缓存中写入的请求数。Key_writes
: 写入缓存的键数。InnoDB_buffer_pool_reads
: 从InnoDB缓存池读取的次数。InnoDB_buffer_pool_pages_dirty
: 缓存池中脏页的数量。Seconds_Behind_Master
: 从服务器与主服务器的延迟时间(秒)。Slave_IO_Running
: 复制IO线程的状态。Slave_SQL_Running
: 复制SQL线程的状态。Innodb_buffer_pool_size
: InnoDB缓冲池的大小。Innodb_buffer_pool_free
: 缓冲池中未使用的空间。Innodb_buffer_pool_wait_free
: 等待可用内存的次数。Innodb_row_lock_current_waits
: 当前等待行锁的次数。minio_memory_used_bytes
: 当前内存使用量(字节数)。minio_cpu_usage
: CPU使用率。minio_cpu_load
: CPU负载(1分钟、5分钟、15分钟平均负载minio_api_requests_total
: API 请求的总数。minio_api_request_duration_seconds
: API 请求的响应时间(秒)。minio_api_requests_rate
: API 请求速率(每秒请求数)。minio_api_errors_total
: API 请求中的错误总数。minio_api_success_total
: 成功处理的 API 请求总数。minio_api_latency_seconds
: API 请求的延迟时间(秒)。minio_network_received_bytes_total
: 从客户端接收的总字节数。minio_network_sent_bytes_total
: 向客户端发送的总字节数。minio_network_error_total
: 网络错误的总数。minio_network_requests_total
: 网络请求总数。minio_errors_total
: 总的错误次数。minio_error_rate
: 错误率(每秒发生的错误数)。minio_object_errs
: 对象存储中的错误数量。minio_request_errs
: API 请求中的错误数量。minio_health_check
: MinIO实例的健康检查状态。
minio_uptime_seconds
: MinIO实例的运行时间(秒)。
minio_heartbeat
: 用于检测节点心跳的状态。
minio_watchdog_timeouts
: 监控超时的次数。
minio_cluster_health
: MinIO集群的健康状况(用于集群部署)。
minio_cluster_nodes
: 集群中可用节点的数量。
在私有化部署环境中,监控与告警系统是维护服务稳定运行的关键。我们利用开源组件 Prometheus 进行数据采集和监控,Alertmanager 用于告警管理,Grafana 作为可视化平台,提供实时数据分析和展示。本监控体系为系统运维和开发团队提供了故障发现和预防的强有力支持。
在下图的流程中,Prometheus 通过配置文件指定的服务发现方式(如 ServiceMonitor 和 PodMonitor)确定要拉取监控指标的目标(Target),包括应用容器和 Pushgateway。Prometheus 通过 HTTP 请求访问这些目标的特定端点(Metric Path),将指标数据拉取并持久化到自身的时序数据库(TSDB)中。
Prometheus 还会周期性地通过 PromQL 计算配置的告警规则,决定是否生成告警并将其发送到 Alertmanager。Alertmanager 接收到告警后负责进行告警通知的分发,发送到邮件或短信等指定渠道。
此外,Grafana 作为可视化平台,连接 Prometheus 数据源,通过可定制的仪表盘实时展示监控数据。Grafana 支持多种图表类型和交互式数据展示,帮助团队直观地了解系统性能、发现趋势并快速定位问题。
设置告警规则,当应用服务的 CPU 使用率持续超过 90% 超过 5 分钟时,触发告警并通过 Alertmanager 发送邮件或短信到指定渠道。
配置监控规则,当某服务在一定时间内频繁重启时,触发中等告警,通知运维人员检查相关服务。
在 Grafana 中创建内存使用仪表盘,设置可视化图表,展示每个服务的内存使用趋势,并标记告警线。
',21)]))}const p=e(i,[["render",l]]);export{g as __pageData,p as default}; diff --git a/docs/assets/docs_monitoring_monitoring.md.xNP4ujNA.lean.js b/docs/assets/docs_monitoring_monitoring.md.xNP4ujNA.lean.js new file mode 100644 index 0000000..ebf78c4 --- /dev/null +++ b/docs/assets/docs_monitoring_monitoring.md.xNP4ujNA.lean.js @@ -0,0 +1 @@ +import{_ as e,c as r,a9 as t,o}from"./chunks/framework.BjXht68r.js";const n="/images/prometheus.png",g=JSON.parse('{"title":"监控系统","description":"A guide in my new Starlight docs site.","frontmatter":{"title":"监控系统","description":"A guide in my new Starlight docs site."},"headers":[],"relativePath":"docs/monitoring/monitoring.md","filePath":"docs/monitoring/monitoring.md"}'),i={name:"docs/monitoring/monitoring.md"};function l(s,a,h,m,d,u){return o(),r("div",null,a[0]||(a[0]=[t('在私有化部署环境中,监控与告警系统是维护服务稳定运行的关键。我们利用开源组件 Prometheus 进行数据采集和监控,Alertmanager 用于告警管理,Grafana 作为可视化平台,提供实时数据分析和展示。本监控体系为系统运维和开发团队提供了故障发现和预防的强有力支持。
在下图的流程中,Prometheus 通过配置文件指定的服务发现方式(如 ServiceMonitor 和 PodMonitor)确定要拉取监控指标的目标(Target),包括应用容器和 Pushgateway。Prometheus 通过 HTTP 请求访问这些目标的特定端点(Metric Path),将指标数据拉取并持久化到自身的时序数据库(TSDB)中。
Prometheus 还会周期性地通过 PromQL 计算配置的告警规则,决定是否生成告警并将其发送到 Alertmanager。Alertmanager 接收到告警后负责进行告警通知的分发,发送到邮件或短信等指定渠道。
此外,Grafana 作为可视化平台,连接 Prometheus 数据源,通过可定制的仪表盘实时展示监控数据。Grafana 支持多种图表类型和交互式数据展示,帮助团队直观地了解系统性能、发现趋势并快速定位问题。
设置告警规则,当应用服务的 CPU 使用率持续超过 90% 超过 5 分钟时,触发告警并通过 Alertmanager 发送邮件或短信到指定渠道。
配置监控规则,当某服务在一定时间内频繁重启时,触发中等告警,通知运维人员检查相关服务。
在 Grafana 中创建内存使用仪表盘,设置可视化图表,展示每个服务的内存使用趋势,并标记告警线。
',21)]))}const p=e(i,[["render",l]]);export{g as __pageData,p as default}; diff --git a/docs/assets/docs_operations_database-import-export.md.BvJpvOCb.js b/docs/assets/docs_operations_database-import-export.md.BvJpvOCb.js new file mode 100644 index 0000000..142f0cd --- /dev/null +++ b/docs/assets/docs_operations_database-import-export.md.BvJpvOCb.js @@ -0,0 +1,4 @@ +import{_ as i,c as a,a9 as t,o as e}from"./chunks/framework.BjXht68r.js";const c=JSON.parse('{"title":"数据备份和恢复","description":"A guide in my new Starlight docs site.","frontmatter":{"title":"数据备份和恢复","description":"A guide in my new Starlight docs site."},"headers":[],"relativePath":"docs/operations/database-import-export.md","filePath":"docs/operations/database-import-export.md"}'),l={name:"docs/operations/database-import-export.md"};function n(p,s,h,k,d,r){return e(),a("div",null,s[0]||(s[0]=[t(`适用于自建minio环境
mysql_backup:
+ enabled: false
+ bucket: finclip-db-backup
打开配置后,每天0点全量备份mysql数据并上传到minio指定桶,保存时间为30天。
恢复MySQL数据库的方法 mysql命令是MySQL官方提供的用于恢复数据库的命令行工具。以下是使用mysql命令恢复数据库的步骤:
1. 登录minio,http://ip:9000下载备份文件
+2. 导入全备数据: mysql -u 用户名 -p 数据库名 < 备份文件名.sql
适用于自建minio环境
mysql_backup:
+ enabled: false
+ bucket: finclip-db-backup
打开配置后,每天0点全量备份mysql数据并上传到minio指定桶,保存时间为30天。
恢复MySQL数据库的方法 mysql命令是MySQL官方提供的用于恢复数据库的命令行工具。以下是使用mysql命令恢复数据库的步骤:
1. 登录minio,http://ip:9000下载备份文件
+2. 导入全备数据: mysql -u 用户名 -p 数据库名 < 备份文件名.sql
一般企业内部都有自己的镜像仓库,你需要将镜像 retag
之后提交到你所使用的仓库,在没有镜像仓库的情况下,我们会部署 registry 来作为内部仓库。以下是一些镜像仓库的基本操作:
拉取镜像:
docker login xxx.example.com
+docker pull xxx.example.com/mop/xxx:version
提交镜像
docker push xxx.example.com/mop/xxx:version
kubernetes创建 docker 登录认证 secret
kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER
+--docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
一般企业内部都有自己的镜像仓库,你需要将镜像 retag
之后提交到你所使用的仓库,在没有镜像仓库的情况下,我们会部署 registry 来作为内部仓库。以下是一些镜像仓库的基本操作:
拉取镜像:
docker login xxx.example.com
+docker pull xxx.example.com/mop/xxx:version
提交镜像
docker push xxx.example.com/mop/xxx:version
kubernetes创建 docker 登录认证 secret
kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER
+--docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
步骤说明:
访问数字中心首页
登录系统
访问许可证更新页面
登录成功后,您将进入系统的首页界面。
在首页页面的右下方,有一个更新许可证”的按钮。
点击“更新许可证”按钮,系统会弹出许可证更新框。
输入新的许可证
输入新的许可证。
检查许可证时间是否正确,然后点击“确定”按钮进行更新。
更新完成
步骤说明:
访问数字中心首页
登录系统
系统提示许可证已过期
输入新的许可证
点击“确定”进行更新
许可证更新成功
1. 如果在更新过程中出现错误提示,怎么办?
2. 系统提示“网络错误”怎么办?
步骤说明:
访问数字中心首页
登录系统
访问许可证更新页面
登录成功后,您将进入系统的首页界面。
在首页页面的右下方,有一个更新许可证”的按钮。
点击“更新许可证”按钮,系统会弹出许可证更新框。
输入新的许可证
输入新的许可证。
检查许可证时间是否正确,然后点击“确定”按钮进行更新。
更新完成
步骤说明:
访问数字中心首页
登录系统
系统提示许可证已过期
输入新的许可证
点击“确定”进行更新
许可证更新成功
1. 如果在更新过程中出现错误提示,怎么办?
2. 系统提示“网络错误”怎么办?
FinClip 后端服务采用高性能的编程语言编写,通常情况下,我们在第一次部署之后便无需做太多变更。对于特定情况,我们可能需要考虑对系统进行维护,以下是一些日常操作的示例说明,以供参考。
FinClip 单机版本采用 docker 管理,集群版本采用 Kubernetes 进行管理,因此,我们采用 docker 或者 kubectl 客户端工具进行服务管理。
1. 重启服务
对于 docker 部署的版本:
docker restart contaienr-id
对于 kubernetes 部署的版本:
kubectl get po
+kubectl delete po pod-id
+#如果有指定命名空间
+kubectl delete po -n namespace pod-id
+
+#或者
+kubectl rollout restart deployment --selector=tier=backend
2. 服务扩缩容
对于Kubernetes部署的集群版本服务,可以对服务进行扩容,以提高QPS承载能力
kubectl scale --replicas=3 deployment/deployment-name
检查服务日志主要是通过查看容器的输出操作。
docker 部署
docker logs contaielr-id
kubernetes部署
kubectl logs --tail=10086 -f pod-id
FinClip 后端服务采用高性能的编程语言编写,通常情况下,我们在第一次部署之后便无需做太多变更。对于特定情况,我们可能需要考虑对系统进行维护,以下是一些日常操作的示例说明,以供参考。
FinClip 单机版本采用 docker 管理,集群版本采用 Kubernetes 进行管理,因此,我们采用 docker 或者 kubectl 客户端工具进行服务管理。
1. 重启服务
对于 docker 部署的版本:
docker restart contaienr-id
对于 kubernetes 部署的版本:
kubectl get po
+kubectl delete po pod-id
+#如果有指定命名空间
+kubectl delete po -n namespace pod-id
+
+#或者
+kubectl rollout restart deployment --selector=tier=backend
2. 服务扩缩容
对于Kubernetes部署的集群版本服务,可以对服务进行扩容,以提高QPS承载能力
kubectl scale --replicas=3 deployment/deployment-name
检查服务日志主要是通过查看容器的输出操作。
docker 部署
docker logs contaielr-id
kubernetes部署
kubectl logs --tail=10086 -f pod-id
FinClip 小程序数字化管理系统是一套私有化小程序平台解决方案,它能为企业应用提供强大、使用灵活且稳定高效的小程序功能,使得企业 App 像微信、支付宝那样可以为开发者和用户提供小程序能力。FinClip拥有完整的小程序生态工具,从 SDK 到管理后端,兼容常用的热门开发框架,助力企业在数字化转型进程中,以小程序化的内容,建立起产品、业务与用户之间的数字连接。 本文档项目旨在提供全面的FinClip运维手册,尽可能涉及FinClip运行维护的方方面面,以保障我们的小程序平台稳定运行。
视频介绍:
本文档是 FinClip 交付团队提供的运维指南,手册主要介绍 FinClip 私有化部署的运维架构和日常维护事项,也包含部分应急处理与运维相关技术知识,比如:
产品官方网站:https://www.finclip.com/
',7)]))}const h=t(p,[["render",n]]);export{m as __pageData,h as default}; diff --git a/docs/assets/docs_overview_product-intro.md.C_DLdR5P.lean.js b/docs/assets/docs_overview_product-intro.md.C_DLdR5P.lean.js new file mode 100644 index 0000000..4548931 --- /dev/null +++ b/docs/assets/docs_overview_product-intro.md.C_DLdR5P.lean.js @@ -0,0 +1 @@ +import{_ as t,c as o,a9 as e,o as r}from"./chunks/framework.BjXht68r.js";const m=JSON.parse('{"title":"产品简介","description":"","frontmatter":{},"headers":[],"relativePath":"docs/overview/product-intro.md","filePath":"docs/overview/product-intro.md"}'),p={name:"docs/overview/product-intro.md"};function n(a,i,l,c,s,d){return r(),o("div",null,i[0]||(i[0]=[e('FinClip 小程序数字化管理系统是一套私有化小程序平台解决方案,它能为企业应用提供强大、使用灵活且稳定高效的小程序功能,使得企业 App 像微信、支付宝那样可以为开发者和用户提供小程序能力。FinClip拥有完整的小程序生态工具,从 SDK 到管理后端,兼容常用的热门开发框架,助力企业在数字化转型进程中,以小程序化的内容,建立起产品、业务与用户之间的数字连接。 本文档项目旨在提供全面的FinClip运维手册,尽可能涉及FinClip运行维护的方方面面,以保障我们的小程序平台稳定运行。
视频介绍:
本文档是 FinClip 交付团队提供的运维指南,手册主要介绍 FinClip 私有化部署的运维架构和日常维护事项,也包含部分应急处理与运维相关技术知识,比如:
产品官方网站:https://www.finclip.com/
',7)]))}const h=t(p,[["render",n]]);export{m as __pageData,h as default}; diff --git a/docs/assets/docs_overview_use-case.md.KhksnZtr.js b/docs/assets/docs_overview_use-case.md.KhksnZtr.js new file mode 100644 index 0000000..b97b432 --- /dev/null +++ b/docs/assets/docs_overview_use-case.md.KhksnZtr.js @@ -0,0 +1 @@ +import{_ as i,c as t,a9 as a,o as l}from"./chunks/framework.BjXht68r.js";const f=JSON.parse('{"title":"适用场景","description":"","frontmatter":{},"headers":[],"relativePath":"docs/overview/use-case.md","filePath":"docs/overview/use-case.md"}'),r={name:"docs/overview/use-case.md"};function n(o,e,p,s,c,d){return l(),t("div",null,e[0]||(e[0]=[a('FinClip 提供强大且灵活的小程序数字化管理服务。从产品的角度,采用 FinClip 有诸多好处。
详细介绍可以移步我们的官方文档 为什么选择 FinClip
本文档关注 FinClip 小程序平台部署相关内容,如果你有以下需求,希望可以对你有所帮助:
无论你是企业、开发者还是运维,FinClip 都能为你提供全面的小程序解决方案。接下来,让我们深入了解 FinClip 的部署流程和最佳实践。
',6)]))}const m=i(r,[["render",n]]);export{f as __pageData,m as default}; diff --git a/docs/assets/docs_overview_use-case.md.KhksnZtr.lean.js b/docs/assets/docs_overview_use-case.md.KhksnZtr.lean.js new file mode 100644 index 0000000..b97b432 --- /dev/null +++ b/docs/assets/docs_overview_use-case.md.KhksnZtr.lean.js @@ -0,0 +1 @@ +import{_ as i,c as t,a9 as a,o as l}from"./chunks/framework.BjXht68r.js";const f=JSON.parse('{"title":"适用场景","description":"","frontmatter":{},"headers":[],"relativePath":"docs/overview/use-case.md","filePath":"docs/overview/use-case.md"}'),r={name:"docs/overview/use-case.md"};function n(o,e,p,s,c,d){return l(),t("div",null,e[0]||(e[0]=[a('FinClip 提供强大且灵活的小程序数字化管理服务。从产品的角度,采用 FinClip 有诸多好处。
详细介绍可以移步我们的官方文档 为什么选择 FinClip
本文档关注 FinClip 小程序平台部署相关内容,如果你有以下需求,希望可以对你有所帮助:
无论你是企业、开发者还是运维,FinClip 都能为你提供全面的小程序解决方案。接下来,让我们深入了解 FinClip 的部署流程和最佳实践。
',6)]))}const m=i(r,[["render",n]]);export{f as __pageData,m as default}; diff --git a/docs/assets/docs_performance_database.md.CX9fd2g3.js b/docs/assets/docs_performance_database.md.CX9fd2g3.js new file mode 100644 index 0000000..4d2f87e --- /dev/null +++ b/docs/assets/docs_performance_database.md.CX9fd2g3.js @@ -0,0 +1 @@ +import{_ as l,c as e,a9 as i,o as t}from"./chunks/framework.BjXht68r.js";const g=JSON.parse('{"title":"数据库调优","description":"数据库调优.","frontmatter":{"title":"数据库调优","description":"数据库调优."},"headers":[],"relativePath":"docs/performance/database.md","filePath":"docs/performance/database.md"}'),r={name:"docs/performance/database.md"};function a(n,o,c,s,d,u){return t(),e("div",null,o[0]||(o[0]=[i('默认情况下,我们采用 MySQL 8作为业务数据库存储业务数据。针对 MySQL 8 ,你可以采用一系列调优方法来提高数据库的性能。例如:
硬盘:使用 SSD 提升读写速度,尤其是对 IO 密集型操作(如 InnoDB 的事务日志)非常重要。
内存:保证有足够的内存供 innodb_buffer_pool
使用,避免频繁的磁盘访问。
CPU:选择多核高性能 CPU,尤其在高并发场景下,多线程查询能显著受益。
操作系统优化
ulimit -n 65535
。ext4
或 XFS
文件系统,并开启 noatime
。numactl --interleave=all
。从运维角度,可以通过以下方式优化配置:
innodb_buffer_pool_size
:设置为物理内存的 60-75%。innodb_log_buffer_size
:对于高事务写入量,设置为 16MB 或更高。innodb_flush_log_at_trx_commit
:设置为 2
,以减少磁盘 IO(非关键数据场景)。sync_binlog=0
:对性能敏感但不要求极高可靠性的场景。max_connections
:根据业务需求设置为合理值,避免连接过多导致资源耗尽。thread_cache_size
:适当增加以减少线程创建开销。performance_schema
和 sys
库,监控慢查询、锁等待和资源利用情况。SHOW ENGINE INNODB STATUS
分析锁和事务性能。long_query_time=1
,捕获耗时 SQL。error.log
中是否有资源不足或配置异常的警告。默认情况下,我们采用 MySQL 8作为业务数据库存储业务数据。针对 MySQL 8 ,你可以采用一系列调优方法来提高数据库的性能。例如:
硬盘:使用 SSD 提升读写速度,尤其是对 IO 密集型操作(如 InnoDB 的事务日志)非常重要。
内存:保证有足够的内存供 innodb_buffer_pool
使用,避免频繁的磁盘访问。
CPU:选择多核高性能 CPU,尤其在高并发场景下,多线程查询能显著受益。
操作系统优化
ulimit -n 65535
。ext4
或 XFS
文件系统,并开启 noatime
。numactl --interleave=all
。从运维角度,可以通过以下方式优化配置:
innodb_buffer_pool_size
:设置为物理内存的 60-75%。innodb_log_buffer_size
:对于高事务写入量,设置为 16MB 或更高。innodb_flush_log_at_trx_commit
:设置为 2
,以减少磁盘 IO(非关键数据场景)。sync_binlog=0
:对性能敏感但不要求极高可靠性的场景。max_connections
:根据业务需求设置为合理值,避免连接过多导致资源耗尽。thread_cache_size
:适当增加以减少线程创建开销。performance_schema
和 sys
库,监控慢查询、锁等待和资源利用情况。SHOW ENGINE INNODB STATUS
分析锁和事务性能。long_query_time=1
,捕获耗时 SQL。error.log
中是否有资源不足或配置异常的警告。修改服务监听端口,用于业务访问,默认端口 :30001 ,编辑 docker-compose.yaml 文件以修改端口配置
gateway:
+ ports:
+ - "30001:8000" # 修改 30001 即可
修改服务监听端口,用于业务访问,默认端口 :30001 ,编辑 docker-compose.yaml 文件以修改端口配置
gateway:
+ ports:
+ - "30001:8000" # 修改 30001 即可
FinClip 小程序数字化管理平台后台服务包括基础组件和业务组件,其中,基础服务包括 MySQL、Redis、Minio 等,业务服务包括前后端服务,所有的服务组件采用 Docker 打包分发,因此,你可以使用任何支持 Docker的操作系统进行部署。
我们将使用一台最低配置要求的服务器,快速部署和体验 FinClip 小程序数字化管理平台。
准备 1:服务器:
数量 | CPU | 内存 | 磁盘空间 | 访问端口 | 架构 |
---|---|---|---|---|---|
1 | 4 核 | 8 GB | 20 GB | 1个访问端口,默认 30001 | x86 |
准备 2:操作系统:
你可以使用任何 支持 docker 的操作系统,我们建议:
准备 3:购买 License
你需要联系我们购买 License, 商务咨询热线:0755-86967467, 官方:www.finclip.com
FinClip 小程序数字化管理平台后台服务包括基础组件和业务组件,其中,基础服务包括 MySQL、Redis、Minio 等,业务服务包括前后端服务,所有的服务组件采用 Docker 打包分发,因此,你可以使用任何支持 Docker的操作系统进行部署。
我们将使用一台最低配置要求的服务器,快速部署和体验 FinClip 小程序数字化管理平台。
准备 1:服务器:
数量 | CPU | 内存 | 磁盘空间 | 访问端口 | 架构 |
---|---|---|---|---|---|
1 | 4 核 | 8 GB | 20 GB | 1个访问端口,默认 30001 | x86 |
准备 2:操作系统:
你可以使用任何 支持 docker 的操作系统,我们建议:
准备 3:购买 License
你需要联系我们购买 License, 商务咨询热线:0755-86967467, 官方:www.finclip.com
一但你完成了服务资源的准备,便可以快速使用我们提供的运维脚本进行 FinClip 的部署,如果你的服务器可以访问互联网,你可以使用一键部署脚本。
+sudo bash -c "$(curl -fsSL https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/finclip_install.bash)"
如果你的服务器无法访问互联网,你可以下载安装包和离线脚本进行安装。
然后将部署包和安装脚本放在同一个目录下,执行安装脚本:
sudo bash finclip_install.bash
执行命令后需要输入一些信息,其中包括:
输入你购买的 License,如: AlsW0yXK5oucrglodeyuS....
输入端口号或直接按回车使用默认端口. 如 80
回车或修改安装目录, 例如 /opt
通过 docker compose 命令确认服务启动正常后,您可以通过以下的链接,访问系统,确认系统是否搭建完成
网站名称 | 访问链接 | 初始账户 | 说明 |
---|---|---|---|
数字中⼼ | http://IP:PORT/ops#/ | admin | PORT:端口号,默认 30001,IP:服务器所在ip地址,如: 172.217.163.46 |
开发中⼼ | http://IP:PORT/dev#/ | 自行注册 | 注册时需要短信验证码,在数字中心开启万能验证码 |
访问地址:FinClip 单节点部署
`,16)]))}const g=e(l,[["render",n]]);export{k as __pageData,g as default}; diff --git a/docs/assets/docs_quickstart_quick-installation.md.CL_Mbnnb.lean.js b/docs/assets/docs_quickstart_quick-installation.md.CL_Mbnnb.lean.js new file mode 100644 index 0000000..cddf3c0 --- /dev/null +++ b/docs/assets/docs_quickstart_quick-installation.md.CL_Mbnnb.lean.js @@ -0,0 +1,2 @@ +import{_ as e,c as a,a9 as i,o as s}from"./chunks/framework.BjXht68r.js";const k=JSON.parse('{"title":"快速安装指南","description":"","frontmatter":{},"headers":[],"relativePath":"docs/quickstart/quick-installation.md","filePath":"docs/quickstart/quick-installation.md"}'),l={name:"docs/quickstart/quick-installation.md"};function n(r,t,h,o,d,p){return s(),a("div",null,t[0]||(t[0]=[i(`一但你完成了服务资源的准备,便可以快速使用我们提供的运维脚本进行 FinClip 的部署,如果你的服务器可以访问互联网,你可以使用一键部署脚本。
+sudo bash -c "$(curl -fsSL https://temp-1251849568.cos.ap-guangzhou.myqcloud.com/finclip_install.bash)"
如果你的服务器无法访问互联网,你可以下载安装包和离线脚本进行安装。
然后将部署包和安装脚本放在同一个目录下,执行安装脚本:
sudo bash finclip_install.bash
执行命令后需要输入一些信息,其中包括:
输入你购买的 License,如: AlsW0yXK5oucrglodeyuS....
输入端口号或直接按回车使用默认端口. 如 80
回车或修改安装目录, 例如 /opt
通过 docker compose 命令确认服务启动正常后,您可以通过以下的链接,访问系统,确认系统是否搭建完成
网站名称 | 访问链接 | 初始账户 | 说明 |
---|---|---|---|
数字中⼼ | http://IP:PORT/ops#/ | admin | PORT:端口号,默认 30001,IP:服务器所在ip地址,如: 172.217.163.46 |
开发中⼼ | http://IP:PORT/dev#/ | 自行注册 | 注册时需要短信验证码,在数字中心开启万能验证码 |
访问地址:FinClip 单节点部署
`,16)]))}const g=e(l,[["render",n]]);export{k as __pageData,g as default}; diff --git a/docs/assets/docs_quickstart_test-function.md.kjIqY3Da.js b/docs/assets/docs_quickstart_test-function.md.kjIqY3Da.js new file mode 100644 index 0000000..6336ba2 --- /dev/null +++ b/docs/assets/docs_quickstart_test-function.md.kjIqY3Da.js @@ -0,0 +1 @@ +import{_ as i,c as a,a9 as t,o as h}from"./chunks/framework.BjXht68r.js";const g=JSON.parse('{"title":"功能测试","description":"自动化功能测试","frontmatter":{"title":"功能测试","description":"自动化功能测试"},"headers":[],"relativePath":"docs/quickstart/test-function.md","filePath":"docs/quickstart/test-function.md"}'),e={name:"docs/quickstart/test-function.md"};function p(k,s,n,l,r,d){return h(),a("div",null,s[0]||(s[0]=[t('在开始测试之前,请确保以下条件已满足:
执行测试命令
服务启动完成后,执行以下命令运行功能测试的脚本:
docker exec $(docker ps | grep private | awk '{print $1}') sh -c "/app/mop_bdd.sh"
导出测试报告
测试完之后可以导出报告(testreport.json)给凡泰人员检查,命令如下:
docker cp $(docker ps | grep private | awk '{print $1}'):/app/abde/testreport.json . && zip -r testreport.zip testreport.json
恢复环境
测试验证无误后,清空数据,恢复环境,命令如下:
bash purge_redeploy.sh
在开始测试之前,请确保以下条件已满足:
执行测试命令
服务启动完成后,执行以下命令运行功能测试的脚本:
docker exec $(docker ps | grep private | awk '{print $1}') sh -c "/app/mop_bdd.sh"
导出测试报告
测试完之后可以导出报告(testreport.json)给凡泰人员检查,命令如下:
docker cp $(docker ps | grep private | awk '{print $1}'):/app/abde/testreport.json . && zip -r testreport.zip testreport.json
恢复环境
测试验证无误后,清空数据,恢复环境,命令如下:
bash purge_redeploy.sh
FinClip 采用容器打包分发,部署在 Linux 服务器中(当然,也支持 Windows)。对于 Linux 系统方面的安全配置,可以参考以下的一些建议:
apt-get update && apt-get upgrade
或 yum update
。unattended-upgrades
(Ubuntu)或 dnf-automatic
(CentOS)。禁用默认账户:
禁止直接以
root
用户登录,编辑
/etc/ssh/sshd_config
PermitRootLogin no
为日常操作创建非特权用户,并通过 sudo
提升权限。
强密码策略:
使用复杂的密码,启用密码复杂性策略:
/etc/security/pwquality.conf
强制密码过期,使用 chage
工具。
限制登录尝试:
pam_tally2
或 faillock
来锁定多次失败登录的账户。修改默认端口
22
改为非标准端口,例如 2222
。启用密钥认证
禁用密码登录,强制使用 SSH 公钥:
PasswordAuthentication no
限制 IP 地址
/etc/hosts.allow
和 /etc/hosts.deny
仅允许特定 IP 登录。启用防火墙:
使用
ufw
(Ubuntu)或
firewalld
(CentOS)管理规则,限制访问只开放必要的端口。
ufw allow 22
+ufw deny 3306
关闭不必要的服务:
使用
systemctl
或
chkconfig
禁用未使用的服务:
systemctl disable service_name
防御端口扫描:
iptables
或使用 Fail2Ban 检测并阻止恶意访问。最小权限原则:
确保文件和目录权限不超过所需,例如:
chmod 700 /root
+chmod 600 /etc/ssh/sshd_config
限制关键文件访问:
setfacl
) 对敏感文件进一步限制用户访问权限。启用日志审计:
配置
auditd
监控关键操作,例如文件更改和账户管理:
auditctl -w /etc/passwd -p wa
定期检查日志:
/var/log
中的系统日志,例如 auth.log
和 syslog
。定期备份
rsync
或 borg
备份数据,并验证可恢复性。异地备份
FinClip 采用容器打包分发,部署在 Linux 服务器中(当然,也支持 Windows)。对于 Linux 系统方面的安全配置,可以参考以下的一些建议:
apt-get update && apt-get upgrade
或 yum update
。unattended-upgrades
(Ubuntu)或 dnf-automatic
(CentOS)。禁用默认账户:
禁止直接以
root
用户登录,编辑
/etc/ssh/sshd_config
PermitRootLogin no
为日常操作创建非特权用户,并通过 sudo
提升权限。
强密码策略:
使用复杂的密码,启用密码复杂性策略:
/etc/security/pwquality.conf
强制密码过期,使用 chage
工具。
限制登录尝试:
pam_tally2
或 faillock
来锁定多次失败登录的账户。修改默认端口
22
改为非标准端口,例如 2222
。启用密钥认证
禁用密码登录,强制使用 SSH 公钥:
PasswordAuthentication no
限制 IP 地址
/etc/hosts.allow
和 /etc/hosts.deny
仅允许特定 IP 登录。启用防火墙:
使用
ufw
(Ubuntu)或
firewalld
(CentOS)管理规则,限制访问只开放必要的端口。
ufw allow 22
+ufw deny 3306
关闭不必要的服务:
使用
systemctl
或
chkconfig
禁用未使用的服务:
systemctl disable service_name
防御端口扫描:
iptables
或使用 Fail2Ban 检测并阻止恶意访问。最小权限原则:
确保文件和目录权限不超过所需,例如:
chmod 700 /root
+chmod 600 /etc/ssh/sshd_config
限制关键文件访问:
setfacl
) 对敏感文件进一步限制用户访问权限。启用日志审计:
配置
auditd
监控关键操作,例如文件更改和账户管理:
auditctl -w /etc/passwd -p wa
定期检查日志:
/var/log
中的系统日志,例如 auth.log
和 syslog
。定期备份
rsync
或 borg
备份数据,并验证可恢复性。异地备份
FinClip 采用典型的三层架构,访问顺序依次为:
用户 --> Nginx --> Gateway --> 前/后端服务 --> 基础服务(MySQL、Redi、Minio)
因此,当用户无法访问系统时,可通过在这些节点上访问下一跳,来定位网络故障点。
',3)]))}const g=i(h,[["render",l]]);export{c as __pageData,g as default}; diff --git a/docs/assets/docs_troubleshoot_accessibility.md.CfayWa57.lean.js b/docs/assets/docs_troubleshoot_accessibility.md.CfayWa57.lean.js new file mode 100644 index 0000000..719b21f --- /dev/null +++ b/docs/assets/docs_troubleshoot_accessibility.md.CfayWa57.lean.js @@ -0,0 +1 @@ +import{_ as i,c as a,a9 as t,o as e}from"./chunks/framework.BjXht68r.js";const c=JSON.parse('{"title":"访问链路检查","description":"访问链路检查","frontmatter":{"title":"访问链路检查","description":"访问链路检查"},"headers":[],"relativePath":"docs/troubleshoot/accessibility.md","filePath":"docs/troubleshoot/accessibility.md"}'),h={name:"docs/troubleshoot/accessibility.md"};function l(n,s,p,k,r,d){return e(),a("div",null,s[0]||(s[0]=[t('FinClip 采用典型的三层架构,访问顺序依次为:
用户 --> Nginx --> Gateway --> 前/后端服务 --> 基础服务(MySQL、Redi、Minio)
因此,当用户无法访问系统时,可通过在这些节点上访问下一跳,来定位网络故障点。
',3)]))}const g=i(h,[["render",l]]);export{c as __pageData,g as default}; diff --git a/docs/assets/docs_troubleshoot_health-check.md.DQPTlJz7.js b/docs/assets/docs_troubleshoot_health-check.md.DQPTlJz7.js new file mode 100644 index 0000000..4e3745f --- /dev/null +++ b/docs/assets/docs_troubleshoot_health-check.md.DQPTlJz7.js @@ -0,0 +1,2 @@ +import{_ as s,c as t,a9 as a,o as i}from"./chunks/framework.BjXht68r.js";const k=JSON.parse('{"title":"服务健康检查","description":"服务健康检查","frontmatter":{"title":"服务健康检查","description":"服务健康检查"},"headers":[],"relativePath":"docs/troubleshoot/health-check.md","filePath":"docs/troubleshoot/health-check.md"}'),l={name:"docs/troubleshoot/health-check.md"};function o(h,e,n,c,p,d){return i(),t("div",null,e[0]||(e[0]=[a(` FinClip 后端服务提供了用于健康检查的 /ready
接口,我们可以通过访问这个接口来检查服务是否健康运行。
GET /ready
+ok
FinClip 后端服务提供了用于健康检查的 /ready
接口,我们可以通过访问这个接口来检查服务是否健康运行。
GET /ready
+ok
通过使用 kubectl客户端工具来访问容器日志:
kubectl logs --tail=10086 pod-id
对于部署了日志平台的环境,可以采用 Grafana 或者 Kibana 进行更加全面的日志检查,参考 日志系统章节。
',3)]))}const g=t(l,[["render",o]]);export{k as __pageData,g as default}; diff --git a/docs/assets/docs_troubleshoot_logs.md.DPKLxczr.lean.js b/docs/assets/docs_troubleshoot_logs.md.DPKLxczr.lean.js new file mode 100644 index 0000000..f4f6a3b --- /dev/null +++ b/docs/assets/docs_troubleshoot_logs.md.DPKLxczr.lean.js @@ -0,0 +1 @@ +import{_ as t,c as e,a9 as i,o as a}from"./chunks/framework.BjXht68r.js";const k=JSON.parse('{"title":"服务日志查看","description":"服务日志查看","frontmatter":{"title":"服务日志查看","description":"服务日志查看"},"headers":[],"relativePath":"docs/troubleshoot/logs.md","filePath":"docs/troubleshoot/logs.md"}'),l={name:"docs/troubleshoot/logs.md"};function o(n,s,p,r,d,h){return a(),e("div",null,s[0]||(s[0]=[i('通过使用 kubectl客户端工具来访问容器日志:
kubectl logs --tail=10086 pod-id
对于部署了日志平台的环境,可以采用 Grafana 或者 Kibana 进行更加全面的日志检查,参考 日志系统章节。
',3)]))}const g=t(l,[["render",o]]);export{k as __pageData,g as default}; diff --git a/docs/assets/index.md.LmHuJbOa.js b/docs/assets/index.md.LmHuJbOa.js new file mode 100644 index 0000000..bca7ef3 --- /dev/null +++ b/docs/assets/index.md.LmHuJbOa.js @@ -0,0 +1 @@ +import{_ as e,c as t,o as i}from"./chunks/framework.BjXht68r.js";const m=JSON.parse('{"title":"FinClip - 小程序数字管理平台","titleTemplate":":title","description":"","frontmatter":{"title":"FinClip - 小程序数字管理平台","titleTemplate":":title","head":[["meta",{"property":"og:description","content":"FinClip 小程序数字化管理系统是一套私有化小程序平台解决方案,它能为企业应用提供强大、使用灵活且稳定高效的小程序功能,使得企业 App 像微信、支付宝那样可以为开发者和用户提供小程序能力。"}]],"layout":"home","hero":{"name":"FinClip","text":"Build SuperApps to empower digital ecosystems.","tagline":"使用 FinClip 打造小程序化数字供应链,质量效率一应俱全!","image":{"src":"/images/fc_home_banner_img4.png","alt":"FinClip"},"actions":[{"theme":"brand","text":"立即访问","link":"/docs/"},{"theme":"alt","text":"探索官方网站","link":"https://finclip.com"}]},"features":[{"icon":"🚀","title":"立即开始!","details":"无需部署,立刻体验。我们为客户提供了强大稳健的 Saas 平台,通过访问 FinClip Clou 即可快速体验。"},{"icon":"🌍","title":"打造应用生态","details":"FinClip 帮助企业自主掌控渠道生态,通过小程序化的支持,企业可以在供给侧获得大量的内容与资源。"},{"icon":"🔋","title":"私有化解决方案","details":"如果你已了解小程序的价值,相信你的企业也想拥有这样的平台,这正是 FinClip 的价值所在!"},{"icon":"😃","title":"联系我们","details":"立即预约 FinClip 产品介绍,咨询商务报价或私有化部署事宜,立即联系 ☎️ 0755-86967467"}]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),n={name:"index.md"};function a(l,o,p,s,c,r){return i(),t("div")}const _=e(n,[["render",a]]);export{m as __pageData,_ as default}; diff --git a/docs/assets/index.md.LmHuJbOa.lean.js b/docs/assets/index.md.LmHuJbOa.lean.js new file mode 100644 index 0000000..bca7ef3 --- /dev/null +++ b/docs/assets/index.md.LmHuJbOa.lean.js @@ -0,0 +1 @@ +import{_ as e,c as t,o as i}from"./chunks/framework.BjXht68r.js";const m=JSON.parse('{"title":"FinClip - 小程序数字管理平台","titleTemplate":":title","description":"","frontmatter":{"title":"FinClip - 小程序数字管理平台","titleTemplate":":title","head":[["meta",{"property":"og:description","content":"FinClip 小程序数字化管理系统是一套私有化小程序平台解决方案,它能为企业应用提供强大、使用灵活且稳定高效的小程序功能,使得企业 App 像微信、支付宝那样可以为开发者和用户提供小程序能力。"}]],"layout":"home","hero":{"name":"FinClip","text":"Build SuperApps to empower digital ecosystems.","tagline":"使用 FinClip 打造小程序化数字供应链,质量效率一应俱全!","image":{"src":"/images/fc_home_banner_img4.png","alt":"FinClip"},"actions":[{"theme":"brand","text":"立即访问","link":"/docs/"},{"theme":"alt","text":"探索官方网站","link":"https://finclip.com"}]},"features":[{"icon":"🚀","title":"立即开始!","details":"无需部署,立刻体验。我们为客户提供了强大稳健的 Saas 平台,通过访问 FinClip Clou 即可快速体验。"},{"icon":"🌍","title":"打造应用生态","details":"FinClip 帮助企业自主掌控渠道生态,通过小程序化的支持,企业可以在供给侧获得大量的内容与资源。"},{"icon":"🔋","title":"私有化解决方案","details":"如果你已了解小程序的价值,相信你的企业也想拥有这样的平台,这正是 FinClip 的价值所在!"},{"icon":"😃","title":"联系我们","details":"立即预约 FinClip 产品介绍,咨询商务报价或私有化部署事宜,立即联系 ☎️ 0755-86967467"}]},"headers":[],"relativePath":"index.md","filePath":"index.md"}'),n={name:"index.md"};function a(l,o,p,s,c,r){return i(),t("div")}const _=e(n,[["render",a]]);export{m as __pageData,_ as default}; diff --git a/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 b/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 new file mode 100644 index 0000000..b6b603d Binary files /dev/null and b/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 differ diff --git a/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 b/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 new file mode 100644 index 0000000..def40a4 Binary files /dev/null and b/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 differ diff --git a/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 b/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 new file mode 100644 index 0000000..e070c3d Binary files /dev/null and b/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 differ diff --git a/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 b/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 new file mode 100644 index 0000000..a3c16ca Binary files /dev/null and b/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 differ diff --git a/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 b/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 new file mode 100644 index 0000000..2210a89 Binary files /dev/null and b/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 differ diff --git a/docs/assets/inter-italic-latin.C2AdPX0b.woff2 b/docs/assets/inter-italic-latin.C2AdPX0b.woff2 new file mode 100644 index 0000000..790d62d Binary files /dev/null and b/docs/assets/inter-italic-latin.C2AdPX0b.woff2 differ diff --git a/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 b/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 new file mode 100644 index 0000000..1eec077 Binary files /dev/null and b/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 differ diff --git a/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 b/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 new file mode 100644 index 0000000..2cfe615 Binary files /dev/null and b/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 differ diff --git a/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 b/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 new file mode 100644 index 0000000..e3886dd Binary files /dev/null and b/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 differ diff --git a/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 b/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 new file mode 100644 index 0000000..36d6748 Binary files /dev/null and b/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 differ diff --git a/docs/assets/inter-roman-greek.BBVDIX6e.woff2 b/docs/assets/inter-roman-greek.BBVDIX6e.woff2 new file mode 100644 index 0000000..2bed1e8 Binary files /dev/null and b/docs/assets/inter-roman-greek.BBVDIX6e.woff2 differ diff --git a/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 b/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 new file mode 100644 index 0000000..9a8d1e2 Binary files /dev/null and b/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 differ diff --git a/docs/assets/inter-roman-latin.Di8DUHzh.woff2 b/docs/assets/inter-roman-latin.Di8DUHzh.woff2 new file mode 100644 index 0000000..07d3c53 Binary files /dev/null and b/docs/assets/inter-roman-latin.Di8DUHzh.woff2 differ diff --git a/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 b/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 new file mode 100644 index 0000000..57bdc22 Binary files /dev/null and b/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 differ diff --git a/docs/assets/style.hhWoPK1O.css b/docs/assets/style.hhWoPK1O.css new file mode 100644 index 0000000..7136c0c --- /dev/null +++ b/docs/assets/style.hhWoPK1O.css @@ -0,0 +1 @@ +@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-cyrillic.C5lxZ8CY.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-greek-ext.CqjqNYQ-.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-greek.BBVDIX6e.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-vietnamese.BjW4sHH5.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-latin-ext.4ZJIpNVo.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-weight:100 900;font-display:swap;src:url(/assets/inter-roman-latin.Di8DUHzh.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-cyrillic-ext.r48I6akx.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-cyrillic.By2_1cv3.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-greek-ext.1u6EdAuj.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-greek.DJ8dCoTZ.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-vietnamese.BSbpV94h.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-latin-ext.CN1xVJS-.woff2) format("woff2");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:italic;font-weight:100 900;font-display:swap;src:url(/assets/inter-italic-latin.C2AdPX0b.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Punctuation SC;font-weight:400;src:local("PingFang SC Regular"),local("Noto Sans CJK SC"),local("Microsoft YaHei");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:500;src:local("PingFang SC Medium"),local("Noto Sans CJK SC"),local("Microsoft YaHei");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:600;src:local("PingFang SC Semibold"),local("Noto Sans CJK SC Bold"),local("Microsoft YaHei Bold");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}@font-face{font-family:Punctuation SC;font-weight:700;src:local("PingFang SC Semibold"),local("Noto Sans CJK SC Bold"),local("Microsoft YaHei Bold");unicode-range:U+201C,U+201D,U+2018,U+2019,U+2E3A,U+2014,U+2013,U+2026,U+00B7,U+007E,U+002F}:root{--vp-c-white: #ffffff;--vp-c-black: #000000;--vp-c-neutral: var(--vp-c-black);--vp-c-neutral-inverse: var(--vp-c-white)}.dark{--vp-c-neutral: var(--vp-c-white);--vp-c-neutral-inverse: var(--vp-c-black)}:root{--vp-c-gray-1: #dddde3;--vp-c-gray-2: #e4e4e9;--vp-c-gray-3: #ebebef;--vp-c-gray-soft: rgba(142, 150, 170, .14);--vp-c-indigo-1: #3451b2;--vp-c-indigo-2: #3a5ccc;--vp-c-indigo-3: #5672cd;--vp-c-indigo-soft: rgba(100, 108, 255, .14);--vp-c-purple-1: #6f42c1;--vp-c-purple-2: #7e4cc9;--vp-c-purple-3: #8e5cd9;--vp-c-purple-soft: rgba(159, 122, 234, .14);--vp-c-green-1: #18794e;--vp-c-green-2: #299764;--vp-c-green-3: #30a46c;--vp-c-green-soft: rgba(16, 185, 129, .14);--vp-c-yellow-1: #915930;--vp-c-yellow-2: #946300;--vp-c-yellow-3: #9f6a00;--vp-c-yellow-soft: rgba(234, 179, 8, .14);--vp-c-red-1: #b8272c;--vp-c-red-2: #d5393e;--vp-c-red-3: #e0575b;--vp-c-red-soft: rgba(244, 63, 94, .14);--vp-c-sponsor: #db2777}.dark{--vp-c-gray-1: #515c67;--vp-c-gray-2: #414853;--vp-c-gray-3: #32363f;--vp-c-gray-soft: rgba(101, 117, 133, .16);--vp-c-indigo-1: #a8b1ff;--vp-c-indigo-2: #5c73e7;--vp-c-indigo-3: #3e63dd;--vp-c-indigo-soft: rgba(100, 108, 255, .16);--vp-c-purple-1: #c8abfa;--vp-c-purple-2: #a879e6;--vp-c-purple-3: #8e5cd9;--vp-c-purple-soft: rgba(159, 122, 234, .16);--vp-c-green-1: #3dd68c;--vp-c-green-2: #30a46c;--vp-c-green-3: #298459;--vp-c-green-soft: rgba(16, 185, 129, .16);--vp-c-yellow-1: #f9b44e;--vp-c-yellow-2: #da8b17;--vp-c-yellow-3: #a46a0a;--vp-c-yellow-soft: rgba(234, 179, 8, .16);--vp-c-red-1: #f66f81;--vp-c-red-2: #f14158;--vp-c-red-3: #b62a3c;--vp-c-red-soft: rgba(244, 63, 94, .16)}:root{--vp-c-bg: #ffffff;--vp-c-bg-alt: #f6f6f7;--vp-c-bg-elv: #ffffff;--vp-c-bg-soft: #f6f6f7}.dark{--vp-c-bg: #1b1b1f;--vp-c-bg-alt: #161618;--vp-c-bg-elv: #202127;--vp-c-bg-soft: #202127}:root{--vp-c-border: #c2c2c4;--vp-c-divider: #e2e2e3;--vp-c-gutter: #e2e2e3}.dark{--vp-c-border: #3c3f44;--vp-c-divider: #2e2e32;--vp-c-gutter: #000000}:root{--vp-c-text-1: rgba(60, 60, 67);--vp-c-text-2: rgba(60, 60, 67, .78);--vp-c-text-3: rgba(60, 60, 67, .56)}.dark{--vp-c-text-1: rgba(255, 255, 245, .86);--vp-c-text-2: rgba(235, 235, 245, .6);--vp-c-text-3: rgba(235, 235, 245, .38)}:root{--vp-c-default-1: var(--vp-c-gray-1);--vp-c-default-2: var(--vp-c-gray-2);--vp-c-default-3: var(--vp-c-gray-3);--vp-c-default-soft: var(--vp-c-gray-soft);--vp-c-brand-1: var(--vp-c-indigo-1);--vp-c-brand-2: var(--vp-c-indigo-2);--vp-c-brand-3: var(--vp-c-indigo-3);--vp-c-brand-soft: var(--vp-c-indigo-soft);--vp-c-brand: var(--vp-c-brand-1);--vp-c-tip-1: var(--vp-c-brand-1);--vp-c-tip-2: var(--vp-c-brand-2);--vp-c-tip-3: var(--vp-c-brand-3);--vp-c-tip-soft: var(--vp-c-brand-soft);--vp-c-note-1: var(--vp-c-brand-1);--vp-c-note-2: var(--vp-c-brand-2);--vp-c-note-3: var(--vp-c-brand-3);--vp-c-note-soft: var(--vp-c-brand-soft);--vp-c-success-1: var(--vp-c-green-1);--vp-c-success-2: var(--vp-c-green-2);--vp-c-success-3: var(--vp-c-green-3);--vp-c-success-soft: var(--vp-c-green-soft);--vp-c-important-1: var(--vp-c-purple-1);--vp-c-important-2: var(--vp-c-purple-2);--vp-c-important-3: var(--vp-c-purple-3);--vp-c-important-soft: var(--vp-c-purple-soft);--vp-c-warning-1: var(--vp-c-yellow-1);--vp-c-warning-2: var(--vp-c-yellow-2);--vp-c-warning-3: var(--vp-c-yellow-3);--vp-c-warning-soft: var(--vp-c-yellow-soft);--vp-c-danger-1: var(--vp-c-red-1);--vp-c-danger-2: var(--vp-c-red-2);--vp-c-danger-3: var(--vp-c-red-3);--vp-c-danger-soft: var(--vp-c-red-soft);--vp-c-caution-1: var(--vp-c-red-1);--vp-c-caution-2: var(--vp-c-red-2);--vp-c-caution-3: var(--vp-c-red-3);--vp-c-caution-soft: var(--vp-c-red-soft)}:root{--vp-font-family-base: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--vp-font-family-mono: ui-monospace, "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace;font-optical-sizing:auto}:root:where(:lang(zh)){--vp-font-family-base: "Punctuation SC", "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"}:root{--vp-shadow-1: 0 1px 2px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .06);--vp-shadow-2: 0 3px 12px rgba(0, 0, 0, .07), 0 1px 4px rgba(0, 0, 0, .07);--vp-shadow-3: 0 12px 32px rgba(0, 0, 0, .1), 0 2px 6px rgba(0, 0, 0, .08);--vp-shadow-4: 0 14px 44px rgba(0, 0, 0, .12), 0 3px 9px rgba(0, 0, 0, .12);--vp-shadow-5: 0 18px 56px rgba(0, 0, 0, .16), 0 4px 12px rgba(0, 0, 0, .16)}:root{--vp-z-index-footer: 10;--vp-z-index-local-nav: 20;--vp-z-index-nav: 30;--vp-z-index-layout-top: 40;--vp-z-index-backdrop: 50;--vp-z-index-sidebar: 60}@media (min-width: 960px){:root{--vp-z-index-sidebar: 25}}:root{--vp-layout-max-width: 1440px}:root{--vp-header-anchor-symbol: "#"}:root{--vp-code-line-height: 1.7;--vp-code-font-size: .875em;--vp-code-color: var(--vp-c-brand-1);--vp-code-link-color: var(--vp-c-brand-1);--vp-code-link-hover-color: var(--vp-c-brand-2);--vp-code-bg: var(--vp-c-default-soft);--vp-code-block-color: var(--vp-c-text-2);--vp-code-block-bg: var(--vp-c-bg-alt);--vp-code-block-divider-color: var(--vp-c-gutter);--vp-code-lang-color: var(--vp-c-text-3);--vp-code-line-highlight-color: var(--vp-c-default-soft);--vp-code-line-number-color: var(--vp-c-text-3);--vp-code-line-diff-add-color: var(--vp-c-success-soft);--vp-code-line-diff-add-symbol-color: var(--vp-c-success-1);--vp-code-line-diff-remove-color: var(--vp-c-danger-soft);--vp-code-line-diff-remove-symbol-color: var(--vp-c-danger-1);--vp-code-line-warning-color: var(--vp-c-warning-soft);--vp-code-line-error-color: var(--vp-c-danger-soft);--vp-code-copy-code-border-color: var(--vp-c-divider);--vp-code-copy-code-bg: var(--vp-c-bg-soft);--vp-code-copy-code-hover-border-color: var(--vp-c-divider);--vp-code-copy-code-hover-bg: var(--vp-c-bg);--vp-code-copy-code-active-text: var(--vp-c-text-2);--vp-code-copy-copied-text-content: "Copied";--vp-code-tab-divider: var(--vp-code-block-divider-color);--vp-code-tab-text-color: var(--vp-c-text-2);--vp-code-tab-bg: var(--vp-code-block-bg);--vp-code-tab-hover-text-color: var(--vp-c-text-1);--vp-code-tab-active-text-color: var(--vp-c-text-1);--vp-code-tab-active-bar-color: var(--vp-c-brand-1)}:root{--vp-button-brand-border: transparent;--vp-button-brand-text: var(--vp-c-white);--vp-button-brand-bg: var(--vp-c-brand-3);--vp-button-brand-hover-border: transparent;--vp-button-brand-hover-text: var(--vp-c-white);--vp-button-brand-hover-bg: var(--vp-c-brand-2);--vp-button-brand-active-border: transparent;--vp-button-brand-active-text: var(--vp-c-white);--vp-button-brand-active-bg: var(--vp-c-brand-1);--vp-button-alt-border: transparent;--vp-button-alt-text: var(--vp-c-text-1);--vp-button-alt-bg: var(--vp-c-default-3);--vp-button-alt-hover-border: transparent;--vp-button-alt-hover-text: var(--vp-c-text-1);--vp-button-alt-hover-bg: var(--vp-c-default-2);--vp-button-alt-active-border: transparent;--vp-button-alt-active-text: var(--vp-c-text-1);--vp-button-alt-active-bg: var(--vp-c-default-1);--vp-button-sponsor-border: var(--vp-c-text-2);--vp-button-sponsor-text: var(--vp-c-text-2);--vp-button-sponsor-bg: transparent;--vp-button-sponsor-hover-border: var(--vp-c-sponsor);--vp-button-sponsor-hover-text: var(--vp-c-sponsor);--vp-button-sponsor-hover-bg: transparent;--vp-button-sponsor-active-border: var(--vp-c-sponsor);--vp-button-sponsor-active-text: var(--vp-c-sponsor);--vp-button-sponsor-active-bg: transparent}:root{--vp-custom-block-font-size: 14px;--vp-custom-block-code-font-size: 13px;--vp-custom-block-info-border: transparent;--vp-custom-block-info-text: var(--vp-c-text-1);--vp-custom-block-info-bg: var(--vp-c-default-soft);--vp-custom-block-info-code-bg: var(--vp-c-default-soft);--vp-custom-block-note-border: transparent;--vp-custom-block-note-text: var(--vp-c-text-1);--vp-custom-block-note-bg: var(--vp-c-default-soft);--vp-custom-block-note-code-bg: var(--vp-c-default-soft);--vp-custom-block-tip-border: transparent;--vp-custom-block-tip-text: var(--vp-c-text-1);--vp-custom-block-tip-bg: var(--vp-c-tip-soft);--vp-custom-block-tip-code-bg: var(--vp-c-tip-soft);--vp-custom-block-important-border: transparent;--vp-custom-block-important-text: var(--vp-c-text-1);--vp-custom-block-important-bg: var(--vp-c-important-soft);--vp-custom-block-important-code-bg: var(--vp-c-important-soft);--vp-custom-block-warning-border: transparent;--vp-custom-block-warning-text: var(--vp-c-text-1);--vp-custom-block-warning-bg: var(--vp-c-warning-soft);--vp-custom-block-warning-code-bg: var(--vp-c-warning-soft);--vp-custom-block-danger-border: transparent;--vp-custom-block-danger-text: var(--vp-c-text-1);--vp-custom-block-danger-bg: var(--vp-c-danger-soft);--vp-custom-block-danger-code-bg: var(--vp-c-danger-soft);--vp-custom-block-caution-border: transparent;--vp-custom-block-caution-text: var(--vp-c-text-1);--vp-custom-block-caution-bg: var(--vp-c-caution-soft);--vp-custom-block-caution-code-bg: var(--vp-c-caution-soft);--vp-custom-block-details-border: var(--vp-custom-block-info-border);--vp-custom-block-details-text: var(--vp-custom-block-info-text);--vp-custom-block-details-bg: var(--vp-custom-block-info-bg);--vp-custom-block-details-code-bg: var(--vp-custom-block-info-code-bg)}:root{--vp-input-border-color: var(--vp-c-border);--vp-input-bg-color: var(--vp-c-bg-alt);--vp-input-switch-bg-color: var(--vp-c-default-soft)}:root{--vp-nav-height: 64px;--vp-nav-bg-color: var(--vp-c-bg);--vp-nav-screen-bg-color: var(--vp-c-bg);--vp-nav-logo-height: 24px}.hide-nav{--vp-nav-height: 0px}.hide-nav .VPSidebar{--vp-nav-height: 22px}:root{--vp-local-nav-bg-color: var(--vp-c-bg)}:root{--vp-sidebar-width: 272px;--vp-sidebar-bg-color: var(--vp-c-bg-alt)}:root{--vp-backdrop-bg-color: rgba(0, 0, 0, .6)}:root{--vp-home-hero-name-color: var(--vp-c-brand-1);--vp-home-hero-name-background: transparent;--vp-home-hero-image-background-image: none;--vp-home-hero-image-filter: none}:root{--vp-badge-info-border: transparent;--vp-badge-info-text: var(--vp-c-text-2);--vp-badge-info-bg: var(--vp-c-default-soft);--vp-badge-tip-border: transparent;--vp-badge-tip-text: var(--vp-c-tip-1);--vp-badge-tip-bg: var(--vp-c-tip-soft);--vp-badge-warning-border: transparent;--vp-badge-warning-text: var(--vp-c-warning-1);--vp-badge-warning-bg: var(--vp-c-warning-soft);--vp-badge-danger-border: transparent;--vp-badge-danger-text: var(--vp-c-danger-1);--vp-badge-danger-bg: var(--vp-c-danger-soft)}:root{--vp-carbon-ads-text-color: var(--vp-c-text-1);--vp-carbon-ads-poweredby-color: var(--vp-c-text-2);--vp-carbon-ads-bg-color: var(--vp-c-bg-soft);--vp-carbon-ads-hover-text-color: var(--vp-c-brand-1);--vp-carbon-ads-hover-poweredby-color: var(--vp-c-text-1)}:root{--vp-local-search-bg: var(--vp-c-bg);--vp-local-search-result-bg: var(--vp-c-bg);--vp-local-search-result-border: var(--vp-c-divider);--vp-local-search-result-selected-bg: var(--vp-c-bg);--vp-local-search-result-selected-border: var(--vp-c-brand-1);--vp-local-search-highlight-bg: var(--vp-c-brand-1);--vp-local-search-highlight-text: var(--vp-c-neutral-inverse)}@media (prefers-reduced-motion: reduce){*,:before,:after{animation-delay:-1ms!important;animation-duration:1ms!important;animation-iteration-count:1!important;background-attachment:initial!important;scroll-behavior:auto!important;transition-duration:0s!important;transition-delay:0s!important}}*,:before,:after{box-sizing:border-box}html{line-height:1.4;font-size:16px;-webkit-text-size-adjust:100%}html.dark{color-scheme:dark}body{margin:0;width:100%;min-width:320px;min-height:100vh;line-height:24px;font-family:var(--vp-font-family-base);font-size:16px;font-weight:400;color:var(--vp-c-text-1);background-color:var(--vp-c-bg);font-synthesis:style;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}main{display:block}h1,h2,h3,h4,h5,h6{margin:0;line-height:24px;font-size:16px;font-weight:400}p{margin:0}strong,b{font-weight:600}a,area,button,[role=button],input,label,select,summary,textarea{touch-action:manipulation}a{color:inherit;text-decoration:inherit}ol,ul{list-style:none;margin:0;padding:0}blockquote{margin:0}pre,code,kbd,samp{font-family:var(--vp-font-family-mono)}img,svg,video,canvas,audio,iframe,embed,object{display:block}figure{margin:0}img,video{max-width:100%;height:auto}button,input,optgroup,select,textarea{border:0;padding:0;line-height:inherit;color:inherit}button{padding:0;font-family:inherit;background-color:transparent;background-image:none}button:enabled,[role=button]:enabled{cursor:pointer}button:focus,button:focus-visible{outline:1px dotted;outline:4px auto -webkit-focus-ring-color}button:focus:not(:focus-visible){outline:none!important}input:focus,textarea:focus,select:focus{outline:none}table{border-collapse:collapse}input{background-color:transparent}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:var(--vp-c-text-3)}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:var(--vp-c-text-3)}input::placeholder,textarea::placeholder{color:var(--vp-c-text-3)}input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}input[type=number]{-moz-appearance:textfield}textarea{resize:vertical}select{-webkit-appearance:none}fieldset{margin:0;padding:0}h1,h2,h3,h4,h5,h6,li,p{overflow-wrap:break-word}vite-error-overlay{z-index:9999}mjx-container{overflow-x:auto}mjx-container>svg{display:inline-block;margin:auto}[class^=vpi-],[class*=" vpi-"],.vp-icon{width:1em;height:1em}[class^=vpi-].bg,[class*=" vpi-"].bg,.vp-icon.bg{background-size:100% 100%;background-color:transparent}[class^=vpi-]:not(.bg),[class*=" vpi-"]:not(.bg),.vp-icon:not(.bg){-webkit-mask:var(--icon) no-repeat;mask:var(--icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit}.vpi-align-left{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M21 6H3M15 12H3M17 18H3'/%3E%3C/svg%3E")}.vpi-arrow-right,.vpi-arrow-down,.vpi-arrow-left,.vpi-arrow-up{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5l7 7-7 7'/%3E%3C/svg%3E")}.vpi-chevron-right,.vpi-chevron-down,.vpi-chevron-left,.vpi-chevron-up{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E")}.vpi-chevron-down,.vpi-arrow-down{transform:rotate(90deg)}.vpi-chevron-left,.vpi-arrow-left{transform:rotate(180deg)}.vpi-chevron-up,.vpi-arrow-up{transform:rotate(-90deg)}.vpi-square-pen{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7'/%3E%3Cpath d='M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z'/%3E%3C/svg%3E")}.vpi-plus{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M12 5v14'/%3E%3C/svg%3E")}.vpi-sun{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41'/%3E%3C/svg%3E")}.vpi-moon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z'/%3E%3C/svg%3E")}.vpi-more-horizontal{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='1'/%3E%3Ccircle cx='19' cy='12' r='1'/%3E%3Ccircle cx='5' cy='12' r='1'/%3E%3C/svg%3E")}.vpi-languages{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m5 8 6 6M4 14l6-6 2-3M2 5h12M7 2h1M22 22l-5-10-5 10M14 18h6'/%3E%3C/svg%3E")}.vpi-heart{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z'/%3E%3C/svg%3E")}.vpi-search{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E")}.vpi-layout-list{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='7' height='7' x='3' y='3' rx='1'/%3E%3Crect width='7' height='7' x='3' y='14' rx='1'/%3E%3Cpath d='M14 4h7M14 9h7M14 15h7M14 20h7'/%3E%3C/svg%3E")}.vpi-delete{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='M20 5H9l-7 7 7 7h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2ZM18 9l-6 6M12 9l6 6'/%3E%3C/svg%3E")}.vpi-corner-down-left{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m9 10-5 5 5 5'/%3E%3Cpath d='M20 4v7a4 4 0 0 1-4 4H4'/%3E%3C/svg%3E")}:root{--vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/svg%3E");--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14 2 2 4-4'/%3E%3C/svg%3E")}.visually-hidden{position:absolute;width:1px;height:1px;white-space:nowrap;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden}.custom-block{border:1px solid transparent;border-radius:8px;padding:16px 16px 8px;line-height:24px;font-size:var(--vp-custom-block-font-size);color:var(--vp-c-text-2)}.custom-block.info{border-color:var(--vp-custom-block-info-border);color:var(--vp-custom-block-info-text);background-color:var(--vp-custom-block-info-bg)}.custom-block.info a,.custom-block.info code{color:var(--vp-c-brand-1)}.custom-block.info a:hover,.custom-block.info a:hover>code{color:var(--vp-c-brand-2)}.custom-block.info code{background-color:var(--vp-custom-block-info-code-bg)}.custom-block.note{border-color:var(--vp-custom-block-note-border);color:var(--vp-custom-block-note-text);background-color:var(--vp-custom-block-note-bg)}.custom-block.note a,.custom-block.note code{color:var(--vp-c-brand-1)}.custom-block.note a:hover,.custom-block.note a:hover>code{color:var(--vp-c-brand-2)}.custom-block.note code{background-color:var(--vp-custom-block-note-code-bg)}.custom-block.tip{border-color:var(--vp-custom-block-tip-border);color:var(--vp-custom-block-tip-text);background-color:var(--vp-custom-block-tip-bg)}.custom-block.tip a,.custom-block.tip code{color:var(--vp-c-tip-1)}.custom-block.tip a:hover,.custom-block.tip a:hover>code{color:var(--vp-c-tip-2)}.custom-block.tip code{background-color:var(--vp-custom-block-tip-code-bg)}.custom-block.important{border-color:var(--vp-custom-block-important-border);color:var(--vp-custom-block-important-text);background-color:var(--vp-custom-block-important-bg)}.custom-block.important a,.custom-block.important code{color:var(--vp-c-important-1)}.custom-block.important a:hover,.custom-block.important a:hover>code{color:var(--vp-c-important-2)}.custom-block.important code{background-color:var(--vp-custom-block-important-code-bg)}.custom-block.warning{border-color:var(--vp-custom-block-warning-border);color:var(--vp-custom-block-warning-text);background-color:var(--vp-custom-block-warning-bg)}.custom-block.warning a,.custom-block.warning code{color:var(--vp-c-warning-1)}.custom-block.warning a:hover,.custom-block.warning a:hover>code{color:var(--vp-c-warning-2)}.custom-block.warning code{background-color:var(--vp-custom-block-warning-code-bg)}.custom-block.danger{border-color:var(--vp-custom-block-danger-border);color:var(--vp-custom-block-danger-text);background-color:var(--vp-custom-block-danger-bg)}.custom-block.danger a,.custom-block.danger code{color:var(--vp-c-danger-1)}.custom-block.danger a:hover,.custom-block.danger a:hover>code{color:var(--vp-c-danger-2)}.custom-block.danger code{background-color:var(--vp-custom-block-danger-code-bg)}.custom-block.caution{border-color:var(--vp-custom-block-caution-border);color:var(--vp-custom-block-caution-text);background-color:var(--vp-custom-block-caution-bg)}.custom-block.caution a,.custom-block.caution code{color:var(--vp-c-caution-1)}.custom-block.caution a:hover,.custom-block.caution a:hover>code{color:var(--vp-c-caution-2)}.custom-block.caution code{background-color:var(--vp-custom-block-caution-code-bg)}.custom-block.details{border-color:var(--vp-custom-block-details-border);color:var(--vp-custom-block-details-text);background-color:var(--vp-custom-block-details-bg)}.custom-block.details a{color:var(--vp-c-brand-1)}.custom-block.details a:hover,.custom-block.details a:hover>code{color:var(--vp-c-brand-2)}.custom-block.details code{background-color:var(--vp-custom-block-details-code-bg)}.custom-block-title{font-weight:600}.custom-block p+p{margin:8px 0}.custom-block.details summary{margin:0 0 8px;font-weight:700;cursor:pointer;-webkit-user-select:none;user-select:none}.custom-block.details summary+p{margin:8px 0}.custom-block a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px;transition:opacity .25s}.custom-block a:hover{opacity:.75}.custom-block code{font-size:var(--vp-custom-block-code-font-size)}.custom-block.custom-block th,.custom-block.custom-block blockquote>p{font-size:var(--vp-custom-block-font-size);color:inherit}.dark .vp-code span{color:var(--shiki-dark, inherit)}html:not(.dark) .vp-code span{color:var(--shiki-light, inherit)}.vp-code-group{margin-top:16px}.vp-code-group .tabs{position:relative;display:flex;margin-right:-24px;margin-left:-24px;padding:0 12px;background-color:var(--vp-code-tab-bg);overflow-x:auto;overflow-y:hidden;box-shadow:inset 0 -1px var(--vp-code-tab-divider)}@media (min-width: 640px){.vp-code-group .tabs{margin-right:0;margin-left:0;border-radius:8px 8px 0 0}}.vp-code-group .tabs input{position:fixed;opacity:0;pointer-events:none}.vp-code-group .tabs label{position:relative;display:inline-block;border-bottom:1px solid transparent;padding:0 12px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-code-tab-text-color);white-space:nowrap;cursor:pointer;transition:color .25s}.vp-code-group .tabs label:after{position:absolute;right:8px;bottom:-1px;left:8px;z-index:1;height:2px;border-radius:2px;content:"";background-color:transparent;transition:background-color .25s}.vp-code-group label:hover{color:var(--vp-code-tab-hover-text-color)}.vp-code-group input:checked+label{color:var(--vp-code-tab-active-text-color)}.vp-code-group input:checked+label:after{background-color:var(--vp-code-tab-active-bar-color)}.vp-code-group div[class*=language-],.vp-block{display:none;margin-top:0!important;border-top-left-radius:0!important;border-top-right-radius:0!important}.vp-code-group div[class*=language-].active,.vp-block.active{display:block}.vp-block{padding:20px 24px}.vp-doc h1,.vp-doc h2,.vp-doc h3,.vp-doc h4,.vp-doc h5,.vp-doc h6{position:relative;font-weight:600;outline:none}.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:28px}.vp-doc h2{margin:48px 0 16px;border-top:1px solid var(--vp-c-divider);padding-top:24px;letter-spacing:-.02em;line-height:32px;font-size:24px}.vp-doc h3{margin:32px 0 0;letter-spacing:-.01em;line-height:28px;font-size:20px}.vp-doc h4{margin:24px 0 0;letter-spacing:-.01em;line-height:24px;font-size:18px}.vp-doc .header-anchor{position:absolute;top:0;left:0;margin-left:-.87em;font-weight:500;-webkit-user-select:none;user-select:none;opacity:0;text-decoration:none;transition:color .25s,opacity .25s}.vp-doc .header-anchor:before{content:var(--vp-header-anchor-symbol)}.vp-doc h1:hover .header-anchor,.vp-doc h1 .header-anchor:focus,.vp-doc h2:hover .header-anchor,.vp-doc h2 .header-anchor:focus,.vp-doc h3:hover .header-anchor,.vp-doc h3 .header-anchor:focus,.vp-doc h4:hover .header-anchor,.vp-doc h4 .header-anchor:focus,.vp-doc h5:hover .header-anchor,.vp-doc h5 .header-anchor:focus,.vp-doc h6:hover .header-anchor,.vp-doc h6 .header-anchor:focus{opacity:1}@media (min-width: 768px){.vp-doc h1{letter-spacing:-.02em;line-height:40px;font-size:32px}}.vp-doc h2 .header-anchor{top:24px}.vp-doc p,.vp-doc summary{margin:16px 0}.vp-doc p{line-height:28px}.vp-doc blockquote{margin:16px 0;border-left:2px solid var(--vp-c-divider);padding-left:16px;transition:border-color .5s;color:var(--vp-c-text-2)}.vp-doc blockquote>p{margin:0;font-size:16px;transition:color .5s}.vp-doc a{font-weight:500;color:var(--vp-c-brand-1);text-decoration:underline;text-underline-offset:2px;transition:color .25s,opacity .25s}.vp-doc a:hover{color:var(--vp-c-brand-2)}.vp-doc strong{font-weight:600}.vp-doc ul,.vp-doc ol{padding-left:1.25rem;margin:16px 0}.vp-doc ul{list-style:disc}.vp-doc ol{list-style:decimal}.vp-doc li+li{margin-top:8px}.vp-doc li>ol,.vp-doc li>ul{margin:8px 0 0}.vp-doc table{display:block;border-collapse:collapse;margin:20px 0;overflow-x:auto}.vp-doc tr{background-color:var(--vp-c-bg);border-top:1px solid var(--vp-c-divider);transition:background-color .5s}.vp-doc tr:nth-child(2n){background-color:var(--vp-c-bg-soft)}.vp-doc th,.vp-doc td{border:1px solid var(--vp-c-divider);padding:8px 16px}.vp-doc th{text-align:left;font-size:14px;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-doc td{font-size:14px}.vp-doc hr{margin:16px 0;border:none;border-top:1px solid var(--vp-c-divider)}.vp-doc .custom-block{margin:16px 0}.vp-doc .custom-block p{margin:8px 0;line-height:24px}.vp-doc .custom-block p:first-child{margin:0}.vp-doc .custom-block div[class*=language-]{margin:8px 0;border-radius:8px}.vp-doc .custom-block div[class*=language-] code{font-weight:400;background-color:transparent}.vp-doc .custom-block .vp-code-group .tabs{margin:0;border-radius:8px 8px 0 0}.vp-doc :not(pre,h1,h2,h3,h4,h5,h6)>code{font-size:var(--vp-code-font-size);color:var(--vp-code-color)}.vp-doc :not(pre)>code{border-radius:4px;padding:3px 6px;background-color:var(--vp-code-bg);transition:color .25s,background-color .5s}.vp-doc a>code{color:var(--vp-code-link-color)}.vp-doc a:hover>code{color:var(--vp-code-link-hover-color)}.vp-doc h1>code,.vp-doc h2>code,.vp-doc h3>code,.vp-doc h4>code{font-size:.9em}.vp-doc div[class*=language-],.vp-block{position:relative;margin:16px -24px;background-color:var(--vp-code-block-bg);overflow-x:auto;transition:background-color .5s}@media (min-width: 640px){.vp-doc div[class*=language-],.vp-block{border-radius:8px;margin:16px 0}}@media (max-width: 639px){.vp-doc li div[class*=language-]{border-radius:8px 0 0 8px}}.vp-doc div[class*=language-]+div[class*=language-],.vp-doc div[class$=-api]+div[class*=language-],.vp-doc div[class*=language-]+div[class$=-api]>div[class*=language-]{margin-top:-8px}.vp-doc [class*=language-] pre,.vp-doc [class*=language-] code{direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}.vp-doc [class*=language-] pre{position:relative;z-index:1;margin:0;padding:20px 0;background:transparent;overflow-x:auto}.vp-doc [class*=language-] code{display:block;padding:0 24px;width:fit-content;min-width:100%;line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-block-color);transition:color .5s}.vp-doc [class*=language-] code .highlighted{background-color:var(--vp-code-line-highlight-color);transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .highlighted.error{background-color:var(--vp-code-line-error-color)}.vp-doc [class*=language-] code .highlighted.warning{background-color:var(--vp-code-line-warning-color)}.vp-doc [class*=language-] code .diff{transition:background-color .5s;margin:0 -24px;padding:0 24px;width:calc(100% + 48px);display:inline-block}.vp-doc [class*=language-] code .diff:before{position:absolute;left:10px}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){filter:blur(.095rem);opacity:.4;transition:filter .35s,opacity .35s}.vp-doc [class*=language-] .has-focused-lines .line:not(.has-focus){opacity:.7;transition:filter .35s,opacity .35s}.vp-doc [class*=language-]:hover .has-focused-lines .line:not(.has-focus){filter:blur(0);opacity:1}.vp-doc [class*=language-] code .diff.remove{background-color:var(--vp-code-line-diff-remove-color);opacity:.7}.vp-doc [class*=language-] code .diff.remove:before{content:"-";color:var(--vp-code-line-diff-remove-symbol-color)}.vp-doc [class*=language-] code .diff.add{background-color:var(--vp-code-line-diff-add-color)}.vp-doc [class*=language-] code .diff.add:before{content:"+";color:var(--vp-code-line-diff-add-symbol-color)}.vp-doc div[class*=language-].line-numbers-mode{padding-left:32px}.vp-doc .line-numbers-wrapper{position:absolute;top:0;bottom:0;left:0;z-index:3;border-right:1px solid var(--vp-code-block-divider-color);padding-top:20px;width:32px;text-align:center;font-family:var(--vp-font-family-mono);line-height:var(--vp-code-line-height);font-size:var(--vp-code-font-size);color:var(--vp-code-line-number-color);transition:border-color .5s,color .5s}.vp-doc [class*=language-]>button.copy{direction:ltr;position:absolute;top:12px;right:12px;z-index:3;border:1px solid var(--vp-code-copy-code-border-color);border-radius:4px;width:40px;height:40px;background-color:var(--vp-code-copy-code-bg);opacity:0;cursor:pointer;background-image:var(--vp-icon-copy);background-position:50%;background-size:20px;background-repeat:no-repeat;transition:border-color .25s,background-color .25s,opacity .25s}.vp-doc [class*=language-]:hover>button.copy,.vp-doc [class*=language-]>button.copy:focus{opacity:1}.vp-doc [class*=language-]>button.copy:hover,.vp-doc [class*=language-]>button.copy.copied{border-color:var(--vp-code-copy-code-hover-border-color);background-color:var(--vp-code-copy-code-hover-bg)}.vp-doc [class*=language-]>button.copy.copied,.vp-doc [class*=language-]>button.copy:hover.copied{border-radius:0 4px 4px 0;background-color:var(--vp-code-copy-code-hover-bg);background-image:var(--vp-icon-copied)}.vp-doc [class*=language-]>button.copy.copied:before,.vp-doc [class*=language-]>button.copy:hover.copied:before{position:relative;top:-1px;transform:translate(calc(-100% - 1px));display:flex;justify-content:center;align-items:center;border:1px solid var(--vp-code-copy-code-hover-border-color);border-right:0;border-radius:4px 0 0 4px;padding:0 10px;width:fit-content;height:40px;text-align:center;font-size:12px;font-weight:500;color:var(--vp-code-copy-code-active-text);background-color:var(--vp-code-copy-code-hover-bg);white-space:nowrap;content:var(--vp-code-copy-copied-text-content)}.vp-doc [class*=language-]>span.lang{position:absolute;top:2px;right:8px;z-index:2;font-size:12px;font-weight:500;-webkit-user-select:none;user-select:none;color:var(--vp-code-lang-color);transition:color .4s,opacity .4s}.vp-doc [class*=language-]:hover>button.copy+span.lang,.vp-doc [class*=language-]>button.copy:focus+span.lang{opacity:0}.vp-doc .VPTeamMembers{margin-top:24px}.vp-doc .VPTeamMembers.small.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}.vp-doc .VPTeamMembers.small.count-2 .container,.vp-doc .VPTeamMembers.small.count-3 .container{max-width:100%!important}.vp-doc .VPTeamMembers.medium.count-1 .container{margin:0!important;max-width:calc((100% - 24px)/2)!important}:is(.vp-external-link-icon,.vp-doc a[href*="://"],.vp-doc a[target=_blank]):not(.no-icon):after{display:inline-block;margin-top:-1px;margin-left:4px;width:11px;height:11px;background:currentColor;color:var(--vp-c-text-3);flex-shrink:0;--icon: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E");-webkit-mask-image:var(--icon);mask-image:var(--icon)}.vp-external-link-icon:after{content:""}.external-link-icon-enabled :is(.vp-doc a[href*="://"],.vp-doc a[target=_blank]):after{content:"";color:currentColor}.vp-sponsor{border-radius:16px;overflow:hidden}.vp-sponsor.aside{border-radius:12px}.vp-sponsor-section+.vp-sponsor-section{margin-top:4px}.vp-sponsor-tier{margin:0 0 4px!important;text-align:center;letter-spacing:1px!important;line-height:24px;width:100%;font-weight:600;color:var(--vp-c-text-2);background-color:var(--vp-c-bg-soft)}.vp-sponsor.normal .vp-sponsor-tier{padding:13px 0 11px;font-size:14px}.vp-sponsor.aside .vp-sponsor-tier{padding:9px 0 7px;font-size:12px}.vp-sponsor-grid+.vp-sponsor-tier{margin-top:4px}.vp-sponsor-grid{display:flex;flex-wrap:wrap;gap:4px}.vp-sponsor-grid.xmini .vp-sponsor-grid-link{height:64px}.vp-sponsor-grid.xmini .vp-sponsor-grid-image{max-width:64px;max-height:22px}.vp-sponsor-grid.mini .vp-sponsor-grid-link{height:72px}.vp-sponsor-grid.mini .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.small .vp-sponsor-grid-link{height:96px}.vp-sponsor-grid.small .vp-sponsor-grid-image{max-width:96px;max-height:24px}.vp-sponsor-grid.medium .vp-sponsor-grid-link{height:112px}.vp-sponsor-grid.medium .vp-sponsor-grid-image{max-width:120px;max-height:36px}.vp-sponsor-grid.big .vp-sponsor-grid-link{height:184px}.vp-sponsor-grid.big .vp-sponsor-grid-image{max-width:192px;max-height:56px}.vp-sponsor-grid[data-vp-grid="2"] .vp-sponsor-grid-item{width:calc((100% - 4px)/2)}.vp-sponsor-grid[data-vp-grid="3"] .vp-sponsor-grid-item{width:calc((100% - 4px * 2) / 3)}.vp-sponsor-grid[data-vp-grid="4"] .vp-sponsor-grid-item{width:calc((100% - 12px)/4)}.vp-sponsor-grid[data-vp-grid="5"] .vp-sponsor-grid-item{width:calc((100% - 16px)/5)}.vp-sponsor-grid[data-vp-grid="6"] .vp-sponsor-grid-item{width:calc((100% - 4px * 5) / 6)}.vp-sponsor-grid-item{flex-shrink:0;width:100%;background-color:var(--vp-c-bg-soft);transition:background-color .25s}.vp-sponsor-grid-item:hover{background-color:var(--vp-c-default-soft)}.vp-sponsor-grid-item:hover .vp-sponsor-grid-image{filter:grayscale(0) invert(0)}.vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.dark .vp-sponsor-grid-item:hover{background-color:var(--vp-c-white)}.dark .vp-sponsor-grid-item.empty:hover{background-color:var(--vp-c-bg-soft)}.vp-sponsor-grid-link{display:flex}.vp-sponsor-grid-box{display:flex;justify-content:center;align-items:center;width:100%}.vp-sponsor-grid-image{max-width:100%;filter:grayscale(1);transition:filter .25s}.dark .vp-sponsor-grid-image{filter:grayscale(1) invert(1)}.VPBadge{display:inline-block;margin-left:2px;border:1px solid transparent;border-radius:12px;padding:0 10px;line-height:22px;font-size:12px;font-weight:500;transform:translateY(-2px)}.VPBadge.small{padding:0 6px;line-height:18px;font-size:10px;transform:translateY(-8px)}.VPDocFooter .VPBadge{display:none}.vp-doc h1>.VPBadge{margin-top:4px;vertical-align:top}.vp-doc h2>.VPBadge{margin-top:3px;padding:0 8px;vertical-align:top}.vp-doc h3>.VPBadge{vertical-align:middle}.vp-doc h4>.VPBadge,.vp-doc h5>.VPBadge,.vp-doc h6>.VPBadge{vertical-align:middle;line-height:18px}.VPBadge.info{border-color:var(--vp-badge-info-border);color:var(--vp-badge-info-text);background-color:var(--vp-badge-info-bg)}.VPBadge.tip{border-color:var(--vp-badge-tip-border);color:var(--vp-badge-tip-text);background-color:var(--vp-badge-tip-bg)}.VPBadge.warning{border-color:var(--vp-badge-warning-border);color:var(--vp-badge-warning-text);background-color:var(--vp-badge-warning-bg)}.VPBadge.danger{border-color:var(--vp-badge-danger-border);color:var(--vp-badge-danger-text);background-color:var(--vp-badge-danger-bg)}.VPBackdrop[data-v-54a304ca]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:var(--vp-z-index-backdrop);background:var(--vp-backdrop-bg-color);transition:opacity .5s}.VPBackdrop.fade-enter-from[data-v-54a304ca],.VPBackdrop.fade-leave-to[data-v-54a304ca]{opacity:0}.VPBackdrop.fade-leave-active[data-v-54a304ca]{transition-duration:.25s}@media (min-width: 1280px){.VPBackdrop[data-v-54a304ca]{display:none}}.NotFound[data-v-6ff51ddd]{padding:64px 24px 96px;text-align:center}@media (min-width: 768px){.NotFound[data-v-6ff51ddd]{padding:96px 32px 168px}}.code[data-v-6ff51ddd]{line-height:64px;font-size:64px;font-weight:600}.title[data-v-6ff51ddd]{padding-top:12px;letter-spacing:2px;line-height:20px;font-size:20px;font-weight:700}.divider[data-v-6ff51ddd]{margin:24px auto 18px;width:64px;height:1px;background-color:var(--vp-c-divider)}.quote[data-v-6ff51ddd]{margin:0 auto;max-width:256px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.action[data-v-6ff51ddd]{padding-top:20px}.link[data-v-6ff51ddd]{display:inline-block;border:1px solid var(--vp-c-brand-1);border-radius:16px;padding:3px 16px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:border-color .25s,color .25s}.link[data-v-6ff51ddd]:hover{border-color:var(--vp-c-brand-2);color:var(--vp-c-brand-2)}.root[data-v-53c99d69]{position:relative;z-index:1}.nested[data-v-53c99d69]{padding-right:16px;padding-left:16px}.outline-link[data-v-53c99d69]{display:block;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .5s}.outline-link[data-v-53c99d69]:hover,.outline-link.active[data-v-53c99d69]{color:var(--vp-c-text-1);transition:color .25s}.outline-link.nested[data-v-53c99d69]{padding-left:13px}.VPDocAsideOutline[data-v-f610f197]{display:none}.VPDocAsideOutline.has-outline[data-v-f610f197]{display:block}.content[data-v-f610f197]{position:relative;border-left:1px solid var(--vp-c-divider);padding-left:16px;font-size:13px;font-weight:500}.outline-marker[data-v-f610f197]{position:absolute;top:32px;left:-1px;z-index:0;opacity:0;width:2px;border-radius:2px;height:18px;background-color:var(--vp-c-brand-1);transition:top .25s cubic-bezier(0,1,.5,1),background-color .5s,opacity .25s}.outline-title[data-v-f610f197]{line-height:32px;font-size:14px;font-weight:600}.VPDocAside[data-v-cb998dce]{display:flex;flex-direction:column;flex-grow:1}.spacer[data-v-cb998dce]{flex-grow:1}.VPDocAside[data-v-cb998dce] .spacer+.VPDocAsideSponsors,.VPDocAside[data-v-cb998dce] .spacer+.VPDocAsideCarbonAds{margin-top:24px}.VPDocAside[data-v-cb998dce] .VPDocAsideSponsors+.VPDocAsideCarbonAds{margin-top:16px}.VPLastUpdated[data-v-1bb0c8a8]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 640px){.VPLastUpdated[data-v-1bb0c8a8]{line-height:32px;font-size:14px;font-weight:500}}.VPDocFooter[data-v-1bcd8184]{margin-top:64px}.edit-info[data-v-1bcd8184]{padding-bottom:18px}@media (min-width: 640px){.edit-info[data-v-1bcd8184]{display:flex;justify-content:space-between;align-items:center;padding-bottom:14px}}.edit-link-button[data-v-1bcd8184]{display:flex;align-items:center;border:0;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.edit-link-button[data-v-1bcd8184]:hover{color:var(--vp-c-brand-2)}.edit-link-icon[data-v-1bcd8184]{margin-right:8px}.prev-next[data-v-1bcd8184]{border-top:1px solid var(--vp-c-divider);padding-top:24px;display:grid;grid-row-gap:8px}@media (min-width: 640px){.prev-next[data-v-1bcd8184]{grid-template-columns:repeat(2,1fr);grid-column-gap:16px}}.pager-link[data-v-1bcd8184]{display:block;border:1px solid var(--vp-c-divider);border-radius:8px;padding:11px 16px 13px;width:100%;height:100%;transition:border-color .25s}.pager-link[data-v-1bcd8184]:hover{border-color:var(--vp-c-brand-1)}.pager-link.next[data-v-1bcd8184]{margin-left:auto;text-align:right}.desc[data-v-1bcd8184]{display:block;line-height:20px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.title[data-v-1bcd8184]{display:block;line-height:20px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1);transition:color .25s}.VPDoc[data-v-e6f2a212]{padding:32px 24px 96px;width:100%}@media (min-width: 768px){.VPDoc[data-v-e6f2a212]{padding:48px 32px 128px}}@media (min-width: 960px){.VPDoc[data-v-e6f2a212]{padding:48px 32px 0}.VPDoc:not(.has-sidebar) .container[data-v-e6f2a212]{display:flex;justify-content:center;max-width:992px}.VPDoc:not(.has-sidebar) .content[data-v-e6f2a212]{max-width:752px}}@media (min-width: 1280px){.VPDoc .container[data-v-e6f2a212]{display:flex;justify-content:center}.VPDoc .aside[data-v-e6f2a212]{display:block}}@media (min-width: 1440px){.VPDoc:not(.has-sidebar) .content[data-v-e6f2a212]{max-width:784px}.VPDoc:not(.has-sidebar) .container[data-v-e6f2a212]{max-width:1104px}}.container[data-v-e6f2a212]{margin:0 auto;width:100%}.aside[data-v-e6f2a212]{position:relative;display:none;order:2;flex-grow:1;padding-left:32px;width:100%;max-width:256px}.left-aside[data-v-e6f2a212]{order:1;padding-left:unset;padding-right:32px}.aside-container[data-v-e6f2a212]{position:fixed;top:0;padding-top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + var(--vp-doc-top-height, 0px) + 48px);width:224px;height:100vh;overflow-x:hidden;overflow-y:auto;scrollbar-width:none}.aside-container[data-v-e6f2a212]::-webkit-scrollbar{display:none}.aside-curtain[data-v-e6f2a212]{position:fixed;bottom:0;z-index:10;width:224px;height:32px;background:linear-gradient(transparent,var(--vp-c-bg) 70%)}.aside-content[data-v-e6f2a212]{display:flex;flex-direction:column;min-height:calc(100vh - (var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px));padding-bottom:32px}.content[data-v-e6f2a212]{position:relative;margin:0 auto;width:100%}@media (min-width: 960px){.content[data-v-e6f2a212]{padding:0 32px 128px}}@media (min-width: 1280px){.content[data-v-e6f2a212]{order:1;margin:0;min-width:640px}}.content-container[data-v-e6f2a212]{margin:0 auto}.VPDoc.has-aside .content-container[data-v-e6f2a212]{max-width:688px}.VPButton[data-v-93dc4167]{display:inline-block;border:1px solid transparent;text-align:center;font-weight:600;white-space:nowrap;transition:color .25s,border-color .25s,background-color .25s}.VPButton[data-v-93dc4167]:active{transition:color .1s,border-color .1s,background-color .1s}.VPButton.medium[data-v-93dc4167]{border-radius:20px;padding:0 20px;line-height:38px;font-size:14px}.VPButton.big[data-v-93dc4167]{border-radius:24px;padding:0 24px;line-height:46px;font-size:16px}.VPButton.brand[data-v-93dc4167]{border-color:var(--vp-button-brand-border);color:var(--vp-button-brand-text);background-color:var(--vp-button-brand-bg)}.VPButton.brand[data-v-93dc4167]:hover{border-color:var(--vp-button-brand-hover-border);color:var(--vp-button-brand-hover-text);background-color:var(--vp-button-brand-hover-bg)}.VPButton.brand[data-v-93dc4167]:active{border-color:var(--vp-button-brand-active-border);color:var(--vp-button-brand-active-text);background-color:var(--vp-button-brand-active-bg)}.VPButton.alt[data-v-93dc4167]{border-color:var(--vp-button-alt-border);color:var(--vp-button-alt-text);background-color:var(--vp-button-alt-bg)}.VPButton.alt[data-v-93dc4167]:hover{border-color:var(--vp-button-alt-hover-border);color:var(--vp-button-alt-hover-text);background-color:var(--vp-button-alt-hover-bg)}.VPButton.alt[data-v-93dc4167]:active{border-color:var(--vp-button-alt-active-border);color:var(--vp-button-alt-active-text);background-color:var(--vp-button-alt-active-bg)}.VPButton.sponsor[data-v-93dc4167]{border-color:var(--vp-button-sponsor-border);color:var(--vp-button-sponsor-text);background-color:var(--vp-button-sponsor-bg)}.VPButton.sponsor[data-v-93dc4167]:hover{border-color:var(--vp-button-sponsor-hover-border);color:var(--vp-button-sponsor-hover-text);background-color:var(--vp-button-sponsor-hover-bg)}.VPButton.sponsor[data-v-93dc4167]:active{border-color:var(--vp-button-sponsor-active-border);color:var(--vp-button-sponsor-active-text);background-color:var(--vp-button-sponsor-active-bg)}html:not(.dark) .VPImage.dark[data-v-ab19afbb]{display:none}.dark .VPImage.light[data-v-ab19afbb]{display:none}.VPHero[data-v-b10c5094]{margin-top:calc((var(--vp-nav-height) + var(--vp-layout-top-height, 0px)) * -1);padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px) 24px 48px}@media (min-width: 640px){.VPHero[data-v-b10c5094]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 48px 64px}}@media (min-width: 960px){.VPHero[data-v-b10c5094]{padding:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 64px 64px}}.container[data-v-b10c5094]{display:flex;flex-direction:column;margin:0 auto;max-width:1152px}@media (min-width: 960px){.container[data-v-b10c5094]{flex-direction:row}}.main[data-v-b10c5094]{position:relative;z-index:10;order:2;flex-grow:1;flex-shrink:0}.VPHero.has-image .container[data-v-b10c5094]{text-align:center}@media (min-width: 960px){.VPHero.has-image .container[data-v-b10c5094]{text-align:left}}@media (min-width: 960px){.main[data-v-b10c5094]{order:1;width:calc((100% / 3) * 2)}.VPHero.has-image .main[data-v-b10c5094]{max-width:592px}}.name[data-v-b10c5094],.text[data-v-b10c5094]{max-width:392px;letter-spacing:-.4px;line-height:40px;font-size:32px;font-weight:700;white-space:pre-wrap}.VPHero.has-image .name[data-v-b10c5094],.VPHero.has-image .text[data-v-b10c5094]{margin:0 auto}.name[data-v-b10c5094]{color:var(--vp-home-hero-name-color)}.clip[data-v-b10c5094]{background:var(--vp-home-hero-name-background);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:var(--vp-home-hero-name-color)}@media (min-width: 640px){.name[data-v-b10c5094],.text[data-v-b10c5094]{max-width:576px;line-height:56px;font-size:48px}}@media (min-width: 960px){.name[data-v-b10c5094],.text[data-v-b10c5094]{line-height:64px;font-size:56px}.VPHero.has-image .name[data-v-b10c5094],.VPHero.has-image .text[data-v-b10c5094]{margin:0}}.tagline[data-v-b10c5094]{padding-top:8px;max-width:392px;line-height:28px;font-size:18px;font-weight:500;white-space:pre-wrap;color:var(--vp-c-text-2)}.VPHero.has-image .tagline[data-v-b10c5094]{margin:0 auto}@media (min-width: 640px){.tagline[data-v-b10c5094]{padding-top:12px;max-width:576px;line-height:32px;font-size:20px}}@media (min-width: 960px){.tagline[data-v-b10c5094]{line-height:36px;font-size:24px}.VPHero.has-image .tagline[data-v-b10c5094]{margin:0}}.actions[data-v-b10c5094]{display:flex;flex-wrap:wrap;margin:-6px;padding-top:24px}.VPHero.has-image .actions[data-v-b10c5094]{justify-content:center}@media (min-width: 640px){.actions[data-v-b10c5094]{padding-top:32px}}@media (min-width: 960px){.VPHero.has-image .actions[data-v-b10c5094]{justify-content:flex-start}}.action[data-v-b10c5094]{flex-shrink:0;padding:6px}.image[data-v-b10c5094]{order:1;margin:-76px -24px -48px}@media (min-width: 640px){.image[data-v-b10c5094]{margin:-108px -24px -48px}}@media (min-width: 960px){.image[data-v-b10c5094]{flex-grow:1;order:2;margin:0;min-height:100%}}.image-container[data-v-b10c5094]{position:relative;margin:0 auto;width:320px;height:320px}@media (min-width: 640px){.image-container[data-v-b10c5094]{width:392px;height:392px}}@media (min-width: 960px){.image-container[data-v-b10c5094]{display:flex;justify-content:center;align-items:center;width:100%;height:100%;transform:translate(-32px,-32px)}}.image-bg[data-v-b10c5094]{position:absolute;top:50%;left:50%;border-radius:50%;width:192px;height:192px;background-image:var(--vp-home-hero-image-background-image);filter:var(--vp-home-hero-image-filter);transform:translate(-50%,-50%)}@media (min-width: 640px){.image-bg[data-v-b10c5094]{width:256px;height:256px}}@media (min-width: 960px){.image-bg[data-v-b10c5094]{width:320px;height:320px}}[data-v-b10c5094] .image-src{position:absolute;top:50%;left:50%;max-width:192px;max-height:192px;transform:translate(-50%,-50%)}@media (min-width: 640px){[data-v-b10c5094] .image-src{max-width:256px;max-height:256px}}@media (min-width: 960px){[data-v-b10c5094] .image-src{max-width:320px;max-height:320px}}.VPFeature[data-v-bd37d1a2]{display:block;border:1px solid var(--vp-c-bg-soft);border-radius:12px;height:100%;background-color:var(--vp-c-bg-soft);transition:border-color .25s,background-color .25s}.VPFeature.link[data-v-bd37d1a2]:hover{border-color:var(--vp-c-brand-1)}.box[data-v-bd37d1a2]{display:flex;flex-direction:column;padding:24px;height:100%}.box[data-v-bd37d1a2]>.VPImage{margin-bottom:20px}.icon[data-v-bd37d1a2]{display:flex;justify-content:center;align-items:center;margin-bottom:20px;border-radius:6px;background-color:var(--vp-c-default-soft);width:48px;height:48px;font-size:24px;transition:background-color .25s}.title[data-v-bd37d1a2]{line-height:24px;font-size:16px;font-weight:600}.details[data-v-bd37d1a2]{flex-grow:1;padding-top:8px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.link-text[data-v-bd37d1a2]{padding-top:8px}.link-text-value[data-v-bd37d1a2]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.link-text-icon[data-v-bd37d1a2]{margin-left:6px}.VPFeatures[data-v-b1eea84a]{position:relative;padding:0 24px}@media (min-width: 640px){.VPFeatures[data-v-b1eea84a]{padding:0 48px}}@media (min-width: 960px){.VPFeatures[data-v-b1eea84a]{padding:0 64px}}.container[data-v-b1eea84a]{margin:0 auto;max-width:1152px}.items[data-v-b1eea84a]{display:flex;flex-wrap:wrap;margin:-8px}.item[data-v-b1eea84a]{padding:8px;width:100%}@media (min-width: 640px){.item.grid-2[data-v-b1eea84a],.item.grid-4[data-v-b1eea84a],.item.grid-6[data-v-b1eea84a]{width:50%}}@media (min-width: 768px){.item.grid-2[data-v-b1eea84a],.item.grid-4[data-v-b1eea84a]{width:50%}.item.grid-3[data-v-b1eea84a],.item.grid-6[data-v-b1eea84a]{width:calc(100% / 3)}}@media (min-width: 960px){.item.grid-4[data-v-b1eea84a]{width:25%}}.container[data-v-c141a4bd]{margin:auto;width:100%;max-width:1280px;padding:0 24px}@media (min-width: 640px){.container[data-v-c141a4bd]{padding:0 48px}}@media (min-width: 960px){.container[data-v-c141a4bd]{width:100%;padding:0 64px}}.vp-doc[data-v-c141a4bd] .VPHomeSponsors,.vp-doc[data-v-c141a4bd] .VPTeamPage{margin-left:var(--vp-offset, calc(50% - 50vw) );margin-right:var(--vp-offset, calc(50% - 50vw) )}.vp-doc[data-v-c141a4bd] .VPHomeSponsors h2{border-top:none;letter-spacing:normal}.vp-doc[data-v-c141a4bd] .VPHomeSponsors a,.vp-doc[data-v-c141a4bd] .VPTeamPage a{text-decoration:none}.VPHome[data-v-07b1ad08]{margin-bottom:96px}@media (min-width: 768px){.VPHome[data-v-07b1ad08]{margin-bottom:128px}}.VPContent[data-v-9a6c75ad]{flex-grow:1;flex-shrink:0;margin:var(--vp-layout-top-height, 0px) auto 0;width:100%}.VPContent.is-home[data-v-9a6c75ad]{width:100%;max-width:100%}.VPContent.has-sidebar[data-v-9a6c75ad]{margin:0}@media (min-width: 960px){.VPContent[data-v-9a6c75ad]{padding-top:var(--vp-nav-height)}.VPContent.has-sidebar[data-v-9a6c75ad]{margin:var(--vp-layout-top-height, 0px) 0 0;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPContent.has-sidebar[data-v-9a6c75ad]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.VPFooter[data-v-566314d4]{position:relative;z-index:var(--vp-z-index-footer);border-top:1px solid var(--vp-c-gutter);padding:32px 24px;background-color:var(--vp-c-bg)}.VPFooter.has-sidebar[data-v-566314d4]{display:none}.VPFooter[data-v-566314d4] a{text-decoration-line:underline;text-underline-offset:2px;transition:color .25s}.VPFooter[data-v-566314d4] a:hover{color:var(--vp-c-text-1)}@media (min-width: 768px){.VPFooter[data-v-566314d4]{padding:32px}}.container[data-v-566314d4]{margin:0 auto;max-width:var(--vp-layout-max-width);text-align:center}.message[data-v-566314d4],.copyright[data-v-566314d4]{line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-2)}.VPLocalNavOutlineDropdown[data-v-883964e0]{padding:12px 20px 11px}@media (min-width: 960px){.VPLocalNavOutlineDropdown[data-v-883964e0]{padding:12px 36px 11px}}.VPLocalNavOutlineDropdown button[data-v-883964e0]{display:block;font-size:12px;font-weight:500;line-height:24px;color:var(--vp-c-text-2);transition:color .5s;position:relative}.VPLocalNavOutlineDropdown button[data-v-883964e0]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPLocalNavOutlineDropdown button.open[data-v-883964e0]{color:var(--vp-c-text-1)}.icon[data-v-883964e0]{display:inline-block;vertical-align:middle;margin-left:2px;font-size:14px;transform:rotate(0);transition:transform .25s}@media (min-width: 960px){.VPLocalNavOutlineDropdown button[data-v-883964e0]{font-size:14px}.icon[data-v-883964e0]{font-size:16px}}.open>.icon[data-v-883964e0]{transform:rotate(90deg)}.items[data-v-883964e0]{position:absolute;top:40px;right:16px;left:16px;display:grid;gap:1px;border:1px solid var(--vp-c-border);border-radius:8px;background-color:var(--vp-c-gutter);max-height:calc(var(--vp-vh, 100vh) - 86px);overflow:hidden auto;box-shadow:var(--vp-shadow-3)}@media (min-width: 960px){.items[data-v-883964e0]{right:auto;left:calc(var(--vp-sidebar-width) + 32px);width:320px}}.header[data-v-883964e0]{background-color:var(--vp-c-bg-soft)}.top-link[data-v-883964e0]{display:block;padding:0 16px;line-height:48px;font-size:14px;font-weight:500;color:var(--vp-c-brand-1)}.outline[data-v-883964e0]{padding:8px 0;background-color:var(--vp-c-bg-soft)}.flyout-enter-active[data-v-883964e0]{transition:all .2s ease-out}.flyout-leave-active[data-v-883964e0]{transition:all .15s ease-in}.flyout-enter-from[data-v-883964e0],.flyout-leave-to[data-v-883964e0]{opacity:0;transform:translateY(-16px)}.VPLocalNav[data-v-2488c25a]{position:sticky;top:0;left:0;z-index:var(--vp-z-index-local-nav);border-bottom:1px solid var(--vp-c-gutter);padding-top:var(--vp-layout-top-height, 0px);width:100%;background-color:var(--vp-local-nav-bg-color)}.VPLocalNav.fixed[data-v-2488c25a]{position:fixed}@media (min-width: 960px){.VPLocalNav[data-v-2488c25a]{top:var(--vp-nav-height)}.VPLocalNav.has-sidebar[data-v-2488c25a]{padding-left:var(--vp-sidebar-width)}.VPLocalNav.empty[data-v-2488c25a]{display:none}}@media (min-width: 1280px){.VPLocalNav[data-v-2488c25a]{display:none}}@media (min-width: 1440px){.VPLocalNav.has-sidebar[data-v-2488c25a]{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.container[data-v-2488c25a]{display:flex;justify-content:space-between;align-items:center}.menu[data-v-2488c25a]{display:flex;align-items:center;padding:12px 24px 11px;line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.menu[data-v-2488c25a]:hover{color:var(--vp-c-text-1);transition:color .25s}@media (min-width: 768px){.menu[data-v-2488c25a]{padding:0 32px}}@media (min-width: 960px){.menu[data-v-2488c25a]{display:none}}.menu-icon[data-v-2488c25a]{margin-right:8px;font-size:14px}.VPOutlineDropdown[data-v-2488c25a]{padding:12px 24px 11px}@media (min-width: 768px){.VPOutlineDropdown[data-v-2488c25a]{padding:12px 32px 11px}}.VPSwitch[data-v-b4ccac88]{position:relative;border-radius:11px;display:block;width:40px;height:22px;flex-shrink:0;border:1px solid var(--vp-input-border-color);background-color:var(--vp-input-switch-bg-color);transition:border-color .25s!important}.VPSwitch[data-v-b4ccac88]:hover{border-color:var(--vp-c-brand-1)}.check[data-v-b4ccac88]{position:absolute;top:1px;left:1px;width:18px;height:18px;border-radius:50%;background-color:var(--vp-c-neutral-inverse);box-shadow:var(--vp-shadow-1);transition:transform .25s!important}.icon[data-v-b4ccac88]{position:relative;display:block;width:18px;height:18px;border-radius:50%;overflow:hidden}.icon[data-v-b4ccac88] [class^=vpi-]{position:absolute;top:3px;left:3px;width:12px;height:12px;color:var(--vp-c-text-2)}.dark .icon[data-v-b4ccac88] [class^=vpi-]{color:var(--vp-c-text-1);transition:opacity .25s!important}.sun[data-v-be9742d9]{opacity:1}.moon[data-v-be9742d9],.dark .sun[data-v-be9742d9]{opacity:0}.dark .moon[data-v-be9742d9]{opacity:1}.dark .VPSwitchAppearance[data-v-be9742d9] .check{transform:translate(18px)}.VPNavBarAppearance[data-v-3f90c1a5]{display:none}@media (min-width: 1280px){.VPNavBarAppearance[data-v-3f90c1a5]{display:flex;align-items:center}}.VPMenuGroup+.VPMenuLink[data-v-7eeeb2dc]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.link[data-v-7eeeb2dc]{display:block;border-radius:6px;padding:0 12px;line-height:32px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);white-space:nowrap;transition:background-color .25s,color .25s}.link[data-v-7eeeb2dc]:hover{color:var(--vp-c-brand-1);background-color:var(--vp-c-default-soft)}.link.active[data-v-7eeeb2dc]{color:var(--vp-c-brand-1)}.VPMenuGroup[data-v-a6b0397c]{margin:12px -12px 0;border-top:1px solid var(--vp-c-divider);padding:12px 12px 0}.VPMenuGroup[data-v-a6b0397c]:first-child{margin-top:0;border-top:0;padding-top:0}.VPMenuGroup+.VPMenuGroup[data-v-a6b0397c]{margin-top:12px;border-top:1px solid var(--vp-c-divider)}.title[data-v-a6b0397c]{padding:0 12px;line-height:32px;font-size:14px;font-weight:600;color:var(--vp-c-text-2);white-space:nowrap;transition:color .25s}.VPMenu[data-v-20ed86d6]{border-radius:12px;padding:12px;min-width:128px;border:1px solid var(--vp-c-divider);background-color:var(--vp-c-bg-elv);box-shadow:var(--vp-shadow-3);transition:background-color .5s;max-height:calc(100vh - var(--vp-nav-height));overflow-y:auto}.VPMenu[data-v-20ed86d6] .group{margin:0 -12px;padding:0 12px 12px}.VPMenu[data-v-20ed86d6] .group+.group{border-top:1px solid var(--vp-c-divider);padding:11px 12px 12px}.VPMenu[data-v-20ed86d6] .group:last-child{padding-bottom:0}.VPMenu[data-v-20ed86d6] .group+.item{border-top:1px solid var(--vp-c-divider);padding:11px 16px 0}.VPMenu[data-v-20ed86d6] .item{padding:0 16px;white-space:nowrap}.VPMenu[data-v-20ed86d6] .label{flex-grow:1;line-height:28px;font-size:12px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.VPMenu[data-v-20ed86d6] .action{padding-left:24px}.VPFlyout[data-v-bfe7971f]{position:relative}.VPFlyout[data-v-bfe7971f]:hover{color:var(--vp-c-brand-1);transition:color .25s}.VPFlyout:hover .text[data-v-bfe7971f]{color:var(--vp-c-text-2)}.VPFlyout:hover .icon[data-v-bfe7971f]{fill:var(--vp-c-text-2)}.VPFlyout.active .text[data-v-bfe7971f]{color:var(--vp-c-brand-1)}.VPFlyout.active:hover .text[data-v-bfe7971f]{color:var(--vp-c-brand-2)}.button[aria-expanded=false]+.menu[data-v-bfe7971f]{opacity:0;visibility:hidden;transform:translateY(0)}.VPFlyout:hover .menu[data-v-bfe7971f],.button[aria-expanded=true]+.menu[data-v-bfe7971f]{opacity:1;visibility:visible;transform:translateY(0)}.button[data-v-bfe7971f]{display:flex;align-items:center;padding:0 12px;height:var(--vp-nav-height);color:var(--vp-c-text-1);transition:color .5s}.text[data-v-bfe7971f]{display:flex;align-items:center;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.option-icon[data-v-bfe7971f]{margin-right:0;font-size:16px}.text-icon[data-v-bfe7971f]{margin-left:4px;font-size:14px}.icon[data-v-bfe7971f]{font-size:20px;transition:fill .25s}.menu[data-v-bfe7971f]{position:absolute;top:calc(var(--vp-nav-height) / 2 + 20px);right:0;opacity:0;visibility:hidden;transition:opacity .25s,visibility .25s,transform .25s}.VPSocialLink[data-v-60a9a2d3]{display:flex;justify-content:center;align-items:center;width:36px;height:36px;color:var(--vp-c-text-2);transition:color .5s}.VPSocialLink[data-v-60a9a2d3]:hover{color:var(--vp-c-text-1);transition:color .25s}.VPSocialLink[data-v-60a9a2d3]>svg,.VPSocialLink[data-v-60a9a2d3]>[class^=vpi-social-]{width:20px;height:20px;fill:currentColor}.VPSocialLinks[data-v-e71e869c]{display:flex;justify-content:center}.VPNavBarExtra[data-v-f953d92f]{display:none;margin-right:-12px}@media (min-width: 768px){.VPNavBarExtra[data-v-f953d92f]{display:block}}@media (min-width: 1280px){.VPNavBarExtra[data-v-f953d92f]{display:none}}.trans-title[data-v-f953d92f]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.item.appearance[data-v-f953d92f],.item.social-links[data-v-f953d92f]{display:flex;align-items:center;padding:0 12px}.item.appearance[data-v-f953d92f]{min-width:176px}.appearance-action[data-v-f953d92f]{margin-right:-2px}.social-links-list[data-v-f953d92f]{margin:-4px -8px}.VPNavBarHamburger[data-v-6bee1efd]{display:flex;justify-content:center;align-items:center;width:48px;height:var(--vp-nav-height)}@media (min-width: 768px){.VPNavBarHamburger[data-v-6bee1efd]{display:none}}.container[data-v-6bee1efd]{position:relative;width:16px;height:14px;overflow:hidden}.VPNavBarHamburger:hover .top[data-v-6bee1efd]{top:0;left:0;transform:translate(4px)}.VPNavBarHamburger:hover .middle[data-v-6bee1efd]{top:6px;left:0;transform:translate(0)}.VPNavBarHamburger:hover .bottom[data-v-6bee1efd]{top:12px;left:0;transform:translate(8px)}.VPNavBarHamburger.active .top[data-v-6bee1efd]{top:6px;transform:translate(0) rotate(225deg)}.VPNavBarHamburger.active .middle[data-v-6bee1efd]{top:6px;transform:translate(16px)}.VPNavBarHamburger.active .bottom[data-v-6bee1efd]{top:6px;transform:translate(0) rotate(135deg)}.VPNavBarHamburger.active:hover .top[data-v-6bee1efd],.VPNavBarHamburger.active:hover .middle[data-v-6bee1efd],.VPNavBarHamburger.active:hover .bottom[data-v-6bee1efd]{background-color:var(--vp-c-text-2);transition:top .25s,background-color .25s,transform .25s}.top[data-v-6bee1efd],.middle[data-v-6bee1efd],.bottom[data-v-6bee1efd]{position:absolute;width:16px;height:2px;background-color:var(--vp-c-text-1);transition:top .25s,background-color .5s,transform .25s}.top[data-v-6bee1efd]{top:0;left:0;transform:translate(0)}.middle[data-v-6bee1efd]{top:6px;left:0;transform:translate(8px)}.bottom[data-v-6bee1efd]{top:12px;left:0;transform:translate(4px)}.VPNavBarMenuLink[data-v-815115f5]{display:flex;align-items:center;padding:0 12px;line-height:var(--vp-nav-height);font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.VPNavBarMenuLink.active[data-v-815115f5],.VPNavBarMenuLink[data-v-815115f5]:hover{color:var(--vp-c-brand-1)}.VPNavBarMenu[data-v-afb2845e]{display:none}@media (min-width: 768px){.VPNavBarMenu[data-v-afb2845e]{display:flex}}/*! @docsearch/css 3.8.0 | MIT License | © Algolia, Inc. and contributors | https://docsearch.algolia.com */:root{--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:rgba(101,108,133,.8);--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 hsla(0,0%,100%,.5),0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px rgba(30,35,90,.4);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 rgba(30,35,90,.4);--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 rgba(69,98,155,.12)}html[data-theme=dark]{--docsearch-text-color:#f5f6f7;--docsearch-container-background:rgba(9,10,17,.8);--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 rgba(3,4,9,.3);--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 #0304094d;--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 rgba(73,76,106,.5),0 -4px 8px 0 rgba(0,0,0,.2);--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}.DocSearch-Button{align-items:center;background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;display:flex;font-weight:500;height:36px;justify-content:space-between;margin:0 0 0 16px;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:none}.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch-Button-Key--pressed{box-shadow:var(--docsearch-key-pressed-shadow);transform:translate3d(0,1px,0)}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder{display:none}}.DocSearch--active{overflow:hidden!important}.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Container a{text-decoration:none}.DocSearch-Link{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:none;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator{display:none}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}}.DocSearch-Reset{animation:fade-in .1s ease-in forwards;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Cancel{display:none}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:transparent}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{color:var(--docsearch-muted-color);display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--deleting{transition:none}}.DocSearch-Hit--deleting{opacity:0;transition:all .25s linear}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit--favoriting{transition:none}}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:all .25s linear;transition-delay:.25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;stroke-width:var(--docsearch-icon-stroke-width);width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit[aria-selected=true] mark{text-decoration:underline}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color);stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{transition:none}}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:none;text-decoration:underline}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@media (max-width:768px){:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh, 1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Dropdown{max-height:calc(var(--docsearch-vh, 1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Cancel{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:none;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}[class*=DocSearch]{--docsearch-primary-color: var(--vp-c-brand-1);--docsearch-highlight-color: var(--docsearch-primary-color);--docsearch-text-color: var(--vp-c-text-1);--docsearch-muted-color: var(--vp-c-text-2);--docsearch-searchbox-shadow: none;--docsearch-searchbox-background: transparent;--docsearch-searchbox-focus-background: transparent;--docsearch-key-gradient: transparent;--docsearch-key-shadow: none;--docsearch-modal-background: var(--vp-c-bg-soft);--docsearch-footer-background: var(--vp-c-bg)}.dark [class*=DocSearch]{--docsearch-modal-shadow: none;--docsearch-footer-shadow: none;--docsearch-logo-color: var(--vp-c-text-2);--docsearch-hit-background: var(--vp-c-default-soft);--docsearch-hit-color: var(--vp-c-text-2);--docsearch-hit-shadow: none}.DocSearch-Button{display:flex;justify-content:center;align-items:center;margin:0;padding:0;width:48px;height:55px;background:transparent;transition:border-color .25s}.DocSearch-Button:hover{background:transparent}.DocSearch-Button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}.DocSearch-Button-Key--pressed{transform:none;box-shadow:none}.DocSearch-Button:focus:not(:focus-visible){outline:none!important}@media (min-width: 768px){.DocSearch-Button{justify-content:flex-start;border:1px solid transparent;border-radius:8px;padding:0 10px 0 12px;width:100%;height:40px;background-color:var(--vp-c-bg-alt)}.DocSearch-Button:hover{border-color:var(--vp-c-brand-1);background:var(--vp-c-bg-alt)}}.DocSearch-Button .DocSearch-Button-Container{display:flex;align-items:center}.DocSearch-Button .DocSearch-Search-Icon{position:relative;width:16px;height:16px;color:var(--vp-c-text-1);fill:currentColor;transition:color .5s}.DocSearch-Button:hover .DocSearch-Search-Icon{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Search-Icon{top:1px;margin-right:8px;width:14px;height:14px;color:var(--vp-c-text-2)}}.DocSearch-Button .DocSearch-Button-Placeholder{display:none;margin-top:2px;padding:0 16px 0 0;font-size:13px;font-weight:500;color:var(--vp-c-text-2);transition:color .5s}.DocSearch-Button:hover .DocSearch-Button-Placeholder{color:var(--vp-c-text-1)}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Placeholder{display:inline-block}}.DocSearch-Button .DocSearch-Button-Keys{direction:ltr;display:none;min-width:auto}@media (min-width: 768px){.DocSearch-Button .DocSearch-Button-Keys{display:flex;align-items:center}}.DocSearch-Button .DocSearch-Button-Key{display:block;margin:2px 0 0;border:1px solid var(--vp-c-divider);border-right:none;border-radius:4px 0 0 4px;padding-left:6px;min-width:0;width:auto;height:22px;line-height:22px;font-family:var(--vp-font-family-base);font-size:12px;font-weight:500;transition:color .5s,border-color .5s}.DocSearch-Button .DocSearch-Button-Key+.DocSearch-Button-Key{border-right:1px solid var(--vp-c-divider);border-left:none;border-radius:0 4px 4px 0;padding-left:2px;padding-right:6px}.DocSearch-Button .DocSearch-Button-Key:first-child{font-size:0!important}.DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"Ctrl";font-size:12px;letter-spacing:normal;color:var(--docsearch-muted-color)}.mac .DocSearch-Button .DocSearch-Button-Key:first-child:after{content:"⌘"}.DocSearch-Button .DocSearch-Button-Key:first-child>*{display:none}.DocSearch-Search-Icon{--icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' stroke-width='1.6' viewBox='0 0 20 20'%3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' d='m14.386 14.386 4.088 4.088-4.088-4.088A7.533 7.533 0 1 1 3.733 3.733a7.533 7.533 0 0 1 10.653 10.653z'/%3E%3C/svg%3E")}.VPNavBarSearch{display:flex;align-items:center}@media (min-width: 768px){.VPNavBarSearch{flex-grow:1;padding-left:24px}}@media (min-width: 960px){.VPNavBarSearch{padding-left:32px}}.dark .DocSearch-Footer{border-top:1px solid var(--vp-c-divider)}.DocSearch-Form{border:1px solid var(--vp-c-brand-1);background-color:var(--vp-c-white)}.dark .DocSearch-Form{background-color:var(--vp-c-default-soft)}.DocSearch-Screen-Icon>svg{margin:auto}.VPNavBarSocialLinks[data-v-ef6192dc]{display:none}@media (min-width: 1280px){.VPNavBarSocialLinks[data-v-ef6192dc]{display:flex;align-items:center}}.title[data-v-9f43907a]{display:flex;align-items:center;border-bottom:1px solid transparent;width:100%;height:var(--vp-nav-height);font-size:16px;font-weight:600;color:var(--vp-c-text-1);transition:opacity .25s}@media (min-width: 960px){.title[data-v-9f43907a]{flex-shrink:0}.VPNavBarTitle.has-sidebar .title[data-v-9f43907a]{border-bottom-color:var(--vp-c-divider)}}[data-v-9f43907a] .logo{margin-right:8px;height:var(--vp-nav-logo-height)}.VPNavBarTranslations[data-v-acee064b]{display:none}@media (min-width: 1280px){.VPNavBarTranslations[data-v-acee064b]{display:flex;align-items:center}}.title[data-v-acee064b]{padding:0 24px 0 12px;line-height:32px;font-size:14px;font-weight:700;color:var(--vp-c-text-1)}.VPNavBar[data-v-9fd4d1dd]{position:relative;height:var(--vp-nav-height);pointer-events:none;white-space:nowrap;transition:background-color .25s}.VPNavBar.screen-open[data-v-9fd4d1dd]{transition:none;background-color:var(--vp-nav-bg-color);border-bottom:1px solid var(--vp-c-divider)}.VPNavBar[data-v-9fd4d1dd]:not(.home){background-color:var(--vp-nav-bg-color)}@media (min-width: 960px){.VPNavBar[data-v-9fd4d1dd]:not(.home){background-color:transparent}.VPNavBar[data-v-9fd4d1dd]:not(.has-sidebar):not(.home.top){background-color:var(--vp-nav-bg-color)}}.wrapper[data-v-9fd4d1dd]{padding:0 8px 0 24px}@media (min-width: 768px){.wrapper[data-v-9fd4d1dd]{padding:0 32px}}@media (min-width: 960px){.VPNavBar.has-sidebar .wrapper[data-v-9fd4d1dd]{padding:0}}.container[data-v-9fd4d1dd]{display:flex;justify-content:space-between;margin:0 auto;max-width:calc(var(--vp-layout-max-width) - 64px);height:var(--vp-nav-height);pointer-events:none}.container>.title[data-v-9fd4d1dd],.container>.content[data-v-9fd4d1dd]{pointer-events:none}.container[data-v-9fd4d1dd] *{pointer-events:auto}@media (min-width: 960px){.VPNavBar.has-sidebar .container[data-v-9fd4d1dd]{max-width:100%}}.title[data-v-9fd4d1dd]{flex-shrink:0;height:calc(var(--vp-nav-height) - 1px);transition:background-color .5s}@media (min-width: 960px){.VPNavBar.has-sidebar .title[data-v-9fd4d1dd]{position:absolute;top:0;left:0;z-index:2;padding:0 32px;width:var(--vp-sidebar-width);height:var(--vp-nav-height);background-color:transparent}}@media (min-width: 1440px){.VPNavBar.has-sidebar .title[data-v-9fd4d1dd]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}.content[data-v-9fd4d1dd]{flex-grow:1}@media (min-width: 960px){.VPNavBar.has-sidebar .content[data-v-9fd4d1dd]{position:relative;z-index:1;padding-right:32px;padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .content[data-v-9fd4d1dd]{padding-right:calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.content-body[data-v-9fd4d1dd]{display:flex;justify-content:flex-end;align-items:center;height:var(--vp-nav-height);transition:background-color .5s}@media (min-width: 960px){.VPNavBar:not(.home.top) .content-body[data-v-9fd4d1dd]{position:relative;background-color:var(--vp-nav-bg-color)}.VPNavBar:not(.has-sidebar):not(.home.top) .content-body[data-v-9fd4d1dd]{background-color:transparent}}@media (max-width: 767px){.content-body[data-v-9fd4d1dd]{column-gap:.5rem}}.menu+.translations[data-v-9fd4d1dd]:before,.menu+.appearance[data-v-9fd4d1dd]:before,.menu+.social-links[data-v-9fd4d1dd]:before,.translations+.appearance[data-v-9fd4d1dd]:before,.appearance+.social-links[data-v-9fd4d1dd]:before{margin-right:8px;margin-left:8px;width:1px;height:24px;background-color:var(--vp-c-divider);content:""}.menu+.appearance[data-v-9fd4d1dd]:before,.translations+.appearance[data-v-9fd4d1dd]:before{margin-right:16px}.appearance+.social-links[data-v-9fd4d1dd]:before{margin-left:16px}.social-links[data-v-9fd4d1dd]{margin-right:-8px}.divider[data-v-9fd4d1dd]{width:100%;height:1px}@media (min-width: 960px){.VPNavBar.has-sidebar .divider[data-v-9fd4d1dd]{padding-left:var(--vp-sidebar-width)}}@media (min-width: 1440px){.VPNavBar.has-sidebar .divider[data-v-9fd4d1dd]{padding-left:calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width))}}.divider-line[data-v-9fd4d1dd]{width:100%;height:1px;transition:background-color .5s}.VPNavBar:not(.home) .divider-line[data-v-9fd4d1dd]{background-color:var(--vp-c-gutter)}@media (min-width: 960px){.VPNavBar:not(.home.top) .divider-line[data-v-9fd4d1dd]{background-color:var(--vp-c-gutter)}.VPNavBar:not(.has-sidebar):not(.home.top) .divider[data-v-9fd4d1dd]{background-color:var(--vp-c-gutter)}}.VPNavScreenAppearance[data-v-a3e2920d]{display:flex;justify-content:space-between;align-items:center;border-radius:8px;padding:12px 14px 12px 16px;background-color:var(--vp-c-bg-soft)}.text[data-v-a3e2920d]{line-height:24px;font-size:12px;font-weight:500;color:var(--vp-c-text-2)}.VPNavScreenMenuLink[data-v-fa963d97]{display:block;border-bottom:1px solid var(--vp-c-divider);padding:12px 0 11px;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:border-color .25s,color .25s}.VPNavScreenMenuLink[data-v-fa963d97]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupLink[data-v-e04f3e85]{display:block;margin-left:12px;line-height:32px;font-size:14px;font-weight:400;color:var(--vp-c-text-1);transition:color .25s}.VPNavScreenMenuGroupLink[data-v-e04f3e85]:hover{color:var(--vp-c-brand-1)}.VPNavScreenMenuGroupSection[data-v-f60dbfa7]{display:block}.title[data-v-f60dbfa7]{line-height:32px;font-size:13px;font-weight:700;color:var(--vp-c-text-2);transition:color .25s}.VPNavScreenMenuGroup[data-v-d99bfeec]{border-bottom:1px solid var(--vp-c-divider);height:48px;overflow:hidden;transition:border-color .5s}.VPNavScreenMenuGroup .items[data-v-d99bfeec]{visibility:hidden}.VPNavScreenMenuGroup.open .items[data-v-d99bfeec]{visibility:visible}.VPNavScreenMenuGroup.open[data-v-d99bfeec]{padding-bottom:10px;height:auto}.VPNavScreenMenuGroup.open .button[data-v-d99bfeec]{padding-bottom:6px;color:var(--vp-c-brand-1)}.VPNavScreenMenuGroup.open .button-icon[data-v-d99bfeec]{transform:rotate(45deg)}.button[data-v-d99bfeec]{display:flex;justify-content:space-between;align-items:center;padding:12px 4px 11px 0;width:100%;line-height:24px;font-size:14px;font-weight:500;color:var(--vp-c-text-1);transition:color .25s}.button[data-v-d99bfeec]:hover{color:var(--vp-c-brand-1)}.button-icon[data-v-d99bfeec]{transition:transform .25s}.group[data-v-d99bfeec]:first-child{padding-top:0}.group+.group[data-v-d99bfeec],.group+.item[data-v-d99bfeec]{padding-top:4px}.VPNavScreenTranslations[data-v-516e4bc3]{height:24px;overflow:hidden}.VPNavScreenTranslations.open[data-v-516e4bc3]{height:auto}.title[data-v-516e4bc3]{display:flex;align-items:center;font-size:14px;font-weight:500;color:var(--vp-c-text-1)}.icon[data-v-516e4bc3]{font-size:16px}.icon.lang[data-v-516e4bc3]{margin-right:8px}.icon.chevron[data-v-516e4bc3]{margin-left:4px}.list[data-v-516e4bc3]{padding:4px 0 0 24px}.link[data-v-516e4bc3]{line-height:32px;font-size:13px;color:var(--vp-c-text-1)}.VPNavScreen[data-v-2dd6d0c7]{position:fixed;top:calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px));right:0;bottom:0;left:0;padding:0 32px;width:100%;background-color:var(--vp-nav-screen-bg-color);overflow-y:auto;transition:background-color .25s;pointer-events:auto}.VPNavScreen.fade-enter-active[data-v-2dd6d0c7],.VPNavScreen.fade-leave-active[data-v-2dd6d0c7]{transition:opacity .25s}.VPNavScreen.fade-enter-active .container[data-v-2dd6d0c7],.VPNavScreen.fade-leave-active .container[data-v-2dd6d0c7]{transition:transform .25s ease}.VPNavScreen.fade-enter-from[data-v-2dd6d0c7],.VPNavScreen.fade-leave-to[data-v-2dd6d0c7]{opacity:0}.VPNavScreen.fade-enter-from .container[data-v-2dd6d0c7],.VPNavScreen.fade-leave-to .container[data-v-2dd6d0c7]{transform:translateY(-8px)}@media (min-width: 768px){.VPNavScreen[data-v-2dd6d0c7]{display:none}}.container[data-v-2dd6d0c7]{margin:0 auto;padding:24px 0 96px;max-width:288px}.menu+.translations[data-v-2dd6d0c7],.menu+.appearance[data-v-2dd6d0c7],.translations+.appearance[data-v-2dd6d0c7]{margin-top:24px}.menu+.social-links[data-v-2dd6d0c7]{margin-top:16px}.appearance+.social-links[data-v-2dd6d0c7]{margin-top:16px}.VPNav[data-v-7ad780c2]{position:relative;top:var(--vp-layout-top-height, 0px);left:0;z-index:var(--vp-z-index-nav);width:100%;pointer-events:none;transition:background-color .5s}@media (min-width: 960px){.VPNav[data-v-7ad780c2]{position:fixed}}.VPSidebarItem.level-0[data-v-edd2eed8]{padding-bottom:24px}.VPSidebarItem.collapsed.level-0[data-v-edd2eed8]{padding-bottom:10px}.item[data-v-edd2eed8]{position:relative;display:flex;width:100%}.VPSidebarItem.collapsible>.item[data-v-edd2eed8]{cursor:pointer}.indicator[data-v-edd2eed8]{position:absolute;top:6px;bottom:6px;left:-17px;width:2px;border-radius:2px;transition:background-color .25s}.VPSidebarItem.level-2.is-active>.item>.indicator[data-v-edd2eed8],.VPSidebarItem.level-3.is-active>.item>.indicator[data-v-edd2eed8],.VPSidebarItem.level-4.is-active>.item>.indicator[data-v-edd2eed8],.VPSidebarItem.level-5.is-active>.item>.indicator[data-v-edd2eed8]{background-color:var(--vp-c-brand-1)}.link[data-v-edd2eed8]{display:flex;align-items:center;flex-grow:1}.text[data-v-edd2eed8]{flex-grow:1;padding:4px 0;line-height:24px;font-size:14px;transition:color .25s}.VPSidebarItem.level-0 .text[data-v-edd2eed8]{font-weight:700;color:var(--vp-c-text-1)}.VPSidebarItem.level-1 .text[data-v-edd2eed8],.VPSidebarItem.level-2 .text[data-v-edd2eed8],.VPSidebarItem.level-3 .text[data-v-edd2eed8],.VPSidebarItem.level-4 .text[data-v-edd2eed8],.VPSidebarItem.level-5 .text[data-v-edd2eed8]{font-weight:500;color:var(--vp-c-text-2)}.VPSidebarItem.level-0.is-link>.item>.link:hover .text[data-v-edd2eed8],.VPSidebarItem.level-1.is-link>.item>.link:hover .text[data-v-edd2eed8],.VPSidebarItem.level-2.is-link>.item>.link:hover .text[data-v-edd2eed8],.VPSidebarItem.level-3.is-link>.item>.link:hover .text[data-v-edd2eed8],.VPSidebarItem.level-4.is-link>.item>.link:hover .text[data-v-edd2eed8],.VPSidebarItem.level-5.is-link>.item>.link:hover .text[data-v-edd2eed8]{color:var(--vp-c-brand-1)}.VPSidebarItem.level-0.has-active>.item>.text[data-v-edd2eed8],.VPSidebarItem.level-1.has-active>.item>.text[data-v-edd2eed8],.VPSidebarItem.level-2.has-active>.item>.text[data-v-edd2eed8],.VPSidebarItem.level-3.has-active>.item>.text[data-v-edd2eed8],.VPSidebarItem.level-4.has-active>.item>.text[data-v-edd2eed8],.VPSidebarItem.level-5.has-active>.item>.text[data-v-edd2eed8],.VPSidebarItem.level-0.has-active>.item>.link>.text[data-v-edd2eed8],.VPSidebarItem.level-1.has-active>.item>.link>.text[data-v-edd2eed8],.VPSidebarItem.level-2.has-active>.item>.link>.text[data-v-edd2eed8],.VPSidebarItem.level-3.has-active>.item>.link>.text[data-v-edd2eed8],.VPSidebarItem.level-4.has-active>.item>.link>.text[data-v-edd2eed8],.VPSidebarItem.level-5.has-active>.item>.link>.text[data-v-edd2eed8]{color:var(--vp-c-text-1)}.VPSidebarItem.level-0.is-active>.item .link>.text[data-v-edd2eed8],.VPSidebarItem.level-1.is-active>.item .link>.text[data-v-edd2eed8],.VPSidebarItem.level-2.is-active>.item .link>.text[data-v-edd2eed8],.VPSidebarItem.level-3.is-active>.item .link>.text[data-v-edd2eed8],.VPSidebarItem.level-4.is-active>.item .link>.text[data-v-edd2eed8],.VPSidebarItem.level-5.is-active>.item .link>.text[data-v-edd2eed8]{color:var(--vp-c-brand-1)}.caret[data-v-edd2eed8]{display:flex;justify-content:center;align-items:center;margin-right:-7px;width:32px;height:32px;color:var(--vp-c-text-3);cursor:pointer;transition:color .25s;flex-shrink:0}.item:hover .caret[data-v-edd2eed8]{color:var(--vp-c-text-2)}.item:hover .caret[data-v-edd2eed8]:hover{color:var(--vp-c-text-1)}.caret-icon[data-v-edd2eed8]{font-size:18px;transform:rotate(90deg);transition:transform .25s}.VPSidebarItem.collapsed .caret-icon[data-v-edd2eed8]{transform:rotate(0)}.VPSidebarItem.level-1 .items[data-v-edd2eed8],.VPSidebarItem.level-2 .items[data-v-edd2eed8],.VPSidebarItem.level-3 .items[data-v-edd2eed8],.VPSidebarItem.level-4 .items[data-v-edd2eed8],.VPSidebarItem.level-5 .items[data-v-edd2eed8]{border-left:1px solid var(--vp-c-divider);padding-left:16px}.VPSidebarItem.collapsed .items[data-v-edd2eed8]{display:none}.no-transition[data-v-51288d80] .caret-icon{transition:none}.group+.group[data-v-51288d80]{border-top:1px solid var(--vp-c-divider);padding-top:10px}@media (min-width: 960px){.group[data-v-51288d80]{padding-top:10px;width:calc(var(--vp-sidebar-width) - 64px)}}.VPSidebar[data-v-42c4c606]{position:fixed;top:var(--vp-layout-top-height, 0px);bottom:0;left:0;z-index:var(--vp-z-index-sidebar);padding:32px 32px 96px;width:calc(100vw - 64px);max-width:320px;background-color:var(--vp-sidebar-bg-color);opacity:0;box-shadow:var(--vp-c-shadow-3);overflow-x:hidden;overflow-y:auto;transform:translate(-100%);transition:opacity .5s,transform .25s ease;overscroll-behavior:contain}.VPSidebar.open[data-v-42c4c606]{opacity:1;visibility:visible;transform:translate(0);transition:opacity .25s,transform .5s cubic-bezier(.19,1,.22,1)}.dark .VPSidebar[data-v-42c4c606]{box-shadow:var(--vp-shadow-1)}@media (min-width: 960px){.VPSidebar[data-v-42c4c606]{padding-top:var(--vp-nav-height);width:var(--vp-sidebar-width);max-width:100%;background-color:var(--vp-sidebar-bg-color);opacity:1;visibility:visible;box-shadow:none;transform:translate(0)}}@media (min-width: 1440px){.VPSidebar[data-v-42c4c606]{padding-left:max(32px,calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));width:calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px)}}@media (min-width: 960px){.curtain[data-v-42c4c606]{position:sticky;top:-64px;left:0;z-index:1;margin-top:calc(var(--vp-nav-height) * -1);margin-right:-32px;margin-left:-32px;height:var(--vp-nav-height);background-color:var(--vp-sidebar-bg-color)}}.nav[data-v-42c4c606]{outline:0}.VPSkipLink[data-v-c8291ffa]{top:8px;left:8px;padding:8px 16px;z-index:999;border-radius:8px;font-size:12px;font-weight:700;text-decoration:none;color:var(--vp-c-brand-1);box-shadow:var(--vp-shadow-3);background-color:var(--vp-c-bg)}.VPSkipLink[data-v-c8291ffa]:focus{height:auto;width:auto;clip:auto;clip-path:none}@media (min-width: 1280px){.VPSkipLink[data-v-c8291ffa]{top:14px;left:16px}}.Layout[data-v-d8b57b2d]{display:flex;flex-direction:column;min-height:100vh}.VPHomeSponsors[data-v-3dc26e1d]{border-top:1px solid var(--vp-c-gutter);padding-top:88px!important}.VPHomeSponsors[data-v-3dc26e1d]{margin:96px 0}@media (min-width: 768px){.VPHomeSponsors[data-v-3dc26e1d]{margin:128px 0}}.VPHomeSponsors[data-v-3dc26e1d]{padding:0 24px}@media (min-width: 768px){.VPHomeSponsors[data-v-3dc26e1d]{padding:0 48px}}@media (min-width: 960px){.VPHomeSponsors[data-v-3dc26e1d]{padding:0 64px}}.container[data-v-3dc26e1d]{margin:0 auto;max-width:1152px}.love[data-v-3dc26e1d]{margin:0 auto;width:fit-content;font-size:28px;color:var(--vp-c-text-3)}.icon[data-v-3dc26e1d]{display:inline-block}.message[data-v-3dc26e1d]{margin:0 auto;padding-top:10px;max-width:320px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.sponsors[data-v-3dc26e1d]{padding-top:32px}.action[data-v-3dc26e1d]{padding-top:40px;text-align:center}.VPTeamPage[data-v-a5329171]{margin:96px 0}@media (min-width: 768px){.VPTeamPage[data-v-a5329171]{margin:128px 0}}.VPHome .VPTeamPageTitle[data-v-a5329171-s]{border-top:1px solid var(--vp-c-gutter);padding-top:88px!important}.VPTeamPageSection+.VPTeamPageSection[data-v-a5329171-s],.VPTeamMembers+.VPTeamPageSection[data-v-a5329171-s]{margin-top:64px}.VPTeamMembers+.VPTeamMembers[data-v-a5329171-s]{margin-top:24px}@media (min-width: 768px){.VPTeamPageTitle+.VPTeamPageSection[data-v-a5329171-s]{margin-top:16px}.VPTeamPageSection+.VPTeamPageSection[data-v-a5329171-s],.VPTeamMembers+.VPTeamPageSection[data-v-a5329171-s]{margin-top:96px}}.VPTeamMembers[data-v-a5329171-s]{padding:0 24px}@media (min-width: 768px){.VPTeamMembers[data-v-a5329171-s]{padding:0 48px}}@media (min-width: 960px){.VPTeamMembers[data-v-a5329171-s]{padding:0 64px}}.VPTeamPageTitle[data-v-46c5e327]{padding:48px 32px;text-align:center}@media (min-width: 768px){.VPTeamPageTitle[data-v-46c5e327]{padding:64px 48px 48px}}@media (min-width: 960px){.VPTeamPageTitle[data-v-46c5e327]{padding:80px 64px 48px}}.title[data-v-46c5e327]{letter-spacing:0;line-height:44px;font-size:36px;font-weight:500}@media (min-width: 768px){.title[data-v-46c5e327]{letter-spacing:-.5px;line-height:56px;font-size:48px}}.lead[data-v-46c5e327]{margin:0 auto;max-width:512px;padding-top:12px;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}@media (min-width: 768px){.lead[data-v-46c5e327]{max-width:592px;letter-spacing:.15px;line-height:28px;font-size:20px}}.VPTeamPageSection[data-v-3bf2e850]{padding:0 32px}@media (min-width: 768px){.VPTeamPageSection[data-v-3bf2e850]{padding:0 48px}}@media (min-width: 960px){.VPTeamPageSection[data-v-3bf2e850]{padding:0 64px}}.title[data-v-3bf2e850]{position:relative;margin:0 auto;max-width:1152px;text-align:center;color:var(--vp-c-text-2)}.title-line[data-v-3bf2e850]{position:absolute;top:16px;left:0;width:100%;height:1px;background-color:var(--vp-c-divider)}.title-text[data-v-3bf2e850]{position:relative;display:inline-block;padding:0 24px;letter-spacing:0;line-height:32px;font-size:20px;font-weight:500;background-color:var(--vp-c-bg)}.lead[data-v-3bf2e850]{margin:0 auto;max-width:480px;padding-top:12px;text-align:center;line-height:24px;font-size:16px;font-weight:500;color:var(--vp-c-text-2)}.members[data-v-3bf2e850]{padding-top:40px}.VPTeamMembersItem[data-v-acff304e]{display:flex;flex-direction:column;gap:2px;border-radius:12px;width:100%;height:100%;overflow:hidden}.VPTeamMembersItem.small .profile[data-v-acff304e]{padding:32px}.VPTeamMembersItem.small .data[data-v-acff304e]{padding-top:20px}.VPTeamMembersItem.small .avatar[data-v-acff304e]{width:64px;height:64px}.VPTeamMembersItem.small .name[data-v-acff304e]{line-height:24px;font-size:16px}.VPTeamMembersItem.small .affiliation[data-v-acff304e]{padding-top:4px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .desc[data-v-acff304e]{padding-top:12px;line-height:20px;font-size:14px}.VPTeamMembersItem.small .links[data-v-acff304e]{margin:0 -16px -20px;padding:10px 0 0}.VPTeamMembersItem.medium .profile[data-v-acff304e]{padding:48px 32px}.VPTeamMembersItem.medium .data[data-v-acff304e]{padding-top:24px;text-align:center}.VPTeamMembersItem.medium .avatar[data-v-acff304e]{width:96px;height:96px}.VPTeamMembersItem.medium .name[data-v-acff304e]{letter-spacing:.15px;line-height:28px;font-size:20px}.VPTeamMembersItem.medium .affiliation[data-v-acff304e]{padding-top:4px;font-size:16px}.VPTeamMembersItem.medium .desc[data-v-acff304e]{padding-top:16px;max-width:288px;font-size:16px}.VPTeamMembersItem.medium .links[data-v-acff304e]{margin:0 -16px -12px;padding:16px 12px 0}.profile[data-v-acff304e]{flex-grow:1;background-color:var(--vp-c-bg-soft)}.data[data-v-acff304e]{text-align:center}.avatar[data-v-acff304e]{position:relative;flex-shrink:0;margin:0 auto;border-radius:50%;box-shadow:var(--vp-shadow-3)}.avatar-img[data-v-acff304e]{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;object-fit:cover}.name[data-v-acff304e]{margin:0;font-weight:600}.affiliation[data-v-acff304e]{margin:0;font-weight:500;color:var(--vp-c-text-2)}.org.link[data-v-acff304e]{color:var(--vp-c-text-2);transition:color .25s}.org.link[data-v-acff304e]:hover{color:var(--vp-c-brand-1)}.desc[data-v-acff304e]{margin:0 auto}.desc[data-v-acff304e] a{font-weight:500;color:var(--vp-c-brand-1);text-decoration-style:dotted;transition:color .25s}.links[data-v-acff304e]{display:flex;justify-content:center;height:56px}.sp-link[data-v-acff304e]{display:flex;justify-content:center;align-items:center;text-align:center;padding:16px;font-size:14px;font-weight:500;color:var(--vp-c-sponsor);background-color:var(--vp-c-bg-soft);transition:color .25s,background-color .25s}.sp .sp-link.link[data-v-acff304e]:hover,.sp .sp-link.link[data-v-acff304e]:focus{outline:none;color:var(--vp-c-white);background-color:var(--vp-c-sponsor)}.sp-icon[data-v-acff304e]{margin-right:8px;font-size:16px}.VPTeamMembers.small .container[data-v-bf782009]{grid-template-columns:repeat(auto-fit,minmax(224px,1fr))}.VPTeamMembers.small.count-1 .container[data-v-bf782009]{max-width:276px}.VPTeamMembers.small.count-2 .container[data-v-bf782009]{max-width:576px}.VPTeamMembers.small.count-3 .container[data-v-bf782009]{max-width:876px}.VPTeamMembers.medium .container[data-v-bf782009]{grid-template-columns:repeat(auto-fit,minmax(256px,1fr))}@media (min-width: 375px){.VPTeamMembers.medium .container[data-v-bf782009]{grid-template-columns:repeat(auto-fit,minmax(288px,1fr))}}.VPTeamMembers.medium.count-1 .container[data-v-bf782009]{max-width:368px}.VPTeamMembers.medium.count-2 .container[data-v-bf782009]{max-width:760px}.container[data-v-bf782009]{display:grid;gap:24px;margin:0 auto;max-width:1152px}:root{--vp-c-white: #ffffff;--vp-c-black: #000000;--vp-c-gray: #8e8e93;--vp-c-text-light-1: #1f2328;--vp-c-text-light-2: #454545;--vp-c-text-light-3: #959595;--vp-c-text-dark-1: rgba(255, 255, 245, .86);--vp-c-text-dark-2: rgba(235, 235, 245, .6);--vp-c-text-dark-3: rgba(235, 235, 245, .38);--vp-c-orange: #5c37f4;--vp-c-orange-soft: rgba(227, 96, 2, .1);--vp-c-orange-light: #371dff;--vp-c-orange-lighter: #2445ff;--vp-c-orange-dark: #0022e0;--vp-c-orange-darker: #223dd6;--vp-c-badge-green-light: #308b58;--vp-c-badge-green-light-bg: #bff8d7;--vp-c-badge-green-dark: #1fd85d;--vp-c-badge-green-dark-bg: #308b5769}:root{--vp-c-bg: #ffffff;--vp-c-bg-elv: #ffffff;--vp-c-bg-elv-up: #ffffff;--vp-c-bg-elv-down: #f6f6f7;--vp-c-bg-elv-mute: #f6f6f7;--vp-c-bg-soft: #f6f6f7;--vp-c-bg-soft-up: #ffffff;--vp-c-bg-soft-down: #e3e3e5;--vp-c-bg-soft-mute: #e3e3e5;--vp-c-bg-alt: #f6f6f7;--vp-c-border: rgba(60, 60, 67, .29);--vp-c-divider: rgba(60, 60, 67, .12);--vp-c-gutter: rgba(60, 60, 67, .12);--vp-c-neutral: var(--vp-c-black);--vp-c-neutral-inverse: var(--vp-c-white);--vp-c-text-1: var(--vp-c-text-light-1);--vp-c-text-2: var(--vp-c-text-light-2);--vp-c-text-3: var(--vp-c-text-light-3);--vp-c-text-inverse-1: var(--vp-c-text-dark-1);--vp-c-text-inverse-2: var(--vp-c-text-dark-2);--vp-c-text-inverse-3: var(--vp-c-text-dark-3);--vp-c-text-code: #4a4a4a;--vp-c-brand: var(--vp-c-orange);--vp-c-brand-light: var(--vp-c-orange-light);--vp-c-brand-lighter: var(--vp-c-orange-lighter);--vp-c-brand-dark: var(--vp-c-orange-dark);--vp-c-brand-darker: var(--vp-c-orange-darker);--vp-c-mute: #f6f6f7;--vp-c-mute-light: #f9f9fc;--vp-c-mute-lighter: #ffffff;--vp-c-mute-dark: #e3e3e5;--vp-c-mute-darker: #d7d7d9;--vp-c-bg-alt: #ffffff;--vp-sidebar-bg-color: var(--vp-c-bg-alt);--vp-code-copy-code-bg: var(--vp-code-block-bg);--vp-code-copy-code-hover-bg: var(--vp-code-block-bg);--vp-badge-info-text: var(--vp-c-badge-green-light);--vp-badge-info-bg: var(--vp-c-badge-green-light-bg)}:root{--vp-font-family-base: -apple-system,BlinkMacSystemFont,segoe ui,Helvetica,Arial,sans-serif,apple color emoji,segoe ui emoji;--vp-font-family-mono: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace}:root{--vp-c-brand-1: var(--vp-c-orange);--vp-c-brand-2: var(--vp-c-orange-light);--vp-c-brand-3: var(--vp-c-orange-lighter);--vp-c-brand-soft: var(--vp-c-orange-soft);--vp-code-color: var(--vp-c-text-light-2)}:root{--vp-code-block-color: var(--vp-c-text-1);--vp-code-block-bg: rgb(246, 248, 250);--vp-code-tab-divider: var(--vp-c-text-light-3);--vp-code-tab-text-color: var(--vp-c-text-light-2);--vp-code-tab-bg: var(--vp-code-block-bg);--vp-code-tab-hover-text-color: var(--vp-c-text-light-1);--vp-code-tab-active-text-color: var(--vp-c-text-light-1);--vp-code-tab-active-bar-color: var(--vp-c-brand);--vp-code-line-highlight-color: rgba(0, 0, 0, .1)}.dark{--vp-c-bg: #1e1e20;--vp-c-bg-elv: #252529;--vp-c-bg-elv-up: #313136;--vp-c-bg-elv-down: #1e1e20;--vp-c-bg-elv-mute: #313136;--vp-c-bg-soft: #252529;--vp-c-bg-soft-up: #313136;--vp-c-bg-soft-down: #1e1e20;--vp-c-bg-soft-mute: #313136;--vp-c-bg-alt: #161618;--vp-c-border: rgba(82, 82, 89, .68);--vp-c-divider: rgba(82, 82, 89, .32);--vp-c-gutter: #000000;--vp-c-neutral: var(--vp-c-white);--vp-c-neutral-inverse: var(--vp-c-black);--vp-c-text-1: var(--vp-c-text-dark-1);--vp-c-text-2: var(--vp-c-text-dark-2);--vp-c-text-3: var(--vp-c-text-dark-3);--vp-c-text-inverse-1: var(--vp-c-text-light-1);--vp-c-text-inverse-2: var(--vp-c-text-light-2);--vp-c-text-inverse-3: var(--vp-c-text-light-3);--vp-c-mute: #313136;--vp-c-mute-light: #3a3a3c;--vp-c-mute-lighter: #505053;--vp-c-mute-dark: #2c2c30;--vp-c-mute-darker: #252529;--vp-code-block-bg: #2a2a2a;--vp-code-tab-hover-text-color: var(--vp-c-text-dark-2);--vp-code-tab-active-text-color: var(--vp-c-text-dark-1);--vp-c-text-code: #e8e8e8;--vp-code-color: var(--vp-c-text-dark-1);--vp-code-tab-text-color: var(--vp-c-text-dark-2);--vp-badge-info-text: var(--vp-c-badge-green-dark);--vp-badge-info-bg: var(--vp-c-badge-green-dark-bg)}.vp-doc h1,.vp-doc h2,.vp-doc h3,.vp-doc h4,.vp-doc h5,.vp-doc h6{font-weight:700}.title{font-weight:700!important}.tagline{max-width:500px!important}.DocSearch-Button{background-color:var(--vp-c-bg-soft)}body{-webkit-font-smoothing:subpixel-antialiased}.VPImage.image-src{max-width:640px}@media screen and (max-width: 960px){.VPHero.has-image .image:not(:has(.kawaii)){display:none}}.vp-code-block-title [data-title]:before,.vp-code-group [data-title]:before{display:inline-block;width:1em;height:1em;margin-right:.5em;margin-bottom:-.2em;background:var(--icon) no-repeat center / contain}.vp-code-block-title-bar{position:relative;margin:16px -24px 0;background-color:var(--vp-code-block-bg);overflow-x:auto;font-size:14px;font-weight:500;color:var(--vp-code-tab-text-color);white-space:nowrap;transition:background-color .5s;border-radius:8px 8px 0 0;padding:0 12px;box-shadow:inset 0 -1px var(--vp-code-tab-divider)}.custom-block .vp-code-block-title-bar{margin:16px 0 0}@media (min-width: 640px){.vp-code-block-title-bar{margin:16px 0 0}}.vp-code-block-title-text{padding:0 12px;line-height:48px}.vp-code-block-title div[class*=language-]{margin-top:0!important;border-top-left-radius:0!important;border-top-right-radius:0!important}.resize-observer[data-v-b329ee4c]{position:absolute;top:0;left:0;z-index:-1;width:100%;height:100%;border:none;background-color:transparent;pointer-events:none;display:block;overflow:hidden;opacity:0}.resize-observer[data-v-b329ee4c] object{display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1}.v-popper__popper{z-index:10000;top:0;left:0;outline:none}.v-popper__popper.v-popper__popper--hidden{visibility:hidden;opacity:0;transition:opacity .15s,visibility .15s;pointer-events:none}.v-popper__popper.v-popper__popper--shown{visibility:visible;opacity:1;transition:opacity .15s}.v-popper__popper.v-popper__popper--skip-transition,.v-popper__popper.v-popper__popper--skip-transition>.v-popper__wrapper{transition:none!important}.v-popper__backdrop{position:absolute;top:0;left:0;width:100%;height:100%;display:none}.v-popper__inner{position:relative;box-sizing:border-box;overflow-y:auto}.v-popper__inner>div{position:relative;z-index:1;max-width:inherit;max-height:inherit}.v-popper__arrow-container{position:absolute;width:10px;height:10px}.v-popper__popper--arrow-overflow .v-popper__arrow-container,.v-popper__popper--no-positioning .v-popper__arrow-container{display:none}.v-popper__arrow-inner,.v-popper__arrow-outer{border-style:solid;position:absolute;top:0;left:0;width:0;height:0}.v-popper__arrow-inner{visibility:hidden;border-width:7px}.v-popper__arrow-outer{border-width:6px}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-inner{left:-2px}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-outer,.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-outer{left:-1px}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-outer{border-bottom-width:0;border-left-color:transparent!important;border-right-color:transparent!important;border-bottom-color:transparent!important}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-inner{top:-2px}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-container{top:0}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-outer{border-top-width:0;border-left-color:transparent!important;border-right-color:transparent!important;border-top-color:transparent!important}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-inner{top:-4px}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-outer{top:-6px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-inner{top:-2px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-outer,.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-outer{top:-1px}.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-outer{border-left-width:0;border-left-color:transparent!important;border-top-color:transparent!important;border-bottom-color:transparent!important}.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-inner{left:-4px}.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-outer{left:-6px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-container{right:-10px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-outer{border-right-width:0;border-top-color:transparent!important;border-right-color:transparent!important;border-bottom-color:transparent!important}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-inner{left:-2px}.v-popper--theme-tooltip .v-popper__inner{background:#000c;color:#fff;border-radius:6px;padding:7px 12px 6px}.v-popper--theme-tooltip .v-popper__arrow-outer{border-color:#000c}.v-popper--theme-dropdown .v-popper__inner{background:#fff;color:#000;border-radius:6px;border:1px solid #ddd;box-shadow:0 6px 30px #0000001a}.v-popper--theme-dropdown .v-popper__arrow-inner{visibility:visible;border-color:#fff}.v-popper--theme-dropdown .v-popper__arrow-outer{border-color:#ddd}:root{--twoslash-border-color: #8888;--twoslash-underline-color: currentColor;--twoslash-highlighted-border: #c37d0d50;--twoslash-highlighted-bg: #c37d0d20;--twoslash-popup-bg: #f8f8f8;--twoslash-popup-color: inherit;--twoslash-popup-shadow: rgba(0, 0, 0, .08) 0px 1px 4px;--twoslash-docs-color: #888;--twoslash-docs-font: sans-serif;--twoslash-code-font: inherit;--twoslash-code-font-size: 1em;--twoslash-matched-color: inherit;--twoslash-unmatched-color: #888;--twoslash-cursor-color: #8888;--twoslash-error-color: #d45656;--twoslash-error-bg: #d4565620;--twoslash-warn-color: #c37d0d;--twoslash-warn-bg: #c37d0d20;--twoslash-tag-color: #3772cf;--twoslash-tag-bg: #3772cf20;--twoslash-tag-warn-color: var(--twoslash-warn-color);--twoslash-tag-warn-bg: var(--twoslash-warn-bg);--twoslash-tag-annotate-color: #1ba673;--twoslash-tag-annotate-bg: #1ba67320}@media (prefers-reduced-motion: reduce){.twoslash *{transition:none!important}}.twoslash:hover .twoslash-hover{border-color:var(--twoslash-underline-color)}.twoslash .twoslash-hover{border-bottom:1px dotted transparent;transition-timing-function:ease;transition:border-color .3s;position:relative}.twoslash .twoslash-popup-container{position:absolute;opacity:0;display:inline-flex;flex-direction:column;transform:translateY(1.1em);background:var(--twoslash-popup-bg);color:var(--twoslash-popup-color);border:1px solid var(--twoslash-border-color);transition:opacity .3s;border-radius:4px;pointer-events:none;z-index:10;-webkit-user-select:none;user-select:none;text-align:left;box-shadow:var(--twoslash-popup-shadow)}.twoslash .twoslash-query-presisted .twoslash-popup-container{z-index:9;transform:translateY(1.5em)}.twoslash .twoslash-hover:hover .twoslash-popup-container,.twoslash .twoslash-error-hover:hover .twoslash-popup-container,.twoslash .twoslash-query-presisted .twoslash-popup-container,.twoslash .twoslash-query-line .twoslash-popup-container{opacity:1;pointer-events:auto}.twoslash .twoslash-popup-container:hover{-webkit-user-select:auto;user-select:auto}.twoslash .twoslash-popup-arrow{position:absolute;top:-4px;left:1em;border-top:1px solid var(--twoslash-border-color);border-right:1px solid var(--twoslash-border-color);background:var(--twoslash-popup-bg);transform:rotate(-45deg);width:6px;height:6px;pointer-events:none}.twoslash .twoslash-popup-code,.twoslash .twoslash-popup-error,.twoslash .twoslash-popup-docs{padding:6px 8px!important}.twoslash .twoslash-popup-code{font-family:var(--twoslash-code-font);font-size:var(--twoslash-code-font-size)}.twoslash .twoslash-popup-docs{color:var(--twoslash-docs-color);font-family:var(--twoslash-docs-font);font-size:.8em;border-top:1px solid var(--twoslash-border-color)}.twoslash .twoslash-popup-error{color:var(--twoslash-error-color);background-color:var(--twoslash-error-bg);font-family:var(--twoslash-docs-font);font-size:.8em}.twoslash .twoslash-popup-docs-tags{display:flex;flex-direction:column;font-family:var(--twoslash-docs-font)}.twoslash .twoslash-popup-docs-tags,.twoslash .twoslash-popup-docs-tag-name{margin-right:.5em}.twoslash .twoslash-popup-docs-tag-name{font-family:var(--twoslash-code-font)}.twoslash .twoslash-query-line .twoslash-popup-container{position:relative;margin-bottom:1.4em;transform:translateY(.6em)}.twoslash .twoslash-error-line{position:relative;background-color:var(--twoslash-error-bg);border-left:3px solid var(--twoslash-error-color);color:var(--twoslash-error-color);padding:6px 12px;margin:.2em 0;min-width:100%;width:max-content}.twoslash .twoslash-error-line.twoslash-error-level-warning{background-color:var(--twoslash-warn-bg);border-left:3px solid var(--twoslash-warn-color);color:var(--twoslash-warn-color)}.twoslash .twoslash-error{background:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left;padding-bottom:2px}.twoslash .twoslash-error.twoslash-error-level-warning{background:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c37d0d'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left;padding-bottom:2px}.twoslash .twoslash-completion-cursor{position:relative}.twoslash .twoslash-completion-cursor .twoslash-completion-list{-webkit-user-select:none;user-select:none;position:absolute;top:0;left:0;transform:translateY(1.2em);margin:3px 0 0 -1px;display:inline-block;z-index:8;box-shadow:var(--twoslash-popup-shadow);background:var(--twoslash-popup-bg);border:1px solid var(--twoslash-border-color)}.twoslash-completion-list{width:240px;font-size:.8rem;padding:4px;display:flex;flex-direction:column;gap:4px}.twoslash-completion-list:hover{-webkit-user-select:auto;user-select:auto}.twoslash-completion-list:before{background-color:var(--twoslash-cursor-color);width:2px;position:absolute;top:-1.6em;height:1.4em;left:-1px;content:" "}.twoslash-completion-list li{overflow:hidden;display:flex;align-items:center;gap:.25em;line-height:1em}.twoslash-completion-list li span.twoslash-completions-unmatched{color:var(--twoslash-unmatched-color)}.twoslash-completion-list .deprecated{text-decoration:line-through;opacity:.5}.twoslash-completion-list li span.twoslash-completions-matched{color:var(--twoslash-matched-color)}.twoslash-highlighted{background-color:var(--twoslash-highlighted-bg);border:1px solid var(--twoslash-highlighted-border);padding:1px 2px;margin:-1px -3px;border-radius:4px}.twoslash-completion-list .twoslash-completions-icon{color:var(--twoslash-unmatched-color);width:1em;flex:none}.twoslash .twoslash-tag-line{position:relative;background-color:var(--twoslash-tag-bg);border-left:3px solid var(--twoslash-tag-color);color:var(--twoslash-tag-color);padding:6px 10px;margin:.2em 0;display:flex;align-items:center;gap:.3em;min-width:100%;width:max-content}.twoslash .twoslash-tag-line .twoslash-tag-icon{width:1.1em;color:inherit}.twoslash .twoslash-tag-line.twoslash-tag-error-line{background-color:var(--twoslash-error-bg);border-left:3px solid var(--twoslash-error-color);color:var(--twoslash-error-color)}.twoslash .twoslash-tag-line.twoslash-tag-warn-line{background-color:var(--twoslash-tag-warn-bg);border-left:3px solid var(--twoslash-tag-warn-color);color:var(--twoslash-tag-warn-color)}.twoslash .twoslash-tag-line.twoslash-tag-annotate-line{background-color:var(--twoslash-tag-annotate-bg);border-left:3px solid var(--twoslash-tag-annotate-color);color:var(--twoslash-tag-annotate-color)}:root{--twoslash-popup-bg: var(--vp-c-bg, inherit);--twoslash-popup-color: var(--vp-c-text-1);--twoslash-docs-color: var(--vp-c-text-1);--twoslash-docs-font: var(--vp-font-family-base);--twoslash-code-font: var(--vp-font-family-mono);--twoslash-code-size: var(--vp-code-font-size);--twoslash-underline-color: #8888;--twoslash-border-color: var(--vp-c-border);--twoslash-cursor-color: var(--vp-c-brand);--twoslash-matched-color: var(--vp-c-brand);--twoslash-unmatched-color: var(--vp-c-text-2)}.v-popper--theme-twoslash{z-index:calc(var(--vp-z-index-local-nav) - 1)}.v-popper--theme-twoslash .v-popper__inner{background:var(--twoslash-popup-bg);color:var(--twoslash-popup-color);border-color:var(--twoslash-border-color)}.v-popper--theme-twoslash .v-popper__arrow-outer{border-color:var(--twoslash-border-color)}.v-popper--theme-twoslash .v-popper__arrow-inner{border-color:var(--twoslash-popup-bg)}.twoslash-popup-container{transform:translateY(1.5em)}.twoslash-query-presisted .twoslash-popup-container{transform:translateY(1.8em)}.twoslash .v-popper{display:inline-block}.twoslash-completion-list .twoslash-completions-icon{color:var(--twoslash-unmatched-color)!important}.twoslash-floating .twoslash-popup-code{max-width:600px;display:block;width:fit-content;min-width:100%;padding:6px 12px;line-height:var(--vp-code-line-height);font-size:var(--twoslash-code-size);transition:color .5s;white-space:pre-wrap}.twoslash-floating .twoslash-popup-docs,.twoslash-floating .twoslash-popup-error{padding:12px!important;font-family:var(--twoslash-docs-font);font-size:.9em;max-height:500px;max-width:700px;overflow-y:auto;overflow-x:hidden;text-wrap:balance}.twoslash-floating .twoslash-popup-docs p:first-child,.twoslash-floating .twoslash-popup-error p:first-child{margin-top:0}.twoslash-floating .twoslash-popup-docs p:last-child,.twoslash-floating .twoslash-popup-error p:last-child{margin-bottom:0}.twoslash-floating .twoslash-popup-docs{border-top:1px solid var(--twoslash-border-color);color:var(--twoslash-docs-color)}.twoslash-floating .twoslash-popup-error{color:var(--twoslash-error-color)}.twoslash-floating .twoslash-popup-error.twoslash-error-level-warning{color:var(--twoslash-warn-color)}.twoslash-floating .twoslash-popup-docs p,.twoslash-floating .twoslash-popup-error p{margin:6px 0;text-wrap:balance}.twoslash-floating .twoslash-popup-docs pre .twoslash-floating .twoslash-popup-error pre{background-color:var(--vp-code-block-bg);border-radius:8px;padding:12px;margin:6px -2px;overflow-x:auto}.twoslash-floating .twoslash-popup-docs-tags{display:flex;flex-direction:column;padding:8px 12px!important}.twoslash-floating .twoslash-popup-docs-tags .twoslash-popup-docs-tag-name{font-family:var(--twoslash-code-font);color:var(--twoslash-unmatched-color);margin-right:.5em}.twoslash-completion-cursor{height:1.2em;width:2px;margin-bottom:-.2em;background:var(--twoslash-cursor-color);display:inline-block;-webkit-user-select:none;user-select:none}.twoslash-floating.twoslash-completion .v-popper__arrow-container{display:none}.twoslash-floating.twoslash-completion .twoslash-completion-list{padding:6px;font-family:var(--twoslash-code-font);font-size:var(--twoslash-code-size)!important}.twoslash-floating.twoslash-completion .twoslash-completion-list li{padding:3px 0} diff --git a/docs/css/syntax.css b/docs/css/syntax.css new file mode 100644 index 0000000..8a64a3b --- /dev/null +++ b/docs/css/syntax.css @@ -0,0 +1,85 @@ +/* Background */ .bg { background-color: #f0f3f3; } +/* PreWrapper */ .chroma { background-color: #f0f3f3; } +/* Other */ .chroma .x { } +/* Error */ .chroma .err { color: #aa0000; background-color: #ffaaaa } +/* CodeLine */ .chroma .cl { } +/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } +/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; } +/* LineHighlight */ .chroma .hl { background-color: #ffffcc } +/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* Line */ .chroma .line { display: flex; } +/* Keyword */ .chroma .k { color: #006699; font-weight: bold } +/* KeywordConstant */ .chroma .kc { color: #006699; font-weight: bold } +/* KeywordDeclaration */ .chroma .kd { color: #006699; font-weight: bold } +/* KeywordNamespace */ .chroma .kn { color: #006699; font-weight: bold } +/* KeywordPseudo */ .chroma .kp { color: #006699 } +/* KeywordReserved */ .chroma .kr { color: #006699; font-weight: bold } +/* KeywordType */ .chroma .kt { color: #007788; font-weight: bold } +/* Name */ .chroma .n { } +/* NameAttribute */ .chroma .na { color: #330099 } +/* NameBuiltin */ .chroma .nb { color: #336666 } +/* NameBuiltinPseudo */ .chroma .bp { } +/* NameClass */ .chroma .nc { color: #00aa88; font-weight: bold } +/* NameConstant */ .chroma .no { color: #336600 } +/* NameDecorator */ .chroma .nd { color: #9999ff } +/* NameEntity */ .chroma .ni { color: #999999; font-weight: bold } +/* NameException */ .chroma .ne { color: #cc0000; font-weight: bold } +/* NameFunction */ .chroma .nf { color: #cc00ff } +/* NameFunctionMagic */ .chroma .fm { } +/* NameLabel */ .chroma .nl { color: #9999ff } +/* NameNamespace */ .chroma .nn { color: #00ccff; font-weight: bold } +/* NameOther */ .chroma .nx { } +/* NameProperty */ .chroma .py { } +/* NameTag */ .chroma .nt { color: #330099; font-weight: bold } +/* NameVariable */ .chroma .nv { color: #003333 } +/* NameVariableClass */ .chroma .vc { } +/* NameVariableGlobal */ .chroma .vg { } +/* NameVariableInstance */ .chroma .vi { } +/* NameVariableMagic */ .chroma .vm { } +/* Literal */ .chroma .l { } +/* LiteralDate */ .chroma .ld { } +/* LiteralString */ .chroma .s { color: #cc3300 } +/* LiteralStringAffix */ .chroma .sa { color: #cc3300 } +/* LiteralStringBacktick */ .chroma .sb { color: #cc3300 } +/* LiteralStringChar */ .chroma .sc { color: #cc3300 } +/* LiteralStringDelimiter */ .chroma .dl { color: #cc3300 } +/* LiteralStringDoc */ .chroma .sd { color: #cc3300; font-style: italic } +/* LiteralStringDouble */ .chroma .s2 { color: #cc3300 } +/* LiteralStringEscape */ .chroma .se { color: #cc3300; font-weight: bold } +/* LiteralStringHeredoc */ .chroma .sh { color: #cc3300 } +/* LiteralStringInterpol */ .chroma .si { color: #aa0000 } +/* LiteralStringOther */ .chroma .sx { color: #cc3300 } +/* LiteralStringRegex */ .chroma .sr { color: #33aaaa } +/* LiteralStringSingle */ .chroma .s1 { color: #cc3300 } +/* LiteralStringSymbol */ .chroma .ss { color: #ffcc33 } +/* LiteralNumber */ .chroma .m { color: #ff6600 } +/* LiteralNumberBin */ .chroma .mb { color: #ff6600 } +/* LiteralNumberFloat */ .chroma .mf { color: #ff6600 } +/* LiteralNumberHex */ .chroma .mh { color: #ff6600 } +/* LiteralNumberInteger */ .chroma .mi { color: #ff6600 } +/* LiteralNumberIntegerLong */ .chroma .il { color: #ff6600 } +/* LiteralNumberOct */ .chroma .mo { color: #ff6600 } +/* Operator */ .chroma .o { color: #555555 } +/* OperatorWord */ .chroma .ow { color: #000000; font-weight: bold } +/* Punctuation */ .chroma .p { } +/* Comment */ .chroma .c { color: #0099ff; font-style: italic } +/* CommentHashbang */ .chroma .ch { color: #0099ff; font-style: italic } +/* CommentMultiline */ .chroma .cm { color: #0099ff; font-style: italic } +/* CommentSingle */ .chroma .c1 { color: #0099ff; font-style: italic } +/* CommentSpecial */ .chroma .cs { color: #0099ff; font-weight: bold; font-style: italic } +/* CommentPreproc */ .chroma .cp { color: #009999 } +/* CommentPreprocFile */ .chroma .cpf { color: #009999 } +/* Generic */ .chroma .g { } +/* GenericDeleted */ .chroma .gd { background-color: #ffcccc } +/* GenericEmph */ .chroma .ge { font-style: italic } +/* GenericError */ .chroma .gr { color: #ff0000 } +/* GenericHeading */ .chroma .gh { color: #003300; font-weight: bold } +/* GenericInserted */ .chroma .gi { background-color: #ccffcc } +/* GenericOutput */ .chroma .go { color: #aaaaaa } +/* GenericPrompt */ .chroma .gp { color: #000099; font-weight: bold } +/* GenericStrong */ .chroma .gs { font-weight: bold } +/* GenericSubheading */ .chroma .gu { color: #003300; font-weight: bold } +/* GenericTraceback */ .chroma .gt { color: #99cc66 } +/* GenericUnderline */ .chroma .gl { text-decoration: underline } +/* TextWhitespace */ .chroma .w { color: #bbbbbb } diff --git a/docs/docs/appendix/contact-information.html b/docs/docs/appendix/contact-information.html new file mode 100644 index 0000000..1b9fe58 --- /dev/null +++ b/docs/docs/appendix/contact-information.html @@ -0,0 +1,31 @@ + + + + + +{description}
-{siteConfig.tagline}
- {/* -