From 628e4b1860347f33fee09a9eb6dabbbb74eb50b3 Mon Sep 17 00:00:00 2001 From: DongShull Date: Fri, 30 Oct 2026 04:32:09 +0800 Subject: [PATCH 01/10] =?UTF-8?q?fea:=20P0=20=E5=9F=BA=E7=BA=BF=E6=95=B4?= =?UTF-8?q?=E5=A4=87=E2=80=94=E2=80=94=E8=87=AA=E6=9B=B4=E6=96=B0=E4=BB=93?= =?UTF-8?q?=E5=BA=93=E5=8F=AF=E9=85=8D=E7=BD=AE(UPDATE=5FREPO)=E3=80=81CI?= =?UTF-8?q?=20=E6=B5=81=E6=B0=B4=E7=BA=BF=E3=80=81=E6=94=B9=E9=80=A0?= =?UTF-8?q?=E8=A7=84=E5=88=92=E5=85=A5=E4=BB=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 40 ++++++++++++++++++ docs/ROADMAP.md | 64 +++++++++++++++++++++++++++++ internal/utiles/getRemoteVersion.go | 2 +- internal/utiles/updateprogram.go | 4 +- internal/utiles/updaterepo.go | 25 +++++++++++ 5 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 docs/ROADMAP.md create mode 100644 internal/utiles/updaterepo.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..80093636 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: + - latest + - dev + pull_request: + branches: + - latest + - dev + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Prepare front placeholder + run: | + mkdir -p front + cat > front/index.html <<'EOF' + dockerCopilot

CI placeholder

+ EOF + + - name: Build + run: go build ./... + + - name: Vet + run: go vet ./... + + - name: Test + run: go test ./... -count=1 diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 00000000..66c3f0e9 --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,64 @@ +# dockerCopilot 改造规划(ROADMAP) + +> 本项目自 v2.2.0 起由 DongShull 独立维护(fork 自 onlyLTY/dockerCopilot v2.1.3,上游已停止更新)。 +> 本文件记录 v2.1.3 基线体检结论与改造路线。 + +## 一、基线缺陷清单(v2.1.3) + +### P0 · 崩溃/数据级 +1. `containerslistlogic.go`:inspect 失败后仍解引用 nil,容器列表接口可被打崩 +2. `updatecontainer.go`:更新失败(create/start)时旧容器停留在改名+停止状态,无回滚 +3. `updatecontainer.go`:更新成功后不清理旧镜像,磁盘慢性泄漏 + +### P1 · 功能错误 +4. 旧容器改名使用秒级时间戳,同秒二次更新必撞名 +5. `checkupdate.go`:digest 比对循环覆盖,"最后一个说了算",多 RepoDigest 时误报/漏报 +6. `image.go`:`strings.Split(":")[1]` 解析 tag,带端口的私有仓库镜像名/tag 错位 +7. 停止容器使用 SIGINT,业界惯例 SIGTERM +8. `getRemoteVersion.go`/`updateprogram.go` 硬编码上游 onlyLTY URL(已改可配置 UPDATE_REPO) +9. `decompressTarGz`:tar 条目名不校验,存在 zip-slip 路径穿越 +10. `module.ImageUpdateData`:cron 写、HTTP 读共用 map,无锁数据竞争 + +### P2 · 卫生级 +11. ProgressStore 只写不删(内存泄漏),重启丢进度,无任务取消 +12. `checkImageInUsed` O(容器×镜像) 双重循环 +13. restore 中永假的死代码分支 +14. JWT 84 天有效、secretKey 兼作签名密钥(记录在案,暂无计划改动) +15. `Timeout: 1e14`、CORS `*`、`InsecureSkipVerify`(已加 REGISTRY_INSECURE 开关) + +## 二、分期计划 + +| 期 | 内容 | 状态 | +|---|---|---| +| P0 | 基线整备:URL 可配置、CI(build/vet/test)、本规划入仓 | ✅ v2.2.0 | +| P1 | 修复批:缺陷 1/4/5/6/7/9/10/12/13 | ✅ v2.2.0 | +| P2 | 更新链重构:旧镜像清理、失败回滚、digest 并发检测、compose 标签感知 | ✅ v2.2.0 | +| P3 | 任务系统:进度落盘、TTL 清理、任务列表/取消 API、SSE 推送 | ✅ v2.2.0 | +| P4 | FnOS 适配:去 privileged 要求、HEALTHCHECK、备份目录运行时可配(Settings API) | ✅ v2.2.0 | +| P5 | 增强:webhook 通知、审计日志、定时自动更新白名单 | ✅ v2.2.0 | + +## 三、配置项一览(环境变量) + +| 变量 | 默认 | 说明 | +|---|---|---| +| `secretKey` | (必填) | 登录密钥,同时用于 JWT 签名,不少于 8 位且非纯数字 | +| `DOCKER_HOST` | unix:///var/run/docker.sock | Docker 守护进程地址 | +| `BACKUP_DIR` | /data/backups | 容器备份目录(优先级:env > Settings API 配置 > 默认) | +| `DelOldContainer` | true | 更新成功后是否删除旧容器("false" 保留) | +| `CLEANUP_OLD_IMAGE` | true | 更新成功后是否清理不再被引用的旧镜像 | +| `UPDATE_REPO` | DongShull/dockerCopilot | 版本检查与自更新仓库 | +| `UPDATE_BRANCH` | latest | 版本检查分支 | +| `githubProxy` | 空 | GitHub 代理前缀 | +| `REGISTRY_INSECURE` | true | registry 检测是否跳过 TLS 校验("false" 严格校验) | +| `NOTIFY_WEBHOOK_URL` | 空 | 任务完成通知 webhook(POST JSON) | +| `AUTOUPDATE_CRON` | 空 | 自动更新周期(cron 表达式,空=关闭) | +| `AUTOUPDATE_WHITELIST` | 空 | 自动更新容器白名单(逗号分隔,`*`=全部有更新的容器) | + +## 四、验收标准(v2.2.0) + +- `go build ./...` / `go vet ./...` / `go test ./...` 全绿 +- 更新一个容器后 `docker images` 不新增悬空镜像 +- 模拟更新失败(拉取超时)后旧容器自动回到原名并恢复运行 +- 重启进程后任务历史仍可查询;进行中任务可取消 +- 50 个镜像的更新检测从串行分钟级进入 10 秒级 +- 非 privileged 容器(仅挂载 docker.sock + 数据卷)可跑通全部功能 diff --git a/internal/utiles/getRemoteVersion.go b/internal/utiles/getRemoteVersion.go index e7413ef6..4b458bcf 100644 --- a/internal/utiles/getRemoteVersion.go +++ b/internal/utiles/getRemoteVersion.go @@ -15,7 +15,7 @@ func GetRemoteVersion() (remoteVersion string, err error) { if githubProxy != "" { githubProxy = strings.TrimRight(githubProxy, "/") + "/" } - versionURL := githubProxy + "https://raw.githubusercontent.com/onlyLTY/dockerCopilot/UGREEN/version" + versionURL := githubProxy + "https://raw.githubusercontent.com/" + UpdateRepo() + "/" + UpdateBranch() + "/version" remoteVersion, err = fetchVersionFromURL(versionURL) if err != nil { return "0.0.0", err diff --git a/internal/utiles/updateprogram.go b/internal/utiles/updateprogram.go index 81f633d6..65157187 100644 --- a/internal/utiles/updateprogram.go +++ b/internal/utiles/updateprogram.go @@ -18,8 +18,8 @@ func UpdateProgram(ctx *svc.ServiceContext) error { if githubProxy != "" { githubProxy = strings.TrimRight(githubProxy, "/") + "/" } - versionURL := githubProxy + "https://raw.githubusercontent.com/onlyLTY/dockerCopilot/UGREEN/version" - releaseBaseURL := githubProxy + "https://github.com/onlyLTY/dockerCopilot/releases/download" + versionURL := githubProxy + "https://raw.githubusercontent.com/" + UpdateRepo() + "/" + UpdateBranch() + "/version" + releaseBaseURL := githubProxy + "https://github.com/" + UpdateRepo() + "/releases/download" logx.Infof("versionURL: %s", versionURL) resp, err := http.Get(versionURL) if err != nil { diff --git a/internal/utiles/updaterepo.go b/internal/utiles/updaterepo.go new file mode 100644 index 00000000..bb2f62e0 --- /dev/null +++ b/internal/utiles/updaterepo.go @@ -0,0 +1,25 @@ +package utiles + +import ( + "os" + "strings" +) + +// UpdateRepo 返回自更新与版本检查所使用的仓库(owner/repo)。 +// 默认指向本项目的自维护 fork,可通过环境变量 UPDATE_REPO 覆盖。 +func UpdateRepo() string { + repo := strings.TrimSpace(os.Getenv("UPDATE_REPO")) + if repo == "" { + repo = "DongShull/dockerCopilot" + } + return repo +} + +// UpdateBranch 返回版本检查读取的分支,默认 latest,可用 UPDATE_BRANCH 覆盖。 +func UpdateBranch() string { + branch := strings.TrimSpace(os.Getenv("UPDATE_BRANCH")) + if branch == "" { + branch = "latest" + } + return branch +} From 5e726b13416ff8fba6be10734f5736efa9309906 Mon Sep 17 00:00:00 2001 From: DongShull Date: Fri, 30 Oct 2026 04:32:49 +0800 Subject: [PATCH 02/10] =?UTF-8?q?fix:=20P1=20=E4=BF=AE=E5=A4=8D=E6=89=B9?= =?UTF-8?q?=E2=80=94=E2=80=94=E5=88=97=E8=A1=A8nil=E5=B4=A9=E6=BA=83/?= =?UTF-8?q?=E7=A7=92=E7=BA=A7=E9=87=8D=E5=90=8D/digest=E8=A6=86=E7=9B=96/?= =?UTF-8?q?=E7=A7=81=E6=9C=89=E4=BB=93=E5=BA=93tag=E8=A7=A3=E6=9E=90/SIGTE?= =?UTF-8?q?RM/=E6=95=B0=E6=8D=AE=E7=AB=9E=E4=BA=89/zip-slip/=E6=AD=BB?= =?UTF-8?q?=E4=BB=A3=E7=A0=81/O(n=C2=B2)/TLS=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../logic/container/containerslistlogic.go | 3 +- internal/module/checkupdate.go | 61 +++++++++++++++---- internal/utiles/getcontainerlist.go | 6 +- internal/utiles/image.go | 23 ++++--- internal/utiles/restartcontainer.go | 2 +- internal/utiles/restorecontainer.go | 5 -- internal/utiles/stopcontainer.go | 2 +- internal/utiles/updatecontainer.go | 4 +- internal/utiles/updateprogram.go | 8 ++- 9 files changed, 78 insertions(+), 36 deletions(-) diff --git a/internal/logic/container/containerslistlogic.go b/internal/logic/container/containerslistlogic.go index a8c44db2..c442fd30 100644 --- a/internal/logic/container/containerslistlogic.go +++ b/internal/logic/container/containerslistlogic.go @@ -70,8 +70,9 @@ func (l *ContainersListLogic) ContainersList() (resp *types.Resp, err error) { if err != nil { containerInfo.CreateImage = "" l.Error("get image name error" + v.ID) + } else { + containerInfo.CreateImage = containerInspect.Config.Image } - containerInfo.CreateImage = containerInspect.Config.Image t := time.Unix(v.Created, 0) containerInfo.CreateTime = t.Format("2006-01-02 15:04:05") containerInfo.RunningTime = v.Status diff --git a/internal/module/checkupdate.go b/internal/module/checkupdate.go index d2200c35..78a11064 100644 --- a/internal/module/checkupdate.go +++ b/internal/module/checkupdate.go @@ -11,7 +11,9 @@ import ( "net" "net/http" url2 "net/url" + "os" "strings" + "sync" "time" ) @@ -20,26 +22,55 @@ type ImageCheckList struct { NeedUpdate bool } type ImageUpdateData struct { + mu sync.RWMutex Data map[string]ImageCheckList } +// Get 返回指定镜像的更新检查结果(并发安全)。 +func (i *ImageUpdateData) Get(imageID string) (ImageCheckList, bool) { + i.mu.RLock() + defer i.mu.RUnlock() + v, ok := i.Data[imageID] + return v, ok +} + const ContentDigestHeader = "Docker-Content-Digest" +const checkUpdateConcurrency = 4 + func NewImageCheck() *ImageUpdateData { return &ImageUpdateData{ Data: map[string]ImageCheckList{}, } } func (i *ImageUpdateData) CheckUpdate(imageList []types.Image) { + results := make(map[string]ImageCheckList) + var resultsMu sync.Mutex + var wg sync.WaitGroup + sem := make(chan struct{}, checkUpdateConcurrency) for _, image := range imageList { if strings.Contains(image.ImageName, "0nlylty/dockercopilot") { continue } - i.checkSingleImage(image) + wg.Add(1) + go func(img types.Image) { + defer wg.Done() + sem <- struct{}{} + defer func() { <-sem }() + if result, ok := i.checkSingleImage(img); ok { + resultsMu.Lock() + results[img.ID] = result + resultsMu.Unlock() + } + }(image) } + wg.Wait() + i.mu.Lock() + i.Data = results + i.mu.Unlock() } -func (i *ImageUpdateData) checkSingleImage(image types.Image) { +func (i *ImageUpdateData) checkSingleImage(image types.Image) (ImageCheckList, bool) { token, err := GetToken(image, "") if err != nil { logx.Error("获取token失败或者无需获取token,继续尝试检查" + err.Error()) @@ -47,34 +78,38 @@ func (i *ImageUpdateData) checkSingleImage(image types.Image) { digestURL, err := BuildManifestURL(image) if err != nil { logx.Error("获取digestURL失败" + err.Error()) - return + return ImageCheckList{}, false } remoteDigest, err := GetDigest(digestURL, token) if err != nil { logx.Error("获取digest失败" + err.Error()) - return + return ImageCheckList{}, false } if len(image.RepoDigests) == 0 { logx.Error("未在本地获取到repoDigest" + image.ImageName + ":" + image.ImageTag) - return + return ImageCheckList{}, false } needUpdate := false for _, localRepoDigests := range image.RepoDigests { - localDigest := strings.Split(localRepoDigests, "@")[1] + parts := strings.Split(localRepoDigests, "@") + if len(parts) != 2 { + continue + } + localDigest := parts[1] + if remoteDigest == "" || localDigest == "" { + logx.Error("Digest为空" + image.ImageName + ":" + image.ImageTag) + continue + } if remoteDigest != localDigest { - if remoteDigest == "" || localDigest == "" { - logx.Error("Digest为空" + image.ImageName + ":" + image.ImageTag) - continue - } + // 任一本地 digest 与远端不同即判定需要更新,不能因后续匹配被覆盖 logx.Info(image.ImageName + ":" + image.ImageTag + " need update") logx.Infof("localDigest: %s, remoteDigest: %s", localDigest, remoteDigest) needUpdate = true } else { logx.Info(image.ImageName + ":" + image.ImageTag + " not need update") - needUpdate = false } } - i.Data[image.ID] = ImageCheckList{NeedUpdate: needUpdate} + return ImageCheckList{NeedUpdate: needUpdate}, true } func BuildManifestURL(image types.Image) (string, error) { @@ -114,7 +149,7 @@ func GetDigest(url string, token string) (string, error) { IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + TLSClientConfig: &tls.Config{InsecureSkipVerify: os.Getenv("REGISTRY_INSECURE") != "false"}, } client := &http.Client{Transport: tr} diff --git a/internal/utiles/getcontainerlist.go b/internal/utiles/getcontainerlist.go index cfc7344e..23119d85 100644 --- a/internal/utiles/getcontainerlist.go +++ b/internal/utiles/getcontainerlist.go @@ -29,10 +29,8 @@ func GetContainerList(ctx *svc.ServiceContext) ([]MyType.Container, error) { func CheckImageUpdate(ctx *svc.ServiceContext, containerListData []MyType.Container) []MyType.Container { for i, v := range containerListData { - if _, ok := ctx.HubImageInfo.Data[v.ImageID]; ok { - if ctx.HubImageInfo.Data[v.ImageID].NeedUpdate { - containerListData[i].Update = true - } + if info, ok := ctx.HubImageInfo.Get(v.ImageID); ok && info.NeedUpdate { + containerListData[i].Update = true } } return containerListData diff --git a/internal/utiles/image.go b/internal/utiles/image.go index b0b37a69..46979d69 100644 --- a/internal/utiles/image.go +++ b/internal/utiles/image.go @@ -38,8 +38,15 @@ func GetImagesList(ctx *svc.ServiceContext) ([]MyType.Image, error) { func splitImageNameAndTag(imagesList []MyType.Image) []MyType.Image { for i, imageInfo := range imagesList { if len(imageInfo.RepoTags) != 0 { - imagesList[i].ImageName = strings.Split(imageInfo.RepoTags[0], ":")[0] - imagesList[i].ImageTag = strings.Split(imageInfo.RepoTags[0], ":")[1] + repoTag := imageInfo.RepoTags[0] + // 用最后一个冒号切分,兼容带端口的私有仓库(如 registry.example.com:5000/app:v1) + if idx := strings.LastIndex(repoTag, ":"); idx > 0 && !strings.Contains(repoTag[idx+1:], "/") { + imagesList[i].ImageName = repoTag[:idx] + imagesList[i].ImageTag = repoTag[idx+1:] + } else { + imagesList[i].ImageName = repoTag + imagesList[i].ImageTag = "None" + } } else if len(imageInfo.RepoDigests) != 0 { imagesList[i].ImageName = strings.Split(imageInfo.RepoDigests[0], "@")[0] imagesList[i].ImageTag = "None" @@ -55,13 +62,13 @@ func checkImageInUsed(svc *svc.ServiceContext, imageList []MyType.Image) ([]MyTy if err != nil { return imageList, err } - // 这里可以用mapreduce 我懒等pr + used := make(map[string]struct{}, len(list)) for _, v := range list { - for i, imageInfo := range imageList { - if v.ImageID == imageInfo.ID { - imageList[i].InUsed = true - break - } + used[v.ImageID] = struct{}{} + } + for i := range imageList { + if _, ok := used[imageList[i].ID]; ok { + imageList[i].InUsed = true } } return imageList, nil diff --git a/internal/utiles/restartcontainer.go b/internal/utiles/restartcontainer.go index 639401f2..cfd05902 100644 --- a/internal/utiles/restartcontainer.go +++ b/internal/utiles/restartcontainer.go @@ -8,7 +8,7 @@ import ( func RestartContainer(ctx *svc.ServiceContext, id string) error { timeout := 10 - signal := "SIGINT" + signal := "SIGTERM" stopOptions := container.StopOptions{ Signal: signal, Timeout: &timeout, diff --git a/internal/utiles/restorecontainer.go b/internal/utiles/restorecontainer.go index f955239a..b54887de 100644 --- a/internal/utiles/restorecontainer.go +++ b/internal/utiles/restorecontainer.go @@ -60,11 +60,6 @@ func RestoreContainer(ctx *svc.ServiceContext, filename string, taskID string) e oldProgress.DetailMsg = info ctx.UpdateProgress(taskID, oldProgress) ctx.DockerClient.NegotiateAPIVersion(context.TODO()) - if err != nil { - backupList = append(backupList, "出现错误"+err.Error()) - logx.Errorf("Failed to inspect container: %v", err) - return err - } reader, err := ctx.DockerClient.ImagePull(context.TODO(), containerInfo.Config.Image, image.PullOptions{}) if err != nil { backupList = append(backupList, containerInfo.Config.Image+"拉取镜像出现错误"+err.Error()) diff --git a/internal/utiles/stopcontainer.go b/internal/utiles/stopcontainer.go index 86ca600b..1a320b52 100644 --- a/internal/utiles/stopcontainer.go +++ b/internal/utiles/stopcontainer.go @@ -8,7 +8,7 @@ import ( func StopContainer(ctx *svc.ServiceContext, id string) error { timeout := 10 - signal := "SIGINT" + signal := "SIGTERM" stopOptions := container.StopOptions{ Signal: signal, Timeout: &timeout, diff --git a/internal/utiles/updatecontainer.go b/internal/utiles/updatecontainer.go index 6ddba209..410c5822 100644 --- a/internal/utiles/updatecontainer.go +++ b/internal/utiles/updatecontainer.go @@ -35,7 +35,7 @@ func UpdateContainer(serviceContext *svc.ServiceContext, id string, name string, } } timeout := 10 - signal := "SIGINT" + signal := "SIGTERM" serviceContext.UpdateProgress(taskID, oldTaskProgress) oldTaskProgress.Message = "正在拉取新镜像" @@ -98,7 +98,7 @@ func UpdateContainer(serviceContext *svc.ServiceContext, id string, name string, oldTaskProgress.Message = "正在重命名旧容器" oldTaskProgress.DetailMsg = "正在重命名旧容器" serviceContext.UpdateProgress(taskID, oldTaskProgress) - currentDate := time.Now().Format("2006-01-02-15-04-05") + currentDate := time.Now().Format("2006-01-02-15-04-05.000000000") err = serviceContext.DockerClient.ContainerRename(context.Background(), id, name+"-"+currentDate) if err != nil { oldTaskProgress.Message = "重命名旧容器失败" diff --git a/internal/utiles/updateprogram.go b/internal/utiles/updateprogram.go index 65157187..79ada9b5 100644 --- a/internal/utiles/updateprogram.go +++ b/internal/utiles/updateprogram.go @@ -9,6 +9,7 @@ import ( "io" "net/http" "os" + "path/filepath" "runtime" "strings" ) @@ -123,7 +124,12 @@ func decompressTarGz(gzFilePath string, dest string) error { return err } - target := dest + "/" + header.Name + target := filepath.Join(dest, filepath.FromSlash(header.Name)) + // 防止 zip-slip:解压目标必须落在 dest 目录内 + cleanDest := filepath.Clean(dest) + if target != cleanDest && !strings.HasPrefix(target, cleanDest+string(os.PathSeparator)) { + return fmt.Errorf("非法的文件路径: %s", header.Name) + } switch header.Typeflag { case tar.TypeDir: From dfaa3a71a5962f24084f22f1f031f88eaa6d36f6 Mon Sep 17 00:00:00 2001 From: DongShull Date: Fri, 30 Oct 2026 04:33:17 +0800 Subject: [PATCH 03/10] =?UTF-8?q?fea:=20P2=20=E6=9B=B4=E6=96=B0=E9=93=BE?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E2=80=94=E2=80=94=E6=97=A7=E9=95=9C=E5=83=8F?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=B8=85=E7=90=86=E3=80=81=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=9B=9E=E6=BB=9A=E3=80=81=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=8F=AF=E5=8F=96=E6=B6=88=E3=80=81compose=20=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=E6=84=9F=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../logic/container/containerslistlogic.go | 3 + internal/logic/container/updatelogic.go | 2 +- internal/utiles/restorecontainer.go | 2 +- internal/utiles/updatecontainer.go | 278 +++++++++--------- 4 files changed, 147 insertions(+), 138 deletions(-) diff --git a/internal/logic/container/containerslistlogic.go b/internal/logic/container/containerslistlogic.go index c442fd30..c6858f6a 100644 --- a/internal/logic/container/containerslistlogic.go +++ b/internal/logic/container/containerslistlogic.go @@ -26,6 +26,7 @@ type Info struct { CreateTime string `json:"createTime"` RunningTime string `json:"runningTime"` HaveUpdate bool `json:"haveUpdate"` + IsCompose bool `json:"isCompose"` } func NewContainersListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ContainersListLogic { @@ -77,6 +78,8 @@ func (l *ContainersListLogic) ContainersList() (resp *types.Resp, err error) { containerInfo.CreateTime = t.Format("2006-01-02 15:04:05") containerInfo.RunningTime = v.Status containerInfo.HaveUpdate = v.Update + // 由 docker compose 创建的容器带 project 标签,前端可提示优先走 compose 更新 + containerInfo.IsCompose = v.Labels["com.docker.compose.project"] != "" containerInfoList = append(containerInfoList, containerInfo) } resp.Data = containerInfoList diff --git a/internal/logic/container/updatelogic.go b/internal/logic/container/updatelogic.go index 4feb0bd5..35e61d3e 100644 --- a/internal/logic/container/updatelogic.go +++ b/internal/logic/container/updatelogic.go @@ -36,7 +36,7 @@ func (l *UpdateLogic) Update(req *types.ContainerUpdateReq) (resp *types.Resp, e }() imageNameAndTag := req.ImageNameAndTag delOldContainer := os.Getenv("DelOldContainer") != "false" - err := utiles.UpdateContainer(l.svcCtx, req.Id, req.ContainerName, imageNameAndTag, delOldContainer, taskID) + err := utiles.UpdateContainer(l.svcCtx, context.Background(), req.Id, req.ContainerName, imageNameAndTag, delOldContainer, taskID) if err != nil { l.Errorf("Error in UpdateContainer: %v", err) } diff --git a/internal/utiles/restorecontainer.go b/internal/utiles/restorecontainer.go index b54887de..56e02150 100644 --- a/internal/utiles/restorecontainer.go +++ b/internal/utiles/restorecontainer.go @@ -66,7 +66,7 @@ func RestoreContainer(ctx *svc.ServiceContext, filename string, taskID string) e logx.Errorf("Failed to pull image: %v", err) continue } - err = decodePullResp(reader, ctx, taskID) + err = decodePullResp(reader, ctx, context.Background(), taskID) if err != nil { backupList = append(backupList, containerInfo.Config.Image+"拉取镜像出现错误"+err.Error()) logx.Errorf("Failed to pull image: %v", err) diff --git a/internal/utiles/updatecontainer.go b/internal/utiles/updatecontainer.go index 410c5822..94f6d236 100644 --- a/internal/utiles/updatecontainer.go +++ b/internal/utiles/updatecontainer.go @@ -4,125 +4,115 @@ import ( "context" "encoding/json" "fmt" + "io" + "os" + "time" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/network" dockerMsgType "github.com/docker/docker/pkg/jsonmessage" "github.com/onlyLTY/dockerCopilot/internal/svc" "github.com/zeromicro/go-zero/core/logx" - "io" - "time" ) -func UpdateContainer(serviceContext *svc.ServiceContext, id string, name string, imageNameAndTag string, delOldContainer bool, taskID string) error { - ctx := context.Background() - serviceContext.UpdateProgress(taskID, svc.TaskProgress{ - TaskID: taskID, - Percentage: 0, - Name: name, - Message: "正在连接Docker", - DetailMsg: "正在连接Docker", - IsDone: false, - }) - var oldTaskProgress, result = serviceContext.GetProgress(taskID) - if !result { - oldTaskProgress = svc.TaskProgress{ - Percentage: 0, - Name: "", - Message: "", - DetailMsg: "", - IsDone: false, +// UpdateContainer 执行一次容器更新:拉取新镜像 → 停止并改名旧容器 → 克隆配置创建新容器 +// → 启动新容器 → 删除旧容器 → 清理旧镜像。任一步失败都会尝试把旧容器恢复到原名并重新启动。 +// ctx 支持取消:任务被取消时在步骤边界退出。 +func UpdateContainer(serviceContext *svc.ServiceContext, ctx context.Context, id string, name string, imageNameAndTag string, delOldContainer bool, taskID string) error { + progress := func(percentage int, message, detailMsg string, isDone bool) { + serviceContext.UpdateProgress(taskID, svc.TaskProgress{ + TaskID: taskID, + Percentage: percentage, + Name: name, + Message: message, + DetailMsg: detailMsg, + IsDone: isDone, + }) + } + cancelled := func() bool { + if ctx.Err() != nil { + progress(100, "任务已取消", "任务已取消", true) + return true } + return false + } + + progress(0, "正在连接Docker", "正在连接Docker", false) + if cancelled() { + return ctx.Err() } + timeout := 10 signal := "SIGTERM" - serviceContext.UpdateProgress(taskID, oldTaskProgress) - oldTaskProgress.Message = "正在拉取新镜像" - oldTaskProgress.Percentage = 10 - oldTaskProgress.DetailMsg = "正在拉取新镜像" - serviceContext.UpdateProgress(taskID, oldTaskProgress) serviceContext.DockerClient.NegotiateAPIVersion(ctx) + + // 先记录旧容器信息:旧镜像 ID 用于更新后的清理,旧容器名用于失败回滚 + inspectedContainer, err := serviceContext.DockerClient.ContainerInspect(ctx, id) + if err != nil { + progress(0, "获取容器信息失败", err.Error(), true) + logx.Errorf("获取容器信息失败: %v", err) + return err + } + oldImageID := inspectedContainer.Image + oldContainerName := name + backupName := name + "-" + time.Now().Format("2006-01-02-15-04-05.000000000") + + // rollback 把旧容器恢复到原名并重新启动;reason 写入进度详情 + rollback := func(reason string) { + bg := context.Background() + if renameErr := serviceContext.DockerClient.ContainerRename(bg, id, oldContainerName); renameErr != nil { + logx.Errorf("回滚重命名失败: %v", renameErr) + progress(100, "更新失败且回滚失败,请手动处理旧容器 "+backupName, reason, true) + return + } + if startErr := serviceContext.DockerClient.ContainerStart(bg, id, container.StartOptions{}); startErr != nil { + logx.Errorf("回滚启动失败: %v", startErr) + progress(100, "更新失败,旧容器已改回原名但启动失败", reason+";启动错误: "+startErr.Error(), true) + return + } + progress(100, "更新失败,已回滚旧容器", reason, true) + } + + // 1. 拉取新镜像(流式进度 10% → 25%) + progress(10, "正在拉取新镜像", "正在拉取新镜像", false) reader, err := serviceContext.DockerClient.ImagePull(ctx, imageNameAndTag, image.PullOptions{}) if err != nil { - oldTaskProgress.Message = "拉取镜像失败" - oldTaskProgress.DetailMsg = err.Error() - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) + progress(100, "拉取镜像失败", err.Error(), true) logx.Errorf("Failed to pull image: %s", err) return err } - err = decodePullResp(reader, serviceContext, taskID) - if err != nil { - oldTaskProgress.Message = "拉取镜像失败" - oldTaskProgress.DetailMsg = err.Error() - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) + if err = decodePullResp(reader, serviceContext, ctx, taskID); err != nil { + progress(100, "拉取镜像失败", err.Error(), true) logx.Errorf("Failed to pull image: %s", err) return err } - oldTaskProgress, result = serviceContext.GetProgress(taskID) - if !result { - oldTaskProgress = svc.TaskProgress{ - Percentage: 0, - Name: "", - Message: "", - DetailMsg: "", - IsDone: false, - } + if cancelled() { + return ctx.Err() } - oldTaskProgress.Message = "拉取镜像成功" - oldTaskProgress.DetailMsg = "拉取镜像成功" - oldTaskProgress.Percentage = 30 - oldTaskProgress.Message = "正在停止容器" - oldTaskProgress.DetailMsg = "正在停止容器" - serviceContext.UpdateProgress(taskID, oldTaskProgress) + // 2. 停止旧容器 + progress(30, "正在停止容器", "正在停止容器", false) stopOptions := container.StopOptions{ Signal: signal, Timeout: &timeout, } - err = serviceContext.DockerClient.ContainerStop(context.Background(), id, stopOptions) - if err != nil { - oldTaskProgress.Message = "停止容器失败" - oldTaskProgress.DetailMsg = err.Error() - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) + if err = serviceContext.DockerClient.ContainerStop(ctx, id, stopOptions); err != nil { + progress(100, "停止容器失败", err.Error(), true) return err } - oldTaskProgress.Message = "容器停止成功" - oldTaskProgress.DetailMsg = "容器停止成功" - oldTaskProgress.Percentage = 40 - serviceContext.UpdateProgress(taskID, oldTaskProgress) - oldTaskProgress.Message = "正在重命名旧容器" - oldTaskProgress.DetailMsg = "正在重命名旧容器" - serviceContext.UpdateProgress(taskID, oldTaskProgress) - currentDate := time.Now().Format("2006-01-02-15-04-05.000000000") - err = serviceContext.DockerClient.ContainerRename(context.Background(), id, name+"-"+currentDate) - if err != nil { - oldTaskProgress.Message = "重命名旧容器失败" - oldTaskProgress.DetailMsg = err.Error() - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) - return err - } - oldTaskProgress.Message = "重命名旧容器成功" - oldTaskProgress.DetailMsg = "重命名旧容器成功" - oldTaskProgress.Percentage = 60 - serviceContext.UpdateProgress(taskID, oldTaskProgress) - oldTaskProgress.Message = "正在创建新容器" - oldTaskProgress.DetailMsg = "正在创建新容器" - serviceContext.UpdateProgress(taskID, oldTaskProgress) - inspectedContainer, err := serviceContext.DockerClient.ContainerInspect(ctx, id) - if err != nil { - oldTaskProgress.Message = "获取容器信息失败" - oldTaskProgress.DetailMsg = err.Error() - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) - logx.Error("获取容器信息失败" + err.Error()) + // 3. 重命名旧容器(腾出原名) + progress(40, "正在重命名旧容器", "正在重命名旧容器", false) + if err = serviceContext.DockerClient.ContainerRename(ctx, id, backupName); err != nil { + // 还没改名成功,旧容器仍是原名,重新拉起即可 + rollback("重命名旧容器失败: " + err.Error()) return err } + + // 4. 克隆旧容器配置创建新容器(只替换镜像) + progress(60, "正在创建新容器", "正在创建新容器", false) inspectedContainer.Config.Hostname = "" inspectedContainer.Config.Image = imageNameAndTag inspectedContainer.Image = imageNameAndTag @@ -131,54 +121,69 @@ func UpdateContainer(serviceContext *svc.ServiceContext, id string, name string, networkingConfig := &network.NetworkingConfig{ EndpointsConfig: inspectedContainer.NetworkSettings.Networks, } - containerName := name - _, err = serviceContext.DockerClient.ContainerCreate(ctx, config, hostConfig, networkingConfig, nil, containerName) - if err != nil { - oldTaskProgress.Message = "创建新容器失败" - oldTaskProgress.DetailMsg = err.Error() - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) + if _, err = serviceContext.DockerClient.ContainerCreate(ctx, config, hostConfig, networkingConfig, nil, oldContainerName); err != nil { + rollback("创建新容器失败: " + err.Error()) return err } - oldTaskProgress.Message = "创建新容器成功" - oldTaskProgress.DetailMsg = "创建新容器成功" - oldTaskProgress.Percentage = 80 - serviceContext.UpdateProgress(taskID, oldTaskProgress) - oldTaskProgress.Message = "正在启动新容器以及删除旧容器(如果不保留旧容器)" - oldTaskProgress.DetailMsg = "正在启动新容器以及删除旧容器(如果不保留旧容器)" - serviceContext.UpdateProgress(taskID, oldTaskProgress) - err = serviceContext.DockerClient.ContainerStart(context.Background(), containerName, container.StartOptions{ - CheckpointID: "", - CheckpointDir: "", - }) - if err != nil { - oldTaskProgress.Message = "启动新容器失败" - oldTaskProgress.DetailMsg = err.Error() - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) + + // 5. 启动新容器 + progress(80, "正在启动新容器", "正在启动新容器", false) + if err = serviceContext.DockerClient.ContainerStart(ctx, oldContainerName, container.StartOptions{}); err != nil { + // 新容器已创建但起不来:先移除它,再回滚旧容器 + _ = serviceContext.DockerClient.ContainerRemove(context.Background(), oldContainerName, container.RemoveOptions{Force: true}) + rollback("启动新容器失败: " + err.Error()) return err } + + // 6. 删除旧容器(默认保留开关可关闭) if delOldContainer { - err = serviceContext.DockerClient.ContainerRemove(context.Background(), id, container.RemoveOptions{}) - if err != nil { - oldTaskProgress.Message = "删除旧容器失败" - oldTaskProgress.DetailMsg = err.Error() - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) - return err + if err = serviceContext.DockerClient.ContainerRemove(ctx, id, container.RemoveOptions{}); err != nil { + // 旧容器删除失败不算更新失败,但需要告知 + logx.Errorf("删除旧容器失败: %v", err) + progress(90, "更新成功(旧容器删除失败,请手动清理 "+backupName+")", err.Error(), false) } } - oldTaskProgress.Message = "更新成功" - oldTaskProgress.DetailMsg = "更新成功" - oldTaskProgress.Percentage = 100 - oldTaskProgress.IsDone = true - serviceContext.UpdateProgress(taskID, oldTaskProgress) + + // 7. 清理旧镜像:仅当旧容器已删除、且旧镜像不再被任何容器引用时删除 + if delOldContainer && os.Getenv("CLEANUP_OLD_IMAGE") != "false" { + progress(95, "正在清理旧镜像", "正在清理旧镜像", false) + if cleanupMsg := cleanupOldImage(serviceContext, oldImageID); cleanupMsg != "" { + progress(100, "更新成功", cleanupMsg, false) + } + } + + progress(100, "更新成功", "更新成功", true) return nil } -func decodePullResp(reader io.Reader, ctx *svc.ServiceContext, taskID string) (err error) { +// cleanupOldImage 在没有任何容器引用 oldImageID 时删除该镜像。 +// 返回补充信息(清理失败原因),失败不影响更新结果。 +func cleanupOldImage(serviceContext *svc.ServiceContext, oldImageID string) string { + if oldImageID == "" { + return "" + } + bg := context.Background() + containers, err := serviceContext.DockerClient.ContainerList(bg, container.ListOptions{All: true}) + if err != nil { + logx.Errorf("清理旧镜像前获取容器列表失败: %v", err) + return "" + } + for _, c := range containers { + if c.ImageID == oldImageID { + // 仍被引用,不删 + return "" + } + } + if _, err := serviceContext.DockerClient.ImageRemove(bg, oldImageID, image.RemoveOptions{}); err != nil { + logx.Errorf("清理旧镜像失败(不影响更新结果): %v", err) + return "旧镜像清理失败: " + err.Error() + } + return "旧镜像已清理" +} + +func decodePullResp(reader io.Reader, svcCtx *svc.ServiceContext, ctx context.Context, taskID string) (err error) { decoder := json.NewDecoder(reader) - var oldTaskProgress, result = ctx.GetProgress(taskID) + var oldTaskProgress, result = svcCtx.GetProgress(taskID) if !result { oldTaskProgress = svc.TaskProgress{ Percentage: 0, @@ -189,6 +194,9 @@ func decodePullResp(reader io.Reader, ctx *svc.ServiceContext, taskID string) (e } } for { + if ctx.Err() != nil { + return ctx.Err() + } var msg dockerMsgType.JSONMessage if err = decoder.Decode(&msg); err != nil { if err == io.EOF { @@ -198,30 +206,28 @@ func decodePullResp(reader io.Reader, ctx *svc.ServiceContext, taskID string) (e oldTaskProgress.DetailMsg = err.Error() oldTaskProgress.Percentage = 25 oldTaskProgress.IsDone = true - ctx.UpdateProgress(taskID, oldTaskProgress) + svcCtx.UpdateProgress(taskID, oldTaskProgress) logx.Errorf("Failed to decode pull image response: %s", err) return fmt.Errorf("拉取镜像失败: %w", err) } - // Print the progress or error information from the response if msg.Error != nil { oldTaskProgress.Message = "拉取镜像失败" oldTaskProgress.DetailMsg = msg.Error.Error() oldTaskProgress.Percentage = 25 oldTaskProgress.IsDone = true - ctx.UpdateProgress(taskID, oldTaskProgress) + svcCtx.UpdateProgress(taskID, oldTaskProgress) logx.Errorf("Error: %s", msg.Error) return fmt.Errorf("拉取镜像失败: %w", msg.Error) + } + var formattedMsg string + if msg.Progress != nil { + formattedMsg = fmt.Sprintf("进度%s: %s", msg.Status, msg.Progress.String()) } else { - var formattedMsg string - if msg.Progress != nil { - formattedMsg = fmt.Sprintf("进度%s: %s", msg.Status, msg.Progress.String()) - } else { - formattedMsg = fmt.Sprintf("进度%s", msg.Status) - } - oldTaskProgress.DetailMsg = formattedMsg - oldTaskProgress.Percentage = 25 - ctx.UpdateProgress(taskID, oldTaskProgress) - logx.Infof("拉取镜像进度\t %s: %s\n", msg.Status, msg.Progress) + formattedMsg = fmt.Sprintf("进度%s", msg.Status) } + oldTaskProgress.DetailMsg = formattedMsg + oldTaskProgress.Percentage = 25 + svcCtx.UpdateProgress(taskID, oldTaskProgress) + logx.Infof("拉取镜像进度\t %s: %s\n", msg.Status, msg.Progress) } } From b818571002cfea75f620b5691c4188dff7fdb125 Mon Sep 17 00:00:00 2001 From: DongShull Date: Fri, 30 Oct 2026 04:34:06 +0800 Subject: [PATCH 04/10] =?UTF-8?q?fea:=20P3=20=E4=BB=BB=E5=8A=A1=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E2=80=94=E2=80=94=E8=BF=9B=E5=BA=A6=E8=90=BD=E7=9B=98?= =?UTF-8?q?=E3=80=81TTL=20=E6=B8=85=E7=90=86=E3=80=81=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=88=97=E8=A1=A8/=E5=8F=96=E6=B6=88=20API=E3=80=81SSE=20?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dockercopilot.api | 9 + .../handler/progress/cancelprogresshandler.go | 28 +++ .../handler/progress/listprogresshandler.go | 21 ++ .../handler/progress/streameventshandler.go | 68 +++++++ internal/handler/routes.go | 15 ++ internal/logic/container/restorelogic.go | 1 + internal/logic/container/updatelogic.go | 4 +- .../logic/progress/cancelprogresslogic.go | 54 +++++ internal/logic/progress/listprogresslogic.go | 32 +++ internal/svc/servicecontext.go | 185 +++++++++++++++++- 10 files changed, 407 insertions(+), 10 deletions(-) create mode 100644 internal/handler/progress/cancelprogresshandler.go create mode 100644 internal/handler/progress/listprogresshandler.go create mode 100644 internal/handler/progress/streameventshandler.go create mode 100644 internal/logic/progress/cancelprogresslogic.go create mode 100644 internal/logic/progress/listprogresslogic.go diff --git a/dockercopilot.api b/dockercopilot.api index 0716fb6d..75bb7c02 100644 --- a/dockercopilot.api +++ b/dockercopilot.api @@ -111,8 +111,17 @@ service dockerCopilot { jwt: Auth ) service dockerCopilot { + @handler ListProgress + get /progress returns (Resp) + @handler GetProgress get /progress/:taskid (GetProgressReq) returns (Resp) + + @handler CancelProgress + post /progress/:taskid/cancel (GetProgressReq) returns (Resp) + + @handler StreamEvents + get /progress/:taskid/events (GetProgressReq) } @server( diff --git a/internal/handler/progress/cancelprogresshandler.go b/internal/handler/progress/cancelprogresshandler.go new file mode 100644 index 00000000..89f060ba --- /dev/null +++ b/internal/handler/progress/cancelprogresshandler.go @@ -0,0 +1,28 @@ +package progress + +import ( + "net/http" + + "github.com/onlyLTY/dockerCopilot/internal/logic/progress" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func CancelProgressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetProgressReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := progress.NewCancelProgressLogic(r.Context(), svcCtx) + resp, err := l.CancelProgress(&req) + if err != nil { + httpx.WriteJson(w, resp.Code, resp) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/progress/listprogresshandler.go b/internal/handler/progress/listprogresshandler.go new file mode 100644 index 00000000..a8c28bd6 --- /dev/null +++ b/internal/handler/progress/listprogresshandler.go @@ -0,0 +1,21 @@ +package progress + +import ( + "net/http" + + "github.com/onlyLTY/dockerCopilot/internal/logic/progress" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func ListProgressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + l := progress.NewListProgressLogic(r.Context(), svcCtx) + resp, err := l.ListProgress() + if err != nil { + httpx.WriteJson(w, resp.Code, resp) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/progress/streameventshandler.go b/internal/handler/progress/streameventshandler.go new file mode 100644 index 00000000..25d42641 --- /dev/null +++ b/internal/handler/progress/streameventshandler.go @@ -0,0 +1,68 @@ +package progress + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +// StreamEventsHandler 以 Server-Sent Events 推送任务进度,替代前端高频轮询。 +// 任务完成或客户端断开时流结束。 +func StreamEventsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetProgressReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + flusher, ok := w.(http.Flusher) + if !ok { + httpx.ErrorCtx(r.Context(), w, fmt.Errorf("streaming unsupported")) + return + } + + header := w.Header() + header.Set("Content-Type", "text/event-stream") + header.Set("Cache-Control", "no-cache") + header.Set("Connection", "keep-alive") + header.Set("X-Accel-Buffering", "no") + w.WriteHeader(http.StatusOK) + flusher.Flush() + + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + lastPayload := "" + for { + select { + case <-r.Context().Done(): + return + case <-ticker.C: + progress, exists := svcCtx.GetProgress(req.TaskId) + if !exists { + fmt.Fprintf(w, "event: error\ndata: {\"msg\":\"taskID 未找到\"}\n\n") + flusher.Flush() + return + } + payload, err := json.Marshal(progress) + if err != nil { + continue + } + if string(payload) != lastPayload { + fmt.Fprintf(w, "data: %s\n\n", payload) + flusher.Flush() + lastPayload = string(payload) + } + if progress.IsDone { + return + } + } + } + } +} diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 5a84662d..5912ae57 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -137,11 +137,26 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( []rest.Route{ + { + Method: http.MethodGet, + Path: "/progress", + Handler: progress.ListProgressHandler(serverCtx), + }, { Method: http.MethodGet, Path: "/progress/:taskid", Handler: progress.GetProgressHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/progress/:taskid/cancel", + Handler: progress.CancelProgressHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/progress/:taskid/events", + Handler: progress.StreamEventsHandler(serverCtx), + }, }, rest.WithJwt(serverCtx.Config.Auth.AccessSecret), rest.WithPrefix("/api"), diff --git a/internal/logic/container/restorelogic.go b/internal/logic/container/restorelogic.go index 8334681f..84a12ec8 100644 --- a/internal/logic/container/restorelogic.go +++ b/internal/logic/container/restorelogic.go @@ -52,6 +52,7 @@ func (l *RestoreLogic) Restore(req *types.ContainerRestoreReq) (resp *types.Resp if r := recover(); r != nil { l.Errorf("Recovered from panic in restoreContainer: %v", r) } + l.svcCtx.FinishTask(taskID) }() err := utiles.RestoreContainer(l.svcCtx, fileName, taskID) if err != nil { diff --git a/internal/logic/container/updatelogic.go b/internal/logic/container/updatelogic.go index 35e61d3e..6921f12d 100644 --- a/internal/logic/container/updatelogic.go +++ b/internal/logic/container/updatelogic.go @@ -27,16 +27,18 @@ func NewUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateLogi func (l *UpdateLogic) Update(req *types.ContainerUpdateReq) (resp *types.Resp, err error) { resp = &types.Resp{} taskID := uuid.New().String() + taskCtx := l.svcCtx.RegisterTask(taskID) go func() { // Catch any panic and log the error defer func() { if r := recover(); r != nil { l.Errorf("Recovered from panic in UpdateContainer: %v", r) } + l.svcCtx.FinishTask(taskID) }() imageNameAndTag := req.ImageNameAndTag delOldContainer := os.Getenv("DelOldContainer") != "false" - err := utiles.UpdateContainer(l.svcCtx, context.Background(), req.Id, req.ContainerName, imageNameAndTag, delOldContainer, taskID) + err := utiles.UpdateContainer(l.svcCtx, taskCtx, req.Id, req.ContainerName, imageNameAndTag, delOldContainer, taskID) if err != nil { l.Errorf("Error in UpdateContainer: %v", err) } diff --git a/internal/logic/progress/cancelprogresslogic.go b/internal/logic/progress/cancelprogresslogic.go new file mode 100644 index 00000000..ea925b97 --- /dev/null +++ b/internal/logic/progress/cancelprogresslogic.go @@ -0,0 +1,54 @@ +package progress + +import ( + "context" + + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CancelProgressLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewCancelProgressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelProgressLogic { + return &CancelProgressLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *CancelProgressLogic) CancelProgress(req *types.GetProgressReq) (resp *types.Resp, err error) { + resp = &types.Resp{} + progress, exists := l.svcCtx.GetProgress(req.TaskId) + if !exists { + resp.Code = 400 + resp.Msg = "taskID 未找到" + resp.Data = map[string]interface{}{} + return resp, nil + } + if progress.IsDone { + resp.Code = 400 + resp.Msg = "任务已结束,无需取消" + resp.Data = map[string]interface{}{} + return resp, nil + } + if !l.svcCtx.CancelTask(req.TaskId) { + resp.Code = 400 + resp.Msg = "任务不可取消(可能已结束)" + resp.Data = map[string]interface{}{} + return resp, nil + } + progress.Message = "正在取消..." + progress.DetailMsg = "已发出取消请求,任务将在当前步骤结束后停止" + l.svcCtx.UpdateProgress(req.TaskId, progress) + resp.Code = 200 + resp.Msg = "success" + resp.Data = map[string]interface{}{"taskID": req.TaskId} + return resp, nil +} diff --git a/internal/logic/progress/listprogresslogic.go b/internal/logic/progress/listprogresslogic.go new file mode 100644 index 00000000..98f8a8db --- /dev/null +++ b/internal/logic/progress/listprogresslogic.go @@ -0,0 +1,32 @@ +package progress + +import ( + "context" + + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type ListProgressLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewListProgressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListProgressLogic { + return &ListProgressLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *ListProgressLogic) ListProgress() (resp *types.Resp, err error) { + resp = &types.Resp{} + resp.Code = 200 + resp.Msg = "success" + resp.Data = l.svcCtx.ListProgress() + return resp, nil +} diff --git a/internal/svc/servicecontext.go b/internal/svc/servicecontext.go index 533ebe4d..ed0f6977 100644 --- a/internal/svc/servicecontext.go +++ b/internal/svc/servicecontext.go @@ -1,12 +1,20 @@ package svc import ( + "context" + "encoding/json" + "os" + "path/filepath" + "sort" + "strconv" + "sync" + "time" + "github.com/docker/docker/client" "github.com/onlyLTY/dockerCopilot/internal/config" "github.com/onlyLTY/dockerCopilot/internal/module" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/rest" - "sync" ) type ServiceContext struct { @@ -21,15 +29,19 @@ type ServiceContext struct { ProgressStore ProgressStoreType DockerClient *client.Client mu sync.Mutex + taskCancels map[string]context.CancelFunc + saveMu sync.Mutex } type TaskProgress struct { - TaskID string - Percentage int - Message string - Name string - DetailMsg string - IsDone bool + TaskID string `json:"taskID"` + Percentage int `json:"percentage"` + Message string `json:"message"` + Name string `json:"name"` + DetailMsg string `json:"detailMsg"` + IsDone bool `json:"isDone"` + StartedAt int64 `json:"startedAt"` + FinishedAt int64 `json:"finishedAt"` } type ProgressStoreType map[string]TaskProgress @@ -39,18 +51,123 @@ func NewServiceContext(c config.Config) *ServiceContext { if err != nil { logx.Errorf("Unable to create docker client: %s", err) } - return &ServiceContext{ + ctx := &ServiceContext{ Config: c, HubImageInfo: module.NewImageCheck(), ProgressStore: make(ProgressStoreType), + taskCancels: make(map[string]context.CancelFunc), DockerClient: cli, } + ctx.loadProgress() + go ctx.taskJanitor() + return ctx +} + +// progressStorePath 进度持久化文件路径,可用 PROGRESS_STORE 覆盖。 +func progressStorePath() string { + if p := os.Getenv("PROGRESS_STORE"); p != "" { + return p + } + return "/data/config/progress.json" +} + +// loadProgress 从磁盘恢复历史任务进度(重启不丢历史)。 +func (ctx *ServiceContext) loadProgress() { + data, err := os.ReadFile(progressStorePath()) + if err != nil { + return + } + var stored ProgressStoreType + if err = json.Unmarshal(data, &stored); err != nil { + logx.Errorf("进度文件解析失败: %v", err) + return + } + ctx.mu.Lock() + for k, v := range stored { + ctx.ProgressStore[k] = v + } + ctx.mu.Unlock() +} + +// saveProgress 原子写入进度文件(临时文件 + rename)。 +func (ctx *ServiceContext) saveProgress() { + ctx.mu.Lock() + data, err := json.Marshal(ctx.ProgressStore) + ctx.mu.Unlock() + if err != nil { + logx.Errorf("进度序列化失败: %v", err) + return + } + ctx.saveMu.Lock() + defer ctx.saveMu.Unlock() + path := progressStorePath() + if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil { + logx.Errorf("创建进度目录失败: %v", err) + return + } + tmp := path + ".tmp" + if err = os.WriteFile(tmp, data, 0644); err != nil { + logx.Errorf("写进度临时文件失败: %v", err) + return + } + if err = os.Rename(tmp, path); err != nil { + logx.Errorf("进度文件落地失败: %v", err) + } +} + +// taskJanitor 定期清理超过 TTL 的已完成任务,避免内存与进度文件无限增长。 +func (ctx *ServiceContext) taskJanitor() { + ttl := 24 * time.Hour + if v := os.Getenv("PROGRESS_TTL_HOURS"); v != "" { + if n, err := strconv.Atoi(v); err == nil && n > 0 { + ttl = time.Duration(n) * time.Hour + } + } + ticker := time.NewTicker(10 * time.Minute) + defer ticker.Stop() + for range ticker.C { + cutoff := time.Now().Add(-ttl).Unix() + removed := false + ctx.mu.Lock() + for k, v := range ctx.ProgressStore { + if v.IsDone && v.FinishedAt > 0 && v.FinishedAt < cutoff { + delete(ctx.ProgressStore, k) + if cancel, ok := ctx.taskCancels[k]; ok { + cancel() + delete(ctx.taskCancels, k) + } + removed = true + } + } + ctx.mu.Unlock() + if removed { + ctx.saveProgress() + } + } } func (ctx *ServiceContext) UpdateProgress(taskID string, progress TaskProgress) { ctx.mu.Lock() - defer ctx.mu.Unlock() + now := time.Now().Unix() + if progress.StartedAt == 0 { + if old, ok := ctx.ProgressStore[taskID]; ok { + progress.StartedAt = old.StartedAt + } + if progress.StartedAt == 0 { + progress.StartedAt = now + } + } + if progress.IsDone { + if old, ok := ctx.ProgressStore[taskID]; ok && old.IsDone && old.FinishedAt > 0 { + progress.FinishedAt = old.FinishedAt + } + if progress.FinishedAt == 0 { + progress.FinishedAt = now + } + } ctx.ProgressStore[taskID] = progress + ctx.mu.Unlock() + ctx.saveProgress() } func (ctx *ServiceContext) GetProgress(taskID string) (TaskProgress, bool) { @@ -59,3 +176,53 @@ func (ctx *ServiceContext) GetProgress(taskID string) (TaskProgress, bool) { progress, ok := ctx.ProgressStore[taskID] return progress, ok } + +// ListProgress 返回全部任务进度,按开始时间倒序。 +func (ctx *ServiceContext) ListProgress() []TaskProgress { + ctx.mu.Lock() + defer ctx.mu.Unlock() + list := make([]TaskProgress, 0, len(ctx.ProgressStore)) + for _, v := range ctx.ProgressStore { + list = append(list, v) + } + sort.Slice(list, func(i, j int) bool { + if list[i].StartedAt != list[j].StartedAt { + return list[i].StartedAt > list[j].StartedAt + } + return list[i].TaskID > list[j].TaskID + }) + return list +} + +// RegisterTask 为任务创建可取消的上下文。 +func (ctx *ServiceContext) RegisterTask(taskID string) context.Context { + taskCtx, cancel := context.WithCancel(context.Background()) + ctx.mu.Lock() + if ctx.taskCancels == nil { + ctx.taskCancels = make(map[string]context.CancelFunc) + } + ctx.taskCancels[taskID] = cancel + ctx.mu.Unlock() + return taskCtx +} + +// CancelTask 取消一个进行中的任务,返回是否找到该任务。 +func (ctx *ServiceContext) CancelTask(taskID string) bool { + ctx.mu.Lock() + cancel, ok := ctx.taskCancels[taskID] + ctx.mu.Unlock() + if ok { + cancel() + } + return ok +} + +// FinishTask 任务收尾,释放取消句柄。 +func (ctx *ServiceContext) FinishTask(taskID string) { + ctx.mu.Lock() + if cancel, ok := ctx.taskCancels[taskID]; ok { + cancel() + delete(ctx.taskCancels, taskID) + } + ctx.mu.Unlock() +} From 58f670f7325fe6c5be117258e891d362e93283a6 Mon Sep 17 00:00:00 2001 From: DongShull Date: Fri, 30 Oct 2026 04:35:20 +0800 Subject: [PATCH 05/10] =?UTF-8?q?fea:=20P4+P5=20FnOS=20=E9=80=82=E9=85=8D?= =?UTF-8?q?=E4=B8=8E=E5=A2=9E=E5=BC=BA=E2=80=94=E2=80=94Settings=20API(?= =?UTF-8?q?=E5=A4=87=E4=BB=BD=E7=9B=AE=E5=BD=95=E5=8F=AF=E9=85=8D)?= =?UTF-8?q?=E3=80=81Dockerfile=20=E5=8E=BB=20privileged+=E5=81=A5=E5=BA=B7?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E3=80=81webhook=20=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E3=80=81=E5=AE=A1=E8=AE=A1=E6=97=A5=E5=BF=97=E3=80=81=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E8=87=AA=E5=8A=A8=E6=9B=B4=E6=96=B0=E7=99=BD=E5=90=8D?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 70 ++++++++++++++++---- docker/Dockerfile | 9 ++- dockercopilot.api | 17 +++++ dockercopilot.go | 16 +++++ internal/handler/routes.go | 18 +++++ internal/handler/settings/settingshandler.go | 40 +++++++++++ internal/logic/container/renamelogic.go | 1 + internal/logic/container/restartlogic.go | 1 + internal/logic/container/restorelogic.go | 3 + internal/logic/container/startlogic.go | 1 + internal/logic/container/stoplogic.go | 1 + internal/logic/container/updatelogic.go | 3 + internal/logic/image/removelogic.go | 1 + internal/logic/settings/settingslogic.go | 57 ++++++++++++++++ internal/types/types.go | 4 ++ internal/utiles/audit.go | 53 +++++++++++++++ internal/utiles/autoupdate.go | 69 +++++++++++++++++++ internal/utiles/backupcontainer.go | 2 +- internal/utiles/backuppath.go | 6 +- internal/utiles/notify.go | 36 ++++++++++ internal/utiles/settings.go | 68 +++++++++++++++++++ 21 files changed, 456 insertions(+), 20 deletions(-) create mode 100644 internal/handler/settings/settingshandler.go create mode 100644 internal/logic/settings/settingslogic.go create mode 100644 internal/utiles/audit.go create mode 100644 internal/utiles/autoupdate.go create mode 100644 internal/utiles/notify.go create mode 100644 internal/utiles/settings.go diff --git a/README.md b/README.md index bcd86172..28f57ca7 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,38 @@ # dockerCopilot + License: AGPLv3 - + + +一个主打便捷的 Docker 容器管理工具,现已支持所有平台。 + +> **维护说明**:本项目自 v2.2.0 起由 [DongShull](https://github.com/DongShull) 独立维护(fork 自 onlyLTY/dockerCopilot v2.1.3), +> 适配飞牛 FnOS(fn_version)与绿联 UGREEN 构建,遵循 AGPLv3 协议分发。 +> 上游自 2026-07 起不再更新。 -# 介绍 +# 功能 -一个主打便捷的docker容器管理工具,现在已经支持所有平台。 -已经实现: -1. 一键更新容器 -2. 指定镜像和tag更新 +1. 一键更新容器(失败自动回滚,成功自动清理旧镜像) +2. 指定镜像和 tag 更新 3. 启动、停止、重启容器 4. 重命名容器 -5. 删除无TAG镜像 +5. 删除无 TAG 镜像 6. 删除未使用镜像 -7. 更新进度查看 -8. 备份容器设置 +7. 更新进度查看(SSE 实时推送 / 轮询双通道,支持取消,重启不丢历史) +8. 备份容器设置(JSON / docker-compose 双格式) 9. 恢复容器设置 +10. 定时自动更新白名单 +11. 操作审计日志与 webhook 通知 ## 使用 -docker compose 安装 +docker compose 安装(推荐;无需 privileged,仅挂载 docker.sock) ``` services: dockercopilot: container_name: dockercopilot restart: always - privileged: true network_mode: bridge ports: - 12712:12712 @@ -40,7 +46,47 @@ services: image: 0nlylty/dockercopilot:latest ``` +> 说明:容器内以 root 运行并挂载 `docker.sock` 即可管理 Docker,**不需要** `privileged: true`。 +> 如需进一步降权,可为 docker.sock 配置 `group_add` 并使用非 root 用户运行。 + +## 环境变量 + +| 变量 | 默认 | 说明 | +|---|---|---| +| `secretKey` | (必填) | 登录密钥(兼作 JWT 签名密钥),不少于 8 位且非纯数字 | +| `DOCKER_HOST` | unix:///var/run/docker.sock | Docker 守护进程地址 | +| `BACKUP_DIR` | /data/backups | 容器备份目录(优先级最高;否则用 Settings 页配置值) | +| `DelOldContainer` | true | 更新成功后删除旧容器(设为 `false` 保留) | +| `CLEANUP_OLD_IMAGE` | true | 更新成功后清理不再被引用的旧镜像(`false` 关闭) | +| `UPDATE_REPO` | DongShull/dockerCopilot | 版本检查与自更新仓库 | +| `UPDATE_BRANCH` | latest | 版本检查分支 | +| `githubProxy` | 空 | GitHub 代理前缀,如 `https://ghproxy.example/` | +| `REGISTRY_INSECURE` | true | registry 检测跳过 TLS 校验(`false` 严格校验) | +| `PROGRESS_STORE` | /data/config/progress.json | 任务进度持久化文件 | +| `PROGRESS_TTL_HOURS` | 24 | 已完成任务保留小时数,超期自动清理 | +| `NOTIFY_WEBHOOK_URL` | 空 | 任务完成通知 webhook(POST JSON) | +| `AUDIT_LOG` | /data/logs/audit.jsonl | 审计日志(JSON Lines) | +| `AUTOUPDATE_CRON` | 空 | 自动更新周期(cron 表达式,空=关闭),如 `0 4 * * *` | +| `AUTOUPDATE_WHITELIST` | 空 | 自动更新容器白名单(逗号分隔;`*` 表示全部有更新的容器) | + +## API 摘要 + +- `POST /api/auth` 登录换 JWT +- `GET /api/containers` / `POST /api/container/:id/{start,stop,restart,rename,update}` +- `GET /api/container/backup` / `GET /api/container/backup2compose` / `POST /api/container/backups/restore` +- `GET /api/images` / `DELETE /api/image/:id` +- `GET /api/progress` / `GET /api/progress/:taskid` / `POST /api/progress/:taskid/cancel` / `GET /api/progress/:taskid/events`(SSE) +- `GET /api/settings` / `PUT /api/settings` +- `GET /api/version` / `PUT /api/program` + ## 开发环境 -go版本:1.21+ +go 版本:1.23+(go.mod 指定);构建前需在 `front/` 放置前端产物(CI 会自动从 +[Docker-Copilot-React](https://github.com/dongshull/Docker-Copilot-React) 拉取构建)。 + +``` +go build ./... +go test ./... +``` +改造规划与缺陷清单见 [docs/ROADMAP.md](docs/ROADMAP.md)。 diff --git a/docker/Dockerfile b/docker/Dockerfile index 83592031..989d747b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,6 @@ # 使用 Alpine 作为基础镜像 FROM alpine -LABEL authors="onlyLTY" +LABEL authors="onlyLTY, DongShull" WORKDIR /app ARG TARGETPLATFORM @@ -20,5 +20,10 @@ ENV secretKey="" \ TZ="Asia/Shanghai" VOLUME ["/data"] + +# 健康检查:主页可访问即视为健康 +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD wget -q -O /dev/null http://127.0.0.1:12712/ || exit 1 + # 设置启动命令 -CMD ["./start.sh"] \ No newline at end of file +CMD ["./start.sh"] diff --git a/dockercopilot.api b/dockercopilot.api index 75bb7c02..0e04b697 100644 --- a/dockercopilot.api +++ b/dockercopilot.api @@ -91,6 +91,10 @@ type VersionReq { Type string `form:"type"` } +type UpdateSettingsReq { + BackupDir string `json:"backupDir"` +} + service dockerCopilot { @handler webindex get / @@ -177,6 +181,19 @@ service dockerCopilot { delete /image/:id (RemoveImageReq) returns (Resp) } +@server( + prefix: /api + group: settings + jwt: Auth +) +service dockerCopilot { + @handler GetSettings + get /settings returns (Resp) + + @handler UpdateSettings + put /settings (UpdateSettingsReq) returns (Resp) +} + @server( prefix: /api group: version diff --git a/dockercopilot.go b/dockercopilot.go index f9143b9e..b7f2c6e9 100644 --- a/dockercopilot.go +++ b/dockercopilot.go @@ -101,6 +101,22 @@ export const customImageLogos = { logx.Errorf("panic添加定时任务出错: %v", err) panic(err) } + // 定时自动更新:AUTOUPDATE_CRON 为 cron 表达式,AUTOUPDATE_WHITELIST 为容器白名单 + if cronExpr := os.Getenv("AUTOUPDATE_CRON"); cronExpr != "" { + _, err = corndanmu.AddFunc(cronExpr, func() { + defer func() { + if r := recover(); r != nil { + logx.Errorf("自动更新任务 panic: %v", r) + } + }() + utiles.RunAutoUpdate(ctx) + }) + if err != nil { + logx.Errorf("自动更新定时任务表达式非法: %v", err) + } else { + logx.Infof("自动更新已启用: %s, 白名单: %s", cronExpr, os.Getenv("AUTOUPDATE_WHITELIST")) + } + } corndanmu.Start() defer corndanmu.Stop() httpx.SetErrorHandler(func(err error) (int, any) { diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 5912ae57..cae07343 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -11,6 +11,7 @@ import ( icons "github.com/onlyLTY/dockerCopilot/internal/handler/icons" image "github.com/onlyLTY/dockerCopilot/internal/handler/image" progress "github.com/onlyLTY/dockerCopilot/internal/handler/progress" + settings "github.com/onlyLTY/dockerCopilot/internal/handler/settings" version "github.com/onlyLTY/dockerCopilot/internal/handler/version" "github.com/onlyLTY/dockerCopilot/internal/svc" @@ -162,6 +163,23 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { rest.WithPrefix("/api"), ) + server.AddRoutes( + []rest.Route{ + { + Method: http.MethodGet, + Path: "/settings", + Handler: settings.GetSettingsHandler(serverCtx), + }, + { + Method: http.MethodPut, + Path: "/settings", + Handler: settings.UpdateSettingsHandler(serverCtx), + }, + }, + rest.WithJwt(serverCtx.Config.Auth.AccessSecret), + rest.WithPrefix("/api"), + ) + server.AddRoutes( []rest.Route{ { diff --git a/internal/handler/settings/settingshandler.go b/internal/handler/settings/settingshandler.go new file mode 100644 index 00000000..a5468fe7 --- /dev/null +++ b/internal/handler/settings/settingshandler.go @@ -0,0 +1,40 @@ +package settings + +import ( + "net/http" + + "github.com/onlyLTY/dockerCopilot/internal/logic/settings" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func GetSettingsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + l := settings.NewSettingsLogic(r.Context(), svcCtx) + resp, err := l.GetSettings() + if err != nil { + httpx.WriteJson(w, resp.Code, resp) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} + +func UpdateSettingsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.UpdateSettingsReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := settings.NewSettingsLogic(r.Context(), svcCtx) + resp, err := l.UpdateSettings(&req) + if err != nil { + httpx.WriteJson(w, resp.Code, resp) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/logic/container/renamelogic.go b/internal/logic/container/renamelogic.go index d95da18b..c0c3f5eb 100644 --- a/internal/logic/container/renamelogic.go +++ b/internal/logic/container/renamelogic.go @@ -33,6 +33,7 @@ func (l *RenameLogic) Rename(req *types.ContainerRenameReq) (resp *types.Resp, e resp.Data = map[string]interface{}{} return resp, err } + utiles.AuditLog("container.rename", req.Id, "") resp.Code = 200 resp.Msg = "success" resp.Data = map[string]interface{}{} diff --git a/internal/logic/container/restartlogic.go b/internal/logic/container/restartlogic.go index e265cefd..da6cca70 100644 --- a/internal/logic/container/restartlogic.go +++ b/internal/logic/container/restartlogic.go @@ -33,6 +33,7 @@ func (l *RestartLogic) Restart(req *types.IdReq) (resp *types.Resp, err error) { resp.Data = map[string]interface{}{} return resp, err } + utiles.AuditLog("container.restart", req.Id, "") resp.Code = 200 resp.Msg = "success" resp.Data = map[string]interface{}{} diff --git a/internal/logic/container/restorelogic.go b/internal/logic/container/restorelogic.go index 84a12ec8..b6cb946d 100644 --- a/internal/logic/container/restorelogic.go +++ b/internal/logic/container/restorelogic.go @@ -58,6 +58,9 @@ func (l *RestoreLogic) Restore(req *types.ContainerRestoreReq) (resp *types.Resp if err != nil { l.Errorf("Error in restoreContainer: %v", err) } + final, _ := l.svcCtx.GetProgress(taskID) + utiles.NotifyTaskDone("restore", fileName, taskID, err == nil, final.Message) + utiles.AuditLog("container.restore", fileName, final.Message) }() resp.Code = 200 resp.Msg = "success" diff --git a/internal/logic/container/startlogic.go b/internal/logic/container/startlogic.go index cbf2adf2..8cb22cd7 100644 --- a/internal/logic/container/startlogic.go +++ b/internal/logic/container/startlogic.go @@ -32,6 +32,7 @@ func (l *StartLogic) Start(req *types.IdReq) (resp *types.Resp, err error) { resp.Data = map[string]interface{}{} return resp, err } + utiles.AuditLog("container.start", req.Id, "") resp.Code = 200 resp.Msg = "success" resp.Data = map[string]interface{}{} diff --git a/internal/logic/container/stoplogic.go b/internal/logic/container/stoplogic.go index dcc10387..1a1f283c 100644 --- a/internal/logic/container/stoplogic.go +++ b/internal/logic/container/stoplogic.go @@ -33,6 +33,7 @@ func (l *StopLogic) Stop(req *types.IdReq) (resp *types.Resp, err error) { resp.Data = map[string]interface{}{} return resp, err } + utiles.AuditLog("container.stop", req.Id, "") resp.Code = 200 resp.Msg = "success" resp.Data = map[string]interface{}{} diff --git a/internal/logic/container/updatelogic.go b/internal/logic/container/updatelogic.go index 6921f12d..c0a2f1ed 100644 --- a/internal/logic/container/updatelogic.go +++ b/internal/logic/container/updatelogic.go @@ -42,6 +42,9 @@ func (l *UpdateLogic) Update(req *types.ContainerUpdateReq) (resp *types.Resp, e if err != nil { l.Errorf("Error in UpdateContainer: %v", err) } + final, _ := l.svcCtx.GetProgress(taskID) + utiles.NotifyTaskDone("update", req.ContainerName, taskID, err == nil, final.Message) + utiles.AuditLog("container.update", req.ContainerName, final.Message) }() resp.Code = 200 resp.Msg = "success" diff --git a/internal/logic/image/removelogic.go b/internal/logic/image/removelogic.go index 21fe84d4..c881a522 100644 --- a/internal/logic/image/removelogic.go +++ b/internal/logic/image/removelogic.go @@ -38,6 +38,7 @@ func (l *RemoveLogic) Remove(req *types.RemoveImageReq) (resp *types.Resp, err e resp.Data = map[string]interface{}{} return resp, nil } + utiles.AuditLog("image.remove", req.Id, "") resp.Code = 200 resp.Msg = "success" resp.Data = map[string]interface{}{} diff --git a/internal/logic/settings/settingslogic.go b/internal/logic/settings/settingslogic.go new file mode 100644 index 00000000..e49e9413 --- /dev/null +++ b/internal/logic/settings/settingslogic.go @@ -0,0 +1,57 @@ +package settings + +import ( + "context" + + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" + "github.com/onlyLTY/dockerCopilot/internal/utiles" + + "github.com/zeromicro/go-zero/core/logx" +) + +type SettingsLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewSettingsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SettingsLogic { + return &SettingsLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *SettingsLogic) GetSettings() (resp *types.Resp, err error) { + resp = &types.Resp{} + s := utiles.LoadSettings() + resp.Code = 200 + resp.Msg = "success" + resp.Data = map[string]interface{}{ + "backupDir": s.BackupDir, + "effectiveBackupDir": utiles.EffectiveBackupDir(), + } + return resp, nil +} + +func (l *SettingsLogic) UpdateSettings(req *types.UpdateSettingsReq) (resp *types.Resp, err error) { + resp = &types.Resp{} + s := utiles.LoadSettings() + s.BackupDir = req.BackupDir + if saveErr := utiles.SaveSettings(s); saveErr != nil { + resp.Code = 500 + resp.Msg = "保存设置失败: " + saveErr.Error() + resp.Data = map[string]interface{}{} + return resp, nil + } + utiles.AuditLog("settings.update", "settings", "backupDir="+req.BackupDir) + resp.Code = 200 + resp.Msg = "success" + resp.Data = map[string]interface{}{ + "backupDir": s.BackupDir, + "effectiveBackupDir": utiles.EffectiveBackupDir(), + } + return resp, nil +} diff --git a/internal/types/types.go b/internal/types/types.go index a39ed544..dd981ea8 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -93,3 +93,7 @@ type VersionReq struct { type GetNewImageReq struct { ImageNameAndTag string `json:"image_name_and_tag"` } + +type UpdateSettingsReq struct { + BackupDir string `json:"backupDir"` +} diff --git a/internal/utiles/audit.go b/internal/utiles/audit.go new file mode 100644 index 00000000..3f078598 --- /dev/null +++ b/internal/utiles/audit.go @@ -0,0 +1,53 @@ +package utiles + +import ( + "encoding/json" + "os" + "path/filepath" + "sync" + "time" +) + +type auditEntry struct { + Time string `json:"time"` + Action string `json:"action"` + Target string `json:"target"` + Detail string `json:"detail"` +} + +var auditMu sync.Mutex + +func auditLogPath() string { + if p := os.Getenv("AUDIT_LOG"); p != "" { + return p + } + return "/data/logs/audit.jsonl" +} + +// AuditLog 追加一条审计记录(JSON Lines),失败静默不影响业务。 +func AuditLog(action, target, detail string) { + entry := auditEntry{ + Time: time.Now().Format("2006-01-02 15:04:05"), + Action: action, + Target: target, + Detail: detail, + } + data, err := json.Marshal(entry) + if err != nil { + return + } + auditMu.Lock() + defer auditMu.Unlock() + path := auditLogPath() + if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return + } + f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return + } + defer func(f *os.File) { + _ = f.Close() + }(f) + _, _ = f.Write(append(data, '\n')) +} diff --git a/internal/utiles/autoupdate.go b/internal/utiles/autoupdate.go new file mode 100644 index 00000000..20e8c959 --- /dev/null +++ b/internal/utiles/autoupdate.go @@ -0,0 +1,69 @@ +package utiles + +import ( + "os" + "strings" + + "github.com/google/uuid" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/zeromicro/go-zero/core/logx" +) + +// RunAutoUpdate 依据 AUTOUPDATE_WHITELIST(逗号分隔容器名,* 表示全部) +// 对有可用更新的容器执行自动更新,逐个串行避免 IO 争抢。 +func RunAutoUpdate(serviceContext *svc.ServiceContext) { + whitelistRaw := strings.TrimSpace(os.Getenv("AUTOUPDATE_WHITELIST")) + if whitelistRaw == "" { + return + } + allowAll := whitelistRaw == "*" + allowed := make(map[string]bool) + for _, name := range strings.Split(whitelistRaw, ",") { + if name = strings.TrimSpace(name); name != "" { + allowed[name] = true + } + } + + images, err := GetImagesList(serviceContext) + if err != nil { + logx.Errorf("自动更新:获取镜像列表失败: %v", err) + return + } + serviceContext.HubImageInfo.CheckUpdate(images) + + containers, err := GetContainerList(serviceContext) + if err != nil { + logx.Errorf("自动更新:获取容器列表失败: %v", err) + return + } + + for _, c := range containers { + if len(c.Names) == 0 || c.Image == "" { + continue + } + name := strings.TrimPrefix(c.Names[0], "/") + if !allowAll && !allowed[name] { + continue + } + info, ok := serviceContext.HubImageInfo.Get(c.ImageID) + if !ok || !info.NeedUpdate { + continue + } + + taskID := uuid.New().String() + taskCtx := serviceContext.RegisterTask(taskID) + logx.Infof("自动更新容器: %s (%s)", name, c.Image) + updateErr := UpdateContainer(serviceContext, taskCtx, c.ID, name, c.Image, true, taskID) + serviceContext.FinishTask(taskID) + + final, _ := serviceContext.GetProgress(taskID) + NotifyTaskDone("autoupdate", name, taskID, updateErr == nil, final.Message) + AuditLog("container.autoupdate", name, final.Message) + } +} + +// AutoUpdateConfigured 自动更新是否已配置(供启动日志使用)。 +func AutoUpdateConfigured() bool { + return strings.TrimSpace(os.Getenv("AUTOUPDATE_CRON")) != "" && + strings.TrimSpace(os.Getenv("AUTOUPDATE_WHITELIST")) != "" +} diff --git a/internal/utiles/backupcontainer.go b/internal/utiles/backupcontainer.go index 45ba6e92..95ccccf3 100644 --- a/internal/utiles/backupcontainer.go +++ b/internal/utiles/backupcontainer.go @@ -48,7 +48,7 @@ func BackupContainer(ctx *svc.ServiceContext) error { logx.Error("Error marshalling data:", err) return err } - backupDir := os.Getenv("BACKUP_DIR") // 从环境变量中获取备份目录 + backupDir := BackupDir() // env BACKUP_DIR > Settings > 默认 /data/backups if backupDir == "" { backupDir = "/data/backups" // 如果环境变量未设置,使用默认值 } diff --git a/internal/utiles/backuppath.go b/internal/utiles/backuppath.go index 6c2151db..269aa269 100644 --- a/internal/utiles/backuppath.go +++ b/internal/utiles/backuppath.go @@ -11,11 +11,7 @@ import ( var backupFilenamePattern = regexp.MustCompile(`^[A-Za-z0-9._-]+$`) func BackupDir() string { - backupDir := os.Getenv("BACKUP_DIR") - if backupDir == "" { - backupDir = "/data/backups" - } - return backupDir + return EffectiveBackupDir() } func ResolveBackupPath(filename string, allowedExts ...string) (string, error) { diff --git a/internal/utiles/notify.go b/internal/utiles/notify.go new file mode 100644 index 00000000..93277fe7 --- /dev/null +++ b/internal/utiles/notify.go @@ -0,0 +1,36 @@ +package utiles + +import ( + "bytes" + "encoding/json" + "net/http" + "os" + "time" +) + +// NotifyTaskDone 在任务收尾时向 NOTIFY_WEBHOOK_URL POST 一条 JSON 通知。 +// 未配置 webhook 时静默跳过;发送失败不影响业务。 +func NotifyTaskDone(kind, name, taskID string, ok bool, message string) { + url := os.Getenv("NOTIFY_WEBHOOK_URL") + if url == "" { + return + } + payload := map[string]interface{}{ + "kind": kind, + "name": name, + "taskID": taskID, + "ok": ok, + "message": message, + "time": time.Now().Format("2006-01-02 15:04:05"), + } + body, err := json.Marshal(payload) + if err != nil { + return + } + client := &http.Client{Timeout: 5 * time.Second} + resp, err := client.Post(url, "application/json", bytes.NewReader(body)) + if err != nil { + return + } + _ = resp.Body.Close() +} diff --git a/internal/utiles/settings.go b/internal/utiles/settings.go new file mode 100644 index 00000000..d9c757c1 --- /dev/null +++ b/internal/utiles/settings.go @@ -0,0 +1,68 @@ +package utiles + +import ( + "encoding/json" + "os" + "path/filepath" + "sync" +) + +// Settings 运行时可修改的设置(持久化到 /data/config/settings.json)。 +type Settings struct { + BackupDir string `json:"backupDir"` +} + +var settingsMu sync.Mutex + +func settingsPath() string { + if p := os.Getenv("SETTINGS_FILE"); p != "" { + return p + } + return "/data/config/settings.json" +} + +// LoadSettings 读取设置文件;文件不存在或损坏时返回空设置。 +func LoadSettings() Settings { + settingsMu.Lock() + defer settingsMu.Unlock() + var s Settings + data, err := os.ReadFile(settingsPath()) + if err != nil { + return s + } + if err = json.Unmarshal(data, &s); err != nil { + return Settings{} + } + return s +} + +// SaveSettings 写入设置文件。 +func SaveSettings(s Settings) error { + settingsMu.Lock() + defer settingsMu.Unlock() + path := settingsPath() + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + data, err := json.MarshalIndent(s, "", " ") + if err != nil { + return err + } + tmp := path + ".tmp" + if err = os.WriteFile(tmp, data, 0644); err != nil { + return err + } + return os.Rename(tmp, path) +} + +// EffectiveBackupDir 返回实际生效的备份目录: +// 环境变量 BACKUP_DIR > Settings 中的 backupDir > 默认 /data/backups。 +func EffectiveBackupDir() string { + if dir := os.Getenv("BACKUP_DIR"); dir != "" { + return dir + } + if s := LoadSettings(); s.BackupDir != "" { + return s.BackupDir + } + return "/data/backups" +} From 875274a06a99b435eb79afad575f329c9dab2108 Mon Sep 17 00:00:00 2001 From: DongShull Date: Fri, 30 Oct 2026 04:35:48 +0800 Subject: [PATCH 06/10] =?UTF-8?q?chore:=20=E7=89=88=E6=9C=AC=E5=8D=87?= =?UTF-8?q?=E8=87=B3=20v2.2.0=EF=BC=88FNOS=20v2.2.0-FNOS=EF=BC=89=EF=BC=8C?= =?UTF-8?q?CI=20Go=20=E7=89=88=E6=9C=AC=E5=AF=B9=E9=BD=90=201.24.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/FNOS.yml | 2 +- .github/workflows/UGREEN.yml | 2 +- .github/workflows/docker-build-push-UGREEN-stable.yml | 2 +- .github/workflows/docker-build-push-UGREEN.yml | 2 +- .github/workflows/docker-build-push-latest-stable.yml | 2 +- .github/workflows/docker-build-push-latest.yml | 2 +- .github/workflows/latest.yml | 2 +- fn_version | 2 +- version | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/FNOS.yml b/.github/workflows/FNOS.yml index 5b1b275e..d9545837 100644 --- a/.github/workflows/FNOS.yml +++ b/.github/workflows/FNOS.yml @@ -75,7 +75,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.23.4' + go-version: '1.24.1' cache: false - name: Build for ${{ matrix.arch }} diff --git a/.github/workflows/UGREEN.yml b/.github/workflows/UGREEN.yml index 1cc21b95..985aecb9 100644 --- a/.github/workflows/UGREEN.yml +++ b/.github/workflows/UGREEN.yml @@ -75,7 +75,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.23.4' + go-version: '1.24.1' cache: false - name: Build for ${{ matrix.arch }} diff --git a/.github/workflows/docker-build-push-UGREEN-stable.yml b/.github/workflows/docker-build-push-UGREEN-stable.yml index 18dd13da..6b119547 100644 --- a/.github/workflows/docker-build-push-UGREEN-stable.yml +++ b/.github/workflows/docker-build-push-UGREEN-stable.yml @@ -75,7 +75,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.23.4' + go-version: '1.24.1' cache: false - name: Build for ${{ matrix.arch }} diff --git a/.github/workflows/docker-build-push-UGREEN.yml b/.github/workflows/docker-build-push-UGREEN.yml index 6d27da34..f5be10c2 100644 --- a/.github/workflows/docker-build-push-UGREEN.yml +++ b/.github/workflows/docker-build-push-UGREEN.yml @@ -73,7 +73,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.23.4' + go-version: '1.24.1' cache: false - name: Build for ${{ matrix.arch }} diff --git a/.github/workflows/docker-build-push-latest-stable.yml b/.github/workflows/docker-build-push-latest-stable.yml index 27753a4b..86bd33d9 100644 --- a/.github/workflows/docker-build-push-latest-stable.yml +++ b/.github/workflows/docker-build-push-latest-stable.yml @@ -75,7 +75,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.23.4' + go-version: '1.24.1' cache: false - name: Build for ${{ matrix.arch }} diff --git a/.github/workflows/docker-build-push-latest.yml b/.github/workflows/docker-build-push-latest.yml index b9f1f705..26fa46d5 100644 --- a/.github/workflows/docker-build-push-latest.yml +++ b/.github/workflows/docker-build-push-latest.yml @@ -73,7 +73,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.23.4' + go-version: '1.24.1' cache: false - name: Build for ${{ matrix.arch }} diff --git a/.github/workflows/latest.yml b/.github/workflows/latest.yml index 58d72eed..3d12451f 100644 --- a/.github/workflows/latest.yml +++ b/.github/workflows/latest.yml @@ -75,7 +75,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.23.4' + go-version: '1.24.1' cache: false - name: Build for ${{ matrix.arch }} diff --git a/fn_version b/fn_version index f475f52f..33c7c2ed 100644 --- a/fn_version +++ b/fn_version @@ -1 +1 @@ -v2.1.3-FNOS +v2.2.0-FNOS diff --git a/version b/version index 535b2f4d..a4b6ac3d 100644 --- a/version +++ b/version @@ -1 +1 @@ -v2.1.3 +v2.2.0 From 53159a80886247ff09f12b2b3f4e3e3716ece679 Mon Sep 17 00:00:00 2001 From: DongShull Date: Fri, 30 Oct 2026 04:40:00 +0800 Subject: [PATCH 07/10] =?UTF-8?q?fix:=20Docker=20=E6=9A=82=E4=B8=8D?= =?UTF-8?q?=E5=8F=AF=E8=BE=BE=E6=97=B6=E4=B8=8D=E5=86=8D=E6=9D=80=E6=AD=BB?= =?UTF-8?q?=E8=BF=9B=E7=A8=8B=E2=80=94=E2=80=94=E5=90=AF=E5=8A=A8=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E4=B8=8E=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E8=AE=B0=E5=BD=95=E9=94=99=E8=AF=AF=E5=B9=B6=E9=87=8D?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dockercopilot.go | 20 +++++++++++++------- internal/utiles/image.go | 5 +++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/dockercopilot.go b/dockercopilot.go index b7f2c6e9..83c9a632 100644 --- a/dockercopilot.go +++ b/dockercopilot.go @@ -82,18 +82,24 @@ export const customImageLogos = { list, err := utiles.GetImagesList(ctx) if err != nil { - logx.Errorf("panic获取镜像列表出错: %v", err) - panic(err) + // Docker 暂不可用时不要杀死进程,交由定时任务稍后重试 + logx.Errorf("启动时获取镜像列表失败(稍后自动重试): %v", err) + } else { + go ctx.HubImageInfo.CheckUpdate(list) } - go ctx.HubImageInfo.CheckUpdate(list) corndanmu := cron.New(cron.WithParser(cron.NewParser( cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow, ))) _, err = corndanmu.AddFunc("30 * * * *", func() { - list, err := utiles.GetImagesList(ctx) - if err != nil { - logx.Errorf("panic获取镜像列表出错: %v", err) - panic(err) + defer func() { + if r := recover(); r != nil { + logx.Errorf("镜像更新检查 panic: %v", r) + } + }() + list, listErr := utiles.GetImagesList(ctx) + if listErr != nil { + logx.Errorf("获取镜像列表出错: %v", listErr) + return } ctx.HubImageInfo.CheckUpdate(list) }) diff --git a/internal/utiles/image.go b/internal/utiles/image.go index 46979d69..fe05a7a5 100644 --- a/internal/utiles/image.go +++ b/internal/utiles/image.go @@ -6,7 +6,7 @@ import ( "github.com/docker/docker/api/types/image" "github.com/onlyLTY/dockerCopilot/internal/svc" MyType "github.com/onlyLTY/dockerCopilot/internal/types" - "log" + "github.com/zeromicro/go-zero/core/logx" "strings" ) @@ -14,7 +14,8 @@ func GetImagesList(ctx *svc.ServiceContext) ([]MyType.Image, error) { var imagesList []MyType.Image dockerImages, err := ctx.DockerClient.ImageList(context.Background(), image.ListOptions{}) if err != nil { - log.Fatalf("Unable to fetch docker images: %s", err) + logx.Errorf("Unable to fetch docker images: %s", err) + return nil, err } for _, img := range dockerImages { From 657cfd2ddb2087dc0f6f8fb3b51369596890a7d8 Mon Sep 17 00:00:00 2001 From: DongShull Date: Fri, 30 Oct 2026 04:42:25 +0800 Subject: [PATCH 08/10] =?UTF-8?q?ci:=20DockerHub=20=E9=95=9C=E5=83=8F?= =?UTF-8?q?=E5=8F=91=E5=B8=83=E5=B7=A5=E4=BD=9C=E6=B5=81=E9=99=90=E5=AE=9A?= =?UTF-8?q?=E4=BB=85=E4=B8=8A=E6=B8=B8=E4=BB=93=E5=BA=93=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=EF=BC=8Cfork=20=E8=B5=B0=20GitHub=20Release=20=E5=88=86?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/docker-build-push-UGREEN-stable.yml | 2 ++ .github/workflows/docker-build-push-UGREEN.yml | 2 ++ .github/workflows/docker-build-push-latest-stable.yml | 2 ++ .github/workflows/docker-build-push-latest.yml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/.github/workflows/docker-build-push-UGREEN-stable.yml b/.github/workflows/docker-build-push-UGREEN-stable.yml index 6b119547..1c8ff46a 100644 --- a/.github/workflows/docker-build-push-UGREEN-stable.yml +++ b/.github/workflows/docker-build-push-UGREEN-stable.yml @@ -10,6 +10,8 @@ on: jobs: build-frontend: + # 仅上游仓库发布 DockerHub 镜像;fork 通过 GitHub Release 分发 + if: github.repository == 'onlyLTY/dockerCopilot' runs-on: ubuntu-latest steps: - name: Checkout frontend code diff --git a/.github/workflows/docker-build-push-UGREEN.yml b/.github/workflows/docker-build-push-UGREEN.yml index f5be10c2..78d2ca97 100644 --- a/.github/workflows/docker-build-push-UGREEN.yml +++ b/.github/workflows/docker-build-push-UGREEN.yml @@ -8,6 +8,8 @@ on: jobs: build-frontend: + # 仅上游仓库发布 DockerHub 镜像;fork 通过 GitHub Release 分发 + if: github.repository == 'onlyLTY/dockerCopilot' runs-on: ubuntu-latest steps: - name: Checkout frontend code diff --git a/.github/workflows/docker-build-push-latest-stable.yml b/.github/workflows/docker-build-push-latest-stable.yml index 86bd33d9..c6fc8520 100644 --- a/.github/workflows/docker-build-push-latest-stable.yml +++ b/.github/workflows/docker-build-push-latest-stable.yml @@ -10,6 +10,8 @@ on: jobs: build-frontend: + # 仅上游仓库发布 DockerHub 镜像;fork 通过 GitHub Release 分发 + if: github.repository == 'onlyLTY/dockerCopilot' runs-on: ubuntu-latest steps: - name: Checkout frontend code diff --git a/.github/workflows/docker-build-push-latest.yml b/.github/workflows/docker-build-push-latest.yml index 26fa46d5..01a2a46f 100644 --- a/.github/workflows/docker-build-push-latest.yml +++ b/.github/workflows/docker-build-push-latest.yml @@ -8,6 +8,8 @@ on: jobs: build-frontend: + # 仅上游仓库发布 DockerHub 镜像;fork 通过 GitHub Release 分发 + if: github.repository == 'onlyLTY/dockerCopilot' runs-on: ubuntu-latest steps: - name: Checkout frontend code From b868b21b33ad6d7de857d26c826f44797a035996 Mon Sep 17 00:00:00 2001 From: DongShull Date: Sat, 31 Oct 2026 23:05:46 +0800 Subject: [PATCH 09/10] =?UTF-8?q?fea:=20=E5=85=A5=E5=BA=93=E6=97=A2?= =?UTF-8?q?=E6=9C=89=E6=9C=AA=E6=8F=90=E4=BA=A4=E5=8A=9F=E8=83=BD=E5=B1=82?= =?UTF-8?q?=E2=80=94=E2=80=94MCP=20=E6=9C=8D=E5=8A=A1=E3=80=81=E7=BB=B4?= =?UTF-8?q?=E6=8A=A4=E6=8A=80=E8=83=BD=E5=8C=85=E3=80=81=E9=81=97=E7=95=99?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=B8=8E=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 此前开发但从未提交到仓库的内容,本次一并入库: - internal/mcp/:内置 MCP 服务(Streamable HTTP /mcp,27 个 dc_* 工具, 覆盖容器/镜像/备份恢复/进度/设置/自更新;Bearer / X-MCP-Token / ?token= 三通道鉴权,恒定时间比较;MCP_TOKEN=off 可显式关闭) 其中包含本次新增:dc_clean_images 批量清理工具、dc_update_container 的 image 参数改可选、版本检查 FNOS 显式语义、备份工具失败清单返回 - skills/dockercopilot-maintainer:面向维护者的开发技能包(SKILL.md + references + scripts),已通过 .dockerignore 排除出镜像 - docs/MCP.md:MCP 接入文档(27 工具清单、鉴权、客户端示例、安全建议) - internal/utiles/dockercontext.go:Docker API 分级超时常量与辅助 - internal/utiles/network.go:sanitizeEndpointSettings,克隆/备份时清理 运行期网络端点字段(NetworkID/IP/MAC 等) - internal/utiles/backup_types.go:备份条目增加 stateKnown/wasRunning/ wasPaused 状态字段,向后兼容旧格式 - 遗留测试入库:mcp / auth / servicecontext / network / restorecontainer / updateprogram / config2yaml / backup_types / backuppath / SSE 流 / login - dockercopilot_test.go、.dockerignore(去除已删除的 static/) 注:internal/mcp 与 docs/MCP.md 内同时携带本次审查批的小幅修改, 详见下一个提交的清单。 --- .dockerignore | 10 + dockercopilot_test.go | 25 ++ docs/MCP.md | 168 +++++++++ .../progress/streameventshandler_test.go | 40 ++ internal/logic/auth/loginlogic_test.go | 48 +++ internal/mcp/mcp_test.go | 210 +++++++++++ internal/mcp/server.go | 110 ++++++ internal/mcp/tools_backup.go | 120 ++++++ internal/mcp/tools_common.go | 73 ++++ internal/mcp/tools_container.go | 158 ++++++++ internal/mcp/tools_image.go | 71 ++++ internal/mcp/tools_progress.go | 46 +++ internal/mcp/tools_settings.go | 60 +++ internal/mcp/tools_version.go | 56 +++ internal/mcp/utils.go | 59 +++ internal/module/auth_test.go | 37 ++ internal/svc/servicecontext_test.go | 46 +++ .../utiles/backup_compose/config2yaml_test.go | 149 ++++++++ internal/utiles/backup_types.go | 15 + internal/utiles/backup_types_test.go | 38 ++ internal/utiles/backuppath_test.go | 31 ++ internal/utiles/dockercontext.go | 22 ++ internal/utiles/network.go | 32 ++ internal/utiles/network_test.go | 82 +++++ internal/utiles/restorecontainer_test.go | 48 +++ internal/utiles/updateprogram_test.go | 105 ++++++ skills/dockercopilot-maintainer/SKILL.md | 342 ++++++++++++++++++ .../references/api.md | 145 ++++++++ .../references/architecture.md | 205 +++++++++++ .../references/fnos.md | 77 ++++ .../references/mcp.md | 114 ++++++ .../references/release.md | 117 ++++++ .../references/troubleshooting.md | 323 +++++++++++++++++ .../scripts/build-linux.sh | 40 ++ .../scripts/dev-check.sh | 54 +++ .../scripts/package-audit.sh | 88 +++++ .../scripts/preflight.sh | 107 ++++++ .../scripts/release-check.sh | 74 ++++ 38 files changed, 3545 insertions(+) create mode 100644 .dockerignore create mode 100644 dockercopilot_test.go create mode 100644 docs/MCP.md create mode 100644 internal/handler/progress/streameventshandler_test.go create mode 100644 internal/logic/auth/loginlogic_test.go create mode 100644 internal/mcp/mcp_test.go create mode 100644 internal/mcp/server.go create mode 100644 internal/mcp/tools_backup.go create mode 100644 internal/mcp/tools_common.go create mode 100644 internal/mcp/tools_container.go create mode 100644 internal/mcp/tools_image.go create mode 100644 internal/mcp/tools_progress.go create mode 100644 internal/mcp/tools_settings.go create mode 100644 internal/mcp/tools_version.go create mode 100644 internal/mcp/utils.go create mode 100644 internal/module/auth_test.go create mode 100644 internal/svc/servicecontext_test.go create mode 100644 internal/utiles/backup_compose/config2yaml_test.go create mode 100644 internal/utiles/backup_types.go create mode 100644 internal/utiles/backup_types_test.go create mode 100644 internal/utiles/backuppath_test.go create mode 100644 internal/utiles/dockercontext.go create mode 100644 internal/utiles/network.go create mode 100644 internal/utiles/network_test.go create mode 100644 internal/utiles/restorecontainer_test.go create mode 100644 internal/utiles/updateprogram_test.go create mode 100644 skills/dockercopilot-maintainer/SKILL.md create mode 100644 skills/dockercopilot-maintainer/references/api.md create mode 100644 skills/dockercopilot-maintainer/references/architecture.md create mode 100644 skills/dockercopilot-maintainer/references/fnos.md create mode 100644 skills/dockercopilot-maintainer/references/mcp.md create mode 100644 skills/dockercopilot-maintainer/references/release.md create mode 100644 skills/dockercopilot-maintainer/references/troubleshooting.md create mode 100644 skills/dockercopilot-maintainer/scripts/build-linux.sh create mode 100644 skills/dockercopilot-maintainer/scripts/dev-check.sh create mode 100644 skills/dockercopilot-maintainer/scripts/package-audit.sh create mode 100644 skills/dockercopilot-maintainer/scripts/preflight.sh create mode 100644 skills/dockercopilot-maintainer/scripts/release-check.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..18282962 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +# 开发资料不进 Docker 构建上下文。 +# Dockerfile 采用白名单 COPY,这里再加一层保险。 +skills/ +docs/ +front/ +assets/ +.github/ +.git/ +logs/ +*.md diff --git a/dockercopilot_test.go b/dockercopilot_test.go new file mode 100644 index 00000000..8b26acb8 --- /dev/null +++ b/dockercopilot_test.go @@ -0,0 +1,25 @@ +package main + +import "testing" + +func TestValidateSecretKey(t *testing.T) { + tests := []struct { + name string + secret string + wantErr bool + }{ + {name: "empty", secret: " ", wantErr: true}, + {name: "unexpanded env", secret: "${secretKey}", wantErr: true}, + {name: "too short", secret: "abc12345", wantErr: true}, + {name: "pure digits", secret: "123456789", wantErr: true}, + {name: "valid", secret: "change-me-please", wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateSecretKey(tt.secret) + if (err != nil) != tt.wantErr { + t.Fatalf("validateSecretKey(%q) error = %v, wantErr %v", tt.secret, err, tt.wantErr) + } + }) + } +} diff --git a/docs/MCP.md b/docs/MCP.md new file mode 100644 index 00000000..56ecb396 --- /dev/null +++ b/docs/MCP.md @@ -0,0 +1,168 @@ +# MCP 接入说明 + +dockerCopilot 自 v2.2.0 起内置 MCP(Model Context Protocol)服务,Agent 可以直接调用 +容器管理、镜像管理、备份恢复、进度查询、设置与自更新等能力,无需再经过网页前端。 + +HTTP API(`/api/*`)与 MCP(`/mcp`)**并存**,脚本和旧客户端不受影响。 + +## 1. 传输与地址 + +| 项 | 值 | +|---|---| +| 协议 | Streamable HTTP(MCP 官方传输,兼容 SSE) | +| 地址 | `http://:12712/mcp` | +| 方法 | `POST`(JSON-RPC 消息)、`GET`(SSE 流)、`DELETE`(结束会话) | +| 版本 | `serverInfo.version` 与程序版本一致 | + +## 2. 鉴权 + +`/mcp` 默认要求 token,取值优先级: + +1. 环境变量 `MCP_TOKEN`(若设置) +2. 否则回退到 `secretKey`(与 `/api` 的 JWT 密钥同源) + +三种携带方式都支持,便于不同客户端: + +```bash +# 1) Bearer +curl -H "Authorization: Bearer " ... + +# 2) 自定义头(Claude Code / Cursor 等常用的 headers 配置) +curl -H "X-MCP-Token: " ... + +# 3) URL 参数(仅支持 URL 配置的客户端) +curl "http://127.0.0.1:12712/mcp?token=" +``` + +显式关闭鉴权(**仅限完全隔离的内网**): + +```yaml +environment: + - MCP_TOKEN=off +``` + +关闭时启动日志会打印一条 error 级别告警。 + +## 3. 客户端配置示例 + +### Claude Code / Cursor / Cline(Streamable HTTP) + +```json +{ + "mcpServers": { + "dockercopilot": { + "type": "streamable-http", + "url": "http://127.0.0.1:12712/mcp", + "headers": { + "Authorization": "Bearer " + } + } + } +} +``` + +### 只支持 URL 的客户端 + +```json +{ + "mcpServers": { + "dockercopilot": { + "url": "http://127.0.0.1:12712/mcp?token=" + } + } +} +``` + +## 4. 工具清单 + +共 27 个工具,命名统一以 `dc_` 开头。 + +### 通用 + +| 工具 | 说明 | +|---|---| +| `dc_ping` | 健康检查 | +| `dc_info` | 版本、监听地址、Docker daemon 真实连通性、备份目录、MCP 鉴权状态 | + +### 容器 + +| 工具 | 参数 | 说明 | +|---|---|---| +| `dc_list_containers` | - | 列出全部容器(含已停止),带 `haveUpdate` / `isCompose` 标记 | +| `dc_inspect_container` | `containerId` | 单容器完整 inspect | +| `dc_start_container` | `containerId` | 启动 | +| `dc_stop_container` | `containerId` | 停止(SIGTERM,10s 宽限) | +| `dc_restart_container` | `containerId` | 重启 | +| `dc_rename_container` | `containerId`, `newName` | 重命名 | +| `dc_update_container` | `containerId`, `containerName`, `image?`, `delOldContainer?` | 一键更新,全链路回滚;`image` 不传或留空时使用容器当前镜像 | +| `dc_autoupdate_run` | - | 手动触发一轮自动更新;**前置条件**:`AUTOUPDATE_CRON` 与 `AUTOUPDATE_WHITELIST` 均已配置,否则报错 | + +### 镜像 + +| 工具 | 参数 | 说明 | +|---|---|---| +| `dc_list_images` | - | 本地镜像列表 | +| `dc_check_image_update` | - | 立即做一次远端 digest 检查并返回结果 | +| `dc_remove_image` | `imageId`, `force?` | 删除镜像 | +| `dc_clean_images` | `filter` | 批量清理:`untagged` 删除无 TAG 镜像,`unused` 删除未使用镜像;返回 `removed` / `failed` 明细 | + +### 备份 / 恢复 + +| 工具 | 参数 | 说明 | +|---|---|---| +| `dc_backup_containers` | - | 备份为 JSON | +| `dc_backup_compose` | - | 导出 docker-compose YAML | +| `dc_list_backups` | - | 备份文件列表 | +| `dc_restore_container` | `filename`, `start?`, `force?` | 从 JSON 备份恢复;`force` 走“改名旧容器→新建→成功后删旧容器”,失败回滚 | +| `dc_delete_backup` | `filename` | 删除备份文件(不动容器) | + +### 进度 + +| 工具 | 参数 | 说明 | +|---|---|---| +| `dc_list_progress` | - | 全部任务(含重启恢复的历史任务) | +| `dc_get_progress` | `taskId` | 单任务进度 | +| `dc_cancel_progress` | `taskId` | 取消任务(步骤边界生效) | + +### 设置 / 版本 + +| 工具 | 参数 | 说明 | +|---|---|---| +| `dc_get_settings` | - | 当前与生效的备份目录 | +| `dc_update_settings` | `backupDir` | 修改备份目录(绝对路径 + 可写校验) | +| `dc_get_version` | - | 本地版本与构建时间 | +| `dc_check_program_update` | - | 检查程序新版本;FnOS 版本返回 `fnos=true` 与提示(不走通用更新链) | +| `dc_update_program` | - | 自更新并重启(会中断当前服务);FnOS 版本会明确拒绝 | + +## 5. 与 HTTP API 的对应关系 + +MCP 工具直接复用 `internal/logic` 与 `internal/utiles` 的实现,与 HTTP API 共享同一套 +锁、进度、审计与回滚逻辑,因此两条通道行为一致。 + +- 更新容器:`dc_update_container` ↔ `POST /api/container/:id/update` +- 恢复容器:`dc_restore_container` ↔ `POST /api/container/backups/restore` +- 进度:`dc_list_progress` ↔ `GET /api/progress` + +## 6. 自检 + +```bash +# 未带 token:应返回 401 +curl -s -o /dev/null -w '%{http_code}\n' -X POST http://127.0.0.1:12712/mcp \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' \ + -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' + +# 带 token:应返回 serverInfo 与 Mcp-Session-Id +curl -s -D - -X POST http://127.0.0.1:12712/mcp \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' \ + -H 'Authorization: Bearer ' \ + -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' +``` + +## 7. 安全建议 + +- `/mcp` 等同 root 级 Docker 控制面:能启停、删除容器与镜像。**不要直接暴露公网**。 +- 建议只监听内网/回环:`ports: ["127.0.0.1:12712:12712"]`。 +- 需要给不同 Agent 分配不同凭据时,用 `MCP_TOKEN` 单独设置,避免泄露 `secretKey`。 +- 不需要 MCP 时可不配置任何客户端;端点存在但没有有效 token 无法调用。 diff --git a/internal/handler/progress/streameventshandler_test.go b/internal/handler/progress/streameventshandler_test.go new file mode 100644 index 00000000..ac242197 --- /dev/null +++ b/internal/handler/progress/streameventshandler_test.go @@ -0,0 +1,40 @@ +package progress + +import ( + "net/http/httptest" + "path/filepath" + "strings" + "testing" + + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/zeromicro/go-zero/rest/pathvar" +) + +func TestStreamEventsHandlerSendsTerminalProgress(t *testing.T) { + t.Setenv("PROGRESS_STORE", filepath.Join(t.TempDir(), "progress.json")) + svcCtx := &svc.ServiceContext{ProgressStore: make(svc.ProgressStoreType)} + svcCtx.UpdateProgress("task-1", svc.TaskProgress{ + TaskID: "task-1", + Percentage: 100, + Message: "done", + Name: "demo", + IsDone: true, + }) + + req := httptest.NewRequest("GET", "/api/progress/task-1/events", nil) + req = pathvar.WithVars(req, map[string]string{"taskid": "task-1"}) + rec := httptest.NewRecorder() + + StreamEventsHandler(svcCtx)(rec, req) + + if rec.Code != 200 { + t.Fatalf("status = %d, want 200; body=%s", rec.Code, rec.Body.String()) + } + body := rec.Body.String() + if !strings.Contains(body, "retry: 3000") { + t.Fatalf("missing SSE retry hint: %q", body) + } + if !strings.Contains(body, `"taskID":"task-1"`) || !strings.Contains(body, `"isDone":true`) { + t.Fatalf("missing terminal progress payload: %q", body) + } +} diff --git a/internal/logic/auth/loginlogic_test.go b/internal/logic/auth/loginlogic_test.go new file mode 100644 index 00000000..ebe92ea7 --- /dev/null +++ b/internal/logic/auth/loginlogic_test.go @@ -0,0 +1,48 @@ +package auth + +import ( + "context" + "testing" + + "github.com/onlyLTY/dockerCopilot/internal/config" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" +) + +func TestLoginRejectsEmptyConfiguredSecret(t *testing.T) { + logic := NewLoginLogic(context.Background(), &svc.ServiceContext{Config: config.Config{}}) + resp, err := logic.Login(&types.LoginReq{SecretKey: ""}) + if err == nil { + t.Fatal("expected error when server secret is empty") + } + if resp.Code != 500 { + t.Fatalf("code = %d, want 500", resp.Code) + } +} + +func TestLoginRejectsWrongSecret(t *testing.T) { + cfg := config.Config{} + cfg.Auth.AccessSecret = "correct-secret" + logic := NewLoginLogic(context.Background(), &svc.ServiceContext{Config: cfg}) + resp, err := logic.Login(&types.LoginReq{SecretKey: "wrong-secret"}) + if err == nil { + t.Fatal("expected error for wrong secret") + } + if resp.Code != 401 { + t.Fatalf("code = %d, want 401", resp.Code) + } +} + +func TestLoginAcceptsCorrectSecret(t *testing.T) { + cfg := config.Config{} + cfg.Auth.AccessSecret = "correct-secret" + cfg.Auth.AccessExpire = 3600 + logic := NewLoginLogic(context.Background(), &svc.ServiceContext{Config: cfg}) + resp, err := logic.Login(&types.LoginReq{SecretKey: "correct-secret"}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp.Code != 200 { + t.Fatalf("code = %d, want 200", resp.Code) + } +} diff --git a/internal/mcp/mcp_test.go b/internal/mcp/mcp_test.go new file mode 100644 index 00000000..42f8f313 --- /dev/null +++ b/internal/mcp/mcp_test.go @@ -0,0 +1,210 @@ +package mcp + +import ( + "bufio" + "bytes" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/config" + "github.com/onlyLTY/dockerCopilot/internal/svc" +) + +func testContext() *svc.ServiceContext { + cfg := config.Config{} + cfg.Auth.AccessSecret = "test-secret-1234" + return &svc.ServiceContext{Config: cfg} +} + +var expectedTools = []string{ + "dc_ping", "dc_info", + "dc_list_containers", "dc_inspect_container", "dc_start_container", "dc_stop_container", + "dc_restart_container", "dc_rename_container", "dc_update_container", "dc_autoupdate_run", + "dc_list_images", "dc_check_image_update", "dc_remove_image", "dc_clean_images", + "dc_backup_containers", "dc_backup_compose", "dc_list_backups", "dc_restore_container", "dc_delete_backup", + "dc_list_progress", "dc_get_progress", "dc_cancel_progress", + "dc_get_settings", "dc_update_settings", + "dc_get_version", "dc_check_program_update", "dc_update_program", +} + +func TestAllToolsRegistered(t *testing.T) { + s := NewServer(testContext()) + got := s.ListTools() + for _, name := range expectedTools { + if _, ok := got[name]; !ok { + t.Errorf("tool %q not registered", name) + } + } + if len(got) != len(expectedTools) { + t.Errorf("registered %d tools, want %d", len(got), len(expectedTools)) + } +} + +func TestAuthMiddleware(t *testing.T) { + ctx := testContext() + next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }) + h := authMiddleware(ctx, next) + + cases := []struct { + name string + modify func(*http.Request) + want int + }{ + {"no token", func(r *http.Request) {}, http.StatusUnauthorized}, + {"wrong token", func(r *http.Request) { r.Header.Set("X-MCP-Token", "nope") }, http.StatusUnauthorized}, + {"bearer", func(r *http.Request) { r.Header.Set("Authorization", "Bearer test-secret-1234") }, http.StatusOK}, + {"x-mcp-token", func(r *http.Request) { r.Header.Set("X-MCP-Token", "test-secret-1234") }, http.StatusOK}, + {"query token", func(r *http.Request) { + q := r.URL.Query() + q.Set("token", "test-secret-1234") + r.URL.RawQuery = q.Encode() + }, http.StatusOK}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + req := httptest.NewRequest(http.MethodPost, "/mcp", nil) + tc.modify(req) + rec := httptest.NewRecorder() + h(rec, req) + if rec.Code != tc.want { + t.Fatalf("status = %d, want %d", rec.Code, tc.want) + } + }) + } +} + +// TestInitializeAndListTools 通过真实 Streamable HTTP 传输验证握手与工具暴露。 +func TestInitializeAndListTools(t *testing.T) { + ctx := testContext() + mcpServer := NewServer(ctx) + h := authMiddleware(ctx, server.NewStreamableHTTPServer(mcpServer)) + ts := httptest.NewServer(h) + defer ts.Close() + + token := "test-secret-1234" + + // 1. initialize + initBody := `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}` + resp, header := postJSONRPC(t, ts.URL, token, "", initBody) + if resp["id"] == nil { + t.Fatalf("initialize 响应缺少 id: %v", resp) + } + sessionID := header.Get("Mcp-Session-Id") + if sessionID == "" { + t.Fatalf("initialize 未返回 Mcp-Session-Id 头: %v", header) + } + + // 2. notifications/initialized + postJSONRPC(t, ts.URL, token, sessionID, `{"jsonrpc":"2.0","method":"notifications/initialized"}`) + + // 3. tools/list + listResp, _ := postJSONRPC(t, ts.URL, token, sessionID, `{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}`) + result, ok := listResp["result"].(map[string]any) + if !ok { + t.Fatalf("tools/list 响应缺少 result: %v", listResp) + } + tools, ok := result["tools"].([]any) + if !ok { + t.Fatalf("tools/list result 缺少 tools: %v", result) + } + names := make(map[string]bool, len(tools)) + for _, item := range tools { + m, _ := item.(map[string]any) + if n, _ := m["name"].(string); n != "" { + names[n] = true + } + } + for _, want := range expectedTools { + if !names[want] { + t.Errorf("tools/list 未包含 %q", want) + } + } +} + +// TestMCPRequiresAuth 确认未带 token 时传输层直接 401。 +func TestMCPRequiresAuth(t *testing.T) { + ctx := testContext() + h := authMiddleware(ctx, server.NewStreamableHTTPServer(NewServer(ctx))) + ts := httptest.NewServer(h) + defer ts.Close() + + req, _ := http.NewRequest(http.MethodPost, ts.URL, strings.NewReader(`{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}`)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json, text/event-stream") + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("请求失败: %v", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusUnauthorized { + t.Fatalf("status = %d, want 401", resp.StatusCode) + } +} + +// postJSONRPC 发送一条 JSON-RPC 消息并按需解析 JSON 或 SSE 响应。 +func postJSONRPC(t *testing.T, baseURL, token, sessionID, body string) (map[string]any, http.Header) { + t.Helper() + req, err := http.NewRequest(http.MethodPost, baseURL, bytes.NewBufferString(body)) + if err != nil { + t.Fatalf("构造请求失败: %v", err) + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json, text/event-stream") + req.Header.Set("Authorization", "Bearer "+token) + if sessionID != "" { + req.Header.Set("Mcp-Session-Id", sessionID) + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("请求失败: %v", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted { + raw, _ := io.ReadAll(resp.Body) + t.Fatalf("status = %d, body = %s", resp.StatusCode, raw) + } + raw, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatalf("读取响应失败: %v", err) + } + if len(bytes.TrimSpace(raw)) == 0 { + return map[string]any{}, resp.Header + } + return parsePayload(t, raw), resp.Header +} + +func parsePayload(t *testing.T, raw []byte) map[string]any { + t.Helper() + trimmed := bytes.TrimSpace(raw) + if trimmed[0] == '{' { + var m map[string]any + if err := json.Unmarshal(trimmed, &m); err != nil { + t.Fatalf("解析 JSON 失败: %v (%s)", err, trimmed) + } + return m + } + // SSE: data: {...} + scanner := bufio.NewScanner(bytes.NewReader(trimmed)) + scanner.Buffer(make([]byte, 0, 64*1024), 4*1024*1024) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if !strings.HasPrefix(line, "data:") { + continue + } + payload := strings.TrimSpace(strings.TrimPrefix(line, "data:")) + var m map[string]any + if err := json.Unmarshal([]byte(payload), &m); err != nil { + continue + } + return m + } + t.Fatalf("无法从响应中解析 JSON-RPC 消息: %s", raw) + return nil +} diff --git a/internal/mcp/server.go b/internal/mcp/server.go new file mode 100644 index 00000000..2f45fe36 --- /dev/null +++ b/internal/mcp/server.go @@ -0,0 +1,110 @@ +package mcp + +import ( + "crypto/subtle" + "net/http" + "os" + "strings" + + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/rest" +) + +// Version 是 MCP server 对外声明的版本,与程序版本保持一致。 +const Version = "2.2.0" + +// Register 把 dockerCopilot 的全部能力注册为 MCP 工具,并挂载到 /mcp(Streamable HTTP)。 +// 与 /api/* 并存:HTTP API 继续给脚本和旧客户端用,MCP 给 Agent 用。 +func Register(s *rest.Server, ctx *svc.ServiceContext) { + mcpServer := NewServer(ctx) + httpSrv := server.NewStreamableHTTPServer(mcpServer) + handler := authMiddleware(ctx, httpSrv) + + s.AddRoutes([]rest.Route{ + {Method: http.MethodGet, Path: "/mcp", Handler: handler}, + {Method: http.MethodPost, Path: "/mcp", Handler: handler}, + {Method: http.MethodDelete, Path: "/mcp", Handler: handler}, + }) + + logx.Infof("MCP 已挂载: /mcp(Streamable HTTP),共 %d 个工具", len(mcpServer.ListTools())) + if mcpAuthDisabled() { + logx.Error("MCP 鉴权已通过 MCP_TOKEN=off 显式关闭,请确保 /mcp 不暴露在公网") + } +} + +// NewServer 构建并注册全部 MCP 工具,供 Register 与测试复用。 +func NewServer(ctx *svc.ServiceContext) *server.MCPServer { + mcpServer := server.NewMCPServer( + "dockerCopilot", + Version, + server.WithToolCapabilities(true), + server.WithRecovery(), + ) + + registerCommonTools(mcpServer, ctx) + registerContainerTools(mcpServer, ctx) + registerImageTools(mcpServer, ctx) + registerBackupTools(mcpServer, ctx) + registerProgressTools(mcpServer, ctx) + registerSettingsTools(mcpServer, ctx) + registerVersionTools(mcpServer, ctx) + + return mcpServer +} + +// mcpAuthDisabled 允许用 MCP_TOKEN=off 显式关闭鉴权(仅建议在完全隔离的内网使用)。 +func mcpAuthDisabled() bool { + v := strings.TrimSpace(strings.ToLower(os.Getenv("MCP_TOKEN"))) + return v == "off" || v == "none" || v == "disabled" +} + +// expectedToken 优先使用 MCP_TOKEN,未设置时退回 secretKey(与 /api 的 JWT 密钥同源)。 +func expectedToken(ctx *svc.ServiceContext) string { + if t := strings.TrimSpace(os.Getenv("MCP_TOKEN")); t != "" && !mcpAuthDisabled() { + return t + } + return ctx.Config.Auth.AccessSecret +} + +// authMiddleware 保护 /mcp:支持 Bearer、X-MCP-Token 和 ?token= 三种携带方式。 +// MCP 客户端(Claude Code / Cursor / Cline 等)通常只支持自定义 Header 或 URL 参数, +// 因此三种都接受。 +func authMiddleware(ctx *svc.ServiceContext, next http.Handler) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if mcpAuthDisabled() { + next.ServeHTTP(w, r) + return + } + want := expectedToken(ctx) + if want == "" { + http.Error(w, `{"code":50000,"msg":"server secretKey 未配置,无法校验 MCP 请求"}`, http.StatusInternalServerError) + return + } + if !tokenMatch(r, want) { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(`{"code":401,"msg":"unauthorized: 需要 Authorization: Bearer 或 X-MCP-Token 或 ?token="}`)) + return + } + next.ServeHTTP(w, r) + } +} + +func tokenMatch(r *http.Request, want string) bool { + candidates := []string{ + strings.TrimSpace(strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")), + strings.TrimSpace(r.Header.Get("X-MCP-Token")), + strings.TrimSpace(r.URL.Query().Get("token")), + } + for _, got := range candidates { + if got == "" { + continue + } + if subtle.ConstantTimeCompare([]byte(got), []byte(want)) == 1 { + return true + } + } + return false +} diff --git a/internal/mcp/tools_backup.go b/internal/mcp/tools_backup.go new file mode 100644 index 00000000..172cef49 --- /dev/null +++ b/internal/mcp/tools_backup.go @@ -0,0 +1,120 @@ +package mcp + +import ( + "context" + "os" + "path/filepath" + + "github.com/google/uuid" + "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/utiles" +) + +func registerBackupTools(s *server.MCPServer, ctx *svc.ServiceContext) { + s.AddTool(mcp.NewTool("dc_backup_containers", + mcp.WithDescription("备份全部容器配置为 JSON 文件,写入生效的备份目录(BACKUP_DIR > 设置 > /data/backups);单个容器失败不中止整体备份,失败清单在返回的 failures 中"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + failures, backupErr := utiles.BackupContainer(ctx) + if backupErr != nil { + return mcp.NewToolResultError(backupErr.Error()), nil + } + utiles.AuditLog("container.backup", "all", "backup completed") + result := map[string]any{ + "result": "backup completed", + "dir": utiles.EffectiveBackupDir(), + "failures": failures, + } + if len(failures) > 0 { + result["result"] = "backup completed with failures" + } + return jsonResult(result), nil + }) + + s.AddTool(mcp.NewTool("dc_backup_compose", + mcp.WithDescription("把容器配置导出为 docker-compose YAML 备份"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + if err := utiles.Backup2Compose(ctx); err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + utiles.AuditLog("container.backup2compose", "all", "compose backup completed") + return textResult("compose backup completed, dir=" + utiles.EffectiveBackupDir()), nil + }) + + s.AddTool(mcp.NewTool("dc_list_backups", + mcp.WithDescription("列出备份目录下的 .json / .yaml 备份文件"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + list, err := utiles.BackupList(ctx) + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + return jsonResult(map[string]any{ + "dir": utiles.EffectiveBackupDir(), + "files": list, + }), nil + }) + + s.AddTool(mcp.NewTool("dc_restore_container", + mcp.WithDescription("从 JSON 备份恢复容器;force=true 时同名容器会被替换(改名旧容器→创建新容器→成功后删除旧容器,失败自动回滚)"), + mcp.WithString("filename", mcp.Required(), mcp.Description("备份文件名(仅 .json)")), + mcp.WithBoolean("start", mcp.Description("是否启动;不传则按备份记录的状态恢复")), + mcp.WithBoolean("force", mcp.Description("是否替换同名容器,默认 false(同名则跳过)")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + args := req.GetArguments() + filename, err := mustString(args, "filename") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + fullPath, err := utiles.ResolveBackupPath(filename, ".json") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + var startOverride *bool + if _, ok := args["start"]; ok { + v := optionalBool(args, "start", false) + startOverride = &v + } + force := optionalBool(args, "force", false) + + taskID := uuid.New().String() + taskCtx := ctx.RegisterTask(taskID) + defer ctx.FinishTask(taskID) + + restoreErr := utiles.RestoreContainer(taskCtx, ctx, filepath.Base(fullPath), taskID, startOverride, force) + final, _ := ctx.GetProgress(taskID) + message := final.Message + if message == "" { + message = "恢复任务已结束" + } + detail := final.DetailMsg + if detail == "" { + detail = message + } + utiles.NotifyTaskDone("restore", filename, taskID, restoreErr == nil, message) + utiles.AuditLog("container.restore", filename, detail) + if restoreErr != nil { + return mcp.NewToolResultError(restoreErr.Error()), nil + } + return jsonResult(final), nil + }) + + s.AddTool(mcp.NewTool("dc_delete_backup", + mcp.WithDescription("删除一个备份文件(只删备份文件,不动容器)"), + mcp.WithString("filename", mcp.Required(), mcp.Description("备份文件名")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + filename, err := mustString(req.GetArguments(), "filename") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + fullPath, err := utiles.ResolveBackupPath(filename, ".json", ".yaml") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + if err = os.Remove(fullPath); err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + utiles.AuditLog("container.backup.delete", filename, "deleted") + return textResult("deleted backup: " + filename), nil + }) +} diff --git a/internal/mcp/tools_common.go b/internal/mcp/tools_common.go new file mode 100644 index 00000000..9bc1995d --- /dev/null +++ b/internal/mcp/tools_common.go @@ -0,0 +1,73 @@ +package mcp + +import ( + "context" + "os" + "runtime" + "time" + + "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/config" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/utiles" +) + +func registerCommonTools(s *server.MCPServer, ctx *svc.ServiceContext) { + s.AddTool(mcp.NewTool("dc_ping", + mcp.WithDescription("健康检查:确认 dockerCopilot 服务存活"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return textResult("pong from dockerCopilot"), nil + }) + + s.AddTool(mcp.NewTool("dc_info", + mcp.WithDescription("获取服务运行信息:版本、构建时间、监听地址、Docker daemon 连通性、备份目录、MCP 鉴权状态"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + info := map[string]any{ + "version": config.Version, + "buildDate": config.BuildDate, + "host": ctx.Config.Host, + "port": ctx.Config.Port, + "dockerHost": os.Getenv("DOCKER_HOST"), + "backupDir": utiles.EffectiveBackupDir(), + "goVersion": runtime.Version(), + "autoUpdateCron": os.Getenv("AUTOUPDATE_CRON"), + "mcpAuthEnabled": !mcpAuthDisabled(), + "mcpTokenSource": mcpTokenSource(), + "toolCount": len(s.ListTools()), + } + + // 真实探测一次 daemon,避免"客户端对象创建成功"被误判成可用。 + if ctx.DockerClient == nil { + info["dockerReady"] = false + info["dockerError"] = "docker client 未初始化" + } else { + pingCtx, cancel := context.WithTimeout(ctx2, 5*time.Second) + pingResp, err := ctx.DockerClient.Ping(pingCtx) + cancel() + if err != nil { + info["dockerReady"] = false + info["dockerError"] = err.Error() + } else { + info["dockerReady"] = true + info["dockerAPIVersion"] = pingResp.APIVersion + info["dockerOSType"] = pingResp.OSType + } + } + if ctx.DockerInitErr != nil { + info["dockerInitErr"] = ctx.DockerInitErr.Error() + } + return jsonResult(info), nil + }) +} + +// mcpTokenSource 说明 /mcp 当前用的是哪个凭据,便于排障。 +func mcpTokenSource() string { + if mcpAuthDisabled() { + return "disabled" + } + if v := os.Getenv("MCP_TOKEN"); v != "" { + return "MCP_TOKEN" + } + return "secretKey" +} diff --git a/internal/mcp/tools_container.go b/internal/mcp/tools_container.go new file mode 100644 index 00000000..48bb48fc --- /dev/null +++ b/internal/mcp/tools_container.go @@ -0,0 +1,158 @@ +package mcp + +import ( + "context" + "os" + + "github.com/google/uuid" + "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/utiles" +) + +func registerContainerTools(s *server.MCPServer, ctx *svc.ServiceContext) { + s.AddTool(mcp.NewTool("dc_list_containers", + mcp.WithDescription("列出所有容器(含已停止),附带是否有可用更新、是否由 docker compose 管理"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + list, err := utiles.GetContainerList(ctx) + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + list = utiles.CheckImageUpdate(ctx, list) + return jsonResult(list), nil + }) + + s.AddTool(mcp.NewTool("dc_inspect_container", + mcp.WithDescription("查看单个容器的完整 inspect 明细"), + mcp.WithString("containerId", mcp.Required(), mcp.Description("容器 ID 或名称")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + id, err := mustString(req.GetArguments(), "containerId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + info, err := utiles.GetContainerInspect(ctx, id) + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + return jsonResult(info), nil + }) + + s.AddTool(mcp.NewTool("dc_start_container", + mcp.WithDescription("启动容器"), + mcp.WithString("containerId", mcp.Required(), mcp.Description("容器 ID 或名称")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + id, err := mustString(req.GetArguments(), "containerId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + if err = utiles.StartContainer(ctx, id); err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + utiles.AuditLog("container.start", id, "started") + return textResult("started: " + id), nil + }) + + s.AddTool(mcp.NewTool("dc_stop_container", + mcp.WithDescription("停止容器(发送 SIGTERM,10 秒宽限期)"), + mcp.WithString("containerId", mcp.Required(), mcp.Description("容器 ID 或名称")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + id, err := mustString(req.GetArguments(), "containerId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + if err = utiles.StopContainer(ctx, id); err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + utiles.AuditLog("container.stop", id, "stopped") + return textResult("stopped: " + id), nil + }) + + s.AddTool(mcp.NewTool("dc_restart_container", + mcp.WithDescription("重启容器"), + mcp.WithString("containerId", mcp.Required(), mcp.Description("容器 ID 或名称")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + id, err := mustString(req.GetArguments(), "containerId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + if err = utiles.RestartContainer(ctx, id); err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + utiles.AuditLog("container.restart", id, "restarted") + return textResult("restarted: " + id), nil + }) + + s.AddTool(mcp.NewTool("dc_rename_container", + mcp.WithDescription("重命名容器"), + mcp.WithString("containerId", mcp.Required(), mcp.Description("容器 ID 或名称")), + mcp.WithString("newName", mcp.Required(), mcp.Description("新容器名")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + args := req.GetArguments() + id, err := mustString(args, "containerId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + newName, err := mustString(args, "newName") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + if err = utiles.RenameContainer(ctx, id, newName); err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + utiles.AuditLog("container.rename", id, "renamed to "+newName) + return textResult("renamed " + id + " -> " + newName), nil + }) + + s.AddTool(mcp.NewTool("dc_update_container", + mcp.WithDescription("一键更新容器:拉取新镜像 → 停止并改名旧容器 → 克隆配置创建新容器 → 启动并等待健康检查 → 删除旧容器 → 清理旧镜像;任一步失败自动回滚旧容器"), + mcp.WithString("containerId", mcp.Required(), mcp.Description("容器 ID")), + mcp.WithString("containerName", mcp.Required(), mcp.Description("容器名(用于进度展示与旧容器命名)")), + mcp.WithString("image", mcp.Description("镜像名:tag;不传或留空则使用容器当前镜像拉取最新版本")), + mcp.WithBoolean("delOldContainer", mcp.Description("更新成功后是否删除旧容器,默认读取 DelOldContainer 环境变量(默认 true)")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + args := req.GetArguments() + id, err := mustString(args, "containerId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + name, err := mustString(args, "containerName") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + // image 可选:留空时 UpdateContainer 会回退到容器当前镜像。 + image := optionalString(args, "image") + delOld := optionalBool(args, "delOldContainer", os.Getenv("DelOldContainer") != "false") + + taskID := uuid.New().String() + taskCtx := ctx.RegisterTask(taskID) + defer ctx.FinishTask(taskID) + + updateErr := utiles.UpdateContainer(ctx, taskCtx, id, name, image, delOld, taskID) + final, _ := ctx.GetProgress(taskID) + message := final.Message + if message == "" { + message = "更新任务已结束" + } + detail := final.DetailMsg + if detail == "" { + detail = message + } + utiles.NotifyTaskDone("update", name, taskID, updateErr == nil, message) + utiles.AuditLog("container.update", name, detail) + if updateErr != nil { + return mcp.NewToolResultError(updateErr.Error()), nil + } + return jsonResult(final), nil + }) + + s.AddTool(mcp.NewTool("dc_autoupdate_run", + mcp.WithDescription("手动触发一轮自动更新:按 AUTOUPDATE_WHITELIST 过滤,仅更新运行中、非 compose 管理、非 dockerCopilot 自身的容器;全局串行,上一轮未结束时本轮跳过"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + if !utiles.AutoUpdateConfigured() { + return mcp.NewToolResultError("自动更新未配置:AUTOUPDATE_CRON 或 AUTOUPDATE_WHITELIST 为空"), nil + } + utiles.RunAutoUpdate(ctx) + return textResult("autoupdate finished"), nil + }) +} diff --git a/internal/mcp/tools_image.go b/internal/mcp/tools_image.go new file mode 100644 index 00000000..3dad31e4 --- /dev/null +++ b/internal/mcp/tools_image.go @@ -0,0 +1,71 @@ +package mcp + +import ( + "context" + + "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/utiles" +) + +func registerImageTools(s *server.MCPServer, ctx *svc.ServiceContext) { + s.AddTool(mcp.NewTool("dc_list_images", + mcp.WithDescription("列出本地镜像(含大小、tag、是否被容器占用)"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + list, err := utiles.GetImagesList(ctx) + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + return jsonResult(list), nil + }) + + s.AddTool(mcp.NewTool("dc_check_image_update", + mcp.WithDescription("立即对所有镜像做一次远端 digest 检查,返回每个镜像 ID 是否有更新(并刷新内部缓存)"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + list, err := utiles.GetImagesList(ctx) + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + ctx.HubImageInfo.CheckUpdate(list) + return jsonResult(ctx.HubImageInfo.Snapshot()), nil + }) + + s.AddTool(mcp.NewTool("dc_remove_image", + mcp.WithDescription("删除镜像;force=true 时强制删除(可能影响仍在引用它的容器)"), + mcp.WithString("imageId", mcp.Required(), mcp.Description("镜像 ID")), + mcp.WithBoolean("force", mcp.Description("是否强制删除,默认 false")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + args := req.GetArguments() + id, err := mustString(args, "imageId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + force := optionalBool(args, "force", false) + if err = utiles.RemoveImage(ctx, id, force); err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + utiles.AuditLog("image.remove", id, "removed") + return textResult("removed image: " + id), nil + }) + + s.AddTool(mcp.NewTool("dc_clean_images", + mcp.WithDescription("批量清理镜像:filter=untagged 删除无 TAG 镜像,filter=unused 删除未被任何容器引用的镜像;逐个尝试,单个失败不影响其它"), + mcp.WithString("filter", mcp.Required(), mcp.Description("清理过滤器:untagged 或 unused")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + filter, err := mustString(req.GetArguments(), "filter") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + removed, failed, cleanErr := utiles.RemoveImagesFiltered(ctx, filter) + if cleanErr != nil { + return mcp.NewToolResultError(cleanErr.Error()), nil + } + utiles.AuditLog("image.cleanup", filter, "removed and failed lists returned to caller") + return jsonResult(map[string]any{ + "filter": filter, + "removed": removed, + "failed": failed, + }), nil + }) +} diff --git a/internal/mcp/tools_progress.go b/internal/mcp/tools_progress.go new file mode 100644 index 00000000..ebf033d7 --- /dev/null +++ b/internal/mcp/tools_progress.go @@ -0,0 +1,46 @@ +package mcp + +import ( + "context" + + "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/svc" +) + +func registerProgressTools(s *server.MCPServer, ctx *svc.ServiceContext) { + s.AddTool(mcp.NewTool("dc_list_progress", + mcp.WithDescription("列出全部任务进度(当前进程内存 + 重启后从磁盘恢复的历史任务)"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return jsonResult(ctx.ListProgress()), nil + }) + + s.AddTool(mcp.NewTool("dc_get_progress", + mcp.WithDescription("查询单个任务的进度详情"), + mcp.WithString("taskId", mcp.Required(), mcp.Description("任务 ID")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + taskID, err := mustString(req.GetArguments(), "taskId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + p, ok := ctx.GetProgress(taskID) + if !ok { + return mcp.NewToolResultError("task not found: " + taskID), nil + } + return jsonResult(p), nil + }) + + s.AddTool(mcp.NewTool("dc_cancel_progress", + mcp.WithDescription("取消一个进行中的任务(任务会在下一个步骤边界退出)"), + mcp.WithString("taskId", mcp.Required(), mcp.Description("任务 ID")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + taskID, err := mustString(req.GetArguments(), "taskId") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + if !ctx.CancelTask(taskID) { + return mcp.NewToolResultError("task not cancellable: " + taskID), nil + } + return textResult("cancel requested: " + taskID), nil + }) +} diff --git a/internal/mcp/tools_settings.go b/internal/mcp/tools_settings.go new file mode 100644 index 00000000..35efae3a --- /dev/null +++ b/internal/mcp/tools_settings.go @@ -0,0 +1,60 @@ +package mcp + +import ( + "context" + "os" + "path/filepath" + "strings" + + "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/utiles" +) + +func registerSettingsTools(s *server.MCPServer, ctx *svc.ServiceContext) { + s.AddTool(mcp.NewTool("dc_get_settings", + mcp.WithDescription("读取运行时设置(当前配置的备份目录与实际生效的备份目录)"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + s := utiles.LoadSettings() + return jsonResult(map[string]any{ + "backupDir": s.BackupDir, + "effectiveBackupDir": utiles.EffectiveBackupDir(), + }), nil + }) + + s.AddTool(mcp.NewTool("dc_update_settings", + mcp.WithDescription("更新运行时设置(目前支持 backupDir,必须是绝对路径且可写)"), + mcp.WithString("backupDir", mcp.Required(), mcp.Description("备份目录绝对路径")), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + dir, err := mustString(req.GetArguments(), "backupDir") + if err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + dir = strings.TrimSpace(dir) + if !filepath.IsAbs(dir) { + return mcp.NewToolResultError("备份目录必须是绝对路径"), nil + } + if err = os.MkdirAll(dir, 0755); err != nil { + return mcp.NewToolResultError("无法创建备份目录: " + err.Error()), nil + } + testFile, testErr := os.CreateTemp(dir, ".write-test-*") + if testErr != nil { + return mcp.NewToolResultError("备份目录不可写: " + testErr.Error()), nil + } + testName := testFile.Name() + _ = testFile.Close() + _ = os.Remove(testName) + + s := utiles.LoadSettings() + s.BackupDir = dir + if err = utiles.SaveSettings(s); err != nil { + return mcp.NewToolResultError("保存设置失败: " + err.Error()), nil + } + utiles.AuditLog("settings.update", "settings", "backupDir="+dir) + return jsonResult(map[string]any{ + "backupDir": s.BackupDir, + "effectiveBackupDir": utiles.EffectiveBackupDir(), + }), nil + }) +} diff --git a/internal/mcp/tools_version.go b/internal/mcp/tools_version.go new file mode 100644 index 00000000..0c18a7c9 --- /dev/null +++ b/internal/mcp/tools_version.go @@ -0,0 +1,56 @@ +package mcp + +import ( + "context" + "errors" + + "github.com/mark3labs/mcp-go/mcp" + "github.com/mark3labs/mcp-go/server" + "github.com/onlyLTY/dockerCopilot/internal/config" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/utiles" +) + +func registerVersionTools(s *server.MCPServer, ctx *svc.ServiceContext) { + s.AddTool(mcp.NewTool("dc_get_version", + mcp.WithDescription("获取当前本地版本号与构建时间"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return jsonResult(map[string]string{ + "version": config.Version, + "buildDate": config.BuildDate, + }), nil + }) + + s.AddTool(mcp.NewTool("dc_check_program_update", + mcp.WithDescription("检查程序是否有新版本(比对远端仓库版本号);FNOS 版本由专用发布包管理,会返回 fnos=true"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + remote, err := utiles.GetRemoteVersion() + if errors.Is(err, utiles.ErrFnosManagedUpdate) { + // FNOS 版本不走通用更新链:明确告知调用方,而不是伪装成“无更新”。 + return jsonResult(map[string]any{ + "localVersion": config.Version, + "fnos": true, + "hasUpdate": false, + "hint": err.Error(), + }), nil + } + if err != nil { + return mcp.NewToolResultError("获取远程版本失败: " + err.Error()), nil + } + return jsonResult(map[string]any{ + "localVersion": config.Version, + "remoteVersion": remote, + "hasUpdate": remote != config.Version, + }), nil + }) + + s.AddTool(mcp.NewTool("dc_update_program", + mcp.WithDescription("更新 dockerCopilot 自身:下载新版本、校验、解压并重启进程(会中断当前服务)"), + ), func(ctx2 context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + if err := utiles.UpdateProgram(ctx); err != nil { + return mcp.NewToolResultError(err.Error()), nil + } + utiles.AuditLog("program.update", "self", "program update triggered") + return textResult("program update triggered, service will restart"), nil + }) +} diff --git a/internal/mcp/utils.go b/internal/mcp/utils.go new file mode 100644 index 00000000..77805aa9 --- /dev/null +++ b/internal/mcp/utils.go @@ -0,0 +1,59 @@ +package mcp + +import ( + "encoding/json" + "fmt" + + "github.com/mark3labs/mcp-go/mcp" +) + +func textResult(s string) *mcp.CallToolResult { + return mcp.NewToolResultText(s) +} + +func jsonResult(v any) *mcp.CallToolResult { + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + return mcp.NewToolResultError(fmt.Sprintf("marshal error: %v", err)) + } + return mcp.NewToolResultText(string(b)) +} + +func mustString(args map[string]any, key string) (string, error) { + v, ok := args[key] + if !ok { + return "", fmt.Errorf("missing required param: %s", key) + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("param %s must be string", key) + } + if s == "" { + return "", fmt.Errorf("param %s cannot be empty", key) + } + return s, nil +} + +func optionalBool(args map[string]any, key string, def bool) bool { + v, ok := args[key] + if !ok { + return def + } + b, ok := v.(bool) + if !ok { + return def + } + return b +} + +func optionalString(args map[string]any, key string) string { + v, ok := args[key] + if !ok { + return "" + } + s, ok := v.(string) + if !ok { + return "" + } + return s +} diff --git a/internal/module/auth_test.go b/internal/module/auth_test.go new file mode 100644 index 00000000..b479c856 --- /dev/null +++ b/internal/module/auth_test.go @@ -0,0 +1,37 @@ +package module + +import ( + "testing" + + ref "github.com/distribution/reference" +) + +func TestGetAuthURLPreservesRealmCaseAndScope(t *testing.T) { + imageRef, err := ref.ParseNormalizedNamed("docker.io/library/nginx") + if err != nil { + t.Fatal(err) + } + authURL, err := GetAuthURL(`Bearer realm="https://Auth.Example.com/Token",service="registry.docker.io"`, imageRef) + if err != nil { + t.Fatalf("GetAuthURL() error = %v", err) + } + if authURL.Host != "Auth.Example.com" || authURL.Path != "/Token" { + t.Fatalf("realm = %s, want https://Auth.Example.com/Token", authURL.String()) + } + if got := authURL.Query().Get("service"); got != "registry.docker.io" { + t.Fatalf("service = %q", got) + } + if got := authURL.Query().Get("scope"); got != "repository:library/nginx:pull" { + t.Fatalf("scope = %q", got) + } +} + +func TestGetAuthURLRejectsMalformedRealm(t *testing.T) { + imageRef, err := ref.ParseNormalizedNamed("nginx") + if err != nil { + t.Fatal(err) + } + if _, err = GetAuthURL(`Bearer realm="not-a-url",service="registry.docker.io"`, imageRef); err == nil { + t.Fatal("GetAuthURL() should reject a realm without scheme/host") + } +} diff --git a/internal/svc/servicecontext_test.go b/internal/svc/servicecontext_test.go new file mode 100644 index 00000000..52ae4826 --- /dev/null +++ b/internal/svc/servicecontext_test.go @@ -0,0 +1,46 @@ +package svc + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "sync" + "testing" +) + +func TestProgressConcurrentUpdatesPersistValidJSON(t *testing.T) { + storePath := filepath.Join(t.TempDir(), "progress.json") + t.Setenv("PROGRESS_STORE", storePath) + + ctx := &ServiceContext{ProgressStore: make(ProgressStoreType)} + var wg sync.WaitGroup + for i := 0; i < 20; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + ctx.UpdateProgress(fmt.Sprintf("task-%d", i), TaskProgress{ + TaskID: fmt.Sprintf("task-%d", i), + Percentage: 100, + Message: "done", + IsDone: true, + }) + }(i) + } + wg.Wait() + + data, err := os.ReadFile(storePath) + if err != nil { + t.Fatalf("read progress store: %v", err) + } + var stored ProgressStoreType + if err = json.Unmarshal(data, &stored); err != nil { + t.Fatalf("progress store is not valid JSON: %v\n%s", err, data) + } + if len(stored) != 20 { + t.Fatalf("stored tasks = %d, want 20", len(stored)) + } + if progress, ok := ctx.GetProgress("task-7"); !ok || !progress.IsDone { + t.Fatalf("task-7 not persisted in memory: %+v, %v", progress, ok) + } +} diff --git a/internal/utiles/backup_compose/config2yaml_test.go b/internal/utiles/backup_compose/config2yaml_test.go new file mode 100644 index 00000000..cff5205e --- /dev/null +++ b/internal/utiles/backup_compose/config2yaml_test.go @@ -0,0 +1,149 @@ +package backupCompose + +import ( + "os" + "path/filepath" + "strings" + "testing" + "time" + + composeType "github.com/compose-spec/compose-go/types" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/network" + "github.com/docker/go-connections/nat" +) + +func TestDockerConfig2ComposeYamlEmptyPortBindingsAndTopLevel(t *testing.T) { + dir := t.TempDir() + id := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + stopTimeout := 15 + containerJSON := types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + ID: id, + Name: "/demo", + Image: "sha256:old", + Platform: "linux", + HostConfig: &container.HostConfig{ + NetworkMode: "demo-net", + PortBindings: nat.PortMap{ + nat.Port("80/tcp"): {}, + }, + CapAdd: []string{"NET_ADMIN"}, + CapDrop: []string{"MKNOD"}, + DNS: []string{"1.1.1.1"}, + Resources: container.Resources{ + Devices: []container.DeviceMapping{ + {PathOnHost: "/dev/fuse", PathInContainer: "/dev/fuse", CgroupPermissions: "rwm"}, + }, + }, + RestartPolicy: container.RestartPolicy{Name: "on-failure", MaximumRetryCount: 3}, + LogConfig: container.LogConfig{Type: "json-file", Config: map[string]string{"max-size": "10m"}}, + }, + }, + Config: &container.Config{ + Hostname: id[:12], // 默认 hostname 等于短容器 ID,不应写入 compose + Image: "nginx:latest", + StopTimeout: &stopTimeout, + Labels: map[string]string{ + "com.docker.compose.project": "old-project", + "app": "demo", + }, + Healthcheck: &container.HealthConfig{ + Test: []string{"CMD-SHELL", "curl -f http://localhost/ || exit 1"}, + Interval: 30 * time.Second, + Timeout: 5 * time.Second, + Retries: 3, + }, + }, + Mounts: []types.MountPoint{ + { + Type: "volume", + Name: "demo-data", + Source: "/var/lib/docker/volumes/demo-data/_data", + Destination: "/data", + RW: true, + }, + { + Type: "tmpfs", + Destination: "/tmp/cache", + RW: true, + }, + }, + NetworkSettings: &types.NetworkSettings{ + Networks: map[string]*network.EndpointSettings{ + "demo-net": { + IPAddress: "172.18.0.5", + Aliases: []string{"demo", "0123456789ab", "real-alias"}, + }, + }, + }, + } + + if err := DockerConfig2ComposeYaml([]types.ContainerJSON{containerJSON}, dir); err != nil { + t.Fatalf("DockerConfig2ComposeYaml() error = %v", err) + } + matches, err := filepath.Glob(filepath.Join(dir, "backup-*.yaml")) + if err != nil || len(matches) != 1 { + t.Fatalf("backup files = %v, err = %v", matches, err) + } + data, err := os.ReadFile(matches[0]) + if err != nil { + t.Fatal(err) + } + text := string(data) + for _, want := range []string{ + "volumes:", + "demo-data:", + "networks:", + "demo-net:", + "healthcheck:", + "cap_add:", + "devices:", + "restart: on-failure:3", + "stop_grace_period: 15s", + "app: demo", + "type: tmpfs", + "target: /tmp/cache", + "real-alias", + } { + if !strings.Contains(text, want) { + t.Fatalf("yaml missing %q:\n%s", want, text) + } + } + for _, notWant := range []string{ + "/var/lib/docker/volumes", + "com.docker.compose.project", + "hostname: abc123", + "172.18.0.5", + "0123456789ab", + } { + if strings.Contains(text, notWant) { + t.Fatalf("yaml should not contain %q:\n%s", notWant, text) + } + } +} + +func TestFormatVolumeServiceConfigSkipsTmpfsAlreadyInHostConfig(t *testing.T) { + containerJSON := types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + HostConfig: &container.HostConfig{ + Tmpfs: map[string]string{"/tmp/cache": "size=64m"}, + }, + }, + Mounts: []types.MountPoint{ + {Type: "tmpfs", Destination: "/tmp/cache", RW: true}, + {Type: "tmpfs", Destination: "/tmp/other", RW: true}, + {Type: "volume", Source: "/var/lib/docker/volumes/anonymous/_data", Destination: "/anon", RW: true}, + }, + } + var service composeType.ServiceConfig + formatVolumeServiceConfig(containerJSON, &service) + + if len(service.Volumes) != 1 { + t.Fatalf("volumes = %#v, want only the tmpfs missing from HostConfig.Tmpfs", service.Volumes) + } + if service.Volumes[0].Target != "/tmp/other" { + t.Fatalf("volume target = %q, want /tmp/other", service.Volumes[0].Target) + } +} diff --git a/internal/utiles/backup_types.go b/internal/utiles/backup_types.go new file mode 100644 index 00000000..bc674981 --- /dev/null +++ b/internal/utiles/backup_types.go @@ -0,0 +1,15 @@ +package utiles + +import ( + dockerBackend "github.com/docker/docker/api/types/backend" +) + +// ContainerBackupEntry 是备份文件中的一条容器记录。 +// 前四个字段来自旧的 ContainerCreateConfig 备份格式,保持向后兼容; +// StateKnown 之后是新增字段,旧备份没有这些字段时按“状态未知”处理。 +type ContainerBackupEntry struct { + dockerBackend.ContainerCreateConfig + StateKnown bool `json:"stateKnown,omitempty"` + WasRunning bool `json:"wasRunning,omitempty"` + WasPaused bool `json:"wasPaused,omitempty"` +} diff --git a/internal/utiles/backup_types_test.go b/internal/utiles/backup_types_test.go new file mode 100644 index 00000000..0a5d823e --- /dev/null +++ b/internal/utiles/backup_types_test.go @@ -0,0 +1,38 @@ +package utiles + +import ( + "encoding/json" + "strings" + "testing" + + dockerBackend "github.com/docker/docker/api/types/backend" +) + +func TestContainerBackupEntryKeepsStateAndOldFormat(t *testing.T) { + entry := ContainerBackupEntry{ + ContainerCreateConfig: dockerBackend.ContainerCreateConfig{Name: "demo"}, + StateKnown: true, + WasRunning: true, + WasPaused: true, + } + data, err := json.Marshal(entry) + if err != nil { + t.Fatal(err) + } + for _, want := range []string{`"Name":"demo"`, `"stateKnown":true`, `"wasRunning":true`, `"wasPaused":true`} { + if !strings.Contains(string(data), want) { + t.Fatalf("marshaled entry missing %s: %s", want, data) + } + } + + var old []ContainerBackupEntry + if err := json.Unmarshal([]byte(`[{"Name":"old","Config":{"Image":"nginx"}}]`), &old); err != nil { + t.Fatal(err) + } + if len(old) != 1 || old[0].Name != "old" || old[0].Config == nil || old[0].Config.Image != "nginx" { + t.Fatalf("old format unmarshal failed: %+v", old) + } + if old[0].StateKnown { + t.Fatal("old format should be treated as state unknown") + } +} diff --git a/internal/utiles/backuppath_test.go b/internal/utiles/backuppath_test.go new file mode 100644 index 00000000..17110b46 --- /dev/null +++ b/internal/utiles/backuppath_test.go @@ -0,0 +1,31 @@ +package utiles + +import ( + "path/filepath" + "testing" +) + +func TestResolveBackupPathRelativeBackupDir(t *testing.T) { + t.Setenv("BACKUP_DIR", ".") + t.Setenv("SETTINGS_FILE", filepath.Join(t.TempDir(), "settings.json")) + + got, err := ResolveBackupPath("backup-2026-01-01.json", ".json") + if err != nil { + t.Fatalf("ResolveBackupPath() error = %v", err) + } + if !filepath.IsAbs(got) { + t.Fatalf("resolved path = %q, want absolute path", got) + } + if filepath.Base(got) != "backup-2026-01-01.json" { + t.Fatalf("base = %q", filepath.Base(got)) + } +} + +func TestResolveBackupPathRejectsTraversal(t *testing.T) { + t.Setenv("BACKUP_DIR", t.TempDir()) + t.Setenv("SETTINGS_FILE", filepath.Join(t.TempDir(), "settings.json")) + + if _, err := ResolveBackupPath("../escape.json", ".json"); err == nil { + t.Fatal("expected traversal error") + } +} diff --git a/internal/utiles/dockercontext.go b/internal/utiles/dockercontext.go new file mode 100644 index 00000000..3ee0178b --- /dev/null +++ b/internal/utiles/dockercontext.go @@ -0,0 +1,22 @@ +package utiles + +import ( + "context" + "time" +) + +const ( + dockerListTimeout = 60 * time.Second + dockerInspectTimeout = 60 * time.Second + dockerMutationTimeout = 2 * time.Minute + dockerNegotiateTimeout = 30 * time.Second +) + +// dockerTimeout 给单次 Docker API 调用加超时。 +// 更新/恢复的 ImagePull 使用任务上下文,不在这里限制,避免大镜像被误杀。 +func dockerTimeout(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) { + if parent == nil { + parent = context.Background() + } + return context.WithTimeout(parent, timeout) +} diff --git a/internal/utiles/network.go b/internal/utiles/network.go new file mode 100644 index 00000000..b346246c --- /dev/null +++ b/internal/utiles/network.go @@ -0,0 +1,32 @@ +package utiles + +import "github.com/docker/docker/api/types/network" + +// sanitizeEndpointSettings 只保留创建容器需要的网络配置,清掉运行期产生的 +// NetworkID/EndpointID/IP/MAC 等字段。否则把旧容器的 inspect 结果直接传给 +// ContainerCreate,可能继承失效的端点信息或造成 MAC/IP 冲突。 +func sanitizeEndpointSettings(networks map[string]*network.EndpointSettings) map[string]*network.EndpointSettings { + if len(networks) == 0 { + return nil + } + result := make(map[string]*network.EndpointSettings, len(networks)) + for name, endpoint := range networks { + if endpoint == nil { + result[name] = nil + continue + } + cleaned := endpoint.Copy() + cleaned.NetworkID = "" + cleaned.EndpointID = "" + cleaned.Gateway = "" + cleaned.IPAddress = "" + cleaned.IPPrefixLen = 0 + cleaned.IPv6Gateway = "" + cleaned.GlobalIPv6Address = "" + cleaned.GlobalIPv6PrefixLen = 0 + cleaned.MacAddress = "" + cleaned.DNSNames = nil + result[name] = cleaned + } + return result +} diff --git a/internal/utiles/network_test.go b/internal/utiles/network_test.go new file mode 100644 index 00000000..d6861414 --- /dev/null +++ b/internal/utiles/network_test.go @@ -0,0 +1,82 @@ +package utiles + +import ( + "testing" + + "github.com/docker/docker/api/types/network" +) + +func TestSanitizeEndpointSettings(t *testing.T) { + original := map[string]*network.EndpointSettings{ + "demo": { + Aliases: []string{"demo-alias"}, + MacAddress: "02:42:ac:11:00:02", + NetworkID: "net-id", + EndpointID: "endpoint-id", + Gateway: "172.18.0.1", + IPAddress: "172.18.0.5", + IPPrefixLen: 16, + IPv6Gateway: "fe80::1", + GlobalIPv6Address: "2001:db8::5", + GlobalIPv6PrefixLen: 64, + DNSNames: []string{"demo"}, + IPAMConfig: &network.EndpointIPAMConfig{ + IPv4Address: "172.18.0.9", + IPv6Address: "2001:db8::9", + }, + }, + "nil": nil, + } + + got := sanitizeEndpointSettings(original) + if got == nil { + t.Fatal("sanitizeEndpointSettings() = nil") + } + demo := got["demo"] + if demo == nil { + t.Fatal("demo endpoint missing") + } + if demo.IPAddress != "" || demo.NetworkID != "" || demo.EndpointID != "" || + demo.Gateway != "" || demo.IPPrefixLen != 0 || demo.IPv6Gateway != "" || + demo.GlobalIPv6Address != "" || demo.GlobalIPv6PrefixLen != 0 || + demo.MacAddress != "" || demo.DNSNames != nil { + t.Fatalf("operational fields were not cleared: %#v", demo) + } + if demo.IPAMConfig == nil || demo.IPAMConfig.IPv4Address != "172.18.0.9" || demo.IPAMConfig.IPv6Address != "2001:db8::9" { + t.Fatalf("IPAMConfig was not preserved: %#v", demo.IPAMConfig) + } + if len(demo.Aliases) != 1 || demo.Aliases[0] != "demo-alias" { + t.Fatalf("Aliases were not preserved: %#v", demo.Aliases) + } + if got["nil"] != nil { + t.Fatalf("nil endpoint should stay nil") + } + if original["demo"].IPAddress != "172.18.0.5" { + t.Fatal("sanitizeEndpointSettings mutated the original map") + } +} + +func TestRestoreNetworkingConfig(t *testing.T) { + if got := restoreNetworkingConfig(nil); got != nil { + t.Fatalf("restoreNetworkingConfig(nil) = %#v, want nil", got) + } + empty := &network.NetworkingConfig{} + if got := restoreNetworkingConfig(empty); got != empty { + t.Fatalf("restoreNetworkingConfig(empty) should return original pointer") + } + config := &network.NetworkingConfig{ + EndpointsConfig: map[string]*network.EndpointSettings{ + "demo": {IPAddress: "172.18.0.5", Aliases: []string{"demo"}}, + }, + } + got := restoreNetworkingConfig(config) + if got.EndpointsConfig["demo"].IPAddress != "" { + t.Fatalf("IPAddress was not cleared: %#v", got.EndpointsConfig["demo"]) + } + if len(got.EndpointsConfig["demo"].Aliases) != 1 { + t.Fatalf("Aliases were not preserved: %#v", got.EndpointsConfig["demo"]) + } + if config.EndpointsConfig["demo"].IPAddress != "172.18.0.5" { + t.Fatal("restoreNetworkingConfig mutated the input") + } +} diff --git a/internal/utiles/restorecontainer_test.go b/internal/utiles/restorecontainer_test.go new file mode 100644 index 00000000..2755c54b --- /dev/null +++ b/internal/utiles/restorecontainer_test.go @@ -0,0 +1,48 @@ +package utiles + +import ( + "strings" + "testing" + "time" +) + +func TestRestoreShouldStart(t *testing.T) { + trueValue := true + falseValue := false + tests := []struct { + name string + entry ContainerBackupEntry + override *bool + want bool + }{ + {name: "old backup defaults to start", entry: ContainerBackupEntry{}, want: true}, + {name: "known stopped stays stopped", entry: ContainerBackupEntry{StateKnown: true, WasRunning: false}, want: false}, + {name: "known running starts", entry: ContainerBackupEntry{StateKnown: true, WasRunning: true}, want: true}, + {name: "override start", entry: ContainerBackupEntry{StateKnown: true, WasRunning: false}, override: &trueValue, want: true}, + {name: "override stop", entry: ContainerBackupEntry{StateKnown: true, WasRunning: true}, override: &falseValue, want: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := restoreShouldStart(tt.entry, tt.override); got != tt.want { + t.Fatalf("restoreShouldStart() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestRestoreOldContainerName(t *testing.T) { + at := time.Date(2026, 10, 30, 12, 34, 56, 123456789, time.UTC) + got := restoreOldContainerName("demo", at) + if !strings.HasPrefix(got, "demo-dc-old-") { + t.Fatalf("restoreOldContainerName() = %q, want demo-dc-old- prefix", got) + } + if got == restoreOldContainerName("demo", at.Add(time.Nanosecond)) { + t.Fatalf("restoreOldContainerName() should be unique per timestamp") + } +} + +func TestRollbackRestoredContainerNoop(t *testing.T) { + if msg := rollbackRestoredContainer(nil, "", "", "", "", false, false); msg != "" { + t.Fatalf("rollbackRestoredContainer() = %q, want empty", msg) + } +} diff --git a/internal/utiles/updateprogram_test.go b/internal/utiles/updateprogram_test.go new file mode 100644 index 00000000..fd5411b9 --- /dev/null +++ b/internal/utiles/updateprogram_test.go @@ -0,0 +1,105 @@ +package utiles + +import ( + "archive/tar" + "compress/gzip" + "crypto/sha256" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "testing" +) + +func writeTarGz(t *testing.T, path string, entries map[string]string) { + t.Helper() + file, err := os.Create(path) + if err != nil { + t.Fatal(err) + } + defer file.Close() + + gzw := gzip.NewWriter(file) + defer gzw.Close() + tw := tar.NewWriter(gzw) + defer tw.Close() + + for name, content := range entries { + header := &tar.Header{ + Name: name, + Mode: 0644, + Size: int64(len(content)), + } + if err := tw.WriteHeader(header); err != nil { + t.Fatal(err) + } + if _, err := tw.Write([]byte(content)); err != nil { + t.Fatal(err) + } + } +} + +func TestDecompressTarGzAllowsNormalRootFile(t *testing.T) { + archive := filepath.Join(t.TempDir(), "dockerCopilot.tar.gz") + writeTarGz(t, archive, map[string]string{"dockerCopilot-new": "binary"}) + + dest := t.TempDir() + if err := decompressTarGz(archive, dest); err != nil { + t.Fatalf("decompressTarGz() error = %v", err) + } + data, err := os.ReadFile(filepath.Join(dest, "dockerCopilot-new")) + if err != nil { + t.Fatal(err) + } + if string(data) != "binary" { + t.Fatalf("content = %q, want binary", data) + } +} + +func TestDecompressTarGzRejectsTraversal(t *testing.T) { + archive := filepath.Join(t.TempDir(), "dockerCopilot.tar.gz") + writeTarGz(t, archive, map[string]string{"../escape": "bad"}) + + dest := t.TempDir() + if err := decompressTarGz(archive, dest); err == nil { + t.Fatal("decompressTarGz() expected traversal error, got nil") + } +} + +func TestVerifySHA256(t *testing.T) { + path := filepath.Join(t.TempDir(), "payload") + if err := os.WriteFile(path, []byte("payload"), 0600); err != nil { + t.Fatal(err) + } + sum := sha256.Sum256([]byte("payload")) + if err := verifySHA256(path, fmt.Sprintf("%x", sum)); err != nil { + t.Fatalf("verifySHA256() error = %v", err) + } + if err := verifySHA256(path, "deadbeef"); err == nil { + t.Fatal("verifySHA256() expected mismatch error") + } +} + +func TestDownloadFileRejectsNon200(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "not found", http.StatusNotFound) + })) + defer server.Close() + + dest := filepath.Join(t.TempDir(), "out") + if err := downloadFile(server.URL, dest); err == nil { + t.Fatal("downloadFile() expected HTTP 404 error") + } +} + +func TestFetchVersionFromURLRejectsNon200(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "not found", http.StatusNotFound) + })) + defer server.Close() + + if _, err := fetchVersionFromURL(server.URL); err == nil { + t.Fatal("fetchVersionFromURL() expected HTTP 404 error") + } +} diff --git a/skills/dockercopilot-maintainer/SKILL.md b/skills/dockercopilot-maintainer/SKILL.md new file mode 100644 index 00000000..c7982740 --- /dev/null +++ b/skills/dockercopilot-maintainer/SKILL.md @@ -0,0 +1,342 @@ +--- +name: dockercopilot-maintainer +description: | + 维护、二开、构建、发布和排障 dockerCopilot(DC)项目时使用。触发场景包括: + 修改 Go 后端、容器更新/回滚、备份与 force 恢复、Compose 导出、Docker 网络清洗、 + 进度任务与 SSE、审计日志、自更新与 SHA256、MCP(/mcp)工具增删与鉴权、HTTP API、 + FNOS/UGREEN 构建、GitHub Actions、Docker 镜像打包、日志中文化, + 以及“DC 这个项目怎么改/怎么发版/为什么失败”。 + 也适用于检查 skills/ 等开发资料是否被误打进镜像。 +metadata: + harness: + emoji: "🧭" + octop: + label: + zh: "dockerCopilot 维护" + en: "dockerCopilot Maintainer" + summary: + zh: "DC 项目的开发、构建、发布与排障全流程技能。" + en: "Full workflow skill for developing, building, releasing and troubleshooting DC." +--- + +# dockerCopilot 维护技能 + +dockerCopilot(简称 DC)是一个 Go 后端 + MCP/HTTP API 的 Docker 容器管理工具, +**已移除网页前端**:所有能力通过 `/api/*`(HTTP)与 `/mcp`(Streamable HTTP)暴露。 +本技能覆盖:代码地图、开发检查、备份恢复、更新回滚、Compose 导出、MCP 工具适配、 +FNOS/UGREEN 构建、CI/Release、镜像边界和日志排障。 + +## 0. 先确认边界 + +工作目录应为 DC 仓库根目录,特征文件: + +```text +go.mod +dockercopilot.go +docker/Dockerfile +internal/ +docs/MCP.md +version +fn_version +ugreen_version +``` + +如果不在仓库根目录,先 `cd` 到包含 `go.mod` 的目录。不要假设路径是 +`/vol1/1000/Github/dockerCopilot`;以实际仓库为准。 + +## 1. 快速预检 + +```bash +skills/dockercopilot-maintainer/scripts/preflight.sh +``` + +它会检查: + +- git 分支/工作区; +- Go、Docker、Node、npm; +- `version` / `fn_version` / `ugreen_version`; +- `internal/mcp` 工具是否可编译、`/mcp` 鉴权配置; +- Docker 守护进程是否可达; +- `.dockerignore` 是否排除 `skills`; +- Dockerfile 是否出现 `COPY .`。 + +## 2. 代码地图 + +| 路径 | 职责 | +|---|---| +| `dockercopilot.go` | 启动、配置、日志、路由注册、定时任务 | +| `internal/handler/` | HTTP handler,goctl 生成 | +| `internal/logic/` | 业务逻辑,参数校验后调用 `internal/utiles` | +| `internal/svc/` | ServiceContext:Docker 客户端、进度、设置、Hub 镜像信息 | +| `internal/utiles/` | Docker 操作、备份/恢复、更新、自更新、审计、网络清洗 | +| `internal/module/` | 镜像仓库鉴权、digest 检查 | +| `internal/types/` | 请求/响应类型 | +| `internal/mcp/` | MCP 工具层:`server.go` 注册与鉴权,`tools_*.go` 按域暴露能力 | +| `docker/Dockerfile` | 运行镜像,白名单 COPY | +| `.github/workflows/` | CI、FNOS、UGREEN、DockerHub | +| `skills/` | 开发资料,**禁止进入镜像** | + +详细说明见 `references/architecture.md`。 + +## 3. 开发检查(每次改完必跑) + +```bash +skills/dockercopilot-maintainer/scripts/dev-check.sh +# 需要 race: +skills/dockercopilot-maintainer/scripts/dev-check.sh --race +``` + +等价手动命令: + +```bash +gofmt -l $(git ls-files '*.go') +go build ./... +go vet ./... +go test ./... -count=1 +go test -race ./... -count=1 +git diff --check +``` + +要求: + +- 新增/修改 Go 文件必须 `gofmt`; +- 不允许 `go vet` 警告; +- 修 bug 先补回归测试; +- Docker 相关逻辑优先用接口/helper 做单元测试,不依赖真实 daemon; +- 提交前 `git diff --check`。 + +## 4. 高风险区域 + +### 4.1 更新容器(`internal/utiles/updatecontainer.go`) + +必须保持: + +1. inspect 旧容器,记录镜像、名称、运行/暂停状态; +2. 拉新镜像; +3. 停止旧容器(paused 先 unpause); +4. 旧容器改名; +5. 创建/启动新容器; +6. 健康检查; +7. 成功后才删除旧容器; +8. 任一步失败回滚:移除新容器、旧容器改回原名、恢复运行/暂停; +9. 旧镜像只在无容器引用时清理; +10. 旧容器删除失败只告警,不算更新失败。 + +不要改成“先删旧容器再建新容器”。 + +### 4.2 恢复(`internal/utiles/restorecontainer.go`) + +- `restoreMu` 串行化恢复; +- 默认幂等:同名容器存在则跳过,镜像不一致报错; +- `force=true`:停止 → 临时改名 → 创建/启动 → 成功才删旧; +- 失败必须 `rollbackRestoredContainer`; +- 旧备份没有 `StateKnown/WasRunning/WasPaused` 时,默认恢复后启动; +- 恢复网络配置必须经过 `restoreNetworkingConfig` / `sanitizeEndpointSettings`。 + +### 4.3 网络清洗(`internal/utiles/network.go`) + +只保留: + +- `Aliases` +- `Links` +- `DriverOpts` +- `IPAMConfig` + +清空: + +- `NetworkID` +- `EndpointID` +- `Gateway` +- `IPAddress` +- `IPPrefixLen` +- `IPv6Gateway` +- `GlobalIPv6Address` +- `MacAddress` +- `DNSNames` + +备份、更新、恢复三条链必须一致。 + +### 4.4 备份与 Compose 导出 + +- JSON 备份要保留 `Config`、`HostConfig`、`NetworkingConfig`、状态; +- Compose 导出要保留 healthcheck、devices、cap_add/cap_drop、security_opt、 + ulimits、extra_hosts、dns、tmpfs、shm_size、user、group_add、logging、 + stop_signal、stop_grace_period、sysctls、资源限制; +- 命名卷用 `MountPoint.Name`,不要导宿主路径; +- 网络别名过滤容器 ID/名称。 + +### 4.5 自更新 + +- 下载限制 512MB; +- 非 200 必须报错; +- 默认校验 SHA256; +- 解压先到临时目录,成功后再替换; +- `FNOS` 版本禁止走通用版自更新; +- `UPDATE_SKIP_CHECKSUM=true` 只作为旧版本过渡。 + +### 4.6 日志 + +- 使用中文; +- `SetupLog` 使用 `Encoding: "plain"`,输出“时间 + 级别 + 内容”; +- 不要恢复 `dockerCopilot:` 前缀; +- HTTP 404/500 等错误要以中文描述输出; +- `docker compose logs` 的前缀用 `--no-log-prefix` 去掉,不要改代码硬扛。 + +## 5. MCP 层(`internal/mcp/`) + +前端已移除,Agent 通过 `/mcp` 调用;`/api/*` 保留给脚本与旧客户端。 + +结构: + +| 文件 | 职责 | +|---|---| +| `server.go` | 构建 MCPServer、注册 26 个工具、挂载 `/mcp`、token 鉴权中间件 | +| `utils.go` | `textResult` / `jsonResult` / 参数读取等公共辅助 | +| `tools_common.go` | `dc_ping` / `dc_info`(含 Docker daemon 真实 Ping) | +| `tools_container.go` | 列表、inspect、启停重启、重命名、更新、自动更新 | +| `tools_image.go` | 镜像列表、更新检查、删除 | +| `tools_backup.go` | JSON/Compose 备份、列表、恢复、删除 | +| `tools_progress.go` | 进度列表/详情/取消 | +| `tools_settings.go` | 备份目录读写 | +| `tools_version.go` | 版本、检查更新、自更新 | + +新增工具必须: + +1. 复用 `internal/utiles` / `internal/logic`,不要在 `internal/mcp` 里重写 Docker 逻辑; +2. 名称以 `dc_` 开头、描述用中文、必填参数用 `mcp.Required()`; +3. 破坏性操作补 `utiles.AuditLog(...)`; +4. 长任务用 `ctx.RegisterTask/CancelTask/FinishTask` 并返回最终进度; +5. 在 `internal/mcp/mcp_test.go` 的 `expectedTools` 里登记,保证工具清单可回归。 + +鉴权:`MCP_TOKEN` > `secretKey`;`MCP_TOKEN=off` 关闭(仅隔离内网)。支持 +`Authorization: Bearer`、`X-MCP-Token`、`?token=` 三种方式。 + +详见 `docs/MCP.md` 与 `references/mcp.md`。 + +## 6. 本地构建 + +```bash +# amd64 + version +skills/dockercopilot-maintainer/scripts/build-linux.sh + +# arm64 + fn_version +skills/dockercopilot-maintainer/scripts/build-linux.sh arm64 fn_version +``` + +产物:`dist/linux//dockerCopilot-new`。 + +手动等价: + +```bash +VERSION=$(cat version) +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a --trimpath \ + -ldflags="-w -s -X 'github.com/onlyLTY/dockerCopilot/internal/config.Version=$VERSION' \ + -X 'github.com/onlyLTY/dockerCopilot/internal/config.BuildDate=$(date)'" \ + -o dist/linux/amd64/dockerCopilot-new . +``` + +## 7. 发布 + +```bash +skills/dockercopilot-maintainer/scripts/release-check.sh +``` + +流程: + +1. 更新 `version` / `fn_version` / `ugreen_version`(按平台); +2. 跑 `dev-check.sh --race`; +3. 跑 `package-audit.sh`; +4. 提交并推送对应分支; +5. GitHub Actions 构建后端 + Docker 镜像(前端步骤已移除); +6. 创建/上传 Release 资产(tar.gz + sha256)。 + +镜像标签: + +| 工作流 | 标签 | +|---|---| +| `docker-build-push-latest.yml` | `dockercopilot:latest-dev` | +| `docker-build-push-latest-stable.yml` | `dockercopilot:latest` | +| `docker-build-push-UGREEN.yml` | `dockercopilot:UGREEN-DEV` | +| `docker-build-push-UGREEN-stable.yml` | `dockercopilot:UGREEN` | + +详细说明见 `references/release.md`。 + +## 8. 镜像边界(本技能的关键约束) + +`skills/` 只用于开发,**不得进入镜像/发布包**。 + +三层保护: + +1. `docker/Dockerfile` 只白名单 COPY: + - `dc-back/dist/$TARGETPLATFORM/dockerCopilot` + - `dc-back/etc/.` + - `start.sh` +2. `.dockerignore` 排除 `skills/`; +3. `scripts/package-audit.sh` 检查: + - Dockerfile 没有 `COPY .` / `ADD .`; + - 没有引用 `skills`; + - `.dockerignore` 含 `skills`; + - 本地发布包不含 `skills/`。 + +每次改 Dockerfile 或打包流程后必须跑: + +```bash +skills/dockercopilot-maintainer/scripts/package-audit.sh +``` + +## 9. FNOS / UGREEN + +- `fn_version` 触发 `FNOS.yml`; +- `ugreen_version` 触发 `UGREEN.yml`; +- FNOS 版本 `config.Version` 含 `FNOS`,禁止通用版自更新覆盖; +- 启动时 Docker 不可达只记录错误,不 `os.Exit`; +- 不需要 `privileged: true`,只挂 `docker.sock`。 + +详见 `references/fnos.md`。 + +## 10. 排障 + +先看: + +```bash +docker logs -f +# 或 +docker compose logs --no-log-prefix -f +``` + +再按 `references/troubleshooting.md` 查: + +- 启动即退出; +- 页面只有占位; +- 更新/恢复失败与回滚残留; +- 端口/IP/MAC 冲突; +- registry digest 检测; +- 自更新 404 / SHA256; +- MCP 401 / 工具不可见 / 客户端握手失败; +- docker.sock 权限。 + +## 11. 交付清单 + +- [ ] `gofmt` 通过 +- [ ] `go build ./...` 通过 +- [ ] `go vet ./...` 通过 +- [ ] `go test ./... -count=1` 通过 +- [ ] 必要时 `go test -race ./...` 通过 +- [ ] 新增回归测试 +- [ ] `git diff --check` 通过 +- [ ] 日志为中文,无 `dockerCopilot:` 前缀 +- [ ] `package-audit.sh` 通过 +- [ ] `/mcp` 工具清单与 `docs/MCP.md` 一致 +- [ ] 版本文件已更新 +- [ ] 没有提交 `.env`、token +- [ ] 文档/ROADMAP 与行为一致 + +## 12. 禁止事项 + +- 不要在日志/错误里输出密钥、token、cookie; +- 不要 `COPY .` 进 Dockerfile; +- 不要把 `skills/` 打进镜像或 Release; +- 不要删除 `force` 恢复的回滚步骤; +- 不要在恢复/更新失败时静默吞错; +- 不要用 `docker system prune -a` 清理用户环境; +- 不要在没有确认时执行删除容器/镜像的破坏性命令。 diff --git a/skills/dockercopilot-maintainer/references/api.md b/skills/dockercopilot-maintainer/references/api.md new file mode 100644 index 00000000..16eee694 --- /dev/null +++ b/skills/dockercopilot-maintainer/references/api.md @@ -0,0 +1,145 @@ +# API 速查 + +> MCP(`/mcp`)与 HTTP API 并存。Agent 优先用 MCP:见 `references/mcp.md` 与 `docs/MCP.md`。 + +所有受保护接口需要 JWT: + +```http +Authorization: Bearer +``` + +登录(form): + +```http +POST /api/auth +Content-Type: application/x-www-form-urlencoded + +secretKey=... +``` + +## 容器 + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/api/containers` | 容器列表 | +| POST | `/api/container/:id/start` | 启动 | +| POST | `/api/container/:id/stop` | 停止 | +| POST | `/api/container/:id/restart` | 重启 | +| POST | `/api/container/:id/rename` | 重命名 | +| POST | `/api/container/:id/update` | 更新 | + +更新(form): + +```http +POST /api/container/:id/update +Content-Type: application/x-www-form-urlencoded + +imageNameAndTag=redis:7&containerName=redis +``` + +- `imageNameAndTag`:目标镜像,可带 tag; +- `containerName`:容器名,用于日志/回滚命名; +- 是否删除旧容器由环境变量 `DelOldContainer` 控制,不在请求体里。 + +## 备份 / 恢复 + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/api/container/backup` | 备份全部容器为 JSON | +| GET | `/api/container/backup2compose` | 导出 Compose | +| GET | `/api/container/listBackups` | 备份文件列表 | +| DELETE | `/api/container/backups` | 删除备份 | +| POST | `/api/container/backups/restore` | 恢复 | + +恢复请求: + +```json +{ + "filename": "backup-2026-10-30.json", + "start": true, + "force": false +} +``` + +- `start` 省略:按备份中的容器状态恢复; +- `force=false`:同名容器存在时跳过/补启动,镜像不一致报错; +- `force=true`:先停止并临时改名旧容器,新建成功后才删除旧容器;失败自动回滚。 + +## 镜像 + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/api/images` | 镜像列表 | +| DELETE | `/api/image/:id` | 删除镜像 | +| DELETE | `/api/images?filter=untagged\|unused` | 批量清理:无 TAG 镜像 / 未使用镜像,返回 removed/failed 明细 | + +## 进度 + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/api/progress` | 任务列表 | +| GET | `/api/progress/:taskid` | 单任务详情 | +| POST | `/api/progress/:taskid/cancel` | 取消任务 | +| GET | `/api/progress/:taskid/events` | SSE 事件流 | + +SSE 事件示例: + +```text +event: progress +data: {"taskid":"...","percentage":40,"message":"正在创建新容器","isDone":false} + +event: ping +data: {} +``` + +## 设置 + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/api/settings` | 读取设置 | +| PUT | `/api/settings` | 更新设置 | + +设置项主要包含备份目录等。`BACKUP_DIR` 环境变量优先级最高。 + +## 图标 + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/api/icons` | 读取自定义图标配置 | +| POST | `/api/icons` | 上传图标 | + +## 版本 / 自更新 + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/api/version` | 当前版本 + 远程版本 | +| PUT | `/api/program` | 触发自更新 | + +自更新依赖: + +- `UPDATE_REPO` +- `UPDATE_BRANCH` +- Release 资产 `dockerCopilot-.tar.gz` 与 `.sha256` +- 可选 `githubProxy` +- `UPDATE_SKIP_CHECKSUM=true` 仅用于旧版本过渡 + +## 错误格式 + +业务错误通常返回: + +```json +{ + "code": 50000, + "msg": "错误信息" +} +``` + +401 返回: + +```json +{ + "code": 401, + "msg": "未授权", + "data": {} +} +``` diff --git a/skills/dockercopilot-maintainer/references/architecture.md b/skills/dockercopilot-maintainer/references/architecture.md new file mode 100644 index 00000000..29292420 --- /dev/null +++ b/skills/dockercopilot-maintainer/references/architecture.md @@ -0,0 +1,205 @@ +# 架构与数据流 + +## 1. 启动链路 + +`main()`: + +1. `SetupLog("./logs")`:`logx.MustSetup` + 控制台 writer;当前使用 `Encoding: "plain"`,日志行只保留时间、级别、内容。 +2. `conf.Load` 读取 `etc/dockerCopilot.yaml`,支持环境变量覆盖。 +3. 校验 `Auth.AccessSecret`(非空、非纯数字、长度 > 8)。 +4. `rest.MustNewServer` + CORS + 401 回调。 +5. `svc.NewServiceContext(c)`: + - 创建 Docker client(`DOCKER_HOST`,默认 `unix:///var/run/docker.sock`); + - 加载进度文件; + - 初始化 Settings。 +6. 注册路由; +7. 启动 cron:镜像更新检查、自动更新白名单; +8. `server.Start()`。 + +Docker 不可达时**不退出进程**,只记录错误,由定时任务稍后重试。 + +## 2. 包职责 + +``` +internal/ +├── config/ 版本、构建时间 +├── handler/ HTTP 参数解析、响应 +├── logic/ 业务编排 +├── module/ 认证、registry digest、镜像更新检查 +├── svc/ ServiceContext、进度持久化、全局锁 +├── types/ 请求/响应结构 +└── utiles/ Docker 原子操作、备份/恢复、更新、Compose、审计 +``` + +### 2.1 `internal/utiles` 重点文件 + +| 文件 | 作用 | +|---|---| +| `getcontainerlist.go` | 容器列表 + 镜像信息 | +| `containerInspect.go` | 容器 inspect 封装 | +| `startcontainer.go` / `stopcontainer.go` / `restartcontainer.go` | 生命周期操作 | +| `renamecontainer.go` | 重命名 | +| `removeimage.go` / `image.go` | 镜像删除/列表 | +| `backupcontainer.go` | 导出容器 JSON 备份 | +| `backuppath.go` | 备份路径解析与文件名校验 | +| `backupslist.go` | 备份列表 | +| `backup2compose.go` | 导出 Compose | +| `backup_compose/config2yaml.go` | Docker inspect → compose-go 结构 | +| `restorecontainer.go` | 从 JSON 恢复,含 `force` 回滚 | +| `updatecontainer.go` | 更新容器,含回滚、健康检查、旧镜像清理 | +| `autoupdate.go` | 白名单自动更新 | +| `updateprogram.go` | 自更新下载、解压、SHA256 | +| `getRemoteVersion.go` | 远程 version 文件 | +| `audit.go` | JSONL 审计日志,10MB 轮转,0600 | +| `network.go` | 端点配置清洗 | + +## 3. 容器更新流程 + +`UpdateContainer`: + +1. `ContainerInspect` 旧容器,记录: + - 旧镜像 ID; + - 旧容器名; + - 是否运行、是否 paused; + - `Config` / `HostConfig` / `NetworkSettings`。 +2. 拉取目标镜像,流式解码进度。 +3. 如果原本运行: + - paused 先 `ContainerUnpause`; + - `ContainerStop`(SIGTERM,10s)。 +4. 旧容器改名 `-`。 +5. `ContainerCreate` 新容器: + - `Config.Image` 替换为目标镜像; + - `Hostname` 清空; + - 网络端点经 `sanitizeEndpointSettings`; + - 名称使用旧名。 +6. 如果原本运行: + - `ContainerStart`; + - 非 paused 时等待健康检查; + - 原本 paused 时启动后 `ContainerPause`。 +7. 删除旧容器(`DelOldContainer=false` 可保留)。 +8. 清理旧镜像(旧容器已删除且无引用)。 + +失败回滚: + +- 删除新容器(如果已创建); +- 旧容器改回原名; +- 原本运行则启动; +- 原本 paused 则恢复 paused。 + +## 4. 容器恢复流程 + +`RestoreContainer`: + +1. 解析文件名(只允许安全字符,防目录穿越)。 +2. 读取 JSON → `[]ContainerBackupEntry`。 +3. 串行化(`restoreMu`),避免并发恢复同名容器。 +4. 逐条: + - 校验 `Config.Image`; + - 计算目标状态: + - `startOverride != nil`:强制; + - 否则 `stateKnown`:按 `wasRunning`; + - 旧备份无状态:默认启动。 + - 同名容器存在: + - 非 `force`:镜像一致则跳过/补启动,不一致报错; + - `force`:进入替换流程。 +5. `force` 替换流程: + - 拉镜像; + - 停止旧容器(paused 先 unpause); + - 改名旧容器; + - 创建新容器; + - 启动(按目标状态); + - 成功后删除旧容器。 +6. 失败:`rollbackRestoredContainer` 清理新容器、恢复旧容器名与状态。 +7. 汇总 `completed` / `failures` 到进度详情。 + +## 5. 备份格式 + +`ContainerBackupEntry` 大致结构: + +```json +{ + "Name": "redis", + "Config": { "...": "Docker container.Config" }, + "HostConfig": { "...": "Docker container.HostConfig" }, + "NetworkingConfig": { + "EndpointsConfig": { + "bridge": { + "Aliases": ["redis"], + "IPAMConfig": null + } + } + }, + "stateKnown": true, + "wasRunning": true, + "wasPaused": false +} +``` + +兼容规则: + +- 旧 JSON 没有 `StateKnown/WasRunning/WasPaused` 时按“未知”处理; +- 恢复默认启动; +- 新增字段必须可选,不能破坏旧文件反序列化。 + +## 6. 进度与 SSE + +- `svc.TaskProgress`:`TaskID/Percentage/Message/Name/DetailMsg/IsDone`。 +- 内存 map + 文件持久化(`PROGRESS_STORE`,默认 `/data/config/progress.json`)。 +- 保存与读取在同一把锁内,临时文件 + rename 原子落盘。 +- 已完成任务按 `PROGRESS_TTL_HOURS` 清理。 +- SSE 端点:`GET /api/progress/:taskid/events`,15s 心跳。 +- 取消:`POST /api/progress/:taskid/cancel`,通过 context cancel 传播。 + +## 7. 日志与审计 + +### 7.1 运行日志 + +`SetupLog`: + +```go +logx.MustSetup(logx.LogConf{ + Path: "./logs", + Level: "info", + KeepDays: 7, + Compress: true, + Mode: "file", + Encoding: "plain", +}) +logx.AddWriter(logx.NewWriter(os.Stdout)) +``` + +- 文件:`logs/access.log`、`error.log` 等; +- 控制台同样输出; +- `plain` 格式:`时间 级别 内容`; +- 不再输出 `dockerCopilot:` 服务名前缀。 + +### 7.2 审计日志 + +`internal/utiles/audit.go`: + +- 路径:`AUDIT_LOG`,默认 `/data/logs/audit.jsonl`; +- 每行一个 JSON:`time/action/target/detail`; +- 文件权限 `0600`; +- 超过 10MB 轮转为 `.1`。 + +## 8. 配置优先级 + +| 配置 | 优先级 | +|---|---| +| 备份目录 | `BACKUP_DIR` env > Settings API > `/data/backups` | +| 进度文件 | `PROGRESS_STORE` env > 默认 | +| 审计日志 | `AUDIT_LOG` env > 默认 | +| 更新仓库 | `UPDATE_REPO` env > 默认 | +| 更新分支 | `UPDATE_BRANCH` env > 默认 | +| 代理 | `githubProxy` env | +| registry TLS | `REGISTRY_INSECURE` env | + +## 9. 镜像边界 + +Dockerfile 只 COPY: + +- `dc-back/dist/$TARGETPLATFORM/dockerCopilot` +- `dc-back/etc/` +- `start.sh` + +`skills/` 仅用于开发辅助,必须被 `.dockerignore` 排除,不进入镜像。 diff --git a/skills/dockercopilot-maintainer/references/fnos.md b/skills/dockercopilot-maintainer/references/fnos.md new file mode 100644 index 00000000..65acaff6 --- /dev/null +++ b/skills/dockercopilot-maintainer/references/fnos.md @@ -0,0 +1,77 @@ +# FNOS / UGREEN 适配 + +## 1. 版本区分 + +| 文件 | 平台 | 用途 | +|---|---|---| +| `version` | 通用 | GitHub Release、latest 镜像 | +| `fn_version` | 飞牛 FnOS | FNOS Release、飞牛专用包 | +| `ugreen_version` | 绿联 UGREEN | UGREEN Release、绿联专用包 | + +## 2. FNOS + +构建入口:`.github/workflows/FNOS.yml` + +- 触发:`fn_version` 变更 / 手动; +- 版本取自 `fn_version`; +- 产物:`dockerCopilot-.tar.gz` + `.sha256`; +- 二进制名:`dockerCopilot-new`; +- 运行逻辑: + +```go +if strings.Contains(config.Version, "FNOS") { + // 飞牛版本使用独立发布包,不访问通用版 version 文件 +} +``` + +### 注意 + +- FNOS 版本不能被通用版自更新覆盖; +- `GetRemoteVersion` 遇到 `FNOS` 直接返回本地版本; +- `UpdateProgram` 遇到 `FNOS` 直接报错,要求使用专用发布包; +- 不要删除这些判断。 + +## 3. UGREEN + +构建入口:`.github/workflows/UGREEN.yml` + +- 触发:`ugreen_version` 变更 / 手动; +- 版本取自 `ugreen_version`; +- 产物同上。 + +## 4. 权限与运行 + +DC 只要求: + +- 挂载 `/var/run/docker.sock`; +- 访问 `/data`; +- 端口 `12712`。 + +不需要 `privileged: true`。 + +如果 NAS 的 Docker socket 属于 `docker` 组,非 root 运行需要: + +```yaml +group_add: + - +``` + +## 5. 开机顺序 + +NAS 开机时 `docker.sock` 可能晚于 DC 容器就绪。启动逻辑必须: + +- Docker 初始化失败只记录错误; +- 不 `os.Exit`; +- 定时任务重试。 + +不要在启动路径恢复 `log.Fatalf`。 + +## 6. 常见问题 + +| 现象 | 检查 | +|---|---| +| FNOS 包被通用版更新覆盖 | `config.Version` 是否含 `FNOS`;`GetRemoteVersion` / `UpdateProgram` 判断是否保留 | +| 容器启动但接口 502 | 检查端口映射与 `secretKey`;`GET /` 应返回 200 JSON | +| 无法管理 Docker | socket 挂载、权限、`DOCKER_HOST` | +| 时区不对 | `TZ=Asia/Shanghai` | +| 图标不显示 | `/data/config/image` 挂载与权限 | diff --git a/skills/dockercopilot-maintainer/references/mcp.md b/skills/dockercopilot-maintainer/references/mcp.md new file mode 100644 index 00000000..7235ebab --- /dev/null +++ b/skills/dockercopilot-maintainer/references/mcp.md @@ -0,0 +1,114 @@ +# MCP 层速查(`internal/mcp/`) + +前端已移除;Agent 走 `/mcp`(Streamable HTTP),脚本走 `/api/*`,两条通道复用同一套 +`internal/utiles` / `internal/logic` 实现。 + +## 1. 端点 + +| 项 | 值 | +|---|---| +| 路径 | `/mcp` | +| 方法 | `POST`(JSON-RPC)、`GET`(SSE)、`DELETE`(结束会话) | +| 协议版本 | `2024-11-05`(客户端协商) | +| 服务端标识 | `dockerCopilot` + `mcp.Version` | + +## 2. 鉴权 + +- token 取值:`MCP_TOKEN` → 回退 `secretKey`; +- `MCP_TOKEN=off|none|disabled` 关闭鉴权(启动时打 error 告警); +- 携带方式:`Authorization: Bearer `、`X-MCP-Token: `、`?token=`; +- 校验用 `crypto/subtle.ConstantTimeCompare`,避免时序侧信道。 + +未授权返回: + +```json +{"code":401,"msg":"unauthorized: 需要 Authorization: Bearer 或 X-MCP-Token 或 ?token="} +``` + +## 3. 工具注册约定 + +```go +s.AddTool(mcp.NewTool("dc_xxx", + mcp.WithDescription("中文描述"), + mcp.WithString("containerId", mcp.Required(), mcp.Description("容器 ID 或名称")), +), func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + // 1) 解析参数 + // 2) 调用 internal/utiles 或 internal/logic + // 3) 破坏性操作写审计 + // 4) 返回 jsonResult/textResult +}) +``` + +约束: + +1. 工具名统一 `dc_` 前缀,中文描述; +2. 必填参数必须 `mcp.Required()`; +3. 工具里不做 HTTP 自调用,直接复用 Go 函数; +4. 错误用 `mcp.NewToolResultError(err.Error())` 返回,让客户端看到 `isError: true`; +5. 长任务: + + ```go + taskID := uuid.New().String() + taskCtx := ctx.RegisterTask(taskID) + defer ctx.FinishTask(taskID) + err := utiles.UpdateContainer(ctx, taskCtx, ..., taskID) + final, _ := ctx.GetProgress(taskID) + ``` + +6. 新增工具必须同步: + - `internal/mcp/mcp_test.go` 的 `expectedTools`; + - `docs/MCP.md` 工具清单; + - `dc_info` 里的 `toolCount`(自动统计,无需手改)。 + +## 4. 工具清单(27) + +| 分组 | 工具 | +|---|---| +| 通用 | `dc_ping` `dc_info` | +| 容器 | `dc_list_containers` `dc_inspect_container` `dc_start_container` `dc_stop_container` `dc_restart_container` `dc_rename_container` `dc_update_container` `dc_autoupdate_run` | +| 镜像 | `dc_list_images` `dc_check_image_update` `dc_remove_image` `dc_clean_images` | +| 备份 | `dc_backup_containers` `dc_backup_compose` `dc_list_backups` `dc_restore_container` `dc_delete_backup` | +| 进度 | `dc_list_progress` `dc_get_progress` `dc_cancel_progress` | +| 设置 | `dc_get_settings` `dc_update_settings` | +| 版本 | `dc_get_version` `dc_check_program_update` `dc_update_program` | + +## 5. 测试 + +```bash +go test ./internal/mcp/ -v +``` + +覆盖: + +- `TestAllToolsRegistered`:工具数量与名字(防漏注册/改名); +- `TestAuthMiddleware`:无 token / 错误 token / 三种正确携带方式; +- `TestInitializeAndListTools`:真实 Streamable HTTP 握手 + `tools/list`; +- `TestMCPRequiresAuth`:未授权传输层 401。 + +## 6. 手动联调 + +```bash +SID=$(curl -s -D - -o /dev/null -X POST http://127.0.0.1:12712/mcp \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' \ + -H "Authorization: Bearer $TOKEN" \ + -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}' \ + | grep -i '^mcp-session-id' | tr -d '\r' | awk '{print $2}') + +curl -s -X POST http://127.0.0.1:12712/mcp \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' \ + -H "Authorization: Bearer $TOKEN" \ + -H "Mcp-Session-Id: $SID" \ + -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"dc_info","arguments":{}}}' +``` + +## 7. 常见坑 + +| 现象 | 原因 | 处理 | +|---|---|---| +| 401 | 未带 token / token 与 `secretKey` 不一致 | 检查三种携带方式与 `MCP_TOKEN` | +| `tools/list` 为空 | 传输层未建立会话 | 先 `initialize`,后续请求带 `Mcp-Session-Id` | +| 工具报 `isError` | 业务错误(如 Docker 不可达) | 看 `content[0].text` 的错误文案 | +| 客户端连不上 | 只支持 stdio | 本项目只提供 Streamable HTTP,需客户端支持 http url | +| 工具数量变少 | `registerXxxTools` 未被 `NewServer` 调用 | 检查 `server.go` 的注册顺序 | diff --git a/skills/dockercopilot-maintainer/references/release.md b/skills/dockercopilot-maintainer/references/release.md new file mode 100644 index 00000000..e12b486e --- /dev/null +++ b/skills/dockercopilot-maintainer/references/release.md @@ -0,0 +1,117 @@ +# 构建与发布 + +## 1. 版本文件 + +| 文件 | 用途 | +|---|---| +| `version` | 通用版 / latest 发布版本 | +| `fn_version` | 飞牛 FnOS 专用版本 | +| `ugreen_version` | 绿联 UGREEN 专用版本 | + +版本号同时通过 ldflags 注入: + +```bash +-X 'github.com/onlyLTY/dockerCopilot/internal/config.Version=' +-X 'github.com/onlyLTY/dockerCopilot/internal/config.BuildDate=' +``` + +## 2. CI + +`.github/workflows/ci.yml`: + +- 触发:push / PR 到 `latest`、`dev`; +- 步骤:`go build ./...` → `go vet ./...` → `go test ./... -count=1`(前端步骤已移除)。 + +本地等价: + +```bash +skills/dockercopilot-maintainer/scripts/dev-check.sh +``` + +## 3. Release 工作流 + +| 工作流 | 触发 | 版本文件 | 产物 | +|---|---|---|---| +| `latest.yml` | `latest` 分支 | `version` | `dockerCopilot-.tar.gz` + `.sha256` | +| `FNOS.yml` | `fn_version` 变更 / 手动 | `fn_version` | 同上,飞牛专用 | +| `UGREEN.yml` | `ugreen_version` 变更 / 手动 | `ugreen_version` | 同上,绿联专用 | + +产物内是单个 `dockerCopilot-new`,`start.sh` 会在启动时把它移动为 `dockerCopilot`。 + +## 4. DockerHub 工作流 + +| 工作流 | 分支 | 镜像 tag | +|---|---|---| +| `docker-build-push-latest.yml` | `latest-dev` | `dockercopilot:latest-dev` | +| `docker-build-push-latest-stable.yml` | `latest`(`version` 变更) | `dockercopilot:latest` | +| `docker-build-push-UGREEN.yml` | `latest-dev` | `dockercopilot:UGREEN-DEV` | +| `docker-build-push-UGREEN-stable.yml` | `latest`(`ugreen_version` 变更) | `dockercopilot:UGREEN` | + +需要 Secrets: + +- `DOCKERHUB_USERNAME` +- `DOCKERHUB_TOKEN` + +fork 也可用;只要配置自己的 Secrets。 + +## 5. 镜像构建 + +`.github/workflows/docker-build-push-*.yml` 的流程: + +1. 交叉编译 `dist/linux//dockerCopilot`; +2. 整理 `dc-back-/{dist,etc}`; +3. Docker buildx 构建并推送; +4. `docker/Dockerfile` 只 COPY: + - `dc-back/dist/$TARGETPLATFORM/dockerCopilot` + - `dc-back/etc/` + - `start.sh` + +## 6. 发布前检查 + +```bash +skills/dockercopilot-maintainer/scripts/release-check.sh +``` + +检查项: + +1. `git status` 是否干净; +2. `version` 与目标 tag 是否一致; +3. `gofmt`、`go build`、`go vet`、`go test`; +4. 是否误提交 `dist/`、`logs/`、临时文件; +5. `.dockerignore` 是否包含 `skills/`; +6. Dockerfile 是否只 COPY 白名单; +7. 是否包含 `.sha256` 生成逻辑。 + +## 7. 发布后验证 + +```bash +# 二进制 +tar -tzf dockerCopilot-amd64.tar.gz + +# 校验 +sha256sum -c dockerCopilot-amd64.tar.gz.sha256 + +# 镜像内不应出现 skills +docker run --rm --entrypoint sh -c 'ls /app' +``` + +镜像 `/app` 应只有: + +```text +dockerCopilot +etc/ +start.sh +``` + +不应出现 `skills/`、`docs/`、`static/`。 + +## 8. 常见发布问题 + +| 问题 | 原因 | 处理 | +|---|---|---| +| Release 404 | `UPDATE_REPO`/`UPDATE_BRANCH` 与资产名不匹配 | 检查 `version`、仓库、资产命名 | +| 自更新 SHA256 失败 | 资产未上传 `.sha256` 或内容不匹配 | 重新生成并上传 | +| DockerHub push 失败 | Secrets 未配置或无权限 | 检查 `DOCKERHUB_USERNAME/TOKEN` | +| 镜像里出现源码 | Dockerfile 被改成 `COPY . .` | 恢复白名单 COPY | +| MCP 端点 401 | 客户端未带 token | 用 `MCP_TOKEN`/`secretKey` 配 Authorization | +| FNOS 版本被通用版覆盖 | 版本检查/更新逻辑未区分 | 保留 `FNOS` 判断 | diff --git a/skills/dockercopilot-maintainer/references/troubleshooting.md b/skills/dockercopilot-maintainer/references/troubleshooting.md new file mode 100644 index 00000000..5a9bc005 --- /dev/null +++ b/skills/dockercopilot-maintainer/references/troubleshooting.md @@ -0,0 +1,323 @@ +# 排障手册 + +## 1. 启动 + +### 启动即退出 + +日志关键字: + +```text +secretKey 配置不合法 +Docker 客户端初始化失败 +``` + +检查: + +```bash +grep -n "secretKey" etc/dockerCopilot.yaml +ls -l /var/run/docker.sock +docker version +``` + +要求: + +- `secretKey` 非空; +- 长度 > 8; +- 不能是纯数字; +- 不能包含未展开的 `${...}`。 + +### 打开首页没有界面 + +本项目已移除网页前端,`GET /` 只返回一段 JSON 状态(`API-only mode`),这是预期行为。 +管理操作走 `/api/*` 或 `/mcp`,见 `docs/MCP.md`。 + +## 2. 容器更新 + +### 更新后容器没了 / 旧容器还在 + +检查进度详情: + +```bash +curl -H "Authorization: Bearer $TOKEN" \ + http://127.0.0.1:12712/api/progress/ +``` + +重点字段: + +- `Percentage` +- `Message` +- `DetailMsg` +- `IsDone` + +日志关键字: + +```text +停止容器失败 +重命名旧容器失败 +创建新容器失败 +启动新容器失败 +新容器健康检查失败 +回滚 +``` + +### 更新成功但端口冲突 + +可能原因: + +1. 旧容器仍在运行; +2. 旧容器 paused,端口仍被占用; +3. 新容器启动前旧容器未停止。 + +处理: + +```bash +docker ps -a --filter name= +docker inspect --format '{{.State.Status}} {{.State.Paused}}' +``` + +`force` 恢复/更新会先停止并改名旧容器;若仍冲突,检查是否有其他容器占用同一端口。 + +### 健康检查超时 + +`waitForContainerHealthy` 默认最多 90 秒。 + +如果容器 `health-start-period` 很长,可能误判。临时处理: + +- 去掉/缩短 healthcheck; +- 或调整 `waitForContainerHealthy` 的超时计算(建议按 `StartPeriod + Interval*Retries` 动态计算,并设上限)。 + +## 3. 备份 / 恢复 + +### 恢复后容器是停止的 + +检查备份 JSON 是否含: + +```json +"stateKnown": true, +"wasRunning": true, +"wasPaused": false +``` + +旧备份没有这些字段时,`restoreShouldStart` 默认返回 `true`。如果仍然停止,检查请求里的 `start` 是否显式传了 `false`。 + +### 同名容器已存在 + +默认行为: + +- 镜像一致:跳过创建,必要时补启动; +- 镜像不一致:报错,提示使用 `force=true`。 + +要覆盖: + +```json +{"filename":"backup.json","force":true} +``` + +### `force=true` 失败后旧容器不见了 + +理论上不会:旧容器先改名,不删除;失败会改回原名。 + +检查: + +```bash +docker ps -a --filter name=-dc-old- +``` + +如果看到 `-dc-old-` 容器,说明回滚改名失败。日志会带: + +```text +回滚异常: 旧容器改回原名失败 +``` + +手动恢复: + +```bash +docker rename -dc-old- +docker start +``` + +### 备份文件读取失败 + +`ResolveBackupPath` 只允许安全文件名: + +- 大小写字母; +- 数字; +- 短横线; +- `.json` 后缀。 + +不要传路径、`..`、斜杠。 + +## 4. 网络 + +### 重建后 IP / MAC 冲突 + +确认是否经过: + +```go +sanitizeEndpointSettings(...) +``` + +应清空: + +- `NetworkID` +- `EndpointID` +- `Gateway` +- `IPAddress` +- `MacAddress` +- `DNSNames` + +保留: + +- `Aliases` +- `Links` +- `DriverOpts` +- `IPAMConfig` + +### 自定义网络丢失 + +Compose 导出只保留非 `bridge/host/none` 的网络;恢复 JSON 时 `NetworkingConfig` 必须包含 `EndpointsConfig`。 + +检查备份: + +```bash +jq '.NetworkingConfig.EndpointsConfig' backup.json +``` + +## 5. 镜像更新检测 + +### 总是提示有更新 + +检查: + +1. registry 是否需要认证; +2. `GetDigest` 是否拿到远程 digest; +3. 本地 `RepoDigests` 是否为空; +4. 是否配置了 `REGISTRY_INSECURE`; +5. 代理是否污染 registry 请求。 + +日志关键字: + +```text +获取token失败 +获取digest失败 +未在本地获取到repoDigest +Digest为空 +``` + +### 私有镜像无法检测 + +`GetBearerHeader` 会使用 `registryAuth`;若没有凭据,只能判断公开接口。 + +## 6. 自更新 + +### 404 + +检查: + +- `UPDATE_REPO` +- `UPDATE_BRANCH` +- `version` 文件内容 +- Release 资产名:`dockerCopilot-.tar.gz` +- `githubProxy` 是否拼接正确 + +日志/错误可能显示: + +```text +获取版本信息失败:未找到 +下载 ... 失败:未找到 +``` + +### SHA256 失败 + +- 确认 `.sha256` 与 tar.gz 同批上传; +- 不要手动改包; +- 旧版本过渡可临时 `UPDATE_SKIP_CHECKSUM=true`,但不推荐长期使用。 + +### 解压后找不到 `dockerCopilot-new` + +发布包结构应为: + +```text +dockerCopilot-new +``` + +或旧结构: + +```text +dist/linux//dockerCopilot-new +``` + +## 7. 日志 + +### 日志中间出现 `dockerCopilot` + +两种来源: + +1. `docker compose logs` 的服务名前缀: + + ```bash + docker compose logs --no-log-prefix -f + ``` + +2. 旧版本 `logx` 配置带了服务名。当前 `SetupLog` 使用: + + ```go + Encoding: "plain" + ``` + + 输出应为: + + ```text + 2026-10-30 01:20:11 INFO 备份容器开始 + ``` + +### 日志是 JSON + +检查 `SetupLog` 是否被改回默认 JSON。应保留: + +```go +Encoding: "plain" +``` + +### 日志级别 + +`SetupLog` 当前固定 `Level: "info"`。需要 debug 时临时改为 `debug`,不要提交。 + +## 8. Docker / 权限 + +### `permission denied` 访问 docker.sock + +```bash +ls -l /var/run/docker.sock +``` + +容器内运行需要挂载 socket;非 root 运行需要 `group_add` 对应 docker 组 GID。 + +### Docker 暂不可用 + +启动时 Docker 不可达不会退出;定时任务会重试。检查: + +```bash +docker version +echo $DOCKER_HOST +``` + +## 9. MCP + +### `/mcp` 返回 401 + +- 确认 token:`MCP_TOKEN` 优先,否则用 `secretKey`; +- 三种携带方式任选其一:`Authorization: Bearer`、`X-MCP-Token`、`?token=`; +- 若刻意关闭:`MCP_TOKEN=off`(仅隔离内网)。 + +### 客户端握手失败 / 工具为空 + +- 本项目只提供 Streamable HTTP,不支持 stdio; +- 先 `initialize` 拿 `Mcp-Session-Id`,后续请求必须带上; +- `Accept` 需包含 `application/json, text/event-stream`; +- 启动日志应出现 `MCP 已挂载: /mcp ... 共 26 个工具`,没有则检查 `mcp.Register` 是否被调用。 + +### 工具返回 `isError` + +业务错误(如 Docker 不可达)会以 `isError: true` + 文本返回,读 `content[0].text`。 +用 `dc_info` 看 `dockerReady` / `dockerError`。 diff --git a/skills/dockercopilot-maintainer/scripts/build-linux.sh b/skills/dockercopilot-maintainer/scripts/build-linux.sh new file mode 100644 index 00000000..0831cde1 --- /dev/null +++ b/skills/dockercopilot-maintainer/scripts/build-linux.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# 本地交叉编译 Linux 二进制。 +# 用法: +# scripts/build-linux.sh [amd64|arm64] [version-file] +# 默认:amd64 + version +set -euo pipefail + +ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" +cd "$ROOT" + +ARCH="${1:-amd64}" +VERSION_FILE="${2:-version}" + +case "$ARCH" in + amd64|arm64) ;; + *) echo "不支持的架构: $ARCH(只支持 amd64 / arm64)" >&2; exit 1 ;; +esac + +if [ ! -f "$VERSION_FILE" ]; then + echo "版本文件不存在: $VERSION_FILE" >&2 + exit 1 +fi + +VERSION="$(tr -d '\r\n' < "$VERSION_FILE")" +BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +OUT_DIR="dist/linux/$ARCH" +OUT="$OUT_DIR/dockerCopilot-new" + +mkdir -p "$OUT_DIR" + +echo "编译: $OUT" +echo "版本: $VERSION" +echo "日期: $BUILD_DATE" + +CGO_ENABLED=0 GOOS=linux GOARCH="$ARCH" \ + go build -a --trimpath \ + -ldflags="-w -s -X 'github.com/onlyLTY/dockerCopilot/internal/config.Version=$VERSION' -X 'github.com/onlyLTY/dockerCopilot/internal/config.BuildDate=$BUILD_DATE'" \ + -o "$OUT" . + +ls -lh "$OUT" diff --git a/skills/dockercopilot-maintainer/scripts/dev-check.sh b/skills/dockercopilot-maintainer/scripts/dev-check.sh new file mode 100644 index 00000000..b6991da3 --- /dev/null +++ b/skills/dockercopilot-maintainer/scripts/dev-check.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# 开发检查:gofmt + build + vet + test,可选 race。 +# 用法: +# scripts/dev-check.sh # 常规 +# scripts/dev-check.sh --race # 追加 -race +set -euo pipefail + +ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" +cd "$ROOT" + +RACE=0 +if [ "${1:-}" = "--race" ] || [ "${RACE:-0}" = "1" ]; then + RACE=1 +fi + +echo "== gofmt ==" +UNFORMATTED="$(gofmt -l $(git ls-files '*.go' 2>/dev/null || find . -name '*.go' -not -path './.git/*'))" +if [ -n "$UNFORMATTED" ]; then + echo "以下文件未格式化:" + echo "$UNFORMATTED" + echo "执行: gofmt -w " + exit 1 +fi +echo "通过" +echo + +echo "== go build ==" +go build ./... +echo "通过" +echo + +echo "== go vet ==" +go vet ./... +echo "通过" +echo + +echo "== go test ==" +go test ./... -count=1 +echo "通过" +echo + +if [ "$RACE" = "1" ]; then + echo "== go test -race ==" + go test -race ./... -count=1 + echo "通过" + echo +fi + +echo "== git diff --check ==" +git diff --check +echo "通过" +echo + +echo "全部检查通过" diff --git a/skills/dockercopilot-maintainer/scripts/package-audit.sh b/skills/dockercopilot-maintainer/scripts/package-audit.sh new file mode 100644 index 00000000..1181d8b1 --- /dev/null +++ b/skills/dockercopilot-maintainer/scripts/package-audit.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# 镜像边界审计:确保 skills/ 不会进入 Docker 镜像。 +set -euo pipefail + +ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" +cd "$ROOT" + +FAIL=0 +warn() { echo "警告: $*"; } +fail() { echo "失败: $*"; FAIL=1; } + +echo "== 1. Dockerfile COPY/ADD 白名单 ==" +DOCKERFILE="docker/Dockerfile" +if [ ! -f "$DOCKERFILE" ]; then + fail "找不到 $DOCKERFILE" +else + # 禁止 COPY . / ADD . + if grep -nE '^[[:space:]]*(COPY|ADD)[[:space:]]+\.([[:space:]]|$)' "$DOCKERFILE"; then + fail "Dockerfile 使用了 COPY . / ADD .,会把 skills 等开发资料带进镜像" + else + echo "未发现 COPY . / ADD ." + fi + + # 逐条检查 COPY/ADD:只允许 dc-back 与 start.sh + while IFS= read -r line; do + case "$line" in + *dc-back*|*start.sh*) + ;; + *) + fail "Dockerfile 出现非白名单 COPY/ADD: $line" + ;; + esac + done < <(grep -E '^[[:space:]]*(COPY|ADD)[[:space:]]' "$DOCKERFILE" || true) + + if grep -q 'skills' "$DOCKERFILE"; then + fail "Dockerfile 显式引用了 skills" + fi +fi +echo + +echo "== 2. .dockerignore ==" +if [ ! -f .dockerignore ]; then + fail "缺少 .dockerignore" +else + if grep -qxE 'skills/?|/skills/?' .dockerignore; then + echo ".dockerignore 已排除 skills" + else + fail ".dockerignore 未排除 skills" + fi +fi +echo + +echo "== 3. 发布包内容(如果已生成) ==" +FOUND=0 +for f in dockerCopilot-*.tar.gz; do + [ -e "$f" ] || continue + FOUND=1 + echo "检查 $f" + if tar -tzf "$f" | grep -qE '(^|/)skills/'; then + fail "$f 包含 skills/" + else + echo " 未包含 skills/" + fi +done +if [ "$FOUND" = "0" ]; then + echo "没有本地发布包,跳过" +fi +echo + +echo "== 4. 源码泄漏检查(Dockerfile) ==" +if grep -rqE 'go:embed[[:space:]]+front' --include='*.go' . 2>/dev/null; then + fail "仍有 go:embed front/*;前端已移除,不应再嵌入" +else + echo "未发现前端 go:embed" +fi +if grep -qE '^[[:space:]]*(COPY|ADD)[[:space:]]+(\./)?(internal|docs|static|assets)' "$DOCKERFILE" 2>/dev/null; then + fail "Dockerfile 直接 COPY 源码/文档目录" +else + echo "未直接 COPY 源码/文档目录" +fi +echo + +if [ "$FAIL" != "0" ]; then + echo "审计未通过" + exit 1 +fi + +echo "审计通过:skills/ 不会进入镜像" diff --git a/skills/dockercopilot-maintainer/scripts/preflight.sh b/skills/dockercopilot-maintainer/scripts/preflight.sh new file mode 100644 index 00000000..65f45501 --- /dev/null +++ b/skills/dockercopilot-maintainer/scripts/preflight.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# dockerCopilot 预检:只读,不修改仓库。 +set -u + +# 常见 Go 安装路径兜底(NAS/非交互 shell 常缺 PATH) +for d in /usr/local/go/bin /tmp/go/bin "$HOME/go/bin"; do + [ -x "$d/go" ] && PATH="$d:$PATH" +done +export PATH + +ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" +cd "$ROOT" || exit 1 + +echo "== 仓库 ==" +echo "路径: $ROOT" +echo "分支: $(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo '非 git 仓库')" +echo "提交: $(git rev-parse --short HEAD 2>/dev/null || echo '无')" +echo + +echo "== 工作区 ==" +if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + if [ -n "$(git status --porcelain)" ]; then + echo "有未提交改动:" + git status --short + else + echo "干净" + fi +else + echo "不是 git 仓库" +fi +echo + +echo "== 工具 ==" +for c in go git docker node npm; do + if command -v "$c" >/dev/null 2>&1; then + case "$c" in + go) v="$("$c" version 2>/dev/null | head -n 1)" ;; + git) v="$("$c" --version 2>/dev/null | head -n 1)" ;; + docker) v="$("$c" --version 2>/dev/null | head -n 1)" ;; + node) v="$("$c" --version 2>/dev/null | head -n 1)" ;; + npm) v="$("$c" --version 2>/dev/null | head -n 1)" ;; + *) v="未知" ;; + esac + printf '%-7s %s\n' "$c" "$v" + else + printf '%-7s 未安装\n' "$c" + fi +done +echo + +echo "== 版本文件 ==" +for f in version fn_version ugreen_version; do + if [ -f "$f" ]; then + printf '%-15s %s\n' "$f" "$(tr -d '\r\n' < "$f")" + else + printf '%-15s 缺失\n' "$f" + fi +done +echo + +echo "== MCP ==" +if [ -d internal/mcp ]; then + TOOL_COUNT=$(grep -rho 'NewTool("dc_[a-z_]*"' internal/mcp/*.go | sort -u | wc -l | tr -d ' ') + echo "internal/mcp 工具数: ${TOOL_COUNT}(期望 26)" + if [ "$TOOL_COUNT" -eq 0 ]; then + echo "警告: 未发现 dc_* 工具注册" + fi + if grep -q "MCP_TOKEN" internal/mcp/server.go 2>/dev/null; then + echo "MCP 鉴权: 已实现(MCP_TOKEN > secretKey)" + else + echo "警告: 未找到 MCP 鉴权逻辑" + fi +else + echo "警告: internal/mcp 不存在,/mcp 未接入" +fi +echo + +echo "== Docker ==" +if command -v docker >/dev/null 2>&1; then + if docker version >/dev/null 2>&1; then + echo "Docker 可用" + docker version --format 'Server: {{.Server.Version}}' 2>/dev/null || true + else + echo "Docker 客户端存在,但无法连接守护进程" + echo "DOCKER_HOST=${DOCKER_HOST:-未设置}" + fi +else + echo "未安装 docker" +fi +echo + +echo "== 构建边界 ==" +if [ -f .dockerignore ]; then + if grep -qx 'skills' .dockerignore 2>/dev/null || grep -qx 'skills/' .dockerignore 2>/dev/null; then + echo ".dockerignore 已排除 skills" + else + echo "警告: .dockerignore 未排除 skills" + fi +else + echo "警告: 没有 .dockerignore(Dockerfile 虽为白名单 COPY,仍建议补上)" +fi + +if grep -qE '^[[:space:]]*(COPY|ADD)[[:space:]]+\. ' docker/Dockerfile 2>/dev/null; then + echo "警告: Dockerfile 出现 COPY . / ADD .,可能把 skills 打进镜像" +else + echo "Dockerfile 未使用 COPY . / ADD ." +fi diff --git a/skills/dockercopilot-maintainer/scripts/release-check.sh b/skills/dockercopilot-maintainer/scripts/release-check.sh new file mode 100644 index 00000000..f111fa88 --- /dev/null +++ b/skills/dockercopilot-maintainer/scripts/release-check.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# 发布前检查:版本、测试、构建、镜像边界。 +# 用法: +# scripts/release-check.sh [version] +# 不传 version 时读取 ./version。 +set -euo pipefail + +ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" +cd "$ROOT" +HERE="$(cd "$(dirname "$0")" && pwd)" + +TARGET="${1:-$(tr -d '\r\n' < version 2>/dev/null || true)}" + +echo "== 目标版本 ==" +if [ -z "$TARGET" ]; then + echo "版本为空" >&2 + exit 1 +fi +echo "$TARGET" +echo + +echo "== 1. 工作区 ==" +if [ -n "$(git status --porcelain 2>/dev/null || true)" ]; then + echo "警告: 工作区有未提交改动" + git status --short +else + echo "干净" +fi +echo + +echo "== 2. 版本文件一致性 ==" +for f in version fn_version ugreen_version; do + if [ -f "$f" ]; then + v="$(tr -d '\r\n' < "$f")" + printf '%-15s %s\n' "$f" "$v" + fi +done +echo "目标: $TARGET" +echo + +echo "== 3. 开发检查 ==" +"$HERE/dev-check.sh" +echo + +echo "== 4. 镜像边界 ==" +"$HERE/package-audit.sh" +echo + +echo "== 5. MCP ==" +if go test ./internal/mcp/ -count=1 >/dev/null 2>&1; then + COUNT=$(grep -rho 'NewTool("dc_[a-z_]*"' internal/mcp/*.go | sort -u | wc -l | tr -d ' ') + echo "MCP 测试通过,注册工具数: ${COUNT}" +else + echo "失败: internal/mcp 测试未通过" >&2 + exit 1 +fi +if grep -q "MCP_TOKEN" docs/MCP.md 2>/dev/null; then + echo "docs/MCP.md 已说明鉴权" +else + echo "警告: docs/MCP.md 缺少 MCP_TOKEN 说明" +fi +echo + +echo "== 6. 敏感文件 ==" +for p in .env .env.local etc/secret.yaml; do + if [ -e "$p" ] && git ls-files --error-unmatch "$p" >/dev/null 2>&1; then + echo "失败: $p 已被 git 跟踪" + exit 1 + fi +done +echo "未发现被跟踪的 .env/secret 文件" +echo + +echo "发布前检查通过" From 6448e43e2badbe6d3e583bbba2449cd64a37c640 Mon Sep 17 00:00:00 2001 From: DongShull Date: Sat, 31 Oct 2026 23:06:20 +0800 Subject: [PATCH 10/10] =?UTF-8?q?fix:=20=E5=85=A8=E9=93=BE=E8=B7=AF?= =?UTF-8?q?=E5=AE=A1=E6=9F=A5=E4=BF=AE=E5=A4=8D=E6=89=B9=20+=20=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E4=B8=AD=E6=96=87=E5=8C=96=EF=BC=88NAS=20dind=20?= =?UTF-8?q?=E9=9A=94=E7=A6=BB=E7=8E=AF=E5=A2=83=20E2E=20=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E9=80=9A=E8=BF=87=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 一、闭环缺口修复 - 自更新链:UpdateProgram 加互斥锁(并发触发返回明确错误); start.sh 换入新版前保留 dockerCopilot.bak,新版启动后 30 秒内退出 且连续 3 次自动回退上一版(信号转发改为 trap+wait,保留 PID1 语义); PUT /api/program 成功路径补审计与 webhook 通知(与 MCP 通道对齐) - FNOS 版本检查假闭环:GetRemoteVersion 返回 ErrFnosManagedUpdate 哨兵, /api/version?type=remote 与 dc_check_program_update 显式返回 fnos=true 与提示,不再伪装"无更新" - 新增批量镜像清理:DELETE /api/images?filter=untagged|unused 与 MCP dc_clean_images(纯函数 PickImagesForCleanup + 单测;单个失败不影响 其余,返回 removed/failed 明细并写审计) 二、健壮性修复 - 备份:单容器 inspect 失败不再中止整体备份(failures 清单返回); 文件名带时间戳,同日多次备份互不覆盖;新增 BACKUP_KEEP(默认 7) 自动清理旧备份,JSON/compose 共用 - MCP dc_update_container 的 image 参数改 optional(留空用容器当前镜像) - GET / 改 json.Marshal 生成且不再暴露 backupDir(修复 BACKUP_DIR 含 引号时健康检查 JSON 非法) - 全局 Timeout 1e14ms→600000ms;SSE 路由拆分并加 rest.WithSSE(); SSE 单连接 30 分钟自限(客户端自动重连) - go/types.Nil 误用 → internal/types.Nil 占位类型;routes.go/types.go 头注释改为"含手工扩展清单";删除 static/ 死资源 三、E2E 实测发现(dind 隔离环境真实 HTTP 往返暴露) - VersionLogic 业务码 50001 被当作 HTTP 状态码写入,net/http 对 >999 丢弃响应体 → 错误时返回空 500;改为 500(业务码不能超过 999) - 拉取镜像阶段取消时误报"拉取镜像失败",改为"任务已取消"(ImagePull 与 decodePullResp 两处分支均处理) 四、日志全量中文化(40+ 条) - 上游遗留英文日志:image name/need update/not need update/localDigest/ Failed to connect/Starting server/备份写入 Error.../panic 兜底等 - 英文错误字符串:unsupported challenge type/no credentials available/ registry responded to head request 等 - 保留英文:go-zero 框架访问日志、Go 标准库错误原文、镜像名/digest 等 数据值 五、文档同步 - README:功能清单落地(5/6 批量清理)、/api/auth 表单格式说明、 BACKUP_KEEP、已知限制(私有镜像无法检查更新/FnOS 更新语义/自更新 回滚边界)、icons API 补文档 - docs/MCP.md:dc_clean_images、image 可选、autoupdate 前置条件、 工具数 27;docs/ROADMAP.md:REGISTRY_INSECURE 默认值对齐、Timeout 缺陷 标注已修;skills/ 维护文档同步 验证:go build/vet/test 全绿(11 个包);NAS dind 隔离环境全链路 E2E (更新链/SSE/取消/备份保留/恢复 force/镜像清理/start.sh 回退/MCP 27 工具/ 远程版本检查)。 另:本提交同时携带此前工作区已有的零散修改一并入库(CI workflows、 docker/Dockerfile、go.mod/go.sum、dockercopilot.api、icons 上传加固等)。 --- .github/workflows/FNOS.yml | 57 +- .github/workflows/UGREEN.yml | 57 +- .github/workflows/ci.yml | 7 - .../docker-build-push-UGREEN-stable.yml | 45 +- .../workflows/docker-build-push-UGREEN.yml | 45 +- .../docker-build-push-latest-stable.yml | 45 +- .../workflows/docker-build-push-latest.yml | 45 +- .github/workflows/latest.yml | 57 +- README.md | 53 +- docker/Dockerfile | 1 - dockercopilot.api | 2 + dockercopilot.go | 114 +- docs/ROADMAP.md | 26 +- etc/dockerCopilot.yaml | 7 +- go.mod | 14 +- go.sum | 27 +- internal/handler/icons/obtainhandler.go | 10 +- internal/handler/icons/uploadhandler.go | 40 +- internal/handler/image/cleanimageshandler.go | 28 + .../handler/progress/streameventshandler.go | 94 +- internal/handler/routes.go | 22 +- internal/handler/webindexhandler.go | 37 +- internal/logic/auth/loginlogic.go | 15 +- internal/logic/container/backuplogic.go | 13 +- .../logic/container/containerslistlogic.go | 21 +- internal/logic/container/renamelogic.go | 13 +- internal/logic/container/restorelogic.go | 30 +- internal/logic/container/updatelogic.go | 25 +- internal/logic/image/cleanimageslogic.go | 60 + internal/logic/image/removelogic.go | 2 +- .../logic/progress/cancelprogresslogic.go | 21 +- internal/logic/settings/settingslogic.go | 37 +- internal/logic/version/updateprogramlogic.go | 4 + internal/logic/version/versionlogic.go | 15 +- internal/module/auth.go | 124 +- internal/module/checkupdate.go | 51 +- internal/svc/servicecontext.go | 60 +- internal/types/types.go | 18 +- internal/utiles/audit.go | 7 +- internal/utiles/autoupdate.go | 73 +- internal/utiles/backup2compose.go | 4 +- internal/utiles/backup_compose/config2yaml.go | 494 +- internal/utiles/backup_compose/types.go | 4 + internal/utiles/backupcontainer.go | 127 +- internal/utiles/backuppath.go | 14 +- internal/utiles/backupretention.go | 76 + internal/utiles/backupretention_test.go | 83 + internal/utiles/backupslist.go | 5 +- internal/utiles/containerInspect.go | 4 +- internal/utiles/getRemoteVersion.go | 27 +- internal/utiles/getcontainerlist.go | 11 +- internal/utiles/image.go | 63 +- internal/utiles/imagecleanup_test.go | 51 + internal/utiles/removeimage.go | 4 +- internal/utiles/renamecontainer.go | 4 +- internal/utiles/restartcontainer.go | 4 +- internal/utiles/restorecontainer.go | 384 +- internal/utiles/startcontainer.go | 4 +- internal/utiles/stopcontainer.go | 4 +- internal/utiles/updatecontainer.go | 249 +- internal/utiles/updateprogram.go | 138 +- start.sh | 74 +- static/asset/Circular-logo.png | Bin 3557 -> 0 bytes static/asset/Circularlogo.png | Bin 3557 -> 0 bytes static/asset/DockerCopilotlogo.png | Bin 55581 -> 0 bytes static/asset/favicon.png | Bin 24435 -> 0 bytes static/asset/github.png | Bin 14426 -> 0 bytes static/asset/ugreen.png | Bin 29290 -> 0 bytes static/asset/zspace.png | Bin 2696 -> 0 bytes static/bootstrap/css/bootstrap.min.css | 6 - static/bootstrap/icons/bootstrap-icons.css | 8227 ----------------- static/bootstrap/icons/bootstrap-icons.json | 2052 ---- .../bootstrap/icons/bootstrap-icons.min.css | 5 - static/bootstrap/icons/bootstrap-icons.scss | 2090 ----- .../icons/fonts/bootstrap-icons.woff | Bin 176088 -> 0 bytes .../icons/fonts/bootstrap-icons.woff2 | Bin 130648 -> 0 bytes static/bootstrap/js/bootstrap.min.js | 7 - 77 files changed, 2489 insertions(+), 13148 deletions(-) create mode 100644 internal/handler/image/cleanimageshandler.go create mode 100644 internal/logic/image/cleanimageslogic.go create mode 100644 internal/utiles/backupretention.go create mode 100644 internal/utiles/backupretention_test.go create mode 100644 internal/utiles/imagecleanup_test.go delete mode 100644 static/asset/Circular-logo.png delete mode 100644 static/asset/Circularlogo.png delete mode 100644 static/asset/DockerCopilotlogo.png delete mode 100644 static/asset/favicon.png delete mode 100644 static/asset/github.png delete mode 100644 static/asset/ugreen.png delete mode 100644 static/asset/zspace.png delete mode 100644 static/bootstrap/css/bootstrap.min.css delete mode 100644 static/bootstrap/icons/bootstrap-icons.css delete mode 100644 static/bootstrap/icons/bootstrap-icons.json delete mode 100644 static/bootstrap/icons/bootstrap-icons.min.css delete mode 100644 static/bootstrap/icons/bootstrap-icons.scss delete mode 100644 static/bootstrap/icons/fonts/bootstrap-icons.woff delete mode 100644 static/bootstrap/icons/fonts/bootstrap-icons.woff2 delete mode 100644 static/bootstrap/js/bootstrap.min.js diff --git a/.github/workflows/FNOS.yml b/.github/workflows/FNOS.yml index d9545837..78a3bf43 100644 --- a/.github/workflows/FNOS.yml +++ b/.github/workflows/FNOS.yml @@ -8,40 +8,11 @@ on: paths: - fn_version -jobs: - build-frontend: - runs-on: ubuntu-latest - steps: - - name: Checkout frontend code - uses: actions/checkout@v3 - with: - repository: dongshull/Docker-Copilot-React - path: './frontend' - ref: 'master' - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '22' - cache: 'npm' - cache-dependency-path: | - frontend/package-lock.json - frontend/package.json - - - name: Build Frontend - run: | - cd frontend - npm ci - npm run build - - - name: Upload Frontend Artifacts - uses: actions/upload-artifact@v4 - with: - name: my-artifact-front-dist - path: frontend/dist +permissions: + contents: write +jobs: build-backend: - needs: [ build-frontend ] runs-on: ubuntu-latest strategy: matrix: @@ -50,15 +21,6 @@ jobs: - name: Checkout code back end uses: actions/checkout@v3 - - name: Download Frontend Artifacts - uses: actions/download-artifact@v4 - with: - pattern: my-artifact-front-* - merge-multiple: true - path: front - - - run: ls -R front - - name: Get version from file id: get_version run: | @@ -84,7 +46,10 @@ jobs: - name: Compress binary run: | - tar -czvf dockerCopilot-${{ matrix.arch }}.tar.gz dist/linux/${{ matrix.arch }}/dockerCopilot-new + tar -czvf dockerCopilot-${{ matrix.arch }}.tar.gz -C dist/linux/${{ matrix.arch }} dockerCopilot-new + + - name: Generate checksum + run: sha256sum dockerCopilot-${{ matrix.arch }}.tar.gz > dockerCopilot-${{ matrix.arch }}.tar.gz.sha256 - name: List current directory run: ls -la @@ -108,12 +73,16 @@ jobs: run: | gh release create ${{ env.version }} \ --title "${{ env.version }}" \ - --notes "Release of version ${{ env.version }}" + --notes "Release of version ${{ env.version }}" \ + || gh release view ${{ env.version }} >/dev/null env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Asset for ${{ matrix.arch }} run: | - gh release upload ${{ env.version }} dockerCopilot-${{ matrix.arch }}.tar.gz + gh release upload ${{ env.version }} \ + dockerCopilot-${{ matrix.arch }}.tar.gz \ + dockerCopilot-${{ matrix.arch }}.tar.gz.sha256 \ + --clobber env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/UGREEN.yml b/.github/workflows/UGREEN.yml index 985aecb9..059d1c74 100644 --- a/.github/workflows/UGREEN.yml +++ b/.github/workflows/UGREEN.yml @@ -8,40 +8,11 @@ on: paths: - ugreen_version -jobs: - build-frontend: - runs-on: ubuntu-latest - steps: - - name: Checkout frontend code - uses: actions/checkout@v3 - with: - repository: dongshull/Docker-Copilot-React - path: './frontend' - ref: 'master' - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '22' - cache: 'npm' - cache-dependency-path: | - frontend/package-lock.json - frontend/package.json - - - name: Build Frontend - run: | - cd frontend - npm ci - npm run build - - - name: Upload Frontend Artifacts - uses: actions/upload-artifact@v4 - with: - name: my-artifact-front-dist - path: frontend/dist +permissions: + contents: write +jobs: build-backend: - needs: [ build-frontend ] runs-on: ubuntu-latest strategy: matrix: @@ -50,15 +21,6 @@ jobs: - name: Checkout code back end uses: actions/checkout@v3 - - name: Download Frontend Artifacts - uses: actions/download-artifact@v4 - with: - pattern: my-artifact-front-* - merge-multiple: true - path: front - - - run: ls -R front - - name: Get version from file id: get_version run: | @@ -84,7 +46,10 @@ jobs: - name: Compress binary run: | - tar -czvf dockerCopilot-${{ matrix.arch }}.tar.gz dist/linux/${{ matrix.arch }}/dockerCopilot-new + tar -czvf dockerCopilot-${{ matrix.arch }}.tar.gz -C dist/linux/${{ matrix.arch }} dockerCopilot-new + + - name: Generate checksum + run: sha256sum dockerCopilot-${{ matrix.arch }}.tar.gz > dockerCopilot-${{ matrix.arch }}.tar.gz.sha256 - name: List current directory run: ls -la @@ -108,12 +73,16 @@ jobs: run: | gh release create ${{ env.version }} \ --title "${{ env.version }}" \ - --notes "Release of version ${{ env.version }}" + --notes "Release of version ${{ env.version }}" \ + || gh release view ${{ env.version }} >/dev/null env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Asset for ${{ matrix.arch }} run: | - gh release upload ${{ env.version }} dockerCopilot-${{ matrix.arch }}.tar.gz + gh release upload ${{ env.version }} \ + dockerCopilot-${{ matrix.arch }}.tar.gz \ + dockerCopilot-${{ matrix.arch }}.tar.gz.sha256 \ + --clobber env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80093636..a0c8009f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,13 +23,6 @@ jobs: go-version-file: go.mod cache: true - - name: Prepare front placeholder - run: | - mkdir -p front - cat > front/index.html <<'EOF' - dockerCopilot

CI placeholder

- EOF - - name: Build run: go build ./... diff --git a/.github/workflows/docker-build-push-UGREEN-stable.yml b/.github/workflows/docker-build-push-UGREEN-stable.yml index 1c8ff46a..d4401fce 100644 --- a/.github/workflows/docker-build-push-UGREEN-stable.yml +++ b/.github/workflows/docker-build-push-UGREEN-stable.yml @@ -9,41 +9,7 @@ on: - ugreen_version jobs: - build-frontend: - # 仅上游仓库发布 DockerHub 镜像;fork 通过 GitHub Release 分发 - if: github.repository == 'onlyLTY/dockerCopilot' - runs-on: ubuntu-latest - steps: - - name: Checkout frontend code - uses: actions/checkout@v3 - with: - repository: dongshull/Docker-Copilot-React - path: './frontend' - ref: 'master' - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '22' - cache: 'npm' - cache-dependency-path: | - frontend/package-lock.json - frontend/package.json - - - name: Build Frontend - run: | - cd frontend - npm ci - npm run build - - - name: Upload Frontend Artifacts - uses: actions/upload-artifact@v4 - with: - name: my-artifact-front-dist - path: frontend/dist - build-backend: - needs: [ build-frontend ] runs-on: ubuntu-latest strategy: matrix: @@ -52,15 +18,6 @@ jobs: - name: Checkout code back end uses: actions/checkout@v3 - - name: Download Frontend Artifacts - uses: actions/download-artifact@v4 - with: - pattern: my-artifact-front-* - merge-multiple: true - path: front - - - run: ls -R front - - name: Get version from file id: get_version run: | @@ -98,7 +55,7 @@ jobs: docker-setup: runs-on: ubuntu-latest - needs: [ build-frontend, build-backend ] + needs: build-backend steps: - name: Checkout code Now Code uses: actions/checkout@v3 diff --git a/.github/workflows/docker-build-push-UGREEN.yml b/.github/workflows/docker-build-push-UGREEN.yml index 78d2ca97..9eec4e2a 100644 --- a/.github/workflows/docker-build-push-UGREEN.yml +++ b/.github/workflows/docker-build-push-UGREEN.yml @@ -7,41 +7,7 @@ on: - latest-dev jobs: - build-frontend: - # 仅上游仓库发布 DockerHub 镜像;fork 通过 GitHub Release 分发 - if: github.repository == 'onlyLTY/dockerCopilot' - runs-on: ubuntu-latest - steps: - - name: Checkout frontend code - uses: actions/checkout@v3 - with: - repository: dongshull/Docker-Copilot-React - path: './frontend' - ref: 'master' - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '22' - cache: 'npm' - cache-dependency-path: | - frontend/package-lock.json - frontend/package.json - - - name: Build Frontend - run: | - cd frontend - npm ci - npm run build - - - name: Upload Frontend Artifacts - uses: actions/upload-artifact@v4 - with: - name: my-artifact-front-dist - path: frontend/dist - build-backend: - needs: [ build-frontend ] runs-on: ubuntu-latest strategy: matrix: @@ -50,15 +16,6 @@ jobs: - name: Checkout code back end uses: actions/checkout@v3 - - name: Download Frontend Artifacts - uses: actions/download-artifact@v4 - with: - pattern: my-artifact-front-* - merge-multiple: true - path: front - - - run: ls -R front - - name: Get version from file id: get_version run: | @@ -96,7 +53,7 @@ jobs: docker-setup: runs-on: ubuntu-latest - needs: [ build-frontend, build-backend ] + needs: build-backend steps: - name: Checkout code Now Code uses: actions/checkout@v3 diff --git a/.github/workflows/docker-build-push-latest-stable.yml b/.github/workflows/docker-build-push-latest-stable.yml index c6fc8520..edf1e7e3 100644 --- a/.github/workflows/docker-build-push-latest-stable.yml +++ b/.github/workflows/docker-build-push-latest-stable.yml @@ -9,41 +9,7 @@ on: - version jobs: - build-frontend: - # 仅上游仓库发布 DockerHub 镜像;fork 通过 GitHub Release 分发 - if: github.repository == 'onlyLTY/dockerCopilot' - runs-on: ubuntu-latest - steps: - - name: Checkout frontend code - uses: actions/checkout@v3 - with: - repository: dongshull/Docker-Copilot-React - path: './frontend' - ref: 'master' - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '22' - cache: 'npm' - cache-dependency-path: | - frontend/package-lock.json - frontend/package.json - - - name: Build Frontend - run: | - cd frontend - npm ci - npm run build - - - name: Upload Frontend Artifacts - uses: actions/upload-artifact@v4 - with: - name: my-artifact-front-dist - path: frontend/dist - build-backend: - needs: [ build-frontend ] runs-on: ubuntu-latest strategy: matrix: @@ -52,15 +18,6 @@ jobs: - name: Checkout code back end uses: actions/checkout@v3 - - name: Download Frontend Artifacts - uses: actions/download-artifact@v4 - with: - pattern: my-artifact-front-* - merge-multiple: true - path: front - - - run: ls -R front - - name: Get version from file id: get_version run: | @@ -98,7 +55,7 @@ jobs: docker-setup: runs-on: ubuntu-latest - needs: [ build-frontend, build-backend ] + needs: build-backend steps: - name: Checkout code Now Code uses: actions/checkout@v3 diff --git a/.github/workflows/docker-build-push-latest.yml b/.github/workflows/docker-build-push-latest.yml index 01a2a46f..1d0e0569 100644 --- a/.github/workflows/docker-build-push-latest.yml +++ b/.github/workflows/docker-build-push-latest.yml @@ -7,41 +7,7 @@ on: - latest-dev jobs: - build-frontend: - # 仅上游仓库发布 DockerHub 镜像;fork 通过 GitHub Release 分发 - if: github.repository == 'onlyLTY/dockerCopilot' - runs-on: ubuntu-latest - steps: - - name: Checkout frontend code - uses: actions/checkout@v3 - with: - repository: dongshull/Docker-Copilot-React - path: './frontend' - ref: 'master' - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '22' - cache: 'npm' - cache-dependency-path: | - frontend/package-lock.json - frontend/package.json - - - name: Build Frontend - run: | - cd frontend - npm ci - npm run build - - - name: Upload Frontend Artifacts - uses: actions/upload-artifact@v4 - with: - name: my-artifact-front-dist - path: frontend/dist - build-backend: - needs: [ build-frontend ] runs-on: ubuntu-latest strategy: matrix: @@ -50,15 +16,6 @@ jobs: - name: Checkout code back end uses: actions/checkout@v3 - - name: Download Frontend Artifacts - uses: actions/download-artifact@v4 - with: - pattern: my-artifact-front-* - merge-multiple: true - path: front - - - run: ls -R front - - name: Get version from file id: get_version run: | @@ -96,7 +53,7 @@ jobs: docker-setup: runs-on: ubuntu-latest - needs: [ build-frontend, build-backend ] + needs: build-backend steps: - name: Checkout code Now Code uses: actions/checkout@v3 diff --git a/.github/workflows/latest.yml b/.github/workflows/latest.yml index 3d12451f..a468fb21 100644 --- a/.github/workflows/latest.yml +++ b/.github/workflows/latest.yml @@ -8,40 +8,11 @@ on: paths: - version -jobs: - build-frontend: - runs-on: ubuntu-latest - steps: - - name: Checkout frontend code - uses: actions/checkout@v3 - with: - repository: dongshull/Docker-Copilot-React - path: './frontend' - ref: 'master' - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '22' - cache: 'npm' - cache-dependency-path: | - frontend/package-lock.json - frontend/package.json - - - name: Build Frontend - run: | - cd frontend - npm ci - npm run build - - - name: Upload Frontend Artifacts - uses: actions/upload-artifact@v4 - with: - name: my-artifact-front-dist - path: frontend/dist +permissions: + contents: write +jobs: build-backend: - needs: [ build-frontend ] runs-on: ubuntu-latest strategy: matrix: @@ -50,15 +21,6 @@ jobs: - name: Checkout code back end uses: actions/checkout@v3 - - name: Download Frontend Artifacts - uses: actions/download-artifact@v4 - with: - pattern: my-artifact-front-* - merge-multiple: true - path: front - - - run: ls -R front - - name: Get version from file id: get_version run: | @@ -84,7 +46,10 @@ jobs: - name: Compress binary run: | - tar -czvf dockerCopilot-${{ matrix.arch }}.tar.gz dist/linux/${{ matrix.arch }}/dockerCopilot-new + tar -czvf dockerCopilot-${{ matrix.arch }}.tar.gz -C dist/linux/${{ matrix.arch }} dockerCopilot-new + + - name: Generate checksum + run: sha256sum dockerCopilot-${{ matrix.arch }}.tar.gz > dockerCopilot-${{ matrix.arch }}.tar.gz.sha256 - name: List current directory run: ls -la @@ -108,12 +73,16 @@ jobs: run: | gh release create ${{ env.version }} \ --title "${{ env.version }}" \ - --notes "Release of version ${{ env.version }}" + --notes "Release of version ${{ env.version }}" \ + || gh release view ${{ env.version }} >/dev/null env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Asset for ${{ matrix.arch }} run: | - gh release upload ${{ env.version }} dockerCopilot-${{ matrix.arch }}.tar.gz + gh release upload ${{ env.version }} \ + dockerCopilot-${{ matrix.arch }}.tar.gz \ + dockerCopilot-${{ matrix.arch }}.tar.gz.sha256 \ + --clobber env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 28f57ca7..e1db1d2c 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,15 @@ 2. 指定镜像和 tag 更新 3. 启动、停止、重启容器 4. 重命名容器 -5. 删除无 TAG 镜像 -6. 删除未使用镜像 +5. 批量删除无 TAG 镜像(`DELETE /api/images?filter=untagged` / MCP `dc_clean_images`) +6. 批量删除未使用镜像(`DELETE /api/images?filter=unused` / MCP `dc_clean_images`) 7. 更新进度查看(SSE 实时推送 / 轮询双通道,支持取消,重启不丢历史) -8. 备份容器设置(JSON / docker-compose 双格式) +8. 备份容器设置(JSON / docker-compose 双格式;每次备份独立文件,超出 `BACKUP_KEEP` 自动清理) 9. 恢复容器设置 10. 定时自动更新白名单 11. 操作审计日志与 webhook 通知 +12. 内置 MCP 服务(Streamable HTTP),Agent 可直接调用全部能力;HTTP API 同时保留 +13. 程序自更新(下载 + SHA256 校验;新版连续启动失败自动回退上一版) ## 使用 @@ -42,51 +44,78 @@ services: environment: - TZ=Asia/Shanghai - DOCKER_HOST=unix:///var/run/docker.sock - - secretKey=密码,不少于八位且非纯数字 - image: 0nlylty/dockercopilot:latest + - secretKey=密码,必须大于八位且非纯数字 + # 改成你的 Docker Hub 账号;或使用 GitHub Release 的二进制自行构建 + image: your-dockerhub-user/dockercopilot:latest ``` > 说明:容器内以 root 运行并挂载 `docker.sock` 即可管理 Docker,**不需要** `privileged: true`。 > 如需进一步降权,可为 docker.sock 配置 `group_add` 并使用非 root 用户运行。 +> +> 本项目**已移除网页前端**,只提供 HTTP API 与 MCP;建议把端口绑定到回环或内网, +> 例如 `127.0.0.1:12712:12712`,因为 `/mcp` 等价于 Docker 控制面。 ## 环境变量 | 变量 | 默认 | 说明 | |---|---|---| -| `secretKey` | (必填) | 登录密钥(兼作 JWT 签名密钥),不少于 8 位且非纯数字 | +| `secretKey` | (必填) | 登录密钥(兼作 JWT 签名密钥),必须大于 8 位且非纯数字;缺失会拒绝启动 | | `DOCKER_HOST` | unix:///var/run/docker.sock | Docker 守护进程地址 | | `BACKUP_DIR` | /data/backups | 容器备份目录(优先级最高;否则用 Settings 页配置值) | +| `BACKUP_KEEP` | 7 | 每种备份(JSON / compose)保留份数,超出自动清理最旧的 | | `DelOldContainer` | true | 更新成功后删除旧容器(设为 `false` 保留) | | `CLEANUP_OLD_IMAGE` | true | 更新成功后清理不再被引用的旧镜像(`false` 关闭) | | `UPDATE_REPO` | DongShull/dockerCopilot | 版本检查与自更新仓库 | | `UPDATE_BRANCH` | latest | 版本检查分支 | +| `UPDATE_SKIP_CHECKSUM` | false | 设为 `true` 时跳过自更新 SHA256 校验(仅用于过渡旧版本,不推荐) | | `githubProxy` | 空 | GitHub 代理前缀,如 `https://ghproxy.example/` | -| `REGISTRY_INSECURE` | true | registry 检测跳过 TLS 校验(`false` 严格校验) | +| `REGISTRY_INSECURE` | false | 设为 `true` 时 registry 检测跳过 TLS 校验(默认严格校验) | | `PROGRESS_STORE` | /data/config/progress.json | 任务进度持久化文件 | | `PROGRESS_TTL_HOURS` | 24 | 已完成任务保留小时数,超期自动清理 | | `NOTIFY_WEBHOOK_URL` | 空 | 任务完成通知 webhook(POST JSON) | | `AUDIT_LOG` | /data/logs/audit.jsonl | 审计日志(JSON Lines) | | `AUTOUPDATE_CRON` | 空 | 自动更新周期(cron 表达式,空=关闭),如 `0 4 * * *` | | `AUTOUPDATE_WHITELIST` | 空 | 自动更新容器白名单(逗号分隔;`*` 表示全部有更新的容器) | +| `MCP_TOKEN` | 空 | `/mcp` 的访问令牌;为空时回退到 `secretKey`,设为 `off` 显式关闭鉴权(仅限隔离内网) | -## API 摘要 +## 接入方式 -- `POST /api/auth` 登录换 JWT +### MCP(推荐给 Agent) + +`http://:12712/mcp`,Streamable HTTP,27 个 `dc_*` 工具覆盖容器、镜像、备份恢复、 +进度、设置与自更新。鉴权支持 `Authorization: Bearer `、`X-MCP-Token` 与 `?token=`。 +详见 [docs/MCP.md](docs/MCP.md)。 + +### HTTP API + +- `POST /api/auth` 登录换 JWT(表单编码:`secretKey=<值>`;注意 `/api/auth` 与 update/rename 等接口只接受 form/query 参数,restore、settings 接口收 JSON body) - `GET /api/containers` / `POST /api/container/:id/{start,stop,restart,rename,update}` - `GET /api/container/backup` / `GET /api/container/backup2compose` / `POST /api/container/backups/restore` + - 备份每次生成独立文件(`backup-<时间戳>.json` / `.yaml`),超出 `BACKUP_KEEP` 的旧备份自动清理;响应里的 `failures` 列出本次备份失败的容器 + - restore body:`{"filename":"backup-2026-01-01.json","start":true|false,"force":false}`;`start` 省略时按备份记录的状态恢复;`force=true` 会先停止并临时改名同名容器,新容器创建/启动成功后才删除旧容器,失败会自动回滚 - `GET /api/images` / `DELETE /api/image/:id` -- `GET /api/progress` / `GET /api/progress/:taskid` / `POST /api/progress/:taskid/cancel` / `GET /api/progress/:taskid/events`(SSE) + - `DELETE /api/images?filter=untagged` 批量删除无 TAG 镜像;`?filter=unused` 批量删除未被容器引用的镜像;响应带 `removed` / `failed` 明细 +- `GET /api/progress` / `GET /api/progress/:taskid` / `POST /api/progress/:taskid/cancel` / `GET /api/progress/:taskid/events`(SSE,请求需带 `Accept: text/event-stream`) - `GET /api/settings` / `PUT /api/settings` - `GET /api/version` / `PUT /api/program` +- `POST /api/icons` / `GET /api/icons` 自定义镜像 logo(`imageName` → 上传图片文件的映射,持久化在 `/data/config`) + +## 已知限制 + +- **私有仓库镜像无法自动检查更新**:程序不持有任何 registry 凭证,私有镜像的 digest 检查会静默跳过(日志可见),`haveUpdate` 恒为 false。 +- **FnOS 版不走在线更新链**:`/api/version?type=remote` 与 `dc_check_program_update` 会返回 `fnos=true` 与提示,自更新被明确禁止;请使用 FNOS 专用发布包更新。 +- **自更新回滚依赖启动脚本**:`start.sh` 会在换入新版前保留 `dockerCopilot.bak`,新版连续 3 次启动失败(启动后 30 秒内退出)自动回退;重建容器也能回到镜像自带版本。 ## 开发环境 -go 版本:1.23+(go.mod 指定);构建前需在 `front/` 放置前端产物(CI 会自动从 -[Docker-Copilot-React](https://github.com/dongshull/Docker-Copilot-React) 拉取构建)。 +go 版本:1.23+(go.mod 指定)。项目不再嵌入前端,`go build ./...` 即可直接构建。 ``` go build ./... go test ./... ``` +仓库内附开发维护技能:[`skills/dockercopilot-maintainer/SKILL.md`](skills/dockercopilot-maintainer/SKILL.md)。 +该目录仅供开发使用,已通过 `.dockerignore` 排除,不会进入镜像或发布包。 + 改造规划与缺陷清单见 [docs/ROADMAP.md](docs/ROADMAP.md)。 diff --git a/docker/Dockerfile b/docker/Dockerfile index 989d747b..59eff54a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,7 +16,6 @@ RUN apk add --no-cache tzdata \ # 设置环境变量 ENV secretKey="" \ DOCKER_HOST="unix:///var/run/docker.sock" \ - BACKUP_DIR="/data/backups" \ TZ="Asia/Shanghai" VOLUME ["/data"] diff --git a/dockercopilot.api b/dockercopilot.api index 0e04b697..e5bbf831 100644 --- a/dockercopilot.api +++ b/dockercopilot.api @@ -60,6 +60,8 @@ type IdReq { type ContainerRestoreReq { Filename string `json:"filename"` + Start *bool `json:"start,optional"` + Force bool `json:"force,optional"` } type DelContainerBackupReq { diff --git a/dockercopilot.go b/dockercopilot.go index 83c9a632..4e3c7e45 100644 --- a/dockercopilot.go +++ b/dockercopilot.go @@ -1,18 +1,19 @@ package main import ( - "embed" "flag" "fmt" - "go/types" - "io/fs" - "log" "net/http" "os" + "strings" + "unicode" + "unicode/utf8" "github.com/onlyLTY/dockerCopilot/internal/config" "github.com/onlyLTY/dockerCopilot/internal/handler" + "github.com/onlyLTY/dockerCopilot/internal/mcp" "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" "github.com/onlyLTY/dockerCopilot/internal/utiles" "github.com/robfig/cron/v3" "github.com/zeromicro/go-zero/core/conf" @@ -23,9 +24,6 @@ import ( xhttp "github.com/zeromicro/x/http" ) -//go:embed front/* -var embeddedFront embed.FS - var configFile = flag.String("f", "etc/dockerCopilot.yaml", "the config file") type UnauthorizedResponse struct { @@ -38,7 +36,7 @@ func main() { logDir := "./logs" ErrSetupLog := SetupLog(logDir) if ErrSetupLog != nil { - logx.Errorf("failed to setup log: %v", ErrSetupLog) + logx.Errorf("初始化日志失败: %v", ErrSetupLog) os.Exit(1) } logx.SetLevel(logx.InfoLevel) @@ -51,6 +49,10 @@ func main() { logx.Errorf("请确认secretKey设置正确,要求非纯数字且大于八位") os.Exit(1) } + if err := validateSecretKey(c.Auth.AccessSecret); err != nil { + logx.Errorf("secretKey 配置不合法: %v", err) + os.Exit(1) + } server := rest.MustNewServer(c.RestConf, rest.WithCors("*"), rest.WithUnauthorizedCallback( func(w http.ResponseWriter, r *http.Request, err error) { response := UnauthorizedResponse{ @@ -62,11 +64,16 @@ func main() { })) defer server.Stop() ctx := svc.NewServiceContext(c) + if ctx.DockerInitErr != nil { + logx.Errorf("Docker 客户端初始化失败: %v", ctx.DockerInitErr) + logx.Errorf("请检查 DOCKER_HOST、DOCKER_TLS_VERIFY、DOCKER_CERT_PATH 等环境变量") + os.Exit(1) + } // Ensure data directory and config exist (Auto-init) dataDir := "/data/config/image" if err := os.MkdirAll(dataDir, 0755); err != nil { - logx.Errorf("Failed to create data directory: %v", err) + logx.Errorf("创建数据目录失败: %v", err) } imageLogosPath := "/data/config/imageLogos.js" @@ -76,7 +83,7 @@ export const customImageLogos = { }; `) if err := os.WriteFile(imageLogosPath, defaultConfig, 0644); err != nil { - logx.Errorf("Failed to create default imageLogos.js: %v", err) + logx.Errorf("创建默认 imageLogos.js 失败: %v", err) } } @@ -119,6 +126,8 @@ export const customImageLogos = { }) if err != nil { logx.Errorf("自动更新定时任务表达式非法: %v", err) + } else if !utiles.AutoUpdateConfigured() { + logx.Errorf("自动更新未完全启用:AUTOUPDATE_WHITELIST 为空,任务将跳过") } else { logx.Infof("自动更新已启用: %s, 白名单: %s", cronExpr, os.Getenv("AUTOUPDATE_WHITELIST")) } @@ -140,70 +149,36 @@ export const customImageLogos = { } }) handler.RegisterHandlers(server, ctx) - RegisterHandlers(server) - fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) + mcp.Register(server, ctx) + fmt.Printf("服务已启动: %s:%d...\n", c.Host, c.Port) logx.Info("程序版本" + config.Version) server.Start() } -func RegisterHandlers(engine *rest.Server) { - frontFS, err := fs.Sub(embeddedFront, "front") - if err != nil { - log.Fatal(err) - } - - frontFileServer := http.StripPrefix("/manager", http.FileServer(http.FS(frontFS))) - assetsHandler := http.FileServer(http.FS(frontFS)) - - // Serve custom icons - iconFileServer := http.StripPrefix("/src/config/image/", http.FileServer(http.Dir("/data/config/image"))) - engine.AddRoutes( - []rest.Route{ - { - Method: http.MethodGet, - Path: "/src/config/image/:file", - Handler: func(w http.ResponseWriter, r *http.Request) { - iconFileServer.ServeHTTP(w, r) - }, - }, - }, - ) - - engine.AddRoutes( - []rest.Route{ - { - Method: http.MethodGet, - Path: "/manager", - Handler: func(w http.ResponseWriter, r *http.Request) { - frontFileServer.ServeHTTP(w, r) - }, - }, - { - Method: http.MethodGet, - Path: "/manager/:path", - Handler: func(w http.ResponseWriter, r *http.Request) { - frontFileServer.ServeHTTP(w, r) - }, - }, - { - Method: http.MethodGet, - Path: "/manager/assets/:path", - Handler: func(w http.ResponseWriter, r *http.Request) { - frontFileServer.ServeHTTP(w, r) - }, - }, - { - Method: http.MethodGet, - Path: "/assets/:path", - Handler: func(w http.ResponseWriter, r *http.Request) { - assetsHandler.ServeHTTP(w, r) - }, - }, - }, - ) +// validateSecretKey 校验 secretKey:去掉首尾空白后长度需大于 8 位,且不能是纯数字。 +func validateSecretKey(secret string) error { + secret = strings.TrimSpace(secret) + // 变量未展开(如 ${secretKey})时长度可能“看起来”合规,必须明确拒绝。 + if strings.Contains(secret, "${") || strings.Contains(secret, "$") { + return fmt.Errorf("secretKey 未展开,请直接填写真实值") + } + if utf8.RuneCountInString(secret) <= 8 { + return fmt.Errorf("长度必须大于 8 位") + } + allDigits := true + for _, r := range secret { + if !unicode.IsDigit(r) { + allDigits = false + break + } + } + if allDigits { + return fmt.Errorf("不能是纯数字") + } + return nil } -// 检查并创建日志目录 +// ensureLogDirectory 检查并创建日志目录 func ensureLogDirectory(logDir string) error { if _, err := os.Stat(logDir); os.IsNotExist(err) { return os.MkdirAll(logDir, 0755) // 创建目录并设置权限 @@ -224,6 +199,9 @@ func SetupLog(logDir string) error { KeepDays: 7, Compress: true, Mode: "file", + // 使用纯文本格式,日志行只保留“时间 + 级别 + 内容”, + // 不再输出 JSON 字段或服务名前缀。 + Encoding: "plain", } logx.MustSetup(logConf) logx.AddWriter(logx.NewWriter(os.Stdout)) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 66c3f0e9..66170fbd 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -24,7 +24,7 @@ 12. `checkImageInUsed` O(容器×镜像) 双重循环 13. restore 中永假的死代码分支 14. JWT 84 天有效、secretKey 兼作签名密钥(记录在案,暂无计划改动) -15. `Timeout: 1e14`、CORS `*`、`InsecureSkipVerify`(已加 REGISTRY_INSECURE 开关) +15. `Timeout: 1e14`、CORS `*`、`InsecureSkipVerify`(已加 REGISTRY_INSECURE 开关;Timeout 已改为 600000ms,SSE 路由带 `WithSSE()` 走 Accept 头豁免,见 `etc/dockerCopilot.yaml` 注释) ## 二、分期计划 @@ -36,6 +36,25 @@ | P3 | 任务系统:进度落盘、TTL 清理、任务列表/取消 API、SSE 推送 | ✅ v2.2.0 | | P4 | FnOS 适配:去 privileged 要求、HEALTHCHECK、备份目录运行时可配(Settings API) | ✅ v2.2.0 | | P5 | 增强:webhook 通知、审计日志、定时自动更新白名单 | ✅ v2.2.0 | +| P6 | 稳定性:SSE 心跳、Docker 调用超时、进度文件并发落盘、Compose 导出保真度 | ✅ 待发版 | +| P7 | Agent 化:移除网页前端、保留 HTTP API、内置 MCP(Streamable HTTP)暴露全部能力 | ✅ 待发版 | + +### P6 补充说明 + +- SSE 增加 15 秒心跳和断线重连提示,避免反向代理在任务长时间无进度时断开连接。 +- 单次 Docker list/inspect/start/stop/rename/remove 调用增加 60 秒~2 分钟超时;镜像拉取仍由任务上下文控制,避免大镜像被误杀。 +- 进度文件落盘与内存快照在同一把锁内完成,修复并发保存时旧快照覆盖新状态的问题。 +- Compose 导出补齐 healthcheck、devices、cap_add/cap_drop、security_opt、ulimits、extra_hosts、dns、tmpfs、shm_size、user、group_add、logging、stop_signal、stop_grace_period、sysctls、资源限制等字段;命名卷改用 MountPoint.Name,避免导出宿主机卷路径。 +- 恢复 `force=true` 改为“停止并临时改名旧容器 → 创建/启动新容器 → 成功后删除旧容器”;任一步失败都会清理半成品并把旧容器改回原名、恢复运行/暂停状态。 +- 备份/更新/恢复统一清洗网络端点:只保留别名、链接、驱动参数和静态 IPAM,清掉运行期 NetworkID/EndpointID/IP/MAC/DNSNames,避免重建时继承失效端点或地址冲突。 + +### P7 补充说明 + +- 前端(`go:embed front/*`、`/manager` 静态路由、CI 的前端构建 job)整体移除,`GET /` 改为返回 JSON 状态,同时满足容器 HEALTHCHECK 的 200 要求。 +- 保留全部 `/api/*` 路由:脚本、CI 与旧客户端不受影响,MCP 与 API 共用同一套 `internal/utiles` / `internal/logic` 实现。 +- 新增 `internal/mcp/`:基于 `mark3labs/mcp-go` 的 Streamable HTTP 服务,挂载 `/mcp`,注册 26 个 `dc_*` 工具,覆盖容器、镜像、备份恢复、进度、设置与自更新。 +- `/mcp` 默认鉴权:`MCP_TOKEN` 优先,未设置时回退 `secretKey`;支持 `Authorization: Bearer`、`X-MCP-Token`、`?token=` 三种携带方式,比较使用常量时间算法。`MCP_TOKEN=off` 可显式关闭(仅隔离内网)。 +- 破坏性 MCP 操作复用现有审计与通知;长任务复用 `RegisterTask`/`CancelTask`/`FinishTask` 与进度持久化。 ## 三、配置项一览(环境变量) @@ -49,10 +68,11 @@ | `UPDATE_REPO` | DongShull/dockerCopilot | 版本检查与自更新仓库 | | `UPDATE_BRANCH` | latest | 版本检查分支 | | `githubProxy` | 空 | GitHub 代理前缀 | -| `REGISTRY_INSECURE` | true | registry 检测是否跳过 TLS 校验("false" 严格校验) | +| `REGISTRY_INSECURE` | false | 设为 `true` 时 registry 检测跳过 TLS 校验(默认严格校验) | | `NOTIFY_WEBHOOK_URL` | 空 | 任务完成通知 webhook(POST JSON) | | `AUTOUPDATE_CRON` | 空 | 自动更新周期(cron 表达式,空=关闭) | | `AUTOUPDATE_WHITELIST` | 空 | 自动更新容器白名单(逗号分隔,`*`=全部有更新的容器) | +| `MCP_TOKEN` | 空 | `/mcp` 访问令牌;空则回退 `secretKey`,`off` 显式关闭鉴权 | ## 四、验收标准(v2.2.0) @@ -62,3 +82,5 @@ - 重启进程后任务历史仍可查询;进行中任务可取消 - 50 个镜像的更新检测从串行分钟级进入 10 秒级 - 非 privileged 容器(仅挂载 docker.sock + 数据卷)可跑通全部功能 +- `go test ./internal/mcp/` 覆盖工具注册、鉴权与 Streamable HTTP 握手 +- MCP 客户端可完成「列容器 → 更新 → 查进度」全流程,`/api/*` 行为不变 diff --git a/etc/dockerCopilot.yaml b/etc/dockerCopilot.yaml index fd64a275..7027fd23 100644 --- a/etc/dockerCopilot.yaml +++ b/etc/dockerCopilot.yaml @@ -1,9 +1,12 @@ Name: dockerCopilot Host: 0.0.0.0 Port: 12712 -Timeout: 100000000000000 +# 全局请求超时 10 分钟(此前是 1e14ms≈3170 年,等于没有超时)。 +# SSE 事件流带 Accept: text/event-stream 请求头,go-zero 的 timeout 中间件对它原生豁免; +# /mcp 的同步工具调用(拉镜像、批量检查)需要分钟级余量,因此全局值放宽到 10 分钟。 +Timeout: 600000 Log: Encoding: plain Auth: AccessSecret: ${secretKey} - AccessExpire: 7257600 \ No newline at end of file + AccessExpire: 7257600 diff --git a/go.mod b/go.mod index 4bfabbf8..da6af1f6 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/onlyLTY/dockerCopilot go 1.23.0 -toolchain go1.24.1 - require ( github.com/compose-spec/compose-go v1.20.2 github.com/distribution/reference v0.5.0 @@ -11,6 +9,7 @@ require ( github.com/docker/go-connections v0.5.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.6.0 + github.com/mark3labs/mcp-go v0.44.0 github.com/robfig/cron/v3 v3.0.1 github.com/zeromicro/go-zero v1.8.2 github.com/zeromicro/x v0.0.0-20240408115609-8224c482b07e @@ -20,7 +19,9 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/log v0.1.0 // indirect @@ -32,6 +33,8 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/invopop/jsonschema v0.13.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect @@ -51,6 +54,9 @@ require ( github.com/prometheus/procfs v0.16.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect + github.com/yosida95/uritemplate/v3 v3.0.2 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect go.opentelemetry.io/otel v1.35.0 // indirect @@ -66,13 +72,13 @@ require ( go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.39.0 // indirect golang.org/x/sync v0.13.0 // indirect golang.org/x/sys v0.32.0 // indirect golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.10.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.26.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a // indirect google.golang.org/grpc v1.71.1 // indirect diff --git a/go.sum b/go.sum index 5150eca4..be573732 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,12 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -29,6 +33,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -50,6 +56,9 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5uk github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= +github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= @@ -60,6 +69,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mark3labs/mcp-go v0.44.0 h1:OlYfcVviAnwNN40QZUrrzU0QZjq3En7rCU5X09a/B7I= +github.com/mark3labs/mcp-go v0.44.0/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -106,12 +119,18 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= +github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= +github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zeromicro/go-zero v1.8.2 h1:AbJckBoojbr1lqCN1dkvURTIHOau7yvKReEd7ZmjuCk= @@ -157,8 +176,8 @@ golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xpp golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -188,8 +207,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/handler/icons/obtainhandler.go b/internal/handler/icons/obtainhandler.go index dc191053..41b73ea9 100644 --- a/internal/handler/icons/obtainhandler.go +++ b/internal/handler/icons/obtainhandler.go @@ -15,12 +15,12 @@ import ( func ObtainHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { jsPath := "/data/config/imageLogos.js" - logx.Infof("Reading icons from: %s", jsPath) + logx.Infof("读取图标配置: %s", jsPath) contentBytes, err := os.ReadFile(jsPath) if err != nil { if os.IsNotExist(err) { - logx.Info("Config file does not exist, returning empty.") + logx.Info("图标配置文件不存在,返回空") httpx.OkJsonCtx(r.Context(), w, types.Resp{ Code: 200, Msg: "Success", @@ -28,8 +28,8 @@ func ObtainHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { }) return } - logx.Errorf("Error reading config: %v", err) - httpx.ErrorCtx(r.Context(), w, fmt.Errorf("failed to read config: %v", err)) + logx.Errorf("读取图标配置失败: %v", err) + httpx.ErrorCtx(r.Context(), w, fmt.Errorf("读取图标配置失败: %v", err)) return } @@ -51,7 +51,7 @@ func ObtainHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { } } - logx.Infof("Total icons found: %d", len(icons)) + logx.Infof("共解析出 %d 个图标", len(icons)) response := struct { Code int `json:"code"` diff --git a/internal/handler/icons/uploadhandler.go b/internal/handler/icons/uploadhandler.go index 253b7139..541d2c07 100644 --- a/internal/handler/icons/uploadhandler.go +++ b/internal/handler/icons/uploadhandler.go @@ -9,6 +9,7 @@ import ( "path/filepath" "regexp" "strings" + "sync" "github.com/google/uuid" "github.com/onlyLTY/dockerCopilot/internal/svc" @@ -28,7 +29,8 @@ var allowedImageTypes = map[string]string{ func UploadHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // 1. 解析 Multipart 表单 + // 1. 解析 Multipart 表单;限制请求体总大小,避免超大文件填盘 + r.Body = http.MaxBytesReader(w, r.Body, 10<<20) err := r.ParseMultipartForm(10 << 20) // 10MB 限制 if err != nil { writeUploadError(w, http.StatusBadRequest, "failed to parse form") @@ -69,12 +71,17 @@ func UploadHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { writeUploadError(w, http.StatusInternalServerError, "failed to create file on server") return } - defer dst.Close() - if _, err := io.Copy(dst, file); err != nil { + _ = dst.Close() + _ = os.Remove(dstPath) writeUploadError(w, http.StatusInternalServerError, "failed to copy file content") return } + if err := dst.Close(); err != nil { + _ = os.Remove(dstPath) + writeUploadError(w, http.StatusInternalServerError, "failed to save file") + return + } // 5. 更新 imageLogos.js jsPath := imageLogosPath @@ -134,7 +141,13 @@ func writeUploadError(w http.ResponseWriter, statusCode int, msg string) { }) } +var imageLogosMu sync.Mutex + func updateImageLogosJS(filePath, imageName, filename string) error { + // 读-改-写必须串行,否则并发上传会互相覆盖。 + imageLogosMu.Lock() + defer imageLogosMu.Unlock() + // 读取文件 contentBytes, err := os.ReadFile(filePath) if err != nil { @@ -168,5 +181,24 @@ func updateImageLogosJS(filePath, imageName, filename string) error { content = content[:lastBraceIdx] + newLine + "\n" + content[lastBraceIdx:] } - return os.WriteFile(filePath, []byte(content), 0644) + tmp, err := os.CreateTemp(filepath.Dir(filePath), ".imageLogos-*.js.tmp") + if err != nil { + return err + } + tmpName := tmp.Name() + defer func() { + _ = os.Remove(tmpName) + }() + if err = tmp.Chmod(0644); err != nil { + _ = tmp.Close() + return err + } + if _, err = tmp.WriteString(content); err != nil { + _ = tmp.Close() + return err + } + if err = tmp.Close(); err != nil { + return err + } + return os.Rename(tmpName, filePath) } diff --git a/internal/handler/image/cleanimageshandler.go b/internal/handler/image/cleanimageshandler.go new file mode 100644 index 00000000..8c7ba8fc --- /dev/null +++ b/internal/handler/image/cleanimageshandler.go @@ -0,0 +1,28 @@ +package image + +import ( + "net/http" + + "github.com/onlyLTY/dockerCopilot/internal/logic/image" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func CleanImagesHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.RemoveImagesReq + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := image.NewCleanImagesLogic(r.Context(), svcCtx) + resp, err := l.CleanImages(&req) + if err != nil { + httpx.WriteJson(w, resp.Code, resp) + } else { + httpx.WriteJson(w, resp.Code, resp) + } + } +} diff --git a/internal/handler/progress/streameventshandler.go b/internal/handler/progress/streameventshandler.go index 25d42641..41bad359 100644 --- a/internal/handler/progress/streameventshandler.go +++ b/internal/handler/progress/streameventshandler.go @@ -11,8 +11,17 @@ import ( "github.com/zeromicro/go-zero/rest/httpx" ) +const ( + progressPollInterval = 500 * time.Millisecond + progressHeartbeatInterval = 15 * time.Second + // progressStreamMaxDuration 单条 SSE 连接的最长时长。到时主动正常关闭, + // 客户端 EventSource 会按 retry 间隔自动重连;避免异常客户端把连接无限占住。 + progressStreamMaxDuration = 30 * time.Minute +) + // StreamEventsHandler 以 Server-Sent Events 推送任务进度,替代前端高频轮询。 -// 任务完成或客户端断开时流结束。 +// 任务完成或客户端断开时流结束。无进度变化时定期发送注释行,避免代理 +// 因长时间没有字节而断开连接。 func StreamEventsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.GetProgressReq @@ -20,8 +29,12 @@ func StreamEventsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { httpx.ErrorCtx(r.Context(), w, err) return } + if req.TaskId == "" { + httpx.ErrorCtx(r.Context(), w, fmt.Errorf("taskID 不能为空")) + return + } - flusher, ok := w.(http.Flusher) + _, ok := w.(http.Flusher) if !ok { httpx.ErrorCtx(r.Context(), w, fmt.Errorf("streaming unsupported")) return @@ -33,33 +46,74 @@ func StreamEventsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { header.Set("Connection", "keep-alive") header.Set("X-Accel-Buffering", "no") w.WriteHeader(http.StatusOK) - flusher.Flush() - ticker := time.NewTicker(500 * time.Millisecond) - defer ticker.Stop() + flush := func() bool { + if err := http.NewResponseController(w).Flush(); err != nil { + return false + } + return true + } + writeRaw := func(value string) bool { + if _, err := fmt.Fprint(w, value); err != nil { + return false + } + return flush() + } + + // EventSource 断线后 3 秒重连;首个进度事件立即发送,不用等第一个 tick。 + if !writeRaw("retry: 3000\n\n") { + return + } lastPayload := "" + sendProgress := func() (done bool, ok bool) { + progress, exists := svcCtx.GetProgress(req.TaskId) + if !exists { + writeRaw("event: error\ndata: {\"msg\":\"taskID 未找到\"}\n\n") + return true, false + } + payload, err := json.Marshal(progress) + if err != nil { + return false, true + } + if string(payload) != lastPayload { + if !writeRaw("data: " + string(payload) + "\n\n") { + return true, false + } + lastPayload = string(payload) + } + if progress.IsDone { + return true, false + } + return false, true + } + + if done, ok := sendProgress(); done || !ok { + return + } + + pollTicker := time.NewTicker(progressPollInterval) + defer pollTicker.Stop() + heartbeatTicker := time.NewTicker(progressHeartbeatInterval) + defer heartbeatTicker.Stop() + + streamDeadline := time.After(progressStreamMaxDuration) for { select { case <-r.Context().Done(): return - case <-ticker.C: - progress, exists := svcCtx.GetProgress(req.TaskId) - if !exists { - fmt.Fprintf(w, "event: error\ndata: {\"msg\":\"taskID 未找到\"}\n\n") - flusher.Flush() + case <-streamDeadline: + // 到达单连接最长时长:发注释行告知后正常结束, + // 客户端 EventSource 按 retry 间隔自动重连继续。 + _ = writeRaw(": stream deadline reached, reconnecting\n\n") + return + case <-heartbeatTicker.C: + if !writeRaw(": keep-alive\n\n") { return } - payload, err := json.Marshal(progress) - if err != nil { - continue - } - if string(payload) != lastPayload { - fmt.Fprintf(w, "data: %s\n\n", payload) - flusher.Flush() - lastPayload = string(payload) - } - if progress.IsDone { + case <-pollTicker.C: + done, ok := sendProgress() + if done || !ok { return } } diff --git a/internal/handler/routes.go b/internal/handler/routes.go index cae07343..b78241b2 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -1,6 +1,6 @@ -// Code generated by goctl. DO NOT EDIT. -// goctl 1.8.5 - +// 基于 goctl 生成,包含手工扩展:GET /(webindexHandler)、进度/设置/版本路由、 +// SSE 事件流(WithSSE)、批量镜像清理(DELETE /images)。若用 goctl 重新生成, +// 请对照 git 历史补回手工部分。 package handler import ( @@ -131,6 +131,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/images", Handler: image.ImagesListHandler(serverCtx), }, + { + // 批量清理:?filter=untagged 删除无 TAG 镜像,?filter=unused 删除未使用镜像 + Method: http.MethodDelete, + Path: "/images", + Handler: image.CleanImagesHandler(serverCtx), + }, }, rest.WithJwt(serverCtx.Config.Auth.AccessSecret), rest.WithPrefix("/api"), @@ -153,6 +159,15 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/progress/:taskid/cancel", Handler: progress.CancelProgressHandler(serverCtx), }, + }, + rest.WithJwt(serverCtx.Config.Auth.AccessSecret), + rest.WithPrefix("/api"), + ) + + // SSE 事件流单独一组:WithSSE 声明为长连接路由,go-zero 对 + // Accept: text/event-stream 的请求不做超时包裹。 + server.AddRoutes( + []rest.Route{ { Method: http.MethodGet, Path: "/progress/:taskid/events", @@ -161,6 +176,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { }, rest.WithJwt(serverCtx.Config.Auth.AccessSecret), rest.WithPrefix("/api"), + rest.WithSSE(), ) server.AddRoutes( diff --git a/internal/handler/webindexhandler.go b/internal/handler/webindexhandler.go index a02b94d8..21cf9c31 100644 --- a/internal/handler/webindexhandler.go +++ b/internal/handler/webindexhandler.go @@ -1,14 +1,47 @@ package handler import ( + "encoding/json" "net/http" + "github.com/onlyLTY/dockerCopilot/internal/config" "github.com/onlyLTY/dockerCopilot/internal/svc" ) +// webindexHandler 在去前端后作为健康检查与能力说明入口。 +// 容器 HEALTHCHECK 会请求 /,必须返回 200。 +// 响应体经 json.Marshal 生成,避免配置值(含引号/反斜杠)破坏 JSON 结构; +// 不再暴露备份目录等本机路径,只保留版本与入口信息。 func webindexHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Location", "/manager") - w.WriteHeader(301) + resp := svcInfoResponse{ + Code: http.StatusOK, + Msg: "dockerCopilot API-only mode", + Data: svcInfoData{ + Version: config.Version, + MCP: "/mcp", + API: "/api", + }, + } + body, err := json.Marshal(resp) + if err != nil { + // Marshal 常量结构不会失败,防御性兜底保证健康检查始终 200。 + body = []byte(`{"code":200,"msg":"dockerCopilot API-only mode"}`) + } + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(http.StatusOK) + _, _ = w.Write(body) } } + +type svcInfoResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data svcInfoData `json:"data"` +} + +type svcInfoData struct { + Version string `json:"version"` + MCP string `json:"mcp"` + API string `json:"api"` +} diff --git a/internal/logic/auth/loginlogic.go b/internal/logic/auth/loginlogic.go index 32ae54b9..6ad36cd2 100644 --- a/internal/logic/auth/loginlogic.go +++ b/internal/logic/auth/loginlogic.go @@ -2,12 +2,15 @@ package auth import ( "context" + "crypto/subtle" "errors" + "strings" + "time" + "github.com/golang-jwt/jwt" "github.com/onlyLTY/dockerCopilot/internal/svc" "github.com/onlyLTY/dockerCopilot/internal/types" "github.com/zeromicro/go-zero/core/logx" - "time" ) type LoginLogic struct { @@ -30,7 +33,15 @@ func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.Resp, err error) { resp = &types.Resp{} - if l.svcCtx.Config.Auth.AccessSecret != req.SecretKey { + expected := strings.TrimSpace(l.svcCtx.Config.Auth.AccessSecret) + if expected == "" { + resp.Code = 500 + resp.Msg = "服务端未配置 secretKey" + resp.Data = JwtResponse{Jwt: ""} + return resp, errors.New("服务端未配置 secretKey") + } + // 恒定时间比较,避免通过响应时间逐步猜出密钥。 + if subtle.ConstantTimeCompare([]byte(expected), []byte(strings.TrimSpace(req.SecretKey))) != 1 { resp.Code = 401 resp.Msg = "无效的secretKey" resp.Data = JwtResponse{Jwt: ""} diff --git a/internal/logic/container/backuplogic.go b/internal/logic/container/backuplogic.go index 4e56b661..099465b5 100644 --- a/internal/logic/container/backuplogic.go +++ b/internal/logic/container/backuplogic.go @@ -2,6 +2,7 @@ package container import ( "context" + "fmt" "github.com/onlyLTY/dockerCopilot/internal/utiles" "github.com/onlyLTY/dockerCopilot/internal/svc" @@ -26,15 +27,19 @@ func NewBackupLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackupLogi func (l *BackupLogic) Backup() (resp *types.Resp, err error) { resp = &types.Resp{} - err = utiles.BackupContainer(l.svcCtx) + failures, err := utiles.BackupContainer(l.svcCtx) if err != nil { resp.Code = 500 resp.Msg = err.Error() - resp.Data = map[string]interface{}{} + resp.Data = map[string]interface{}{"failures": failures} return resp, err } - resp.Msg = "success" resp.Code = 200 - resp.Data = map[string]interface{}{} + if len(failures) > 0 { + resp.Msg = fmt.Sprintf("备份完成,%d 个容器失败", len(failures)) + } else { + resp.Msg = "success" + } + resp.Data = map[string]interface{}{"failures": failures} return resp, nil } diff --git a/internal/logic/container/containerslistlogic.go b/internal/logic/container/containerslistlogic.go index c6858f6a..e93af8ff 100644 --- a/internal/logic/container/containerslistlogic.go +++ b/internal/logic/container/containerslistlogic.go @@ -2,9 +2,11 @@ package container import ( "context" - "github.com/onlyLTY/dockerCopilot/internal/utiles" + "strings" "time" + "github.com/onlyLTY/dockerCopilot/internal/utiles" + "github.com/onlyLTY/dockerCopilot/internal/svc" "github.com/onlyLTY/dockerCopilot/internal/types" @@ -55,22 +57,25 @@ func (l *ContainersListLogic) ContainersList() (resp *types.Resp, err error) { containerInfo.Id = v.ID containerInfo.Status = v.State if len(v.Names) > 0 { - ContainerName := v.Names[0][1:] - containerInfo.Name = ContainerName + containerInfo.Name = strings.TrimPrefix(v.Names[0], "/") } else { - containerInfo.Name = "get container name error" - l.Error("get container name error" + v.ID) + containerInfo.Name = "获取容器名失败" + l.Error("获取容器名失败: " + v.ID) } if v.Image != "" { containerInfo.UsingImage = v.Image } else { containerInfo.UsingImage = v.ImageID - l.Error("image dont have name" + v.ID) + l.Error("容器镜像无名称: " + v.ID) } containerInspect, err := utiles.GetContainerInspect(l.svcCtx, v.ID) - if err != nil { + if err != nil || containerInspect.Config == nil { containerInfo.CreateImage = "" - l.Error("get image name error" + v.ID) + if err != nil { + l.Error("获取容器创建镜像失败: " + v.ID + ": " + err.Error()) + } else { + l.Error("容器配置为空: " + v.ID) + } } else { containerInfo.CreateImage = containerInspect.Config.Image } diff --git a/internal/logic/container/renamelogic.go b/internal/logic/container/renamelogic.go index c0c3f5eb..5e5c1316 100644 --- a/internal/logic/container/renamelogic.go +++ b/internal/logic/container/renamelogic.go @@ -2,6 +2,8 @@ package container import ( "context" + "strings" + "github.com/onlyLTY/dockerCopilot/internal/utiles" "github.com/onlyLTY/dockerCopilot/internal/svc" @@ -26,14 +28,21 @@ func NewRenameLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RenameLogi func (l *RenameLogic) Rename(req *types.ContainerRenameReq) (resp *types.Resp, err error) { resp = &types.Resp{} - err = utiles.RenameContainer(l.svcCtx, req.Id, req.NewName) + newName := strings.TrimSpace(req.NewName) + if newName == "" { + resp.Code = 400 + resp.Msg = "新容器名不能为空" + resp.Data = map[string]interface{}{} + return resp, nil + } + err = utiles.RenameContainer(l.svcCtx, req.Id, newName) if err != nil { resp.Code = 400 resp.Msg = err.Error() resp.Data = map[string]interface{}{} return resp, err } - utiles.AuditLog("container.rename", req.Id, "") + utiles.AuditLog("container.rename", req.Id, "newName="+newName) resp.Code = 200 resp.Msg = "success" resp.Data = map[string]interface{}{} diff --git a/internal/logic/container/restorelogic.go b/internal/logic/container/restorelogic.go index b6cb946d..4e82f547 100644 --- a/internal/logic/container/restorelogic.go +++ b/internal/logic/container/restorelogic.go @@ -46,21 +46,41 @@ func (l *RestoreLogic) Restore(req *types.ContainerRestoreReq) (resp *types.Resp resp.Data = map[string]interface{}{} return resp, err } + taskCtx := l.svcCtx.RegisterTask(taskID) go func() { // Catch any panic and log the error defer func() { if r := recover(); r != nil { - l.Errorf("Recovered from panic in restoreContainer: %v", r) + l.Errorf("恢复容器任务 panic 已恢复: %v", r) + msg := fmt.Sprintf("恢复任务异常中断: %v", r) + l.svcCtx.UpdateProgress(taskID, svc.TaskProgress{ + TaskID: taskID, + Percentage: 100, + Name: "恢复容器", + Message: "恢复失败", + DetailMsg: msg, + IsDone: true, + }) + utiles.NotifyTaskDone("restore", fileName, taskID, false, msg) + utiles.AuditLog("container.restore", fileName, msg) } l.svcCtx.FinishTask(taskID) }() - err := utiles.RestoreContainer(l.svcCtx, fileName, taskID) + err := utiles.RestoreContainer(taskCtx, l.svcCtx, fileName, taskID, req.Start, req.Force) if err != nil { - l.Errorf("Error in restoreContainer: %v", err) + l.Errorf("恢复容器出错: %v", err) } final, _ := l.svcCtx.GetProgress(taskID) - utiles.NotifyTaskDone("restore", fileName, taskID, err == nil, final.Message) - utiles.AuditLog("container.restore", fileName, final.Message) + message := final.Message + if message == "" { + message = "恢复任务已结束" + } + detail := final.DetailMsg + if detail == "" { + detail = message + } + utiles.NotifyTaskDone("restore", fileName, taskID, err == nil, message) + utiles.AuditLog("container.restore", fileName, detail) }() resp.Code = 200 resp.Msg = "success" diff --git a/internal/logic/container/updatelogic.go b/internal/logic/container/updatelogic.go index c0a2f1ed..69157f37 100644 --- a/internal/logic/container/updatelogic.go +++ b/internal/logic/container/updatelogic.go @@ -2,12 +2,14 @@ package container import ( "context" + "fmt" + "os" + "github.com/google/uuid" "github.com/onlyLTY/dockerCopilot/internal/svc" "github.com/onlyLTY/dockerCopilot/internal/types" "github.com/onlyLTY/dockerCopilot/internal/utiles" "github.com/zeromicro/go-zero/core/logx" - "os" ) type UpdateLogic struct { @@ -32,7 +34,18 @@ func (l *UpdateLogic) Update(req *types.ContainerUpdateReq) (resp *types.Resp, e // Catch any panic and log the error defer func() { if r := recover(); r != nil { - l.Errorf("Recovered from panic in UpdateContainer: %v", r) + l.Errorf("更新容器任务 panic 已恢复: %v", r) + msg := fmt.Sprintf("更新任务异常中断: %v", r) + l.svcCtx.UpdateProgress(taskID, svc.TaskProgress{ + TaskID: taskID, + Percentage: 100, + Name: req.ContainerName, + Message: "更新失败", + DetailMsg: msg, + IsDone: true, + }) + utiles.NotifyTaskDone("update", req.ContainerName, taskID, false, msg) + utiles.AuditLog("container.update", req.ContainerName, msg) } l.svcCtx.FinishTask(taskID) }() @@ -40,11 +53,15 @@ func (l *UpdateLogic) Update(req *types.ContainerUpdateReq) (resp *types.Resp, e delOldContainer := os.Getenv("DelOldContainer") != "false" err := utiles.UpdateContainer(l.svcCtx, taskCtx, req.Id, req.ContainerName, imageNameAndTag, delOldContainer, taskID) if err != nil { - l.Errorf("Error in UpdateContainer: %v", err) + l.Errorf("更新容器出错: %v", err) } final, _ := l.svcCtx.GetProgress(taskID) + detail := final.DetailMsg + if detail == "" { + detail = final.Message + } utiles.NotifyTaskDone("update", req.ContainerName, taskID, err == nil, final.Message) - utiles.AuditLog("container.update", req.ContainerName, final.Message) + utiles.AuditLog("container.update", req.ContainerName, detail) }() resp.Code = 200 resp.Msg = "success" diff --git a/internal/logic/image/cleanimageslogic.go b/internal/logic/image/cleanimageslogic.go new file mode 100644 index 00000000..cc5ab931 --- /dev/null +++ b/internal/logic/image/cleanimageslogic.go @@ -0,0 +1,60 @@ +package image + +import ( + "context" + "strconv" + + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/onlyLTY/dockerCopilot/internal/types" + "github.com/onlyLTY/dockerCopilot/internal/utiles" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CleanImagesLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewCleanImagesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CleanImagesLogic { + return &CleanImagesLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +// CleanImages 批量清理镜像:filter=untagged 删除无 TAG 镜像, +// filter=unused 删除未被任何容器引用的镜像。单个失败不影响其它。 +func (l *CleanImagesLogic) CleanImages(req *types.RemoveImagesReq) (resp *types.Resp, err error) { + resp = &types.Resp{} + if req.Filter != utiles.CleanupFilterUntagged && req.Filter != utiles.CleanupFilterUnused { + resp.Code = 400 + resp.Msg = "filter 参数错误,只支持 untagged(无 TAG 镜像)或 unused(未使用镜像)" + resp.Data = map[string]interface{}{} + return resp, nil + } + removed, failed, err := utiles.RemoveImagesFiltered(l.svcCtx, req.Filter) + if err != nil { + resp.Code = 500 + resp.Msg = err.Error() + resp.Data = map[string]interface{}{} + return resp, err + } + // 已删除/失败清单都进审计,删除操作不可恢复,必须留痕。 + utiles.AuditLog("image.cleanup", req.Filter, + "removed="+strconv.Itoa(len(removed))+", failed="+strconv.Itoa(len(failed))) + resp.Code = 200 + if len(failed) > 0 { + resp.Msg = "清理完成,部分镜像删除失败" + } else { + resp.Msg = "success" + } + resp.Data = map[string]interface{}{ + "filter": req.Filter, + "removed": removed, + "failed": failed, + } + return resp, nil +} diff --git a/internal/logic/image/removelogic.go b/internal/logic/image/removelogic.go index c881a522..6af9d13d 100644 --- a/internal/logic/image/removelogic.go +++ b/internal/logic/image/removelogic.go @@ -31,7 +31,7 @@ func (l *RemoveLogic) Remove(req *types.RemoveImageReq) (resp *types.Resp, err e if strings.HasPrefix(imageId, "sha256:") { imageId = strings.TrimPrefix(imageId, "sha256:") } - err = utiles.RemoveImage(l.svcCtx, req.Id, req.Force) + err = utiles.RemoveImage(l.svcCtx, imageId, req.Force) if err != nil { resp.Code = 409 resp.Msg = err.Error() diff --git a/internal/logic/progress/cancelprogresslogic.go b/internal/logic/progress/cancelprogresslogic.go index ea925b97..fcbc8ffa 100644 --- a/internal/logic/progress/cancelprogresslogic.go +++ b/internal/logic/progress/cancelprogresslogic.go @@ -25,28 +25,13 @@ func NewCancelProgressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ca func (l *CancelProgressLogic) CancelProgress(req *types.GetProgressReq) (resp *types.Resp, err error) { resp = &types.Resp{} - progress, exists := l.svcCtx.GetProgress(req.TaskId) - if !exists { + ok, msg := l.svcCtx.CancelActiveTask(req.TaskId) + if !ok { resp.Code = 400 - resp.Msg = "taskID 未找到" + resp.Msg = msg resp.Data = map[string]interface{}{} return resp, nil } - if progress.IsDone { - resp.Code = 400 - resp.Msg = "任务已结束,无需取消" - resp.Data = map[string]interface{}{} - return resp, nil - } - if !l.svcCtx.CancelTask(req.TaskId) { - resp.Code = 400 - resp.Msg = "任务不可取消(可能已结束)" - resp.Data = map[string]interface{}{} - return resp, nil - } - progress.Message = "正在取消..." - progress.DetailMsg = "已发出取消请求,任务将在当前步骤结束后停止" - l.svcCtx.UpdateProgress(req.TaskId, progress) resp.Code = 200 resp.Msg = "success" resp.Data = map[string]interface{}{"taskID": req.TaskId} diff --git a/internal/logic/settings/settingslogic.go b/internal/logic/settings/settingslogic.go index e49e9413..4eaeb84d 100644 --- a/internal/logic/settings/settingslogic.go +++ b/internal/logic/settings/settingslogic.go @@ -2,6 +2,9 @@ package settings import ( "context" + "os" + "path/filepath" + "strings" "github.com/onlyLTY/dockerCopilot/internal/svc" "github.com/onlyLTY/dockerCopilot/internal/types" @@ -38,15 +41,45 @@ func (l *SettingsLogic) GetSettings() (resp *types.Resp, err error) { func (l *SettingsLogic) UpdateSettings(req *types.UpdateSettingsReq) (resp *types.Resp, err error) { resp = &types.Resp{} + dir := strings.TrimSpace(req.BackupDir) + if dir == "" { + resp.Code = 400 + resp.Msg = "备份目录不能为空" + resp.Data = map[string]interface{}{} + return resp, nil + } + if !filepath.IsAbs(dir) { + resp.Code = 400 + resp.Msg = "备份目录必须是绝对路径" + resp.Data = map[string]interface{}{} + return resp, nil + } + if mkErr := os.MkdirAll(dir, 0755); mkErr != nil { + resp.Code = 400 + resp.Msg = "无法创建备份目录: " + mkErr.Error() + resp.Data = map[string]interface{}{} + return resp, nil + } + testFile, testErr := os.CreateTemp(dir, ".write-test-*") + if testErr != nil { + resp.Code = 400 + resp.Msg = "备份目录不可写: " + testErr.Error() + resp.Data = map[string]interface{}{} + return resp, nil + } + testName := testFile.Name() + _ = testFile.Close() + _ = os.Remove(testName) + s := utiles.LoadSettings() - s.BackupDir = req.BackupDir + s.BackupDir = dir if saveErr := utiles.SaveSettings(s); saveErr != nil { resp.Code = 500 resp.Msg = "保存设置失败: " + saveErr.Error() resp.Data = map[string]interface{}{} return resp, nil } - utiles.AuditLog("settings.update", "settings", "backupDir="+req.BackupDir) + utiles.AuditLog("settings.update", "settings", "backupDir="+dir) resp.Code = 200 resp.Msg = "success" resp.Data = map[string]interface{}{ diff --git a/internal/logic/version/updateprogramlogic.go b/internal/logic/version/updateprogramlogic.go index 07c1c34a..610436c9 100644 --- a/internal/logic/version/updateprogramlogic.go +++ b/internal/logic/version/updateprogramlogic.go @@ -35,6 +35,10 @@ func (l *UpdateProgramLogic) UpdateProgram() (resp *types.Resp, err error) { } resp.Code = 200 resp.Msg = "success" + // 与 MCP 通道保持一致:自更新成功也要留审计与通知(进程 10 秒后退出, + // 必须在退出前完成落盘)。 + utiles.AuditLog("program.update", "self", "program update triggered via HTTP API") + utiles.NotifyTaskDone("program", "self", "", true, "程序自更新完成,服务即将重启换入新版本") go func() { time.Sleep(10 * time.Second) os.Exit(1) diff --git a/internal/logic/version/versionlogic.go b/internal/logic/version/versionlogic.go index 4cf7c9d8..f9579891 100644 --- a/internal/logic/version/versionlogic.go +++ b/internal/logic/version/versionlogic.go @@ -2,6 +2,7 @@ package version import ( "context" + "errors" "github.com/onlyLTY/dockerCopilot/internal/config" @@ -37,8 +38,20 @@ func (l *VersionLogic) Version(req *types.VersionReq) (resp *types.Resp, err err return resp, nil } else if req.Type == "remote" { remoteVersion, err := utiles.GetRemoteVersion() + if errors.Is(err, utiles.ErrFnosManagedUpdate) { + // FNOS 版本不走通用更新链:明确告知用户,而不是伪装成“无更新”。 + resp.Code = 200 + resp.Msg = err.Error() + resp.Data = map[string]string{ + "remoteVersion": config.Version, + "fnos": "true", + } + return resp, nil + } if err != nil { - resp.Code = 50001 + // 注意:resp.Code 会被 handler 当作 HTTP 状态码写入,业务码不能超过 999, + // 否则 net/http 直接丢弃响应体(曾导致错误时返回空 500)。 + resp.Code = 500 resp.Msg = "获取版本错误" + err.Error() resp.Data = map[string]string{ "remoteVersion": config.Version, diff --git a/internal/module/auth.go b/internal/module/auth.go index 18eecb4d..becf9694 100644 --- a/internal/module/auth.go +++ b/internal/module/auth.go @@ -1,31 +1,70 @@ package module import ( + "crypto/tls" "encoding/json" "errors" "fmt" - ref "github.com/distribution/reference" - "github.com/onlyLTY/dockerCopilot/internal/types" - "github.com/zeromicro/go-zero/core/logx" "io" "net/http" "net/url" + "os" "strings" + "sync" "time" + + ref "github.com/distribution/reference" + "github.com/onlyLTY/dockerCopilot/internal/types" + "github.com/zeromicro/go-zero/core/logx" ) const ChallengeHeader = "WWW-Authenticate" const ( DefaultRegistryDomain = "docker.io" - DefaultRegistryHost = "index.docker.io" + DefaultRegistryHost = "registry-1.docker.io" ) +var registryHTTPClient = newRegistryHTTPClient() + +func newRegistryHTTPClient() *http.Client { + transport, ok := http.DefaultTransport.(*http.Transport) + if !ok { + transport = &http.Transport{} + } else { + transport = transport.Clone() + } + if os.Getenv("REGISTRY_INSECURE") == "true" { + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} // #nosec G402 -- 由用户显式开启 + } + return &http.Client{Transport: transport, Timeout: 15 * time.Second} +} + +// host 探测结果缓存,避免每个镜像都重新跑一遍 10 个加速器。 +type hostCheckResult struct { + ok bool + at time.Time +} + +var hostCheckCache sync.Map + +func checkHostCached(host string) bool { + if v, ok := hostCheckCache.Load(host); ok { + r := v.(hostCheckResult) + if time.Since(r.at) < 10*time.Minute { + return r.ok + } + } + ok := checkHost(host) + hostCheckCache.Store(host, hostCheckResult{ok: ok, at: time.Now()}) + return ok +} + var DefaultAcceleratorHostList = []string{"docker.1ms.run", "docker.m.daocloud.io", "docker.1panel.top", "docker.1panel.live", "proxy.1panel.live", "dockerproxy.1panel.live", "docker.1panel.dev", "docker.anye.in", "hub.rat.dev", "docker.amingg.com"} func GetToken(image types.Image, registryAuth string) (string, error) { - logx.Infof("image name %s", image.ImageName) + logx.Infof("镜像名称: %s", image.ImageName) normalizedRef, err := ref.ParseNormalizedNamed(image.ImageName) if err != nil { return "", err @@ -38,9 +77,8 @@ func GetToken(image types.Image, registryAuth string) (string, error) { return "", err } - client := &http.Client{} var res *http.Response - if res, err = client.Do(req); err != nil { + if res, err = registryHTTPClient.Do(req); err != nil { return "", err } defer func(Body io.ReadCloser) { @@ -51,19 +89,20 @@ func GetToken(image types.Image, registryAuth string) (string, error) { }(res.Body) v := res.Header.Get(ChallengeHeader) - challenge := strings.ToLower(v) - if strings.HasPrefix(challenge, "basic") { + challenge := strings.TrimSpace(v) + lowerChallenge := strings.ToLower(challenge) + if strings.HasPrefix(lowerChallenge, "basic") { if registryAuth == "" { - return "", fmt.Errorf("no credentials available") + return "", fmt.Errorf("无可用凭证") } return fmt.Sprintf("Basic %s", registryAuth), nil } - if strings.HasPrefix(challenge, "bearer") { + if strings.HasPrefix(lowerChallenge, "bearer") { return GetBearerHeader(challenge, normalizedRef, registryAuth) } - return "", errors.New("unsupported challenge type from registry") + return "", errors.New("registry 返回了不支持的认证质询类型") } func GetChallengeRequest(URL url.URL) (*http.Request, error) { @@ -72,12 +111,11 @@ func GetChallengeRequest(URL url.URL) (*http.Request, error) { return nil, err } req.Header.Set("Accept", "*/*") - req.Header.Set("User-Agent", "Watchtower (Docker)") + req.Header.Set("User-Agent", "dockerCopilot") return req, nil } func GetBearerHeader(challenge string, imageRef ref.Named, registryAuth string) (string, error) { - client := http.Client{} authURL, err := GetAuthURL(challenge, imageRef) if err != nil { @@ -93,44 +131,64 @@ func GetBearerHeader(challenge string, imageRef ref.Named, registryAuth string) logx.Info("私有镜像,无法获取是否有更新") r.Header.Add("Authorization", fmt.Sprintf("Basic %s", registryAuth)) } else { - logx.Info("No credentials found.") + logx.Info("未找到凭证。") } var authResponse *http.Response - if authResponse, err = client.Do(r); err != nil { + if authResponse, err = registryHTTPClient.Do(r); err != nil { return "", err } + defer func(Body io.ReadCloser) { + if closeErr := Body.Close(); closeErr != nil { + logx.Errorf("GetBearerHeader关闭Body失败: %v", closeErr) + } + }(authResponse.Body) - body, _ := io.ReadAll(authResponse.Body) + body, err := io.ReadAll(io.LimitReader(authResponse.Body, 1<<20)) + if err != nil { + return "", err + } + if authResponse.StatusCode < 200 || authResponse.StatusCode >= 300 { + return "", fmt.Errorf("获取 registry token 失败: %s", authResponse.Status) + } tokenResponse := &types.TokenResponse{} err = json.Unmarshal(body, tokenResponse) if err != nil { return "", err } + if tokenResponse.Token == "" { + return "", fmt.Errorf("registry 返回的 token 为空") + } return fmt.Sprintf("Bearer %s", tokenResponse.Token), nil } func GetAuthURL(challenge string, imageRef ref.Named) (*url.URL, error) { - loweredChallenge := strings.ToLower(challenge) - raw := strings.TrimPrefix(loweredChallenge, "bearer") + raw := strings.TrimSpace(challenge) + if idx := strings.IndexByte(raw, ' '); idx >= 0 { + raw = raw[idx+1:] + } pairs := strings.Split(raw, ",") values := make(map[string]string, len(pairs)) for _, pair := range pairs { - trimmed := strings.Trim(pair, " ") + trimmed := strings.TrimSpace(pair) if key, val, ok := strings.Cut(trimmed, "="); ok { - values[key] = strings.Trim(val, `"`) + // challenge 参数名大小写不敏感,但 realm URL 的路径必须保留原始大小写。 + values[strings.ToLower(key)] = strings.Trim(val, `"`) } } if values["realm"] == "" || values["service"] == "" { - return nil, fmt.Errorf("challenge header did not include all values needed to construct an auth url") + return nil, fmt.Errorf("challenge 头缺少构造认证 URL 所需的字段") } - authURL, _ := url.Parse(values["realm"]) + authURL, err := url.Parse(values["realm"]) + if err != nil || authURL.Host == "" || (authURL.Scheme != "http" && authURL.Scheme != "https") { + return nil, fmt.Errorf("registry 返回了非法的 realm: %q", values["realm"]) + } q := authURL.Query() q.Add("service", values["service"]) @@ -144,7 +202,10 @@ func GetAuthURL(challenge string, imageRef ref.Named) (*url.URL, error) { } func GetChallengeURL(imageRef ref.Named) url.URL { - host, _ := GetRegistryAddress(imageRef.Name()) + host, err := GetRegistryAddress(imageRef.Name()) + if err != nil || host == "" { + host = DefaultRegistryHost + } URL := url.URL{ Scheme: "https", @@ -163,11 +224,11 @@ func GetRegistryAddress(imageRef string) (string, error) { address := ref.Domain(normalizedRef) if address == DefaultRegistryDomain { - if checkHost(DefaultRegistryHost) { + if checkHostCached(DefaultRegistryHost) { address = DefaultRegistryHost } else { for _, host := range DefaultAcceleratorHostList { - if checkHost(host) { + if checkHostCached(host) { address = host break } @@ -182,20 +243,21 @@ func GetRegistryAddress(imageRef string) (string, error) { func checkHost(host string) bool { URL := "https://" + host + "/v2/" - // 创建带有超时设置的 http.Client + // 复用 registry 客户端 transport,确保 REGISTRY_INSECURE 对探测同样生效。 client := http.Client{ - Timeout: 5 * time.Second, + Transport: registryHTTPClient.Transport, + Timeout: 5 * time.Second, } // 发送 HEAD 请求 resp, err := client.Get(URL) if err != nil { - logx.Errorf("Failed to connect to %s: %s", URL, err) + logx.Errorf("连接 %s 失败: %s", URL, err) return false } defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { - logx.Errorf("关闭body失败" + err.Error()) + logx.Errorf("关闭body失败: %v", err) } }(resp.Body) @@ -205,6 +267,6 @@ func checkHost(host string) bool { return true } - logx.Errorf("Failed to connect to %s: %s", URL, resp.Status) + logx.Errorf("连接 %s 失败: %s", URL, resp.Status) return false } diff --git a/internal/module/checkupdate.go b/internal/module/checkupdate.go index 78a11064..4674145e 100644 --- a/internal/module/checkupdate.go +++ b/internal/module/checkupdate.go @@ -34,6 +34,17 @@ func (i *ImageUpdateData) Get(imageID string) (ImageCheckList, bool) { return v, ok } +// Snapshot 返回当前全部检查结果的副本(并发安全),供 MCP 等外部调用方读取。 +func (i *ImageUpdateData) Snapshot() map[string]ImageCheckList { + i.mu.RLock() + defer i.mu.RUnlock() + out := make(map[string]ImageCheckList, len(i.Data)) + for k, v := range i.Data { + out[k] = v + } + return out +} + const ContentDigestHeader = "Docker-Content-Digest" const checkUpdateConcurrency = 4 @@ -49,7 +60,7 @@ func (i *ImageUpdateData) CheckUpdate(imageList []types.Image) { var wg sync.WaitGroup sem := make(chan struct{}, checkUpdateConcurrency) for _, image := range imageList { - if strings.Contains(image.ImageName, "0nlylty/dockercopilot") { + if strings.Contains(strings.ToLower(image.ImageName), "dockercopilot") { continue } wg.Add(1) @@ -59,6 +70,11 @@ func (i *ImageUpdateData) CheckUpdate(imageList []types.Image) { defer func() { <-sem }() if result, ok := i.checkSingleImage(img); ok { resultsMu.Lock() + // 同一 image ID 可能有多个 tag。只要任意一个 tag 有更新就保留 + // NeedUpdate=true,避免最后一个完成的 goroutine 把结果覆盖成 false。 + if old, exists := results[img.ID]; exists { + result.NeedUpdate = result.NeedUpdate || old.NeedUpdate + } results[img.ID] = result resultsMu.Unlock() } @@ -71,9 +87,13 @@ func (i *ImageUpdateData) CheckUpdate(imageList []types.Image) { } func (i *ImageUpdateData) checkSingleImage(image types.Image) (ImageCheckList, bool) { + if image.ImageName == "" || image.ImageName == "None" || image.ImageTag == "" || image.ImageTag == "None" { + // 只有 digest、没有 tag 的镜像无法构造 manifests/ 请求。 + return ImageCheckList{}, false + } token, err := GetToken(image, "") if err != nil { - logx.Error("获取token失败或者无需获取token,继续尝试检查" + err.Error()) + logx.Errorf("获取 token 失败(%s),将继续直接尝试检查", err) } digestURL, err := BuildManifestURL(image) if err != nil { @@ -91,22 +111,25 @@ func (i *ImageUpdateData) checkSingleImage(image types.Image) (ImageCheckList, b } needUpdate := false for _, localRepoDigests := range image.RepoDigests { - parts := strings.Split(localRepoDigests, "@") + parts := strings.SplitN(localRepoDigests, "@", 2) if len(parts) != 2 { continue } - localDigest := parts[1] + localRepo, localDigest := parts[0], parts[1] + // 只比较同一仓库的 digest,避免同一镜像 ID 的其它 tag/仓库造成误报。 + if localRepo != image.ImageName && !strings.HasSuffix(localRepo, "/"+image.ImageName) { + continue + } if remoteDigest == "" || localDigest == "" { logx.Error("Digest为空" + image.ImageName + ":" + image.ImageTag) continue } if remoteDigest != localDigest { - // 任一本地 digest 与远端不同即判定需要更新,不能因后续匹配被覆盖 - logx.Info(image.ImageName + ":" + image.ImageTag + " need update") - logx.Infof("localDigest: %s, remoteDigest: %s", localDigest, remoteDigest) + logx.Info(image.ImageName + ":" + image.ImageTag + " 有可用更新") + logx.Infof("本地digest: %s, 远程digest: %s", localDigest, remoteDigest) needUpdate = true } else { - logx.Info(image.ImageName + ":" + image.ImageTag + " not need update") + logx.Info(image.ImageName + ":" + image.ImageTag + " 无需更新") } } return ImageCheckList{NeedUpdate: needUpdate}, true @@ -149,11 +172,15 @@ func GetDigest(url string, token string) (string, error) { IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, - TLSClientConfig: &tls.Config{InsecureSkipVerify: os.Getenv("REGISTRY_INSECURE") != "false"}, + TLSClientConfig: &tls.Config{InsecureSkipVerify: os.Getenv("REGISTRY_INSECURE") == "true"}, } - client := &http.Client{Transport: tr} + client := &http.Client{Transport: tr, Timeout: 20 * time.Second} - req, _ := http.NewRequest("HEAD", url, nil) + req, err := http.NewRequest("HEAD", url, nil) + if err != nil { + return "", err + } + req.Header.Set("User-Agent", "dockerCopilot") if token != "" { req.Header.Add("Authorization", token) @@ -179,7 +206,7 @@ func GetDigest(url string, token string) (string, error) { if wwwAuthHeader == "" { wwwAuthHeader = "not present" } - return "", fmt.Errorf("registry responded to head request with %q, auth: %q", res.Status, wwwAuthHeader) + return "", fmt.Errorf("registry 对 HEAD 请求返回 %q,认证头: %q", res.Status, wwwAuthHeader) } return res.Header.Get(ContentDigestHeader), nil } diff --git a/internal/svc/servicecontext.go b/internal/svc/servicecontext.go index ed0f6977..e509a8e2 100644 --- a/internal/svc/servicecontext.go +++ b/internal/svc/servicecontext.go @@ -28,9 +28,11 @@ type ServiceContext struct { IndexCheckMiddleware rest.Middleware ProgressStore ProgressStoreType DockerClient *client.Client + DockerInitErr error mu sync.Mutex taskCancels map[string]context.CancelFunc saveMu sync.Mutex + lastProgressSave time.Time } type TaskProgress struct { @@ -49,7 +51,7 @@ type ProgressStoreType map[string]TaskProgress func NewServiceContext(c config.Config) *ServiceContext { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { - logx.Errorf("Unable to create docker client: %s", err) + logx.Errorf("创建 Docker 客户端失败: %s", err) } ctx := &ServiceContext{ Config: c, @@ -57,6 +59,7 @@ func NewServiceContext(c config.Config) *ServiceContext { ProgressStore: make(ProgressStoreType), taskCancels: make(map[string]context.CancelFunc), DockerClient: cli, + DockerInitErr: err, } ctx.loadProgress() go ctx.taskJanitor() @@ -82,18 +85,36 @@ func (ctx *ServiceContext) loadProgress() { logx.Errorf("进度文件解析失败: %v", err) return } + now := time.Now().Unix() + interrupted := false ctx.mu.Lock() for k, v := range stored { + if !v.IsDone { + // 进程刚重启,磁盘里还处于“进行中”的任务不可能再继续执行。 + v.IsDone = true + v.FinishedAt = now + v.Percentage = 100 + v.Message = "进程重启,任务已中断" + v.DetailMsg = "任务执行期间服务重启,请重新发起" + interrupted = true + } ctx.ProgressStore[k] = v } ctx.mu.Unlock() + if interrupted { + ctx.saveProgress() + } } // saveProgress 原子写入进度文件(临时文件 + rename)。 +// 序列化和落盘都持有 ctx.mu:否则并发保存时,旧快照可能后落盘, +// 把更新的任务状态覆盖掉。进度写入频率已被 UpdateProgress 限制, +// 这里短暂持锁不会成为任务更新的瓶颈。 func (ctx *ServiceContext) saveProgress() { ctx.mu.Lock() + defer ctx.mu.Unlock() + data, err := json.Marshal(ctx.ProgressStore) - ctx.mu.Unlock() if err != nil { logx.Errorf("进度序列化失败: %v", err) return @@ -166,8 +187,15 @@ func (ctx *ServiceContext) UpdateProgress(taskID string, progress TaskProgress) } } ctx.ProgressStore[taskID] = progress + // 高频拉取进度只留在内存;最多每秒落盘一次,完成时立即落盘。 + shouldSave := progress.IsDone || time.Since(ctx.lastProgressSave) >= time.Second + if shouldSave { + ctx.lastProgressSave = time.Now() + } ctx.mu.Unlock() - ctx.saveProgress() + if shouldSave { + ctx.saveProgress() + } } func (ctx *ServiceContext) GetProgress(taskID string) (TaskProgress, bool) { @@ -217,6 +245,32 @@ func (ctx *ServiceContext) CancelTask(taskID string) bool { return ok } +// CancelActiveTask 原子地检查并取消任务,避免“刚好完成”时被取消逻辑覆盖状态。 +func (ctx *ServiceContext) CancelActiveTask(taskID string) (ok bool, msg string) { + ctx.mu.Lock() + progress, exists := ctx.ProgressStore[taskID] + if !exists { + ctx.mu.Unlock() + return false, "taskID 未找到" + } + if progress.IsDone { + ctx.mu.Unlock() + return false, "任务已结束,无需取消" + } + cancel, exists := ctx.taskCancels[taskID] + if !exists { + ctx.mu.Unlock() + return false, "任务不可取消(可能已结束)" + } + cancel() + progress.Message = "正在取消..." + progress.DetailMsg = "已发出取消请求,任务将在当前步骤结束后停止" + ctx.ProgressStore[taskID] = progress + ctx.mu.Unlock() + ctx.saveProgress() + return true, "" +} + // FinishTask 任务收尾,释放取消句柄。 func (ctx *ServiceContext) FinishTask(taskID string) { ctx.mu.Lock() diff --git a/internal/types/types.go b/internal/types/types.go index dd981ea8..ef443b39 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -1,8 +1,12 @@ -// Code generated by goctl. DO NOT EDIT. -// goctl 1.8.5 +// 基于 goctl 生成的类型定义,包含手工扩展(Nil、RemoveImagesReq、 +// ContainerRestoreReq 等)。若用 goctl 重新生成,请对照 git 历史补回手工部分。 package types +// Nil 用作 BaseResponse 泛型的占位类型,表示“无数据”。 +// 不要再用 go/types.Nil 之类的第三方类型充当占位符。 +type Nil struct{} + type ContainerRenameReq struct { IdReq NewName string `form:"newName"` @@ -10,6 +14,10 @@ type ContainerRenameReq struct { type ContainerRestoreReq struct { Filename string `json:"filename"` + // Start 为空时按备份记录的状态恢复;true/false 强制启动或不启动。 + Start *bool `json:"start,optional"` + // Force 为 true 时,同名容器会被删除后重建;默认跳过同名容器。 + Force bool `json:"force,optional"` } type ContainerUpdateReq struct { @@ -58,6 +66,12 @@ type RemoveImageReq struct { Force bool `form:"force,default=false"` } +// RemoveImagesReq 批量镜像清理请求: +// filter=untagged 删除无 TAG 镜像,filter=unused 删除未被任何容器引用的镜像。 +type RemoveImagesReq struct { + Filter string `form:"filter"` +} + type RenameContainerReq struct { OldName string `json:"oldName"` NewName string `json:"newName"` diff --git a/internal/utiles/audit.go b/internal/utiles/audit.go index 3f078598..70123f69 100644 --- a/internal/utiles/audit.go +++ b/internal/utiles/audit.go @@ -42,7 +42,12 @@ func AuditLog(action, target, detail string) { if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil { return } - f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + // 简单轮转:超过 10MB 就保留一份 .1,避免长期运行无限增长。 + if info, statErr := os.Stat(path); statErr == nil && info.Size() > 10<<20 { + _ = os.Remove(path + ".1") + _ = os.Rename(path, path+".1") + } + f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) if err != nil { return } diff --git a/internal/utiles/autoupdate.go b/internal/utiles/autoupdate.go index 20e8c959..89796c19 100644 --- a/internal/utiles/autoupdate.go +++ b/internal/utiles/autoupdate.go @@ -1,17 +1,28 @@ package utiles import ( + "fmt" "os" "strings" + "sync" "github.com/google/uuid" "github.com/onlyLTY/dockerCopilot/internal/svc" "github.com/zeromicro/go-zero/core/logx" ) +// 自动更新是全局串行任务:一轮没跑完时下一轮直接跳过,避免重复检查和并发更新。 +var autoUpdateMu sync.Mutex + // RunAutoUpdate 依据 AUTOUPDATE_WHITELIST(逗号分隔容器名,* 表示全部) // 对有可用更新的容器执行自动更新,逐个串行避免 IO 争抢。 func RunAutoUpdate(serviceContext *svc.ServiceContext) { + if !autoUpdateMu.TryLock() { + logx.Infof("自动更新:上一轮仍在执行,本轮跳过") + return + } + defer autoUpdateMu.Unlock() + whitelistRaw := strings.TrimSpace(os.Getenv("AUTOUPDATE_WHITELIST")) if whitelistRaw == "" { return @@ -37,11 +48,26 @@ func RunAutoUpdate(serviceContext *svc.ServiceContext) { return } + // 与手动更新保持一致:默认删除旧容器,显式 DelOldContainer=false 时保留。 + delOldContainer := os.Getenv("DelOldContainer") != "false" + for _, c := range containers { if len(c.Names) == 0 || c.Image == "" { continue } + if c.State != "running" { + // 自动更新不应该把原本停止的容器启动起来。 + continue + } + if c.Labels["com.docker.compose.project"] != "" { + // Compose 容器交给 compose 管理,避免破坏 compose 状态。 + continue + } name := strings.TrimPrefix(c.Names[0], "/") + if strings.Contains(strings.ToLower(c.Image), "dockercopilot") { + // 不自动更新自己,避免更新过程中进程被杀。 + continue + } if !allowAll && !allowed[name] { continue } @@ -50,15 +76,46 @@ func RunAutoUpdate(serviceContext *svc.ServiceContext) { continue } - taskID := uuid.New().String() - taskCtx := serviceContext.RegisterTask(taskID) - logx.Infof("自动更新容器: %s (%s)", name, c.Image) - updateErr := UpdateContainer(serviceContext, taskCtx, c.ID, name, c.Image, true, taskID) - serviceContext.FinishTask(taskID) + func() { + taskID := uuid.New().String() + taskCtx := serviceContext.RegisterTask(taskID) + notified := false + defer func() { + if r := recover(); r != nil { + msg := fmt.Sprintf("自动更新异常中断: %v", r) + serviceContext.UpdateProgress(taskID, svc.TaskProgress{ + TaskID: taskID, + Percentage: 100, + Name: name, + Message: "自动更新失败", + DetailMsg: msg, + IsDone: true, + }) + if !notified { + NotifyTaskDone("autoupdate", name, taskID, false, msg) + AuditLog("container.autoupdate", name, msg) + } + logx.Errorf("自动更新容器 %s panic: %v", name, r) + } + serviceContext.FinishTask(taskID) + }() + + logx.Infof("自动更新容器: %s (%s)", name, c.Image) + updateErr := UpdateContainer(serviceContext, taskCtx, c.ID, name, c.Image, delOldContainer, taskID) - final, _ := serviceContext.GetProgress(taskID) - NotifyTaskDone("autoupdate", name, taskID, updateErr == nil, final.Message) - AuditLog("container.autoupdate", name, final.Message) + final, _ := serviceContext.GetProgress(taskID) + message := final.Message + if message == "" { + message = "自动更新已结束" + } + detail := final.DetailMsg + if detail == "" { + detail = message + } + NotifyTaskDone("autoupdate", name, taskID, updateErr == nil, message) + AuditLog("container.autoupdate", name, detail) + notified = true + }() } } diff --git a/internal/utiles/backup2compose.go b/internal/utiles/backup2compose.go index 37f08692..6996c4d5 100644 --- a/internal/utiles/backup2compose.go +++ b/internal/utiles/backup2compose.go @@ -22,10 +22,12 @@ func Backup2Compose(ctx *svc.ServiceContext) (err error) { } containerJSONs = append(containerJSONs, inspectedContainer) } - err = backupCompose.DockerConfig2ComposeYaml(containerJSONs) + err = backupCompose.DockerConfig2ComposeYaml(containerJSONs, BackupDir()) if err != nil { logx.Error("备份失败" + err.Error()) return err } + // 与 JSON 备份共用保留策略:超出 BACKUP_KEEP(默认 7)的旧 compose 备份自动清理。 + pruneOldBackups(BackupDir(), "backup-*.yaml", BackupKeepCount()) return nil } diff --git a/internal/utiles/backup_compose/config2yaml.go b/internal/utiles/backup_compose/config2yaml.go index 9058bbcf..c9e99d61 100644 --- a/internal/utiles/backup_compose/config2yaml.go +++ b/internal/utiles/backup_compose/config2yaml.go @@ -1,108 +1,524 @@ package backupCompose import ( - composeType "github.com/compose-spec/compose-go/types" - dockerTypes "github.com/docker/docker/api/types" - composeNat "github.com/docker/go-connections/nat" - "github.com/zeromicro/go-zero/core/logx" + "fmt" "os" "path/filepath" - "sigs.k8s.io/yaml" "strconv" "strings" "time" + + composeType "github.com/compose-spec/compose-go/types" + dockerTypes "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + composeNat "github.com/docker/go-connections/nat" + "github.com/zeromicro/go-zero/core/logx" + "sigs.k8s.io/yaml" ) // DockerConfig2ComposeYaml 将docker config转换为docker-compose.yaml -func DockerConfig2ComposeYaml(containerJSONs []dockerTypes.ContainerJSON) (err error) { +func DockerConfig2ComposeYaml(containerJSONs []dockerTypes.ContainerJSON, backupDir string) (err error) { var c composeYaml c.Services = make(map[string]composeType.ServiceConfig, len(containerJSONs)) - for _, containerJSON := range containerJSONs { + c.Volumes = make(composeType.Volumes) + c.Networks = make(composeType.Networks) + for i, containerJSON := range containerJSONs { var s composeType.ServiceConfig formatBaseServiceConfig(containerJSON, &s) + if s.Name == "" { + s.Name = fmt.Sprintf("container-%d", i+1) + s.ContainerName = s.Name + } formatEnvServiceConfig(containerJSON, &s) formatNetworkServiceConfig(containerJSON, &s) formatVolumeServiceConfig(containerJSON, &s) c.Services[s.Name] = s + + // 收集命名卷。bind mount 不需要顶层声明。 + for _, mount := range containerJSON.Mounts { + if mount.Type == "volume" { + source := volumeSource(mount) + if source == "" { + continue + } + volumeConfig := composeType.VolumeConfig{Name: source} + if mount.Driver != "" { + volumeConfig.Driver = mount.Driver + } + c.Volumes[source] = volumeConfig + } + } + // 收集自定义网络。default/bridge/host/none 不需要在 compose 里声明。 + if containerJSON.NetworkSettings != nil { + for networkName := range containerJSON.NetworkSettings.Networks { + if networkName == "" || networkName == "bridge" || networkName == "host" || networkName == "none" { + continue + } + c.Networks[networkName] = composeType.NetworkConfig{Name: networkName} + } + } + } + if len(c.Volumes) == 0 { + c.Volumes = nil } + if len(c.Networks) == 0 { + c.Networks = nil + } + // write to file - backupDir := os.Getenv("BACKUP_DIR") // 从环境变量中获取备份目录 if backupDir == "" { - backupDir = "/data/backups" // 如果环境变量未设置,使用默认值 + backupDir = "/data/backups" } _, err = os.Stat(backupDir) if os.IsNotExist(err) { err = os.MkdirAll(backupDir, 0755) if err != nil { - logx.Error("Error creating backup directory:", err) + logx.Errorf("创建备份目录失败: %v", err) return err } } yamlData, yamlMarshalErr := yaml.Marshal(c) if yamlMarshalErr != nil { - logx.Errorf("Error marshalling data err is: %v", yamlMarshalErr) + logx.Errorf("序列化 compose 数据失败: %v", yamlMarshalErr) + return yamlMarshalErr } - currentDate := time.Now().Format("2006-01-02") - fileName := "backup-" + currentDate + ".yaml" + // 文件名带时间戳:同一天多次导出互不覆盖;旧备份由调用方按 BACKUP_KEEP 清理。 + fileName := "backup-" + time.Now().Format("2006-01-02-150405") + ".yaml" fullPath := filepath.Join(backupDir, fileName) - err = os.WriteFile(fullPath, yamlData, 0644) + tmp, err := os.CreateTemp(backupDir, ".backup-*.yaml.tmp") if err != nil { - logx.Error("Error writing to file:", err) + logx.Errorf("创建 compose 临时文件失败: %v", err) + return err + } + tmpName := tmp.Name() + defer func() { + _ = os.Remove(tmpName) + }() + if err = tmp.Chmod(0600); err != nil { + _ = tmp.Close() + logx.Errorf("设置 compose 临时文件权限失败: %v", err) + return err + } + if _, err = tmp.Write(yamlData); err != nil { + _ = tmp.Close() + logx.Errorf("写入 compose 临时文件失败: %v", err) + return err + } + if err = tmp.Close(); err != nil { + logx.Errorf("关闭 compose 临时文件失败: %v", err) + return err + } + if err = os.Rename(tmpName, fullPath); err != nil { + logx.Errorf("替换 compose 备份文件失败: %v", err) return err } return } func formatBaseServiceConfig(containerJSON dockerTypes.ContainerJSON, s *composeType.ServiceConfig) { - s.Image = containerJSON.Config.Image + if containerJSON.Config != nil { + cfg := containerJSON.Config + s.Image = cfg.Image + s.Tty = cfg.Tty + s.StdinOpen = cfg.OpenStdin + s.User = cfg.User + s.DomainName = cfg.Domainname + if cfg.MacAddress != "" { + s.MacAddress = cfg.MacAddress + } + // 容器默认 hostname 是容器 ID;导出成固定值会在重建时变成旧 ID, + // 只有用户显式设置了 hostname 才写入 compose。 + if cfg.Hostname != "" && !sameShortID(cfg.Hostname, containerJSON.ID) { + s.Hostname = cfg.Hostname + } + if len(cfg.Entrypoint) > 0 { + s.Entrypoint = composeType.ShellCommand(cfg.Entrypoint) + } + s.WorkingDir = cfg.WorkingDir + if len(cfg.Cmd) > 0 { + s.Command = composeType.ShellCommand(cfg.Cmd) + } + s.Labels = cleanComposeLabels(cfg.Labels) + s.StopSignal = cfg.StopSignal + if cfg.StopTimeout != nil { + s.StopGracePeriod = durationPtr(time.Duration(*cfg.StopTimeout) * time.Second) + } + s.HealthCheck = formatHealthCheck(cfg.Healthcheck) + s.Expose = formatExposedPorts(cfg.ExposedPorts) + } name, cutNameResult := strings.CutPrefix(containerJSON.Name, "/") if !cutNameResult { - logx.Infof("cutting name is: %s", containerJSON.Name) + logx.Infof("容器名缺少 / 前缀: %s", containerJSON.Name) } s.ContainerName = name s.Name = name - s.Tty = containerJSON.Config.Tty - if len(containerJSON.Config.Entrypoint) > 0 { - s.Entrypoint = composeType.ShellCommand(containerJSON.Config.Entrypoint) + if containerJSON.HostConfig != nil { + formatHostConfig(containerJSON.HostConfig, containerJSON.Config, s) } - s.WorkingDir = containerJSON.Config.WorkingDir - s.Restart = string(containerJSON.HostConfig.RestartPolicy.Name) - s.Privileged = containerJSON.HostConfig.Privileged - if len(containerJSON.Config.Cmd) > 0 { - s.Command = composeType.ShellCommand(containerJSON.Config.Cmd) + if containerJSON.Platform != "" { + s.Platform = containerJSON.Platform } return } +func formatHostConfig(h *container.HostConfig, cfg *container.Config, s *composeType.ServiceConfig) { + s.Restart = formatRestartPolicy(h.RestartPolicy) + s.Privileged = h.Privileged + s.ReadOnly = h.ReadonlyRootfs + s.Init = h.Init + s.CapAdd = []string(h.CapAdd) + s.CapDrop = []string(h.CapDrop) + s.CgroupParent = h.CgroupParent + s.Cgroup = string(h.Cgroup) + s.DNS = composeType.StringList(h.DNS) + s.DNSOpts = h.DNSOptions + s.DNSSearch = composeType.StringList(h.DNSSearch) + s.ExtraHosts = parseExtraHosts(h.ExtraHosts) + s.GroupAdd = h.GroupAdd + s.Ipc = string(h.IpcMode) + s.Links = h.Links + s.Pid = string(h.PidMode) + s.SecurityOpt = h.SecurityOpt + s.ShmSize = composeType.UnitBytes(h.ShmSize) + s.Sysctls = composeType.Mapping(h.Sysctls) + s.Tmpfs = formatTmpfs(h.Tmpfs) + s.Ulimits = formatUlimits(h.Ulimits) + s.UserNSMode = string(h.UsernsMode) + s.Uts = string(h.UTSMode) + s.VolumeDriver = h.VolumeDriver + s.VolumesFrom = h.VolumesFrom + s.Runtime = h.Runtime + s.Isolation = string(h.Isolation) + s.Devices = formatDevices(h.Devices) + s.DeviceCgroupRules = h.DeviceCgroupRules + s.Annotations = composeType.Mapping(h.Annotations) + s.OomScoreAdj = int64(h.OomScoreAdj) + s.OomKillDisable = h.OomKillDisable != nil && *h.OomKillDisable + if h.PidsLimit != nil { + s.PidsLimit = *h.PidsLimit + } + if h.MemorySwappiness != nil { + s.MemSwappiness = composeType.UnitBytes(*h.MemorySwappiness) + } + s.MemLimit = composeType.UnitBytes(h.Memory) + s.MemReservation = composeType.UnitBytes(h.MemoryReservation) + s.MemSwapLimit = composeType.UnitBytes(h.MemorySwap) + s.CPUShares = h.CPUShares + s.CPUQuota = h.CPUQuota + s.CPUPeriod = h.CPUPeriod + s.CPURTPeriod = h.CPURealtimePeriod + s.CPURTRuntime = h.CPURealtimeRuntime + s.CPUSet = h.CpusetCpus + s.CPUS = float32(h.NanoCPUs) / 1e9 + s.CPUCount = h.CPUCount + s.CPUPercent = float32(h.CPUPercent) + if h.BlkioWeight > 0 { + s.BlkioConfig = &composeType.BlkioConfig{Weight: h.BlkioWeight} + } + if h.LogConfig.Type != "" || len(h.LogConfig.Config) > 0 { + logging := &composeType.LoggingConfig{ + Options: composeType.Options(h.LogConfig.Config), + } + if h.LogConfig.Type != "" { + logging.Driver = h.LogConfig.Type + } + s.Logging = logging + } + if cfg != nil { + if cfg.NetworkDisabled { + s.NetworkMode = "none" + } + } +} + func formatEnvServiceConfig(containerJSON dockerTypes.ContainerJSON, s *composeType.ServiceConfig) { + if containerJSON.Config == nil { + return + } s.Environment = composeType.NewMappingWithEquals(containerJSON.Config.Env) - return } func formatNetworkServiceConfig(containerJSON dockerTypes.ContainerJSON, s *composeType.ServiceConfig) { - s.NetworkMode = string(containerJSON.HostConfig.NetworkMode) - for containerPort, v := range containerJSON.HostConfig.PortBindings { - var p composeType.ServicePortConfig + if containerJSON.HostConfig == nil { + return + } + mode := string(containerJSON.HostConfig.NetworkMode) + // compose 的 network_mode 只接受 host/none/container:...;自定义网络要用 + // services..networks 挂载,不能把网络名塞进 network_mode。 + if mode == "host" || mode == "none" || strings.HasPrefix(mode, "container:") { + s.NetworkMode = mode + } + if containerJSON.NetworkSettings != nil { + for networkName, endpoint := range containerJSON.NetworkSettings.Networks { + if networkName == "" || networkName == "bridge" || networkName == "host" || networkName == "none" { + continue + } + networkConfig := &composeType.ServiceNetworkConfig{} + if endpoint != nil { + networkConfig.Aliases = filterAliases(endpoint.Aliases, containerJSON.ID, containerJSON.Name) + // 只导出用户静态指定的地址;运行中的 IPAddress 是 Docker 动态分配的, + // 写成 ipv4_address 会在重建时造成地址冲突。 + if endpoint.IPAMConfig != nil { + networkConfig.Ipv4Address = endpoint.IPAMConfig.IPv4Address + networkConfig.Ipv6Address = endpoint.IPAMConfig.IPv6Address + networkConfig.LinkLocalIPs = endpoint.IPAMConfig.LinkLocalIPs + } + } + if s.Networks == nil { + s.Networks = make(map[string]*composeType.ServiceNetworkConfig) + } + s.Networks[networkName] = networkConfig + } + } + for containerPort, bindings := range containerJSON.HostConfig.PortBindings { + if len(bindings) == 0 { + // 某些容器的 PortBindings 是空切片,直接 v[0] 会 panic。 + logx.Errorf("端口 %s 没有绑定地址,跳过", containerPort) + continue + } proto, port := composeNat.SplitProtoPort(string(containerPort)) portNum, convertErr := strconv.Atoi(port) if convertErr != nil { - logx.Errorf("Error converting port err is: %v", convertErr) + logx.Errorf("端口转换失败: %v", convertErr) continue } - p.Target = uint32(portNum) - p.Published = v[0].HostPort - p.Protocol = proto - s.Ports = append(s.Ports, p) + for _, binding := range bindings { + s.Ports = append(s.Ports, composeType.ServicePortConfig{ + HostIP: binding.HostIP, + Published: binding.HostPort, + Target: uint32(portNum), + Protocol: proto, + }) + } } } func formatVolumeServiceConfig(containerJSON dockerTypes.ContainerJSON, s *composeType.ServiceConfig) { for _, containerVolume := range containerJSON.Mounts { - var v composeType.ServiceVolumeConfig - v.Type = string(containerVolume.Type) - v.Source = containerVolume.Source - v.Target = containerVolume.Destination - v.ReadOnly = containerVolume.RW + if string(containerVolume.Type) == "tmpfs" { + // HostConfig.Tmpfs 已经会导出成 tmpfs:,这里再写 volumes 会造成重复挂载点。 + if containerJSON.HostConfig != nil { + if _, exists := containerJSON.HostConfig.Tmpfs[containerVolume.Destination]; exists { + continue + } + } + // tmpfs 没有 Source,长语法只需要 type + target。 + s.Volumes = append(s.Volumes, composeType.ServiceVolumeConfig{ + Type: "tmpfs", + Target: containerVolume.Destination, + ReadOnly: !containerVolume.RW, + }) + continue + } + source := volumeSource(containerVolume) + if source == "" { + continue + } + v := composeType.ServiceVolumeConfig{ + Type: string(containerVolume.Type), + Source: source, + Target: containerVolume.Destination, + ReadOnly: !containerVolume.RW, + } + for _, part := range strings.Split(containerVolume.Mode, ",") { + switch strings.TrimSpace(part) { + case "z", "Z": + if v.Bind == nil { + v.Bind = &composeType.ServiceVolumeBind{} + } + v.Bind.SELinux = part + case "nocopy": + if v.Type == "volume" { + v.Volume = &composeType.ServiceVolumeVolume{NoCopy: true} + } + } + } + if containerVolume.Propagation != "" { + if v.Bind == nil { + v.Bind = &composeType.ServiceVolumeBind{} + } + v.Bind.Propagation = string(containerVolume.Propagation) + } s.Volumes = append(s.Volumes, v) } } + +func filterAliases(aliases []string, containerID, containerName string) []string { + if len(aliases) == 0 { + return nil + } + name := strings.TrimPrefix(containerName, "/") + shortID := containerID + if len(shortID) > 12 { + shortID = shortID[:12] + } + result := make([]string, 0, len(aliases)) + for _, alias := range aliases { + if alias == "" || alias == name || alias == containerID || alias == shortID { + continue + } + result = append(result, alias) + } + if len(result) == 0 { + return nil + } + return result +} + +func volumeSource(mount dockerTypes.MountPoint) string { + if mount.Type == "volume" { + // 匿名卷/异常卷没有 Name 时不要退化成 Source 宿主机路径,否则会导出非法卷名。 + return mount.Name + } + return mount.Source +} + +func formatExposedPorts(ports composeNat.PortSet) composeType.StringOrNumberList { + if len(ports) == 0 { + return nil + } + result := make([]string, 0, len(ports)) + for port := range ports { + result = append(result, string(port)) + } + return composeType.StringOrNumberList(result) +} + +func formatRestartPolicy(policy container.RestartPolicy) string { + name := string(policy.Name) + if name == "on-failure" && policy.MaximumRetryCount > 0 { + return fmt.Sprintf("on-failure:%d", policy.MaximumRetryCount) + } + return name +} + +func formatHealthCheck(hc *container.HealthConfig) *composeType.HealthCheckConfig { + if hc == nil { + return nil + } + if len(hc.Test) == 1 && strings.EqualFold(hc.Test[0], "NONE") { + return &composeType.HealthCheckConfig{Disable: true} + } + // 没有 test 的 healthcheck 无法还原;继续写会生成 compose 不接受的空 test。 + if len(hc.Test) == 0 { + return nil + } + out := &composeType.HealthCheckConfig{ + Test: composeType.HealthCheckTest(hc.Test), + } + if hc.Interval > 0 { + out.Interval = durationPtr(hc.Interval) + } + if hc.Timeout > 0 { + out.Timeout = durationPtr(hc.Timeout) + } + if hc.StartPeriod > 0 { + out.StartPeriod = durationPtr(hc.StartPeriod) + } + if hc.StartInterval > 0 { + out.StartInterval = durationPtr(hc.StartInterval) + } + if hc.Retries > 0 { + retries := uint64(hc.Retries) + out.Retries = &retries + } + return out +} + +func durationPtr(d time.Duration) *composeType.Duration { + value := composeType.Duration(d) + return &value +} + +func parseExtraHosts(hosts []string) composeType.HostsList { + if len(hosts) == 0 { + return nil + } + result := make(composeType.HostsList, len(hosts)) + for _, entry := range hosts { + host, ip, ok := strings.Cut(entry, ":") + if !ok || host == "" || ip == "" { + continue + } + result[host] = ip + } + return result +} + +func formatTmpfs(tmpfs map[string]string) composeType.StringList { + if len(tmpfs) == 0 { + return nil + } + result := make([]string, 0, len(tmpfs)) + for path, opts := range tmpfs { + if opts == "" { + result = append(result, path) + } else { + result = append(result, path+":"+opts) + } + } + return composeType.StringList(result) +} + +func formatUlimits(ulimits []*container.Ulimit) map[string]*composeType.UlimitsConfig { + if len(ulimits) == 0 { + return nil + } + result := make(map[string]*composeType.UlimitsConfig, len(ulimits)) + for _, ulimit := range ulimits { + if ulimit == nil || ulimit.Name == "" { + continue + } + item := &composeType.UlimitsConfig{} + if ulimit.Soft == ulimit.Hard { + item.Single = int(ulimit.Soft) + } else { + item.Soft = int(ulimit.Soft) + item.Hard = int(ulimit.Hard) + } + result[ulimit.Name] = item + } + return result +} + +func formatDevices(devices []container.DeviceMapping) []string { + if len(devices) == 0 { + return nil + } + result := make([]string, 0, len(devices)) + for _, device := range devices { + entry := device.PathOnHost + ":" + device.PathInContainer + if device.CgroupPermissions != "" { + entry += ":" + device.CgroupPermissions + } + result = append(result, entry) + } + return result +} + +func cleanComposeLabels(labels map[string]string) composeType.Labels { + if len(labels) == 0 { + return nil + } + result := make(composeType.Labels, len(labels)) + for key, value := range labels { + if strings.HasPrefix(key, "com.docker.compose.") { + continue + } + result[key] = value + } + if len(result) == 0 { + return nil + } + return result +} + +func sameShortID(hostname, id string) bool { + if hostname == "" || id == "" { + return false + } + if len(id) > 12 { + id = id[:12] + } + return hostname == id +} diff --git a/internal/utiles/backup_compose/types.go b/internal/utiles/backup_compose/types.go index 4688a31d..2a03f018 100644 --- a/internal/utiles/backup_compose/types.go +++ b/internal/utiles/backup_compose/types.go @@ -6,4 +6,8 @@ import ( type composeYaml struct { Services map[string]composeType.ServiceConfig `yaml:"services" json:"services"` + // 顶层声明命名卷和自定义网络。没有这两个声明时,导出的 compose 在 + // `docker compose up` 时无法还原卷/网络,只能得到匿名卷。 + Volumes composeType.Volumes `yaml:"volumes,omitempty" json:"volumes,omitempty"` + Networks composeType.Networks `yaml:"networks,omitempty" json:"networks,omitempty"` } diff --git a/internal/utiles/backupcontainer.go b/internal/utiles/backupcontainer.go index 95ccccf3..276b6f48 100644 --- a/internal/utiles/backupcontainer.go +++ b/internal/utiles/backupcontainer.go @@ -3,50 +3,89 @@ package utiles import ( "context" "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "time" + dockerBackend "github.com/docker/docker/api/types/backend" "github.com/docker/docker/api/types/network" "github.com/onlyLTY/dockerCopilot/internal/svc" "github.com/zeromicro/go-zero/core/logx" - "os" - "path/filepath" - "time" ) -func BackupContainer(ctx *svc.ServiceContext) error { +// BackupContainer 把全部容器配置备份为一个 JSON 文件。 +// 单个容器 inspect 失败不中止整体备份,失败清单通过返回值带回; +// 全部容器都失败时才返回错误。 +func BackupContainer(ctx *svc.ServiceContext) (failures []string, err error) { + if ctx.DockerClient == nil { + return nil, fmt.Errorf("Docker 客户端未初始化,请检查 DOCKER_HOST 配置") + } containerList, err := GetContainerList(ctx) if err != nil { - return err + return nil, err } - var backupList []dockerBackend.ContainerCreateConfig - for i, v := range containerList { + backupList := make([]ContainerBackupEntry, 0, len(containerList)) + failures = make([]string, 0) + for i := range containerList { containerID := containerList[i].ID - ctx.DockerClient.NegotiateAPIVersion(context.TODO()) - inspectedContainer, err := ctx.DockerClient.ContainerInspect(context.TODO(), containerID) + inspectCtx, cancel := dockerTimeout(context.Background(), dockerInspectTimeout) + inspectedContainer, err := ctx.DockerClient.ContainerInspect(inspectCtx, containerID) + cancel() if err != nil { - logx.Error("获取容器信息失败" + err.Error()) - return err + // 一个坏容器不应该挡住其它容器的日常备份。 + logx.Errorf("容器 %s 获取信息失败,跳过备份: %v", containerID, err) + failures = append(failures, containerID+": "+err.Error()) + continue + } + if inspectedContainer.Config == nil { + logx.Errorf("容器 %s 配置为空,跳过备份", containerID) + failures = append(failures, containerID+": 配置为空,无法备份") + continue } - var containerName string - if len(v.Names) > 0 { - containerName = v.Names[0][1:] - } else { - containerName = "get container name error" - logx.Error("get container name error" + v.ID) + containerName := strings.TrimPrefix(inspectedContainer.Name, "/") + if containerName == "" && len(containerList[i].Names) > 0 { + containerName = strings.TrimPrefix(containerList[i].Names[0], "/") + } + if containerName == "" { + containerName = containerID + if len(containerName) > 12 { + containerName = containerName[:12] + } + logx.Errorf("容器 %s 名称为空,使用 ID 作为备份名称", containerID) } inspectedContainer.Config.Hostname = "" inspectedContainer.Image = inspectedContainer.Config.Image - config := inspectedContainer.Config - hostConfig := inspectedContainer.HostConfig + var endpoints map[string]*network.EndpointSettings + if inspectedContainer.NetworkSettings != nil { + endpoints = sanitizeEndpointSettings(inspectedContainer.NetworkSettings.Networks) + } networkingConfig := &network.NetworkingConfig{ - EndpointsConfig: inspectedContainer.NetworkSettings.Networks, + EndpointsConfig: endpoints, + } + entry := ContainerBackupEntry{ + ContainerCreateConfig: dockerBackend.ContainerCreateConfig{ + Config: inspectedContainer.Config, + HostConfig: inspectedContainer.HostConfig, + NetworkingConfig: networkingConfig, + Name: containerName, + }, } - createConfig := dockerBackend.ContainerCreateConfig{Config: config, HostConfig: hostConfig, NetworkingConfig: networkingConfig, Name: containerName} - backupList = append(backupList, createConfig) + if inspectedContainer.State != nil { + entry.StateKnown = true + entry.WasRunning = inspectedContainer.State.Running + entry.WasPaused = inspectedContainer.State.Paused + } + backupList = append(backupList, entry) + } + if len(backupList) == 0 && len(failures) > 0 { + return failures, fmt.Errorf("全部 %d 个容器备份失败,未生成备份文件", len(failures)) } jsonData, err := json.MarshalIndent(backupList, "", " ") if err != nil { - logx.Error("Error marshalling data:", err) - return err + logx.Error("数据序列化失败:", err) + return failures, err } backupDir := BackupDir() // env BACKUP_DIR > Settings > 默认 /data/backups if backupDir == "" { @@ -56,17 +95,41 @@ func BackupContainer(ctx *svc.ServiceContext) error { if os.IsNotExist(err) { err = os.MkdirAll(backupDir, 0755) if err != nil { - logx.Error("Error creating backup directory:", err) - return err + logx.Errorf("创建备份目录失败: %v", err) + return failures, err } } - currentDate := time.Now().Format("2006-01-02") - fileName := "backup-" + currentDate + ".json" + // 文件名带时间戳:同一天多次备份互不覆盖,可回退到任一次; + // 超出保留份数(BACKUP_KEEP,默认 7)的旧备份自动清理。 + fileName := "backup-" + time.Now().Format("2006-01-02-150405") + ".json" fullPath := filepath.Join(backupDir, fileName) - err = os.WriteFile(fullPath, jsonData, 0644) + tmp, err := os.CreateTemp(backupDir, ".backup-*.json.tmp") if err != nil { - logx.Error("Error writing to file:", err) - return err + logx.Errorf("创建备份临时文件失败: %v", err) + return failures, err + } + tmpName := tmp.Name() + defer func() { + _ = os.Remove(tmpName) + }() + if err = tmp.Chmod(0600); err != nil { + _ = tmp.Close() + logx.Errorf("设置备份临时文件权限失败: %v", err) + return failures, err + } + if _, err = tmp.Write(jsonData); err != nil { + _ = tmp.Close() + logx.Errorf("写入备份临时文件失败: %v", err) + return failures, err + } + if err = tmp.Close(); err != nil { + logx.Errorf("关闭备份临时文件失败: %v", err) + return failures, err + } + if err = os.Rename(tmpName, fullPath); err != nil { + logx.Errorf("替换备份文件失败: %v", err) + return failures, err } - return nil + pruneOldBackups(backupDir, "backup-*.json", BackupKeepCount()) + return failures, nil } diff --git a/internal/utiles/backuppath.go b/internal/utiles/backuppath.go index 269aa269..5c1f7ad7 100644 --- a/internal/utiles/backuppath.go +++ b/internal/utiles/backuppath.go @@ -19,6 +19,9 @@ func ResolveBackupPath(filename string, allowedExts ...string) (string, error) { if name == "" { return "", fmt.Errorf("非法文件名") } + if name == "." || name == ".." { + return "", fmt.Errorf("非法文件名") + } if name != filepath.Base(name) { return "", fmt.Errorf("非法文件名") } @@ -40,10 +43,13 @@ func ResolveBackupPath(filename string, allowedExts ...string) (string, error) { } } - base := filepath.Clean(BackupDir()) - fullPath := filepath.Clean(filepath.Join(base, name)) - basePrefix := base + string(os.PathSeparator) - if fullPath != base && !strings.HasPrefix(fullPath, basePrefix) { + base, err := filepath.Abs(filepath.Clean(BackupDir())) + if err != nil { + return "", fmt.Errorf("备份目录不合法") + } + fullPath := filepath.Join(base, name) + rel, err := filepath.Rel(base, fullPath) + if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) { return "", fmt.Errorf("非法文件名") } diff --git a/internal/utiles/backupretention.go b/internal/utiles/backupretention.go new file mode 100644 index 00000000..7d1767b5 --- /dev/null +++ b/internal/utiles/backupretention.go @@ -0,0 +1,76 @@ +package utiles + +import ( + "os" + "path/filepath" + "sort" + "strconv" + "strings" + + "github.com/zeromicro/go-zero/core/logx" +) + +// backupKeepDefault 每种备份(JSON / compose)默认保留份数。 +const backupKeepDefault = 7 + +// BackupKeepCount 备份保留份数:env BACKUP_KEEP,默认 7,最小 1。 +// 每次备份生成带时间戳的新文件,超出的旧备份由 pruneOldBackups 清理。 +func BackupKeepCount() int { + if v := os.Getenv("BACKUP_KEEP"); v != "" { + if n, err := strconv.Atoi(v); err == nil && n > 0 { + return n + } + logx.Errorf("BACKUP_KEEP 非法: %q,使用默认值 %d", v, backupKeepDefault) + } + return backupKeepDefault +} + +// pruneOldBackups 按修改时间保留最近 keep 个匹配 pattern 的备份文件。 +// 隐藏文件(含备份临时文件)不参与清理。返回被删除的文件名; +// 删除失败只记日志,不影响本次备份结果。 +func pruneOldBackups(dir, pattern string, keep int) []string { + if keep <= 0 { + keep = 1 + } + entries, err := os.ReadDir(dir) + if err != nil { + logx.Errorf("清理旧备份失败,读取目录出错: %v", err) + return nil + } + type backupFile struct { + name string + modTime int64 + } + var files []backupFile + for _, entry := range entries { + if entry.IsDir() { + continue + } + name := entry.Name() + if strings.HasPrefix(name, ".") { + continue + } + matched, matchErr := filepath.Match(pattern, name) + if matchErr != nil || !matched { + continue + } + info, statErr := entry.Info() + if statErr != nil { + continue + } + files = append(files, backupFile{name: name, modTime: info.ModTime().UnixNano()}) + } + if len(files) <= keep { + return nil + } + sort.Slice(files, func(i, j int) bool { return files[i].modTime > files[j].modTime }) + var removed []string + for _, f := range files[keep:] { + if rmErr := os.Remove(filepath.Join(dir, f.name)); rmErr != nil { + logx.Errorf("删除旧备份 %s 失败: %v", f.name, rmErr) + continue + } + removed = append(removed, f.name) + } + return removed +} diff --git a/internal/utiles/backupretention_test.go b/internal/utiles/backupretention_test.go new file mode 100644 index 00000000..2bff45e0 --- /dev/null +++ b/internal/utiles/backupretention_test.go @@ -0,0 +1,83 @@ +package utiles + +import ( + "os" + "path/filepath" + "testing" + "time" +) + +func TestBackupKeepCountDefault(t *testing.T) { + t.Setenv("BACKUP_KEEP", "") + if got := BackupKeepCount(); got != 7 { + t.Fatalf("default keep = %d, want 7", got) + } +} + +func TestBackupKeepCountFromEnv(t *testing.T) { + t.Setenv("BACKUP_KEEP", "3") + if got := BackupKeepCount(); got != 3 { + t.Fatalf("keep = %d, want 3", got) + } +} + +func TestBackupKeepCountInvalidFallsBack(t *testing.T) { + t.Setenv("BACKUP_KEEP", "abc") + if got := BackupKeepCount(); got != 7 { + t.Fatalf("invalid keep should fall back to 7, got %d", got) + } + t.Setenv("BACKUP_KEEP", "-2") + if got := BackupKeepCount(); got != 7 { + t.Fatalf("negative keep should fall back to 7, got %d", got) + } +} + +func TestPruneOldBackupsKeepsNewest(t *testing.T) { + dir := t.TempDir() + names := []string{"backup-1.json", "backup-2.json", "backup-3.json", "backup-4.json", "backup-5.json"} + for i, name := range names { + path := filepath.Join(dir, name) + if err := os.WriteFile(path, []byte("{}"), 0o600); err != nil { + t.Fatal(err) + } + stamp := time.Now().Add(-time.Duration(len(names)-i) * time.Hour) + if err := os.Chtimes(path, stamp, stamp); err != nil { + t.Fatal(err) + } + } + // 隐藏文件(临时文件)不参与清理。 + if err := os.WriteFile(filepath.Join(dir, ".backup-x.json.tmp"), []byte("tmp"), 0o600); err != nil { + t.Fatal(err) + } + + removed := pruneOldBackups(dir, "backup-*.json", 3) + if len(removed) != 2 { + t.Fatalf("expected 2 removed, got %v", removed) + } + // 最旧的两个(backup-1/2)应被删除。 + for _, gone := range []string{"backup-1.json", "backup-2.json"} { + if _, err := os.Stat(filepath.Join(dir, gone)); !os.IsNotExist(err) { + t.Fatalf("%s should be removed", gone) + } + } + for _, kept := range []string{"backup-3.json", "backup-4.json", "backup-5.json"} { + if _, err := os.Stat(filepath.Join(dir, kept)); err != nil { + t.Fatalf("%s should be kept: %v", kept, err) + } + } + if _, err := os.Stat(filepath.Join(dir, ".backup-x.json.tmp")); err != nil { + t.Fatal("hidden temp file should not be touched") + } +} + +func TestPruneOldBackupsNoopWhenUnderKeep(t *testing.T) { + dir := t.TempDir() + for _, name := range []string{"backup-a.json", "backup-b.json"} { + if err := os.WriteFile(filepath.Join(dir, name), []byte("{}"), 0o600); err != nil { + t.Fatal(err) + } + } + if removed := pruneOldBackups(dir, "backup-*.json", 7); removed != nil { + t.Fatalf("expected no removal, got %v", removed) + } +} diff --git a/internal/utiles/backupslist.go b/internal/utiles/backupslist.go index 8e3502a1..6729dd89 100644 --- a/internal/utiles/backupslist.go +++ b/internal/utiles/backupslist.go @@ -8,10 +8,7 @@ import ( func BackupList(ctx *svc.ServiceContext) ([]string, error) { var backupList []string - dir := os.Getenv("BACKUP_DIR") // 从环境变量中获取备份目录 - if dir == "" { - dir = "/data/backups" // 如果环境变量未设置,使用默认值 - } + dir := BackupDir() // env BACKUP_DIR > Settings > 默认 /data/backups entries, err := os.ReadDir(dir) if err != nil { return nil, err diff --git a/internal/utiles/containerInspect.go b/internal/utiles/containerInspect.go index 48d4ce29..c24d9b9f 100644 --- a/internal/utiles/containerInspect.go +++ b/internal/utiles/containerInspect.go @@ -7,7 +7,9 @@ import ( ) func GetContainerInspect(ctx *svc.ServiceContext, id string) (types.ContainerJSON, error) { - inspectedContainer, err := ctx.DockerClient.ContainerInspect(context.TODO(), id) + requestCtx, cancel := dockerTimeout(context.Background(), dockerInspectTimeout) + defer cancel() + inspectedContainer, err := ctx.DockerClient.ContainerInspect(requestCtx, id) if err != nil { return types.ContainerJSON{}, err } diff --git a/internal/utiles/getRemoteVersion.go b/internal/utiles/getRemoteVersion.go index 4b458bcf..b20267bf 100644 --- a/internal/utiles/getRemoteVersion.go +++ b/internal/utiles/getRemoteVersion.go @@ -1,16 +1,30 @@ package utiles import ( + "errors" + "fmt" "io" "net/http" "os" "strings" + "time" "github.com/onlyLTY/dockerCopilot/internal/config" "github.com/zeromicro/go-zero/core/logx" ) +// ErrFnosManagedUpdate 表示 FNOS 版本的版本检查与自更新由专用发布包管理, +// 不走通用在线更新链。调用方应显式向用户说明,而不是伪装成“无更新”。 +var ErrFnosManagedUpdate = errors.New("FnOS 版本由专用发布包管理,不支持在线版本检查与自更新") + func GetRemoteVersion() (remoteVersion string, err error) { + localVersion := config.Version + if strings.Contains(localVersion, "FNOS") { + // FNOS 版本使用独立发布包,不需要也不应该访问通用版 version 文件。 + logx.Infof("飞牛版本,不支持在线版本检查") + return "", ErrFnosManagedUpdate + } + githubProxy := os.Getenv("githubProxy") if githubProxy != "" { githubProxy = strings.TrimRight(githubProxy, "/") + "/" @@ -20,12 +34,6 @@ func GetRemoteVersion() (remoteVersion string, err error) { if err != nil { return "0.0.0", err } - - localVersion := config.Version - if strings.Contains(localVersion, "FNOS") { - logx.Infof("飞牛版本,无需在线更新") - return localVersion, nil - } if localVersion == remoteVersion { logx.Info("版本一致:", localVersion) return remoteVersion, nil @@ -38,6 +46,7 @@ func GetRemoteVersion() (remoteVersion string, err error) { func fetchVersionFromURL(url string) (string, error) { client := &http.Client{ + Timeout: 30 * time.Second, Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, }, @@ -54,7 +63,11 @@ func fetchVersionFromURL(url string) (string, error) { } }(resp.Body) - versionData, err := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("获取版本信息失败:%s", resp.Status) + } + + versionData, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) if err != nil { return "", err } diff --git a/internal/utiles/getcontainerlist.go b/internal/utiles/getcontainerlist.go index 23119d85..3d68046f 100644 --- a/internal/utiles/getcontainerlist.go +++ b/internal/utiles/getcontainerlist.go @@ -2,6 +2,8 @@ package utiles import ( "context" + "fmt" + "github.com/docker/docker/api/types/container" "github.com/onlyLTY/dockerCopilot/internal/svc" MyType "github.com/onlyLTY/dockerCopilot/internal/types" @@ -9,12 +11,17 @@ import ( ) func GetContainerList(ctx *svc.ServiceContext) ([]MyType.Container, error) { + if ctx.DockerClient == nil { + return nil, fmt.Errorf("Docker 客户端未初始化,请检查 DOCKER_HOST 配置") + } // 获取所有容器(包括停止的容器) - dockerContainerList, err := ctx.DockerClient.ContainerList(context.Background(), container.ListOptions{ + requestCtx, cancel := dockerTimeout(context.Background(), dockerListTimeout) + defer cancel() + dockerContainerList, err := ctx.DockerClient.ContainerList(requestCtx, container.ListOptions{ All: true, // 设置为true来获取所有容器 }) if err != nil { - logx.Errorf("get container list error: %v", err) + logx.Errorf("获取容器列表失败: %v", err) return nil, err } var containerList []MyType.Container diff --git a/internal/utiles/image.go b/internal/utiles/image.go index fe05a7a5..628ca261 100644 --- a/internal/utiles/image.go +++ b/internal/utiles/image.go @@ -12,9 +12,14 @@ import ( func GetImagesList(ctx *svc.ServiceContext) ([]MyType.Image, error) { var imagesList []MyType.Image - dockerImages, err := ctx.DockerClient.ImageList(context.Background(), image.ListOptions{}) + if ctx.DockerClient == nil { + return nil, fmt.Errorf("Docker 客户端未初始化,请检查 DOCKER_HOST 配置") + } + requestCtx, cancel := dockerTimeout(context.Background(), dockerListTimeout) + defer cancel() + dockerImages, err := ctx.DockerClient.ImageList(requestCtx, image.ListOptions{}) if err != nil { - logx.Errorf("Unable to fetch docker images: %s", err) + logx.Errorf("获取镜像列表失败: %s", err) return nil, err } @@ -86,3 +91,57 @@ func calculateImageSize(imagesList []MyType.Image) []MyType.Image { } return imagesList } + +// 批量镜像清理过滤器:删除无 TAG 镜像 / 删除未被容器引用的镜像。 +const ( + CleanupFilterUntagged = "untagged" + CleanupFilterUnused = "unused" +) + +// isUntaggedImage 判断镜像是否没有可用的 tag。 +// splitImageNameAndTag 会把无 tag 镜像的 ImageTag 归一为 "None", +// 少数异常镜像的 RepoTags 里是字面 ":",这里一并覆盖。 +func isUntaggedImage(img MyType.Image) bool { + return img.ImageTag == "None" || img.ImageTag == "" || + img.ImageName == "None" || img.ImageName == "" +} + +// PickImagesForCleanup 按过滤器挑选待清理镜像(纯函数,便于测试)。 +// untagged:无 TAG 镜像;unused:未被任何容器(含已停止容器)引用的镜像。 +func PickImagesForCleanup(images []MyType.Image, filter string) []MyType.Image { + picked := make([]MyType.Image, 0, len(images)) + for _, img := range images { + switch filter { + case CleanupFilterUntagged: + if isUntaggedImage(img) { + picked = append(picked, img) + } + case CleanupFilterUnused: + if !img.InUsed { + picked = append(picked, img) + } + } + } + return picked +} + +// RemoveImagesFiltered 批量删除镜像,逐个尝试,单个失败不影响其它。 +// 返回已删除与失败的镜像清单(失败时带原因)。filter 只接受上面两个常量。 +func RemoveImagesFiltered(ctx *svc.ServiceContext, filter string) (removed []string, failed []string, err error) { + if filter != CleanupFilterUntagged && filter != CleanupFilterUnused { + return nil, nil, fmt.Errorf("filter 只支持 %s 或 %s", CleanupFilterUntagged, CleanupFilterUnused) + } + images, err := GetImagesList(ctx) + if err != nil { + return nil, nil, err + } + for _, img := range PickImagesForCleanup(images, filter) { + if removeErr := RemoveImage(ctx, img.ID, false); removeErr != nil { + logx.Errorf("批量清理镜像失败 %s: %v", img.ID, removeErr) + failed = append(failed, img.ID+" ("+img.ImageName+":"+img.ImageTag+"): "+removeErr.Error()) + continue + } + removed = append(removed, img.ID+" ("+img.ImageName+":"+img.ImageTag+")") + } + return removed, failed, nil +} diff --git a/internal/utiles/imagecleanup_test.go b/internal/utiles/imagecleanup_test.go new file mode 100644 index 00000000..12754a76 --- /dev/null +++ b/internal/utiles/imagecleanup_test.go @@ -0,0 +1,51 @@ +package utiles + +import ( + "testing" + + MyType "github.com/onlyLTY/dockerCopilot/internal/types" +) + +func TestPickImagesForCleanupUntagged(t *testing.T) { + images := []MyType.Image{ + {ImageName: "nginx", ImageTag: "latest", InUsed: false}, + {ImageName: "None", ImageTag: "None", InUsed: false}, + {ImageName: "", ImageTag: "", InUsed: true}, + {ImageName: "redis", ImageTag: "None", InUsed: false}, + } + picked := PickImagesForCleanup(images, CleanupFilterUntagged) + if len(picked) != 3 { + t.Fatalf("expected 3 untagged images, got %d: %+v", len(picked), picked) + } + for _, img := range picked { + if img.ImageName == "nginx" { + t.Fatalf("tagged image should not be picked: %+v", img) + } + } +} + +func TestPickImagesForCleanupUnused(t *testing.T) { + images := []MyType.Image{ + {ImageName: "nginx", ImageTag: "latest", InUsed: false}, + {ImageName: "redis", ImageTag: "7", InUsed: true}, + {ImageName: "None", ImageTag: "None", InUsed: false}, + } + picked := PickImagesForCleanup(images, CleanupFilterUnused) + if len(picked) != 2 { + t.Fatalf("expected 2 unused images, got %d", len(picked)) + } + for _, img := range picked { + if img.InUsed { + t.Fatalf("used image should not be picked: %+v", img) + } + } +} + +func TestPickImagesForCleanupUnknownFilter(t *testing.T) { + images := []MyType.Image{ + {ImageName: "nginx", ImageTag: "latest", InUsed: false}, + } + if picked := PickImagesForCleanup(images, "bogus"); len(picked) != 0 { + t.Fatalf("unknown filter should pick nothing, got %d", len(picked)) + } +} diff --git a/internal/utiles/removeimage.go b/internal/utiles/removeimage.go index 60c6af4a..9d597115 100644 --- a/internal/utiles/removeimage.go +++ b/internal/utiles/removeimage.go @@ -7,7 +7,9 @@ import ( ) func RemoveImage(ctx *svc.ServiceContext, imageID string, force bool) error { - _, err := ctx.DockerClient.ImageRemove(context.Background(), imageID, image.RemoveOptions{Force: force}) + requestCtx, cancel := dockerTimeout(context.Background(), dockerMutationTimeout) + defer cancel() + _, err := ctx.DockerClient.ImageRemove(requestCtx, imageID, image.RemoveOptions{Force: force}) if err != nil { return err } diff --git a/internal/utiles/renamecontainer.go b/internal/utiles/renamecontainer.go index 849ab4a7..3183820b 100644 --- a/internal/utiles/renamecontainer.go +++ b/internal/utiles/renamecontainer.go @@ -6,7 +6,9 @@ import ( ) func RenameContainer(ctx *svc.ServiceContext, id string, newName string) error { - err := ctx.DockerClient.ContainerRename(context.TODO(), id, newName) + requestCtx, cancel := dockerTimeout(context.Background(), dockerMutationTimeout) + defer cancel() + err := ctx.DockerClient.ContainerRename(requestCtx, id, newName) if err != nil { return err } diff --git a/internal/utiles/restartcontainer.go b/internal/utiles/restartcontainer.go index cfd05902..e874dee3 100644 --- a/internal/utiles/restartcontainer.go +++ b/internal/utiles/restartcontainer.go @@ -13,7 +13,9 @@ func RestartContainer(ctx *svc.ServiceContext, id string) error { Signal: signal, Timeout: &timeout, } - err := ctx.DockerClient.ContainerRestart(context.Background(), id, stopOptions) + requestCtx, cancel := dockerTimeout(context.Background(), dockerMutationTimeout) + defer cancel() + err := ctx.DockerClient.ContainerRestart(requestCtx, id, stopOptions) if err != nil { return err } diff --git a/internal/utiles/restorecontainer.go b/internal/utiles/restorecontainer.go index 56e02150..31b85f5f 100644 --- a/internal/utiles/restorecontainer.go +++ b/internal/utiles/restorecontainer.go @@ -3,89 +3,361 @@ package utiles import ( "context" "encoding/json" - dockerBackend "github.com/docker/docker/api/types/backend" - "github.com/docker/docker/api/types/image" - "github.com/onlyLTY/dockerCopilot/internal/svc" - "github.com/zeromicro/go-zero/core/logx" + "fmt" "os" "strconv" "strings" + "sync" + "time" + + dockerTypes "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/image" + "github.com/docker/docker/api/types/network" + dockerclient "github.com/docker/docker/client" + "github.com/onlyLTY/dockerCopilot/internal/svc" + "github.com/zeromicro/go-zero/core/logx" ) -func RestoreContainer(ctx *svc.ServiceContext, filename string, taskID string) error { - var backupList []string - oldProgress := svc.TaskProgress{ +// 恢复会按容器名做冲突判断,两个恢复任务并发时可能都认为“不存在” +// 然后同时创建同名容器;这里串行化整个恢复流程。 +var restoreMu sync.Mutex + +func restoreShouldStart(entry ContainerBackupEntry, startOverride *bool) bool { + if startOverride != nil { + return *startOverride + } + if entry.StateKnown { + return entry.WasRunning + } + // 旧备份没有状态字段:保持之前“恢复后启动”的行为。 + return true +} + +// restoreOldContainerName 为被替换的旧容器生成临时名。 +// 恢复流程先把旧容器改名而不是直接删除,新容器创建/启动失败时才能完整回滚。 +func restoreOldContainerName(name string, at time.Time) string { + return name + "-dc-old-" + at.Format("20060102-150405.000000000") +} + +// rollbackRestoredContainer 在 force 恢复失败时清理新容器并把旧容器恢复原名/原状态。 +// oldTempName 为空表示旧容器尚未改名;newID 为空表示还没有创建新容器。 +func rollbackRestoredContainer(serviceContext *svc.ServiceContext, oldID, oldName, oldTempName, newID string, wasRunning, wasPaused bool) string { + var problems []string + bg, cancel := dockerTimeout(context.Background(), dockerMutationTimeout) + defer cancel() + + // 新容器可能还占着原名,必须先移除才能把旧容器改回去。 + if newID != "" { + if err := serviceContext.DockerClient.ContainerRemove(bg, newID, container.RemoveOptions{Force: true}); err != nil { + problems = append(problems, "新容器清理失败: "+err.Error()) + } + } + if oldTempName != "" { + if err := serviceContext.DockerClient.ContainerRename(bg, oldID, oldName); err != nil { + problems = append(problems, "旧容器改回原名失败: "+err.Error()) + } + } + if wasRunning { + if wasPaused { + _ = serviceContext.DockerClient.ContainerUnpause(bg, oldID) + } + current, inspectErr := serviceContext.DockerClient.ContainerInspect(bg, oldID) + if inspectErr != nil || current.State == nil || !current.State.Running { + if startErr := serviceContext.DockerClient.ContainerStart(bg, oldID, container.StartOptions{}); startErr != nil { + problems = append(problems, "旧容器重新启动失败: "+startErr.Error()) + } + } + if wasPaused { + if pauseErr := serviceContext.DockerClient.ContainerPause(bg, oldID); pauseErr != nil { + problems = append(problems, "旧容器恢复暂停状态失败: "+pauseErr.Error()) + } + } + } + if len(problems) == 0 { + return "" + } + return ";回滚异常: " + strings.Join(problems, ";") +} + +// inspectRestoreTarget 返回同名容器;不存在时返回 nil。 +func restoreNetworkingConfig(config *network.NetworkingConfig) *network.NetworkingConfig { + if config == nil || len(config.EndpointsConfig) == 0 { + return config + } + return &network.NetworkingConfig{ + EndpointsConfig: sanitizeEndpointSettings(config.EndpointsConfig), + } +} + +func inspectRestoreTarget(ctx context.Context, serviceContext *svc.ServiceContext, name string) (*dockerTypes.ContainerJSON, error) { + existing, err := serviceContext.DockerClient.ContainerInspect(ctx, name) + if err != nil { + if dockerclient.IsErrNotFound(err) { + return nil, nil + } + return nil, err + } + return &existing, nil +} + +// RestoreContainer 从备份 JSON 恢复容器。 +// 默认按容器在备份时的运行状态恢复;startOverride 可强制启动/不启动。 +// 同名容器已存在时默认跳过(镜像不一致则报错),force=true 时删除后重建。 +func RestoreContainer(taskCtx context.Context, serviceContext *svc.ServiceContext, filename string, taskID string, startOverride *bool, force bool) error { + progress := svc.TaskProgress{ TaskID: taskID, Percentage: 0, - Message: "", - Name: "", + Message: "准备恢复容器", + Name: "恢复容器", DetailMsg: "", IsDone: false, } - oldProgress.Name = "恢复容器" + if serviceContext.DockerClient == nil { + progress.Message = "恢复失败" + progress.DetailMsg = "Docker 客户端未初始化,请检查 DOCKER_HOST 配置" + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) + return fmt.Errorf("Docker 客户端未初始化,请检查 DOCKER_HOST 配置") + } + restoreMu.Lock() + defer restoreMu.Unlock() fullPath, err := ResolveBackupPath(filename, ".json") if err != nil { - logx.Errorf("Failed to resolve backup path: %v", err) - oldProgress.Message = "非法文件名" - oldProgress.DetailMsg = err.Error() - oldProgress.IsDone = true - ctx.UpdateProgress(taskID, oldProgress) + logx.Errorf("解析备份文件路径失败: %v", err) + progress.Message = "非法文件名" + progress.DetailMsg = err.Error() + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) return err } content, err := os.ReadFile(fullPath) if err != nil { - logx.Errorf("Failed to read file: %v", err) - oldProgress.Percentage = 0 - oldProgress.Message = "读取文件失败或者未找到文件。请确认文件名仅由大小写字母、数字和短横线组成" - oldProgress.DetailMsg = err.Error() - oldProgress.IsDone = true - ctx.UpdateProgress(taskID, oldProgress) + logx.Errorf("读取备份文件失败: %v", err) + progress.Percentage = 0 + progress.Message = "读取文件失败或者未找到文件。请确认文件名仅由大小写字母、数字和短横线组成" + progress.DetailMsg = err.Error() + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) return err } - var configList []dockerBackend.ContainerCreateConfig - err = json.Unmarshal(content, &configList) - if err != nil { - logx.Errorf("Failed to parse json: %v", err) - oldProgress.Percentage = 0 - oldProgress.Message = "解析文件失败" - oldProgress.DetailMsg = err.Error() - oldProgress.IsDone = true - ctx.UpdateProgress(taskID, oldProgress) + // 新格式在 ContainerCreateConfig 之外带 stateKnown/wasRunning/wasPaused; + // 旧格式(只有 Name/Config/HostConfig/...)同样能反序列化,状态按未知处理。 + var configList []ContainerBackupEntry + if err = json.Unmarshal(content, &configList); err != nil { + logx.Errorf("解析备份 JSON 失败: %v", err) + progress.Percentage = 0 + progress.Message = "解析文件失败" + progress.DetailMsg = err.Error() + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) return err } - for i, containerInfo := range configList { - info := "正在恢复第" + strconv.Itoa(i+1) + "个容器" - oldProgress.Percentage = int(float64(i) / float64(len(configList)) * 100) - oldProgress.Message = info - oldProgress.DetailMsg = info - ctx.UpdateProgress(taskID, oldProgress) - ctx.DockerClient.NegotiateAPIVersion(context.TODO()) - reader, err := ctx.DockerClient.ImagePull(context.TODO(), containerInfo.Config.Image, image.PullOptions{}) - if err != nil { - backupList = append(backupList, containerInfo.Config.Image+"拉取镜像出现错误"+err.Error()) - logx.Errorf("Failed to pull image: %v", err) + if len(configList) == 0 { + progress.Percentage = 100 + progress.Message = "备份文件中没有容器" + progress.DetailMsg = "备份文件中没有容器" + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) + return fmt.Errorf("备份文件中没有容器") + } + + negotiateCtx, negotiateCancel := dockerTimeout(taskCtx, dockerNegotiateTimeout) + serviceContext.DockerClient.NegotiateAPIVersion(negotiateCtx) + negotiateCancel() + var failures []string + var completed []string + for i, entry := range configList { + if err = taskCtx.Err(); err != nil { + progress.Percentage = 100 + progress.Message = "任务已取消" + progress.DetailMsg = "已取消恢复,已完成部分不会回滚" + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) + return err + } + if entry.Config == nil || strings.TrimSpace(entry.Config.Image) == "" { + failures = append(failures, fmt.Sprintf("第 %d 个容器缺少镜像配置", i+1)) continue } - err = decodePullResp(reader, ctx, context.Background(), taskID) + + info := "正在恢复第" + strconv.Itoa(i+1) + "个容器" + progress.Percentage = int(float64(i) / float64(len(configList)) * 90) + progress.Message = info + progress.DetailMsg = info + serviceContext.UpdateProgress(taskID, progress) + + startDesired := restoreShouldStart(entry, startOverride) + keepPaused := startOverride == nil && entry.StateKnown && entry.WasPaused + hasName := strings.TrimSpace(entry.Name) != "" + var replaceExisting *dockerTypes.ContainerJSON + + // 幂等恢复:同名容器已存在时,默认不重复创建。 + if hasName { + existing, inspectErr := inspectRestoreTarget(taskCtx, serviceContext, entry.Name) + if inspectErr != nil { + failures = append(failures, entry.Name+" 检查同名容器失败: "+inspectErr.Error()) + continue + } + if existing != nil { + if force { + // 拉镜像成功后再停止/改名旧容器;创建或启动失败时还能完整回滚。 + replaceExisting = existing + } else { + if existing.Config != nil && existing.Config.Image != entry.Config.Image { + failures = append(failures, entry.Name+" 已存在且镜像不一致(现有 "+existing.Config.Image+",备份 "+entry.Config.Image+"),如需覆盖请使用 force=true") + continue + } + if startDesired { + if existing.State != nil && existing.State.Paused { + if !keepPaused { + if unpauseErr := serviceContext.DockerClient.ContainerUnpause(taskCtx, existing.ID); unpauseErr != nil { + failures = append(failures, entry.Name+" 已存在但取消暂停失败: "+unpauseErr.Error()) + continue + } + } + } else if existing.State == nil || !existing.State.Running { + if startErr := serviceContext.DockerClient.ContainerStart(taskCtx, existing.ID, container.StartOptions{}); startErr != nil { + failures = append(failures, entry.Name+" 已存在但启动失败: "+startErr.Error()) + continue + } + } + if keepPaused && (existing.State == nil || !existing.State.Paused) { + if pauseErr := serviceContext.DockerClient.ContainerPause(taskCtx, existing.ID); pauseErr != nil { + failures = append(failures, entry.Name+" 已存在但暂停失败: "+pauseErr.Error()) + continue + } + } + } + completed = append(completed, entry.Name+" 已存在,跳过创建") + progress.Percentage = int(float64(i+1) / float64(len(configList)) * 90) + progress.DetailMsg = entry.Name + " 已存在,跳过创建" + serviceContext.UpdateProgress(taskID, progress) + continue + } + } + } + + err = func() error { + reader, pullErr := serviceContext.DockerClient.ImagePull(taskCtx, entry.Config.Image, image.PullOptions{}) + if pullErr != nil { + return fmt.Errorf("拉取镜像失败: %w", pullErr) + } + defer func() { + if closeErr := reader.Close(); closeErr != nil { + logx.Errorf("关闭镜像拉取流失败: %v", closeErr) + } + }() + if pullErr = decodePullResp(reader, serviceContext, taskCtx, taskID); pullErr != nil { + return fmt.Errorf("拉取镜像失败: %w", pullErr) + } + return nil + }() if err != nil { - backupList = append(backupList, containerInfo.Config.Image+"拉取镜像出现错误"+err.Error()) - logx.Errorf("Failed to pull image: %v", err) + logx.Errorf("恢复容器 %s 拉取镜像失败: %v", entry.Name, err) + failures = append(failures, entry.Name+" 拉取镜像失败: "+err.Error()) continue } - _, err = ctx.DockerClient.ContainerCreate(context.TODO(), containerInfo.Config, containerInfo.HostConfig, containerInfo.NetworkingConfig, nil, containerInfo.Name) - if err != nil { - logx.Errorf("Failed to create container: %v", err) - info = "正在恢复第" + strconv.Itoa(i+1) + "个容器" - backupList = append(backupList, containerInfo.Name+"恢复失败"+err.Error()) + + oldID := "" + oldWasRunning := false + oldWasPaused := false + oldTempName := "" + if replaceExisting != nil { + if replaceExisting.State == nil { + failures = append(failures, entry.Name+" 旧容器状态未知,无法安全执行 force 覆盖") + continue + } + oldID = replaceExisting.ID + oldWasRunning = replaceExisting.State.Running + oldWasPaused = replaceExisting.State.Paused + stopTimeout := 10 + if oldWasRunning { + if oldWasPaused { + if unpauseErr := serviceContext.DockerClient.ContainerUnpause(taskCtx, replaceExisting.ID); unpauseErr != nil { + failures = append(failures, entry.Name+" 旧容器取消暂停失败: "+unpauseErr.Error()) + continue + } + } + if stopErr := serviceContext.DockerClient.ContainerStop(taskCtx, replaceExisting.ID, container.StopOptions{Signal: "SIGTERM", Timeout: &stopTimeout}); stopErr != nil { + rollbackMsg := rollbackRestoredContainer(serviceContext, replaceExisting.ID, entry.Name, "", "", oldWasRunning, oldWasPaused) + failures = append(failures, entry.Name+" 旧容器停止失败: "+stopErr.Error()+rollbackMsg) + continue + } + } + oldTempName = restoreOldContainerName(entry.Name, time.Now()) + if renameErr := serviceContext.DockerClient.ContainerRename(taskCtx, replaceExisting.ID, oldTempName); renameErr != nil { + rollbackMsg := rollbackRestoredContainer(serviceContext, replaceExisting.ID, entry.Name, "", "", oldWasRunning, oldWasPaused) + failures = append(failures, entry.Name+" 旧容器改名失败: "+renameErr.Error()+rollbackMsg) + continue + } + } + + created, createErr := serviceContext.DockerClient.ContainerCreate( + taskCtx, + entry.Config, + entry.HostConfig, + restoreNetworkingConfig(entry.NetworkingConfig), + nil, + entry.Name, + ) + if createErr != nil { + rollbackMsg := rollbackRestoredContainer(serviceContext, oldID, entry.Name, oldTempName, "", oldWasRunning, oldWasPaused) + logx.Errorf("恢复容器 %s 创建失败: %v", entry.Name, createErr) + failures = append(failures, entry.Name+" 创建失败: "+createErr.Error()+rollbackMsg) continue - } else { - backupList = append(backupList, containerInfo.Name+"恢复成功") } + if startDesired { + if startErr := serviceContext.DockerClient.ContainerStart(taskCtx, created.ID, container.StartOptions{}); startErr != nil { + rollbackMsg := rollbackRestoredContainer(serviceContext, oldID, entry.Name, oldTempName, created.ID, oldWasRunning, oldWasPaused) + failures = append(failures, entry.Name+" 启动失败: "+startErr.Error()+rollbackMsg) + continue + } + if keepPaused { + if pauseErr := serviceContext.DockerClient.ContainerPause(taskCtx, created.ID); pauseErr != nil { + rollbackMsg := rollbackRestoredContainer(serviceContext, oldID, entry.Name, oldTempName, created.ID, oldWasRunning, oldWasPaused) + failures = append(failures, entry.Name+" 启动成功但暂停失败: "+pauseErr.Error()+rollbackMsg) + continue + } + } + } + + // 新容器已经创建并达到目标状态,才真正删除被替换的旧容器。 + result := entry.Name + " 恢复成功" + if replaceExisting != nil && oldTempName != "" { + cleanupCtx, cleanupCancel := dockerTimeout(context.Background(), dockerMutationTimeout) + if removeErr := serviceContext.DockerClient.ContainerRemove(cleanupCtx, replaceExisting.ID, container.RemoveOptions{Force: true}); removeErr != nil { + result = entry.Name + " 恢复成功,但旧容器清理失败,请手动删除 " + oldTempName + ": " + removeErr.Error() + } + cleanupCancel() + } + completed = append(completed, result) + progress.Percentage = int(float64(i+1) / float64(len(configList)) * 90) + progress.DetailMsg = result + serviceContext.UpdateProgress(taskID, progress) + } + + if err = taskCtx.Err(); err != nil { + progress.Percentage = 100 + progress.Message = "任务已取消" + progress.DetailMsg = "已取消恢复,已完成部分不会回滚" + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) + return err + } + + progress.Percentage = 100 + details := append([]string{}, completed...) + details = append(details, failures...) + progress.DetailMsg = strings.Join(details, ";\n") + if len(failures) > 0 { + progress.Message = fmt.Sprintf("恢复完成,%d 个容器失败", len(failures)) + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) + return fmt.Errorf("%d 个容器恢复失败: %s", len(failures), strings.Join(failures, ";")) } - oldProgress.Percentage = 100 - oldProgress.DetailMsg = strings.Join(backupList, ",\n") - oldProgress.Message = "恢复完成" - oldProgress.IsDone = true - ctx.UpdateProgress(taskID, oldProgress) + progress.Message = "恢复完成" + progress.IsDone = true + serviceContext.UpdateProgress(taskID, progress) return nil } diff --git a/internal/utiles/startcontainer.go b/internal/utiles/startcontainer.go index fce4433e..d06b48a7 100644 --- a/internal/utiles/startcontainer.go +++ b/internal/utiles/startcontainer.go @@ -7,8 +7,10 @@ import ( ) func StartContainer(ctx *svc.ServiceContext, id string) error { + requestCtx, cancel := dockerTimeout(context.Background(), dockerMutationTimeout) + defer cancel() startOptions := container.StartOptions{} - err := ctx.DockerClient.ContainerStart(context.Background(), id, startOptions) + err := ctx.DockerClient.ContainerStart(requestCtx, id, startOptions) if err != nil { return err } diff --git a/internal/utiles/stopcontainer.go b/internal/utiles/stopcontainer.go index 1a320b52..dd9c885d 100644 --- a/internal/utiles/stopcontainer.go +++ b/internal/utiles/stopcontainer.go @@ -13,7 +13,9 @@ func StopContainer(ctx *svc.ServiceContext, id string) error { Signal: signal, Timeout: &timeout, } - err := ctx.DockerClient.ContainerStop(context.Background(), id, stopOptions) + requestCtx, cancel := dockerTimeout(context.Background(), dockerMutationTimeout) + defer cancel() + err := ctx.DockerClient.ContainerStop(requestCtx, id, stopOptions) if err != nil { return err } diff --git a/internal/utiles/updatecontainer.go b/internal/utiles/updatecontainer.go index 94f6d236..a9f07037 100644 --- a/internal/utiles/updatecontainer.go +++ b/internal/utiles/updatecontainer.go @@ -6,6 +6,8 @@ import ( "fmt" "io" "os" + "strings" + "sync" "time" "github.com/docker/docker/api/types/container" @@ -16,10 +18,23 @@ import ( "github.com/zeromicro/go-zero/core/logx" ) +// 同一个容器只允许一个更新流程,避免手动更新与自动更新并发改名/创建。 +var containerUpdateLocks sync.Map + +func lockContainerUpdate(id string) func() { + value, _ := containerUpdateLocks.LoadOrStore(id, &sync.Mutex{}) + mutex := value.(*sync.Mutex) + mutex.Lock() + return mutex.Unlock +} + // UpdateContainer 执行一次容器更新:拉取新镜像 → 停止并改名旧容器 → 克隆配置创建新容器 // → 启动新容器 → 删除旧容器 → 清理旧镜像。任一步失败都会尝试把旧容器恢复到原名并重新启动。 // ctx 支持取消:任务被取消时在步骤边界退出。 func UpdateContainer(serviceContext *svc.ServiceContext, ctx context.Context, id string, name string, imageNameAndTag string, delOldContainer bool, taskID string) error { + unlock := lockContainerUpdate(id) + defer unlock() + progress := func(percentage int, message, detailMsg string, isDone bool) { serviceContext.UpdateProgress(taskID, svc.TaskProgress{ TaskID: taskID, @@ -46,7 +61,9 @@ func UpdateContainer(serviceContext *svc.ServiceContext, ctx context.Context, id timeout := 10 signal := "SIGTERM" - serviceContext.DockerClient.NegotiateAPIVersion(ctx) + negotiateCtx, negotiateCancel := dockerTimeout(ctx, dockerNegotiateTimeout) + serviceContext.DockerClient.NegotiateAPIVersion(negotiateCtx) + negotiateCancel() // 先记录旧容器信息:旧镜像 ID 用于更新后的清理,旧容器名用于失败回滚 inspectedContainer, err := serviceContext.DockerClient.ContainerInspect(ctx, id) @@ -55,22 +72,78 @@ func UpdateContainer(serviceContext *svc.ServiceContext, ctx context.Context, id logx.Errorf("获取容器信息失败: %v", err) return err } + if inspectedContainer.Config == nil { + err = fmt.Errorf("旧容器配置为空,无法更新") + progress(0, "获取容器配置失败", err.Error(), true) + return err + } + if inspectedContainer.HostConfig == nil { + err = fmt.Errorf("旧容器 HostConfig 为空,无法克隆配置") + progress(0, "获取容器配置失败", err.Error(), true) + return err + } + if strings.TrimSpace(imageNameAndTag) == "" { + imageNameAndTag = inspectedContainer.Config.Image + } + if strings.TrimSpace(imageNameAndTag) == "" { + err = fmt.Errorf("镜像名称为空") + progress(0, "更新失败", err.Error(), true) + return err + } oldImageID := inspectedContainer.Image - oldContainerName := name - backupName := name + "-" + time.Now().Format("2006-01-02-15-04-05.000000000") + oldContainerName := strings.TrimPrefix(inspectedContainer.Name, "/") + if oldContainerName == "" { + oldContainerName = name + } + wasRunning := inspectedContainer.State != nil && inspectedContainer.State.Running + wasPaused := inspectedContainer.State != nil && inspectedContainer.State.Paused + backupName := oldContainerName + "-" + time.Now().Format("2006-01-02-15-04-05.000000000") + renamed := false + newCreated := false + var warnings []string + if inspectedContainer.Config.Labels["com.docker.compose.project"] != "" { + warnings = append(warnings, "该容器由 Compose 管理,本次按容器方式重建;建议优先使用 docker compose pull/up 更新") + } - // rollback 把旧容器恢复到原名并重新启动;reason 写入进度详情 + // rollback 只恢复本流程真正改过名的旧容器;原本停止的容器不会被误启动。 rollback := func(reason string) { - bg := context.Background() - if renameErr := serviceContext.DockerClient.ContainerRename(bg, id, oldContainerName); renameErr != nil { - logx.Errorf("回滚重命名失败: %v", renameErr) - progress(100, "更新失败且回滚失败,请手动处理旧容器 "+backupName, reason, true) - return + bg, bgCancel := dockerTimeout(context.Background(), dockerMutationTimeout) + defer bgCancel() + // 新容器还占着原名时先移除,否则旧容器改不回去。 + if newCreated { + if removeErr := serviceContext.DockerClient.ContainerRemove(bg, oldContainerName, container.RemoveOptions{Force: true}); removeErr != nil { + logx.Errorf("回滚移除新容器失败: %v", removeErr) + } + newCreated = false } - if startErr := serviceContext.DockerClient.ContainerStart(bg, id, container.StartOptions{}); startErr != nil { - logx.Errorf("回滚启动失败: %v", startErr) - progress(100, "更新失败,旧容器已改回原名但启动失败", reason+";启动错误: "+startErr.Error(), true) - return + if renamed { + if renameErr := serviceContext.DockerClient.ContainerRename(bg, id, oldContainerName); renameErr != nil { + logx.Errorf("回滚重命名失败: %v", renameErr) + progress(100, "更新失败且回滚失败,请手动处理旧容器 "+backupName, reason, true) + return + } + renamed = false + } + if wasRunning { + // 原本是 paused 的容器,先取消暂停再确保运行,最后恢复暂停状态。 + if wasPaused { + _ = serviceContext.DockerClient.ContainerUnpause(bg, id) + } + current, inspectErr := serviceContext.DockerClient.ContainerInspect(bg, id) + if inspectErr != nil || current.State == nil || !current.State.Running { + if startErr := serviceContext.DockerClient.ContainerStart(bg, id, container.StartOptions{}); startErr != nil { + logx.Errorf("回滚启动失败: %v", startErr) + progress(100, "更新失败,旧容器已改回原名但启动失败", reason+";启动错误: "+startErr.Error(), true) + return + } + } + if wasPaused { + if pauseErr := serviceContext.DockerClient.ContainerPause(bg, id); pauseErr != nil { + logx.Errorf("回滚恢复暂停状态失败: %v", pauseErr) + progress(100, "更新失败,旧容器已恢复但暂停状态恢复失败", reason+";暂停错误: "+pauseErr.Error(), true) + return + } + } } progress(100, "更新失败,已回滚旧容器", reason, true) } @@ -79,37 +152,62 @@ func UpdateContainer(serviceContext *svc.ServiceContext, ctx context.Context, id progress(10, "正在拉取新镜像", "正在拉取新镜像", false) reader, err := serviceContext.DockerClient.ImagePull(ctx, imageNameAndTag, image.PullOptions{}) if err != nil { + if ctx.Err() != nil { + progress(100, "任务已取消", "任务已在拉取镜像阶段取消", true) + return ctx.Err() + } progress(100, "拉取镜像失败", err.Error(), true) - logx.Errorf("Failed to pull image: %s", err) + logx.Errorf("拉取镜像失败: %s", err) return err } + defer func() { + if closeErr := reader.Close(); closeErr != nil { + logx.Errorf("关闭镜像拉取流失败: %v", closeErr) + } + }() if err = decodePullResp(reader, serviceContext, ctx, taskID); err != nil { + if ctx.Err() != nil { + // 取消发生在拉取阶段时,错误本质是 context.Canceled, + // 如实报“任务已取消”而不是误导性的“拉取镜像失败”。 + progress(100, "任务已取消", "任务已在拉取镜像阶段取消", true) + return ctx.Err() + } progress(100, "拉取镜像失败", err.Error(), true) - logx.Errorf("Failed to pull image: %s", err) + logx.Errorf("拉取镜像失败: %s", err) return err } if cancelled() { return ctx.Err() } - // 2. 停止旧容器 + // 2. 停止旧容器(原本停止的容器跳过,避免更新后把它误启动) progress(30, "正在停止容器", "正在停止容器", false) stopOptions := container.StopOptions{ Signal: signal, Timeout: &timeout, } - if err = serviceContext.DockerClient.ContainerStop(ctx, id, stopOptions); err != nil { - progress(100, "停止容器失败", err.Error(), true) - return err + if wasRunning { + // Docker 不允许直接 stop paused 容器,先取消暂停;回滚/新容器启动后会恢复。 + if wasPaused { + if err = serviceContext.DockerClient.ContainerUnpause(ctx, id); err != nil { + rollback("取消旧容器暂停失败: " + err.Error()) + return err + } + } + if err = serviceContext.DockerClient.ContainerStop(ctx, id, stopOptions); err != nil { + rollback("停止容器失败: " + err.Error()) + return err + } } // 3. 重命名旧容器(腾出原名) progress(40, "正在重命名旧容器", "正在重命名旧容器", false) if err = serviceContext.DockerClient.ContainerRename(ctx, id, backupName); err != nil { - // 还没改名成功,旧容器仍是原名,重新拉起即可 + // 还没改名成功,旧容器仍是原名,只恢复它原来的运行状态 rollback("重命名旧容器失败: " + err.Error()) return err } + renamed = true // 4. 克隆旧容器配置创建新容器(只替换镜像) progress(60, "正在创建新容器", "正在创建新容器", false) @@ -118,21 +216,40 @@ func UpdateContainer(serviceContext *svc.ServiceContext, ctx context.Context, id inspectedContainer.Image = imageNameAndTag config := inspectedContainer.Config hostConfig := inspectedContainer.HostConfig + var endpoints map[string]*network.EndpointSettings + if inspectedContainer.NetworkSettings != nil { + endpoints = sanitizeEndpointSettings(inspectedContainer.NetworkSettings.Networks) + } networkingConfig := &network.NetworkingConfig{ - EndpointsConfig: inspectedContainer.NetworkSettings.Networks, + EndpointsConfig: endpoints, } if _, err = serviceContext.DockerClient.ContainerCreate(ctx, config, hostConfig, networkingConfig, nil, oldContainerName); err != nil { rollback("创建新容器失败: " + err.Error()) return err } + newCreated = true - // 5. 启动新容器 - progress(80, "正在启动新容器", "正在启动新容器", false) - if err = serviceContext.DockerClient.ContainerStart(ctx, oldContainerName, container.StartOptions{}); err != nil { - // 新容器已创建但起不来:先移除它,再回滚旧容器 - _ = serviceContext.DockerClient.ContainerRemove(context.Background(), oldContainerName, container.RemoveOptions{Force: true}) - rollback("启动新容器失败: " + err.Error()) - return err + // 5. 启动新容器并等待健康检查;原 paused 容器启动后再暂停。 + if wasRunning { + progress(80, "正在启动新容器", "正在启动新容器", false) + if err = serviceContext.DockerClient.ContainerStart(ctx, oldContainerName, container.StartOptions{}); err != nil { + // 新容器已创建但起不来:rollback 会移除它并恢复旧容器。 + rollback("启动新容器失败: " + err.Error()) + return err + } + if !wasPaused { + progress(85, "正在等待容器健康", "正在等待新容器通过健康检查", false) + if err = waitForContainerHealthy(ctx, serviceContext, oldContainerName, inspectedContainer.Config.Healthcheck); err != nil { + rollback("新容器健康检查失败: " + err.Error()) + return err + } + } + if wasPaused { + if err = serviceContext.DockerClient.ContainerPause(ctx, oldContainerName); err != nil { + rollback("恢复新容器暂停状态失败: " + err.Error()) + return err + } + } } // 6. 删除旧容器(默认保留开关可关闭) @@ -140,7 +257,9 @@ func UpdateContainer(serviceContext *svc.ServiceContext, ctx context.Context, id if err = serviceContext.DockerClient.ContainerRemove(ctx, id, container.RemoveOptions{}); err != nil { // 旧容器删除失败不算更新失败,但需要告知 logx.Errorf("删除旧容器失败: %v", err) - progress(90, "更新成功(旧容器删除失败,请手动清理 "+backupName+")", err.Error(), false) + warning := "旧容器删除失败,请手动清理 " + backupName + ": " + err.Error() + warnings = append(warnings, warning) + progress(90, "更新成功(旧容器删除失败)", warning, false) } } @@ -148,25 +267,75 @@ func UpdateContainer(serviceContext *svc.ServiceContext, ctx context.Context, id if delOldContainer && os.Getenv("CLEANUP_OLD_IMAGE") != "false" { progress(95, "正在清理旧镜像", "正在清理旧镜像", false) if cleanupMsg := cleanupOldImage(serviceContext, oldImageID); cleanupMsg != "" { - progress(100, "更新成功", cleanupMsg, false) + warnings = append(warnings, cleanupMsg) + progress(95, "更新成功(旧镜像未清理)", cleanupMsg, false) } } - progress(100, "更新成功", "更新成功", true) + detail := "更新成功" + if len(warnings) > 0 { + detail = strings.Join(warnings, ";\n") + } + progress(100, "更新成功", detail, true) return nil } +// waitForContainerHealthy 在容器启动后确认它没有立刻退出。 +// 有 HEALTHCHECK 时等待 healthy;没有时只观察 2 秒,避免把“启动成功但马上崩”当成成功。 +func waitForContainerHealthy(ctx context.Context, serviceContext *svc.ServiceContext, name string, healthcheck *container.HealthConfig) error { + checkCtx, cancel := context.WithTimeout(ctx, 90*time.Second) + defer cancel() + + hasHealthcheck := healthcheck != nil && len(healthcheck.Test) > 0 && + !(len(healthcheck.Test) == 1 && strings.EqualFold(healthcheck.Test[0], "NONE")) + stableDeadline := time.Now().Add(2 * time.Second) + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-checkCtx.Done(): + if ctx.Err() != nil { + return ctx.Err() + } + return fmt.Errorf("等待容器健康超时") + case <-ticker.C: + inspected, err := serviceContext.DockerClient.ContainerInspect(checkCtx, name) + if err != nil { + return fmt.Errorf("检查新容器状态失败: %w", err) + } + if inspected.State == nil { + return fmt.Errorf("新容器状态为空") + } + if !inspected.State.Running { + return fmt.Errorf("新容器已退出,退出码 %d", inspected.State.ExitCode) + } + if hasHealthcheck && inspected.State.Health != nil { + switch strings.ToLower(string(inspected.State.Health.Status)) { + case "healthy": + return nil + case "unhealthy": + return fmt.Errorf("新容器健康检查结果为 unhealthy") + } + } else if !hasHealthcheck && time.Now().After(stableDeadline) { + return nil + } + } + } +} + // cleanupOldImage 在没有任何容器引用 oldImageID 时删除该镜像。 // 返回补充信息(清理失败原因),失败不影响更新结果。 func cleanupOldImage(serviceContext *svc.ServiceContext, oldImageID string) string { if oldImageID == "" { return "" } - bg := context.Background() - containers, err := serviceContext.DockerClient.ContainerList(bg, container.ListOptions{All: true}) + listCtx, listCancel := dockerTimeout(context.Background(), dockerListTimeout) + containers, err := serviceContext.DockerClient.ContainerList(listCtx, container.ListOptions{All: true}) + listCancel() if err != nil { logx.Errorf("清理旧镜像前获取容器列表失败: %v", err) - return "" + return "旧镜像清理检查失败(未确认是否仍被引用): " + err.Error() } for _, c := range containers { if c.ImageID == oldImageID { @@ -174,11 +343,13 @@ func cleanupOldImage(serviceContext *svc.ServiceContext, oldImageID string) stri return "" } } - if _, err := serviceContext.DockerClient.ImageRemove(bg, oldImageID, image.RemoveOptions{}); err != nil { + removeCtx, removeCancel := dockerTimeout(context.Background(), dockerMutationTimeout) + defer removeCancel() + if _, err := serviceContext.DockerClient.ImageRemove(removeCtx, oldImageID, image.RemoveOptions{}); err != nil { logx.Errorf("清理旧镜像失败(不影响更新结果): %v", err) return "旧镜像清理失败: " + err.Error() } - return "旧镜像已清理" + return "" } func decodePullResp(reader io.Reader, svcCtx *svc.ServiceContext, ctx context.Context, taskID string) (err error) { @@ -205,18 +376,16 @@ func decodePullResp(reader io.Reader, svcCtx *svc.ServiceContext, ctx context.Co oldTaskProgress.Message = "拉取镜像失败" oldTaskProgress.DetailMsg = err.Error() oldTaskProgress.Percentage = 25 - oldTaskProgress.IsDone = true svcCtx.UpdateProgress(taskID, oldTaskProgress) - logx.Errorf("Failed to decode pull image response: %s", err) + logx.Errorf("解析镜像拉取响应失败: %s", err) return fmt.Errorf("拉取镜像失败: %w", err) } if msg.Error != nil { oldTaskProgress.Message = "拉取镜像失败" oldTaskProgress.DetailMsg = msg.Error.Error() oldTaskProgress.Percentage = 25 - oldTaskProgress.IsDone = true svcCtx.UpdateProgress(taskID, oldTaskProgress) - logx.Errorf("Error: %s", msg.Error) + logx.Errorf("registry 返回错误: %s", msg.Error) return fmt.Errorf("拉取镜像失败: %w", msg.Error) } var formattedMsg string diff --git a/internal/utiles/updateprogram.go b/internal/utiles/updateprogram.go index 79ada9b5..07c6b0bb 100644 --- a/internal/utiles/updateprogram.go +++ b/internal/utiles/updateprogram.go @@ -3,7 +3,10 @@ package utiles import ( "archive/tar" "compress/gzip" + "crypto/sha256" + "errors" "fmt" + "github.com/onlyLTY/dockerCopilot/internal/config" "github.com/onlyLTY/dockerCopilot/internal/svc" "github.com/zeromicro/go-zero/core/logx" "io" @@ -12,20 +15,38 @@ import ( "path/filepath" "runtime" "strings" + "sync" + "time" ) +// updateProgramMu 串行化自更新:并发两次调用会交错写同一个 +// dockerCopilot.tar.gz / dockerCopilot-new,可能装上损坏或错版的包。 +var updateProgramMu sync.Mutex + +// ErrUpdateProgramRunning 已有一轮自更新在执行时返回。 +var ErrUpdateProgramRunning = errors.New("已有一轮自更新在执行,请稍后再试") + func UpdateProgram(ctx *svc.ServiceContext) error { + if !updateProgramMu.TryLock() { + return ErrUpdateProgramRunning + } + defer updateProgramMu.Unlock() + + if strings.Contains(config.Version, "FNOS") { + return fmt.Errorf("飞牛版本请使用 FNOS 专用发布包更新,禁止覆盖为通用版") + } githubProxy := os.Getenv("githubProxy") if githubProxy != "" { githubProxy = strings.TrimRight(githubProxy, "/") + "/" } versionURL := githubProxy + "https://raw.githubusercontent.com/" + UpdateRepo() + "/" + UpdateBranch() + "/version" releaseBaseURL := githubProxy + "https://github.com/" + UpdateRepo() + "/releases/download" - logx.Infof("versionURL: %s", versionURL) - resp, err := http.Get(versionURL) + logx.Infof("版本检查地址: %s", versionURL) + client := &http.Client{Timeout: 60 * time.Second} + resp, err := client.Get(versionURL) if err != nil { logx.Info("没有获取到最新版本信息:", err) - return nil + return err } defer func(Body io.ReadCloser) { err := Body.Close() @@ -34,11 +55,14 @@ func UpdateProgram(ctx *svc.ServiceContext) error { } }(resp.Body) - versionData, err := io.ReadAll(resp.Body) - logx.Infof("versionData: %s", versionData) + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("获取版本信息失败: HTTP %s", resp.Status) + } + versionData, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) + logx.Infof("远端版本文件内容: %s", versionData) if err != nil { logx.Info("没有获取到最新版本信息:", err) - return nil + return err } version := strings.TrimSpace(string(versionData)) @@ -47,24 +71,70 @@ func UpdateProgram(ctx *svc.ServiceContext) error { downloadURL := fmt.Sprintf("%s/%s/dockerCopilot-%s.tar.gz", releaseBaseURL, version, runtime.GOARCH) logx.Info("下载链接:", downloadURL) dest := "dockerCopilot.tar.gz" + checksumDest := dest + ".sha256" + defer func() { + _ = os.Remove(dest) + _ = os.Remove(checksumDest) + }() if err := downloadFile(downloadURL, dest); err != nil { logx.Error("下载失败:", err) return err } + if os.Getenv("UPDATE_SKIP_CHECKSUM") != "true" { + if err := downloadFile(downloadURL+".sha256", checksumDest); err != nil { + return fmt.Errorf("下载校验文件失败(如为旧版本可临时设置 UPDATE_SKIP_CHECKSUM=true): %w", err) + } + checksumData, readErr := os.ReadFile(checksumDest) + if readErr != nil { + return readErr + } + fields := strings.Fields(string(checksumData)) + if len(fields) == 0 { + return fmt.Errorf("校验文件为空") + } + if err := verifySHA256(dest, fields[0]); err != nil { + return fmt.Errorf("安装包 SHA256 校验失败: %w", err) + } + logx.Info("SHA256 校验通过") + } logx.Info("下载成功") - if err := decompressTarGz(dest, "."); err != nil { + // 先解压到临时目录,成功后再原子替换;避免解压失败留下半个 dockerCopilot-new + // 被 start.sh 在下次启动时误当成新版本。 + tmpDir, err := os.MkdirTemp(".", ".dc-update-") + if err != nil { + return err + } + defer func() { + _ = os.RemoveAll(tmpDir) + }() + if err := decompressTarGz(dest, tmpDir); err != nil { logx.Info("解压缩失败:", err) return err } - logx.Info("解压缩成功") - return nil + candidates := []string{ + filepath.Join(tmpDir, "dockerCopilot-new"), + filepath.Join(tmpDir, "dist", "linux", runtime.GOARCH, "dockerCopilot-new"), + } + for _, candidate := range candidates { + if info, statErr := os.Stat(candidate); statErr == nil && info.Mode().IsRegular() { + if err := os.Rename(candidate, "dockerCopilot-new"); err != nil { + return err + } + logx.Info("解压缩成功") + return nil + } + } + return fmt.Errorf("解压完成但未找到 dockerCopilot-new") } +const maxUpdateAssetSize = 512 << 20 // 512MB,足够覆盖当前发布包,同时防止异常响应写满磁盘 + func downloadFile(url string, dest string) error { - resp, err := http.Get(url) + client := &http.Client{Timeout: 10 * time.Minute} + resp, err := client.Get(url) if err != nil { return err } @@ -75,6 +145,10 @@ func downloadFile(url string, dest string) error { } }(resp.Body) + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("下载 %s 失败: HTTP %s", url, resp.Status) + } + out, err := os.Create(dest) if err != nil { return err @@ -86,8 +160,31 @@ func downloadFile(url string, dest string) error { } }(out) - _, err = io.Copy(out, resp.Body) - return err + written, err := io.Copy(out, io.LimitReader(resp.Body, maxUpdateAssetSize+1)) + if err != nil { + return err + } + if written > maxUpdateAssetSize { + return fmt.Errorf("下载文件超过大小限制 %d 字节", maxUpdateAssetSize) + } + return nil +} + +func verifySHA256(path, expected string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + h := sha256.New() + if _, err := io.Copy(h, file); err != nil { + return err + } + actual := fmt.Sprintf("%x", h.Sum(nil)) + if !strings.EqualFold(actual, strings.TrimSpace(expected)) { + return fmt.Errorf("期望 %s,实际 %s", expected, actual) + } + return nil } func decompressTarGz(gzFilePath string, dest string) error { @@ -125,9 +222,17 @@ func decompressTarGz(gzFilePath string, dest string) error { } target := filepath.Join(dest, filepath.FromSlash(header.Name)) - // 防止 zip-slip:解压目标必须落在 dest 目录内 - cleanDest := filepath.Clean(dest) - if target != cleanDest && !strings.HasPrefix(target, cleanDest+string(os.PathSeparator)) { + // 防止 zip-slip:用绝对路径判断,避免 dest="." 时把正常文件全部误判。 + absDest, err := filepath.Abs(dest) + if err != nil { + return err + } + absTarget, err := filepath.Abs(target) + if err != nil { + return err + } + rel, err := filepath.Rel(absDest, absTarget) + if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) { return fmt.Errorf("非法的文件路径: %s", header.Name) } @@ -137,6 +242,9 @@ func decompressTarGz(gzFilePath string, dest string) error { return err } case tar.TypeReg: + if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { + return err + } outFile, err := os.Create(target) if err != nil { return err diff --git a/start.sh b/start.sh index 828a37d8..3548c079 100644 --- a/start.sh +++ b/start.sh @@ -1,12 +1,72 @@ #!/bin/sh -cd "${WORKDIR}" || exit -# 判断当前目录下是否存在名为 dockerCopilot-new 的二进制文件 +cd "${WORKDIR:-/app}" || exit + +# 新发布包把二进制放在归档根目录;旧发布包在 dist/linux// 下。 +new_bin="" if [ -f "./dockerCopilot-new" ]; then - # 如果存在,则用它覆盖 dockerCopilot - mv ./dockerCopilot-new ./dockerCopilot - # 赋予 dockerCopilot 执行权限 + new_bin="./dockerCopilot-new" +else + for candidate in ./dist/linux/*/dockerCopilot-new; do + if [ -f "$candidate" ]; then + new_bin="$candidate" + break + fi + done +fi + +if [ -n "$new_bin" ]; then + # 换入新版本前保留上一版(dockerCopilot.bak),供启动失败时自动回退。 + if [ -f ./dockerCopilot ]; then + cp ./dockerCopilot ./dockerCopilot.bak + fi + mv "$new_bin" ./dockerCopilot chmod +x ./dockerCopilot + # 清掉上一轮回退可能留下的失败版本残留。 + rm -f ./dockerCopilot.failed fi -# 运行 dockerCopilot -./dockerCopilot +# ---- 自更新闭环:新版连续启动失败时自动回退到上一版 ---- +FAIL_THRESHOLD=3 +FAIL_FILE=./.start-fail-count +child="" + +on_term() { + # docker stop 发来的 SIGTERM 转发给子进程,让它优雅退出。 + if [ -n "$child" ]; then + kill -TERM "$child" 2>/dev/null + fi +} +trap on_term TERM INT + +while true; do + start_ts=$(date +%s) + ./dockerCopilot & + child=$! + wait "$child" + code=$? + child="" + elapsed=$(( $(date +%s) - start_ts )) + + # 以下情况不算启动失败: + # - 正常退出(0)或被信号终止(143=SIGTERM/137=SIGKILL); + # - 已稳定运行超过 30 秒(自更新的主动退出发生在服务运行良久之后, + # 崩溃循环则会在启动后几秒内退出)。 + if [ "$elapsed" -ge 30 ] || [ "$code" -eq 0 ] || [ "$code" -eq 143 ] || [ "$code" -eq 137 ]; then + rm -f "$FAIL_FILE" + break + fi + + fails=$(cat "$FAIL_FILE" 2>/dev/null || echo 0) + fails=$((fails + 1)) + echo "$fails" > "$FAIL_FILE" + echo "dockerCopilot exited with code $code after ${elapsed}s (fail $fails/$FAIL_THRESHOLD)" >&2 + + if [ "$fails" -ge "$FAIL_THRESHOLD" ] && [ -f ./dockerCopilot.bak ]; then + echo "rolling back to previous binary" >&2 + mv ./dockerCopilot ./dockerCopilot.failed + mv ./dockerCopilot.bak ./dockerCopilot + chmod +x ./dockerCopilot + rm -f "$FAIL_FILE" + fi + sleep 2 +done diff --git a/static/asset/Circular-logo.png b/static/asset/Circular-logo.png deleted file mode 100644 index 9d0cdd50b0cdf5c7b48a37b48835443ddebd6eb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3557 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 diff --git a/static/asset/Circularlogo.png b/static/asset/Circularlogo.png deleted file mode 100644 index 9d0cdd50b0cdf5c7b48a37b48835443ddebd6eb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3557 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 diff --git a/static/asset/DockerCopilotlogo.png b/static/asset/DockerCopilotlogo.png deleted file mode 100644 index eeb39bfd8bcd7586d48df4b07cf1219869d3978f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55581 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 diff --git a/static/asset/ugreen.png b/static/asset/ugreen.png deleted file mode 100644 index 1fbebfafccdcce87d7b135c7ea46907178b69ae3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29290 zcmdSB^;cWp6E2Js9E!U`u_DFY-JRl2ad#&`p}14rU5h)x-QAty?sD__uJx|>U%2;& zy>fE)NzTlfnLW=uvy%vAMJW_S0z?Q12oxDiDaa%uQREm)wevsI z-W1qbBL<)7Bo)}Nf6K5(B=_SDz(xLoRmM>MqYsIJA+qXo<=OGEIo|Bw-MA?Dn#uFH z&UY}`dCTo{xY_x5Vsq~N`16$=q!_2@{VMal$(CTbq|WcvUo5(I%hBo#H!M7r19YY5 zq$C*K+J~~QN{Tw?0hMZlOTz#aU90gj^)l$F&HOGUXxw>MbDuZkDg3fj<=3~fxDynl z3vX%P{eIGH*y&Y2ev*_eSpwssdNC8=bOIT@b54tf7G5#}A!OUa+L5vEmo=|5R!yml zA0&xqjm+gwNU&2ZNvX%Nj@NSY(*1eJOz-85&O=QDqXWsfa-;2e=!hq%V{w#tuoNJH zHdxPD79%VO6+P%zAK6lmL7;^?iI6&sxSPi>a=GB`F3NqIGexB5u~h70wklw#31umL zTzqfvWc~XD&_EnySMU7vW6N?Uhz4l7~Mgq>rqEY}3>x0Ico9ksRk z4w`bxT1@fW87p74b^ zZ!;fDQ5s1O+2gxZt;&n(QN#(7e7e})-u~TvTV1oY@pFn7EX-?hNme5zazMQSwrd-m z%`=}Hj9KF}DFJi)gP)fEqKpt9C;9M3D0Bu1(q&4-cJ!|B(48wAcjFl^lmHH7t4j0r zN4g8ha6~_Ljn7zD3hso}fye89I)xZ_j2y(8#nP6dBem^B93O;ee ziYZ9G-CM9jyjG1a=89a1f9MY)102Kf&dycQuSIsAh;g~D@jg`Dm*cfqRk9aQL%?_{|UzOhr za_wZj=Q9+&^Ymy2ctU!M#X0h0go%R`#f|>(OFRcJ3|%J4k&o^Q+8gq|Hv(^_7G$H} zx$nQA_Rqkz71vO*lwriR19>#1%3RgMk$shadLEDEo2vU3G?dZ&PkIvymi4V;K1+5q z@kW8#dyK=X=6PBS+TtQ>I!s5nEj#~KLX;WSM3N-B1Ult0g zQn^}`f#=JI$QNtYv4bfLFt)#bD8Y5EjyCGM!K_9F67f1RHj~xpkvmr0?U1hrs>>{i zN=1X$6scS;iolJ`*s|5#PUp~`N1FLW5eIg2I|<^TYboI-`xK8n^}^!rH_u2X?z1Or zSchl=DHu&gJ(7=$w@=I$f|bm-i{D$g_MJzZvYl7d4oK~cE9T<_oVJ_j_HBD9SN|^c zh&b(5*sXb9t5^Bn?r%R$=6xrx9&#8_F{!8?}Q3g)Z%p$#=~7u) z8OZ+5OH;dMEEuvDQ)$GCp1W#&uqD|-7`uavdoP9`WN-fGe(?dDm0mmZCHzc_bD;Hf zm%g9jnF+z5qndUqtr`YQ^q|3M-9IvPS?E{03orV=Cqy~@xi#UX&OO8xr;oZG2lV{% z>7~wGw0riatJvB3vAUG;=BK#N?pRzL4*`jjyl;0b+)QhxM-M&$*#2xE0z#6! z?Xp*6kJ{~bby2&f>c@?PIgcMMDByeDCPz6DymH$|rzA+XsPa{jipNYJ-vNeYu;v>g zJ}Y=d8dQr}X6+EzDu~o`^Bc#|Zncu&X44_w#=W~;iqXR{MUSQ?Zg>r%qygUXOSH3H z`s{yP#n%K-5VcpqBJkZyaR?o<&F4KD{tIdd`iBvFi`L!px(GHdCL!d{L^amM|K$v6>R4{GWsIh7 zdg{_KOu`^b*&!wPV~>D`PRFgjN2SUHlB9<|z5t?&mdmA?`t&)=u^(VB6*f@yYkh8RPd@-Rpsc-X;4N$)4F3MQ~!phm7)y@@poqMsMQB z$)@YMY0ObudQPKI)+08eXxTk_*TO!A3*7#=bzpML6eEJj8gKM$O6eG>T^s`_Z-6wN>&)0cKU2qb1 zue$$k9a6En^9p!0P-?r<#Nqo|vW4~qcwu{D!uv5*?E%O+a$|a6B!#Ovw=w1e77`=-qQy>c;W6>_F+&rrp9&FZ-%(TAuV#U-7?D0W z>rWNB`qD==aaN1Fgi1*Y{G)1rzk?|LD>RANj{62JIGz z?bF1ROU`#$)J)ZEVk^0ZyeVrC?H~lz7rnE=f_n!}9JR6XaDL~17n4k*Auce!8aO@8 zK6X>YVmc634F9Q#>FF02K7<&Dg^oU7d(6O#XiO>xYzqQ~xLMmDAsQZqZiN2{ym%7a zyr~%wSx{w!t~(FKf*u{l1j<&`Hv}sl5;|dT+Q00m?3Ihf6@w4~>%u_zgjt~Fmr?%# z)|sMLibDS7&)hV}ul0>)&Xt$PjFRQw-N3g4mjH%-Ez{``C91J0B_9tzu7Oxogg`wu z6UQJ3AF6HTT^*^hzZNNuRi9EGA5`1o<`uxbH+9@^JSGky5z?25rq5u%8+b?8Lu(54 z=?nO1)iUi$C31h8K>DO#>~y>(7RqGd)3?ZKCWRb_^>bDe?G&{VvM|l>XFk4-@o|sA zXtv^tz?zW zdHhJBuMUcWIE3QyU}@-xk+P%=9E>C0@K~ z!Ra=d40e3Lusk$zTr*^oqRh5uZZeB)D*bKG40|3&GCIc4`?x~oIkI@O;}L$-4Y zf%tN-_#qWPHr$o`KgCiv><##XJbUM+NUs$`C0uZusqMQLUSm7~C)Qr2r-f!hl4lj3 zVe-Ma9#*&~O~`(kUyQ%SiG@jaiXJP&_i$Qqe=U%m2<}5C(XJK zHz0P287im~m7Z(f4`b};{YNO&!RBEA>A{pupQ_NU#~q$uTe# z!ziT%Mnqc{vA_Mi#gUEC?LS3?D(A zaQl-9n8yU|_w(?-rnxu|^|h=&9FXoC&a1ZZ##O*oRWq`?T7S z`h*6^_+}C|;JtkZmCsLQ7|Y7=w6FC9pho0MxI4E%B}-sC=srahe6 zb(K_NYW%O>q(cw#4rPHQDC4Y)=`oYY%|@qTm~G7Fg;FDfx(EJ0HR1VstC)P%lw*#R z0(U0d;M>dQuWWE=-rKqVj@!@0h?^B~ImWz?BpT^hQ=`+(nRy?Oy|++(xcuilU+8^m z-Co`t&Uo#%`)z-1R9TJ0{b@72>8@KV^KHbzAE$Q1m$`(FgIxYJXD~I*DEAbCl;`UD z<^GzggD;O>px#&?+gsI%nfs&FuG1#3W#P4uV8z({^X}vk?(TP4T=we)F6>$U##osp z4KU~fvI~XhUE?w6vikwayw;R!OR-oJ6I4J*a$fk-WImP7%9rWV|NY18me;2P=)QS# zI-#28*cPVNCtmH^`rHN&Lu3A2nLHL+Wf0Ni=zhw8b;|iLC^MjmqPy3Q z3z^B#6S=*&^;UD0*zUh5AU2rmRg#8Y{Q^#@x}UGarj9~W!D3;WWoqHbRd1lmCNi*VM&C^1C;=K1oR%r4w@u6BuR&Ma>?qK(Oa zL8hO4EUOMzf)aK#tXrr{ttauk7+Y;Gp}BVoNRk8xbVBX8 zgHtjjEf%d!V?x>h7;|M}tm^dY`A*yfjHpR5xY3J6yX?$TDuI|BTuv_SV#9bYMo|ACEhw zum10jqL&n0?GDi)xQV&CZ`!&+YD$q3#(E1CublL zaPqP*m1~0ug8#gF$2>gG^AVulp0npY$~wA6l#2KNsMKTtUaTk0PcluUaSPpUOyTO6 zpSr5UZO^~-S$X;AszuH+@7%^^yg4FtA_qUZx6lgy0Z%~ZZPHl zDT$NiuDD!v3NiqkSE6o%VfN8qjdQ)dVrdvf{^K(J#s-^kWc~X#@#kP1TC85Sl_PY= z&21nj@9^TeZXdalC!!E_wHtPW@mQGS(Yr?|p+h%M&m?cM6ol?)r^o|<$NjSa)EwZg zz%xT7e2UN;yuOH-XT}V~MoJ0CL=)_)FROljZZuuxJw;RWG|CZz(x+M!Pb|6l zIQ+h&pY#0sAKBriJvaYF$i>m3$AZhs<_y_=j9BQT9Qqz;wByjI_GNfi7akT=V=6y*BA-YR)JLgP&eyHx}cLzdks z6~L`wV{wg_>C+DfPtd49g>*3%DqqlK{6Stm$l(x)*RGao(7e9_9X_|d z8(@Cy?m3jrvq|}L)X94D7ctm>Sl~^37tH#l;FsK+zdFeStj7jD5U+_`%*muEQ`EFYroA{hX!t>aI$;VA}~9Y$;$1g z)olQi2Y>U{Hk-7+(1xHs`WO*D^ZtannqJraJUxe`HE7Rjb03BnvXm<+eQCVfD=RZ|W?aJTyJdmmZZ*Md>j{+=(0)1DDdkoT#f@pGPi6O7{2ce>>Q zl~jL>TdnYlejZJEiH&8Hy}Z8g<@=N)47l4|K5aeTjkkYq<0U_9a!tL;PVFpcKw-5Z zdBvs0NYUb7%GP~I1;NsHq|4VCzV&%fiie-Vu}ndhpO zKf-IRvzuN_f!DV0Fgmf?g`U3SeUlFqn&aira-Y4q64q6L35tr;4P9H2DXYY^-CTX! z@M;lg)vmBG>!~4cvb1U3SPE*tVCKRVSQ%J+R>XsRn>J2`mQnG+8_8O=r(I{igI z;VEL?iE_aTxtK1qRhj2(T@|+IKqtVnW{*cITVp}WW*tU+8@oR16I^tcCjnF6-?rpF zs}d|MCEYzl(**ziv~8B(Ma)~Emcr9fC~ zq0r`DSuxv>*`=gtR-$*^{=E#%xM(TDuXrmzC*FKp7qW?j-~Fe=!$Z`t7L?4M7`kry ze34jG&LqGs?zx8aS$~iRqIN#~e9?8Vk~^G~o!>yngVw@#ERfOwQ8n19`HNZ|MJs49 zz#Qw|9|Pi>-&B37d_{{uFUsVk+0}}G@ATjJG&hWrJjf0Es`AV)^&HFVu|+HR zc3JS*eQHMznq254vHt^A&eexA4@y59`BX&MlCXZGuGf z9p`92Na=ld+T>0JNCd1>9xs5(PDswZ;TRg3+WixP=4HO2%J0D`nzUGXC0RZg<=+HS zR(J`PQM%iBe76$<@KNN3tc0%0yDv|GSF%L(>ijXNLzg~JA6LwV&yGVTEE=#L&vALr zbK#}};elbLymi_gqk%r~qnao`Lz@1ImZIU${&K77`26-7mfFOv-qR;}`EurSDi)ex zaRQdbEmgZpCJ1V~9UzJg9zX1N*9c9QV`i8dhD+v<%^*2vc z4YjRy?_p&(QqhVESOtME;tPm*Ed<)ryVzILb6|Ja86x@Fx^l9sVq2tnU>MC1+f$(! z;58-|x>eK3?0Z#TM@ny0|I>{d>hwbA^_9*G$rbDzyEg)MhvkOPN!68l1G;+PN1F$D z)==VY^S5uJ=VI2-uj`?lb~}-WL0xw1zM4(^$W`S=#r~Eg2HQbvTKRKmI_B!|b`vkV zWeqZ!!jbT)!OJ9;5u!otj!wD%h0riP074sK-#JX8hrEPw#$tWCM zUNDXl{~Qdiw3tXqKS6G(zzqL|xAgc!f}1on!;c&jTH(#d}t=(SPHc3}bo|=dSI1~h-Y6Q=*>+3E^yo~bPYZ!NE zPs*VTkbz1XqI}(lcSz;Z-d~m)#lp(lu`tT6E78lVm9fz9aVD#~_5r%9JY@i0{%!SS z$5S>EVQ-_25Dha^P}WUhBGhEVsLC%f z%Ox+yU-^R~?Uw!TU-=@>1avQVfzxjZl=&KNB)J;w6`Ftnu`qWMTkE4j3R`d@fgo6~ zT8=<~eB^e$5rkjfw225uywP^4IKLG1I8Oylc)U4^PJFI71Yle(zaU`O;Po41)d<`s z?+x?`Md_bJjW9ldw)JQkV4|~&Qa1$an|Y^ zD+~D_eg3v){%IidU30&CEF88<%NPD)%n29Ssu)Ts-~CU&J(p>Ab#Ay@AAKGR#pD_ z>}J{3hPC;-2Mnz=wD8bNovP63n+zGU#lTC)b=|~`Q6fLf0@!A%7;GmQiK`K294M&R zn-9U9sMz2Rnj;wSmE&+Ko&}8R4mpjq((g20YB+qY*v+!l1J`l8%x)*#P24sf=*7MU z)qmt8y>-t+r!StNj}6v#3n{El#Nfn@eGx1#b?xTD#6kl)&x8g`N>S{OTkqfv?PQ+Y zz8fwi6ypNg+*RvN;*9yjkpR{U)MKupJ-7`Go(E4>G{Ep5wh2&cyd31)s2yAUj=1Ws z0>osNAG%c?gVt2`0PpJv=2ElA3PcSd27{5 zrfM^4UXc&y=M~xN+P+SxrrpDejUee2$<&A}n!t;4i#Dp#5B-m~zV8OuU9W#_bhCeD zGPaN1xjKlJrYQ`yiWfcB$GGkCgc4%2N|0roa7%dY#{GHLnC%vvC(~ zL8Tw=VJBM3Tc&-Fw58Zj?;tPRq+H>B(Q~if37YshOY};i4(|S6LV8#=@nR&8R*nUw zUi|39CrpLddQN|gdIqxF6ZL7(B43$1a{zcyuTw^Pq%JTaR?)*VOl4XsZZd>A$}QKr zZ7@Y?r^wZ-&}Uu1r3$*F3o0aW;X;v=Yaz7@F8tYnR>=cJpcpLw;<|O>>XgAPY?n@} z{K*;qU#~qJO)I?Re-J}GLkjwVZZC_@Z`zqY``@A5ZB7Q}8xitOxZ4vMfW1Ly{Yrcu zbTNlSPy{Vmei$j^HMGDPWVrS7=GR$$2Ax{w-Sfvc`i`roThNzw8_ZNsziq85X$Dvi zh=>V8=JspEY=@J;C#Q(BRiN@cV_%A$?$Cky0$kNo=%5)eF`()j59rqn*xwsP1LZ5x z-4Ewa3Q2uycq`>hLyo>1c!F-hVdAy8&8Q>sW=>bV6sR4a>9PLzKjHlx6g0XWJLPRRhN9_^Smf7^;9&5_8e#2WPpV{Pa_h>nYyI;EzW(MJTnf#o zUAQ@jN>4uEQmTSIJHDxM(>iqfh=&8!YQN|3B_;Vt-in3U?>tYVGiOKdioJS{Qa- z+t~fxu3ApKZ!l^P=_KCkzV2gq&QB{(9pCMMH=vo5V@^K@o6T*}ql1gam~FYZD>glhvjNj;qx_XD%2&$bFjrQBo+1Hb!nu=`v&Q< z`(kg!rtTQ+Wjmbt)5>!THb6`K;N*z-@$7%Q8c6gWl~FgVWS3}QK9j$>baAE z+L@1NookzIKEXZy6o)xp&qrEL^IicQPyKfvq0d-_pEQ^=onY^ls0kfP&0u=3fYNX~ zi%5)Y(Y?9|_t&B}8E*kIgBk|CJqXm9j^*C)2WiPlU-nj{GF6_(C1;}Kx&w5c!kK+@ z0rnL!e((l&U0T2pcRrTN1VSIj#O>94v?0?+d*p{EWZZl-zk8v+?#}AfOP5$)hPTIs zPr|Exvt~71THqO6o(Xy+18~N`Jg}o2^S3tn_TtX%XW4f`t+yGS8U$v))!&i!2PZAF zfwWj9CLoyiGt)`CG1v9@XX6zetB%LZ0<`UodD7S6R60mj z=DW6%2svVS&~Eaf#(!~TE*w;G;IHFi{1<99&k5d^kqM@3_-F(s_YB$%rE+O0!Q_g- z3S*-RxL1w|=IxIa*KMl6+i}>yEb?^XgeswiR4(6tZ2U!k=i-n5OFuB($TaWGM)02! zG(1qtIrZcY9Uz7)0zcIh-pxRXwEcG|+(KJIJgBBw!qp%q7?0XrFjuUEHfM=EYB@NZioiiQ-{;AtDLBH8adnCC8g0MQ z!DG8oPi?!_#B{dYC2+QEoEVDPIDCqbClP4vN*q)to=e_+20d32n*P@!H2wAv*!8i0 ztOw_0+7HnjA1!c*1fBIl7^d{JzhOoJ_*@RucAnvJIjm$66Ql{PZ*o{8;j~>wZ?fOS zY8s~5&*s)?f84OD_#Pg7FO?3T$DaZ)TlYteeKoeHJAetx>v<}dC&Ng8PcoF11T!iU8Oa|ht08MB$DQ*;k0i#P{aO}a zw6nH~5&&7@9qf&6FfSz|%%`&w#%)A6$IhGKnO8It(vcyV-8aGeH{HVf^eCBzOjHeB zs(}f+#y}K%p{VJf5H7*9qKIFLA(GRCdl(Xfm8ksu-tU1uRttu1F!U5GWJhp^OsNsV z)rkFO(BBqSqzC`>v9cPC#2B92vV_!LwcF*!Cqhw~_vuKvA#^h|WD=1j0(qzort3u# zWFQ;v5g}Dd)rf-<0LaLSXt!F72*ZSL<_{val+hvl=IkALe&a`)NL0P4D8oq`!f9A> z^)5(?Ho+08&TT(fNDS!$g>;#6cR70W+sD+beU~ty@~^n1wNZB&pBnx-zZ2&4;ycUO zax$x+46C+u2M|n2?uFr zA#-}Vc44(qAAlC9-*Z6w|l@jMIKk@n=FVwQqaY z%Zwgp@?J$mni~`xGUrT>jrG^o!mH){s!oNo2Eb%NK5-o%XdboXj3I=Wl*0MQPG{skua!i=woI*yA z2`23hbwN4l1~L0EukGyizCJdQ?J&G74zk>Kghvd|x)*u?Ep|{w^ zzPS+tD3?`sR1HS2Fsz!gn9VA#M3xwkQ^o(ApnzLj_d@Ec_Bq3}m>Njnmm^v}lU~hx zLfXw5bw-sn#$a9DS}tSJCWj}Mh8J|%yN0ahUmS@d!dItw4h;W#WSj$CFieBYb3GsS zC1+o^YmEdlXTmvr{qnLypwh>a=`sm3IEHqaBVg&kc=ZgQh_A~xCK6@Z+N7s2Jn5S9 zi!=@yO2`5}H65Wse-Mds5RyDCT&Tp48Vatiw?YW8uhk;&n%m+_=?tCSYX^m><@asgD|hK*z}7Cu#5 zu35kA%r4Z2Ey9H!4NiR{1~Qqa){%3m?#xOn)G!^@pq5eaXbldLad3L_HQ_jcR7sZ% zx7ihHzeQ?pUd(cDrt!);B(*D9SXcjrD4zQ&J&C@4<0*-8>c)c!?M#}{FYlb0ZL9A# z`0T8#VWJE$b!glK*X}>ah4I;?X-1Gn&xljSbCpS^3*NsX@j!^L^~5_bb_qj3P$=Yz z3SIGsMk*Ir0|ywi!X+3qLmSyx*Kbex2D?qr2@lWPz$S{Pz#JD?p4DzecCN32NcIkVC?>t4rf5!$DWU%$*$@g5N& zi6PLWk*NrUz$T~TYAeh)mg%MYK525!$vVVwR+Z5VWOBY8YpPoFQbW$}kIdqg5@=-j zwKZ#A0lM(HWDb$BM-1kBoAq>}XiSL;!C*hrCJ{d%4-Y8>u}bo?NQg$$ zOX0tL4MycxUFxkg59F>>rs^`QO$?tGj+H)m0iEDTzvb z@lkc0*cYurvn&)ag>AeV^^cOLV9J$Z_kGD=CPGLu*3dp2G^x#saPYRxBEXYfn1Dq- zx(7`sak8JY3m)Bn*EP_p z>^_W0Dq|(*7G{^4s_@RTaK=h+OF+v*@NO4JXMhHyW1Y0pcK@zRG#S+FQSE#v@r!3? z4Pl3zrOxp|olPk~nWM`5!XUZBM|ET}OHy45s^G!c6kg>g@ZOucLlFM_-g=y0%%IW} zgQQ|hgN2Cj(LVw_m$%MyHo=zVgZ=XW^N6HHbMZ1T1uC#v!Ybsd*&Qs0^{GMht0#qc z@l&yhnM;L7P)_}rOeQNlP7L;m`_7vH!o1E5ax&Ui7Ix*txq)P9;!Zy_YaORj>Q5qd z#uE`eTG!>Yx9=3~aa;Z8yla`V-ok47aOSIwnaBHEq`{qlL52o$c!0f(g_9Ru_%acD zwACz&h}UAowB(75oYT_`6SE&@g%h#jS6N(b{;Ew5ZJ2~y>M2?N3?6&J{%@3@#=B%( zE%EViU6hQQ7>zm0`)921y#It(j7q5T>X&~LCBp|Lh}Zt6=?=?wxW%6A8gXhSZD6HoeIguBGG-6ZaF;?N?t2#ZcUmcilsJX12m~&4Dzw( z#j-LxW5j#(1pNEQg_761zyGDPR@DgE#aV-7f1fs0TnP&wNx4Kutl*_Gk7ttoE0025 z!j(k@EIe;AKyjXWditv_xe+#tPwzU5WnN|=s}8UBU**9BEE657(;7&1s%~l3K5Ozz z_!dU$f#O8bLXF)_#f*(`^S>i*vHV1ww(HY>6Z`T9#y|$Iq*TyyHAJPPIw3{S!}^EA zsoSkna6W+0<;Y#{!l)4kKJyfq(^5BC}?U{4TJ^zLdI(X;$CaQR0$Nfw~wM=>D8s9*YQ-6 zVAKVlU@Q$++bOuvpB5-`^s;qpts;DJZZ%ijoW~eBv!c2M)01SFjT0w29|Kgizj|EG z`2FY^X2mMvB={kf&oV7D@g4snQutT1A!S5jJ@hwHb$+jv1EkCs6)9hVI;%R^C^uia zC^N|mKhe5!LSz;hKeZ_QB2JY+U;NRRA}E+c)t;K}s7Z8CdFKNvQYsT#_s2+VOM0p4 zOYxYy@$0DBwkRE;;UA;e666!~k;dByKRV5~+VX;|kelhxC^F|f^kh2MLS%Gt)bBh) zX?X>VOURme8qlidvfC!GIaOGJ&f=;~tgu^zL*4fcJ6>|QWB1$XGyZ>olIYpNBdi8J zU%#m-pLr;kMVAHVGl~y}hWtX%meXW}+nQmW@FQr6a-ANR?)vYJ?UN-mCMNkm~DX2bXSEERUVK&%8ermPX-HAWK5rQ%24kcV%ia zx&JWESvN0N$-q;;e;)c$)qS>k`?X|CP(6RhlWGO4X!2lEX1fH@zHA$b4{#tu3=Ia+LWE6XTogj=1=ew^6c0~3YR6oqeXA8k9?pV;b*Jfb zx`RfL9pky4{?P+tE^|Kh1o@!tqo^7gV&Tg!@m^ZYW-J7uehIkeaK@};8CEHmT)vf2 zLbbW*jLD=K7_8_!@fi#l)F{mxBRHBhdyJ_T~jCTH2?D2&Y2WOOgdq zjL_}1uQO;0wH_sov&ZBZtskt+@nYw@%E>YZ>y?c$WD_EMEso%9Ohy;PlOBbzFsijk z4Kd=WO&Nc)yT+F~r2UQJN4Hvmx<-DS{I3E;0+`^8nPj;5S7|p z3GI{B`hPiXSK3xWU8%NQE}{Frw7SB*yDq{BQWW|34vIITh(DN;Ej#`>Er-Z2tS+Eu zvPPbU+ikuHAvW*FcT_ugvj~EndNTgK0@scw79404ysoA9)=2BLQ}aBodxZh?g5(9>5_rED1^<2*&C3m2 z@l$oQ-e<*Es?>$#7p9Kk7T(R4A&XEpN5|f#TCvU(PIpoFdO{IV{1b?eH{S_e$ek2D zHRQ#~`jy-iV&rS#%}QCn8ptTgSJ|B)R8HWgjAl={6M}lgOJ7qQU%x+*&wR0-kCmd5 zt_&fX%#JDO4>Fyx#gISbSPC;5gVy;MxC5Eq2*u;KS5jYX?KaVrnj5LDUE!!hGwTT> zWEkQe;eQZwl5ib8;qLKR1BeFC(UWE`!ck{XT1mcyXk-{S&9*mb^Cy-U@2<) znni{1Wh;yFb@h}a5jk&ilaaSrd3I2`cr30$0T2342=sSQeJdERd5{6b_9H@J4h5|Q zsi-cZMH3wEik5STzPYP0c71skCKT8wXGMkmax_zcPdD4zBW=$>#V&(^#hOCJOa^%i zla%)yg5jrXl!G@4zp%i15GjIT5;wz7-fx&hV;+i>T~AaqiTAas%J~aD#k5Mj;;(I| z9>O10jz84sG!_bOl4+iCyv$XG_QPUVQPOim7}N3g(_GT|nFC`5nd62DO)soGxiu!jyo^sK|D9H{gi=Ilo|O&E3_LH1l@Xv&l^R`c7+jGu?+!F%nblC zZO6s-L?p1?vB^k!$&#B_(ZL^+>E_MX=p}{bTeIQkLKj37`(qoOsHm7F9e4sl+yUr# zY^eim(|3l?DiVIHJ$JPxAJsBG!G>1SaHeq(b4pO;gS4R(nbN*>%mV~SI^FWNBZ(}L zNeBsF*oZUfpyn+k_C*BpWFo64*W?JBfISEW@-rraGNjA&v}gpU$&$RXAcx|92nbmI zw8mSjBM4>%_?V)?zOro$XZ`3V+G9*E;-4J|VG<~M;xUX-+gh)#s>;rf!XY>A zsVokgzL3cPys{#!;Hr^q*M6sZru4HGO6LxzIH^{e?CVA{=qZ0@?xQ@ruoAX-T!j$i z-hU8M+39=GfCd=dNlxe-YGU>BiLn?t7dx9a%58B7JI#S46Ui1j6(Jy`wC2&$ve`pl z0Qnc1NJt%59H`1aby8bF&^6xq=9TE0lUoWjzM1`QGz^lhaLmY#!i_l%W}*<# zKbVl<7)lGa6*0ax+|dw8`U~Y`aq51*y}=I^`ixw@~vsm6uJIeI3sC$EqaSqi55>A*vkPCTGlQ zryox%=Bk@XVK=fsLTUI=5Qw`ZO`|5Qk*hKv^{?#-E$phJ@s5KQO{XDM*KzJb&Y#z$ zjUAPzlUG26vCAx!HlWcOcHv}S+%vN2oOI`jnsBEl#d8Z3lg<*QMF&ypF8t zx6p5K84;CyM`v~eQ6=xisE2wH$P$i%;ZUt*WZq#^Q6-`85)G|>X(Fh=t-E+Bj(vj{ zl!nEOP`*nEWI3jSrB>}8E0!*jh)R;h%cr2kYJDouZ_wD8p;@JQi}2qwlWgrNgJ_f~ ze@+v>O-8klrue;I=thWA`VcH@r^{`rlP188%K<@+4g9Lyo!GTM?E&2>4k&?uzOUI4Vnpz~ywq(2>T0T}Nxx5$TBK`-OILutsY8V(N z7Z*uoMOPeR&})(e84;y2RAQ z%OHMK9RZXO)CvK?I{e>%0Z@q91+!S0GUesaP1#f?EP&VrE#ngZRE+=Opgr@M&THVI z_`(D1rByqE7LUg06ke9HQ>Odsvn0Yeti+S6MKCCf{!&uQ$X$vAH-4vNdh&vxiHOe9 z+ExFD0k(U!?2A zqDh*NjZ+${K>JkKey$N;&}_6=0vi-RAr^@@d0oyqD1T`!ORnl?z8PfQJQ z#mxy_Q0VssO5tmu%oem(e?QbO_Mrb005Jd0Und4fg2QwfJdCki9C+X6NnB@ z2oESZ1e7T;VF|BMNdsy}0}4iaqeW5_|tYrYN zN}lOSfL^rDO2GzGZP1gmNU%9Y^4`0JVW~Wbl-koTS11lX>==RRBg@`#-A+nO#426@ zP?`(|C6R6_Fnprlg2+0rvbYZBLP%bd1zN=;c7_9mIjMTo@tjda>V4_hj1ddca2ZW98AqO_{1sijBb|a>=fXaKQw7- zIAo^wWmx6*Z@Pj?O6(QD?33D9>J$T)6C&neFv7OPI`1eVWQOc=yn6Mn+~)x=Gdbvx zqq%V?|5}K|AetDT$t>2u^AwS%whSTl+$PlL^6{%IHOmR!Rq4 z>J*GJ!@!Z6i~;A~ra=H0aO}?R3FzgZ{ z;l&rr$Q|UgKugkrYh|GZ8&s$O@PX0gC=M{vPzQ-swQ(Y2Te|%*SB9KU2m&5|u?$$A zR(aGO({74AGk#XJ4?u#6v=Wej*vIsePLxCCGFd6mU*bTI1PXkzES2n&f=dP^`WPk# z<05PBi+w2vVMY69$^{`JIT=GBgsx`7t0x68B0)l;Cn+kHEg~d9NNWybLTL2e3Ii)s z#M4BQW&=(+Ns>54r~uU@bT%!M4`soDC&O5sf|M3A$j{DdWrM|ApFzZ=(xU$^r%|y- zf(4==K@7?K1P)JLxZDLxSIFKFc1{60jFcVSiIAH)=;UUKz`T^@Q4<|iOH#Aafkmvb zDjzCZ;sA27Du&+*FF^=jGzXM!rvO3iIQ0tv`=B8IMSVFtT>$8!02LupG$n8-gFM%% zDj;N}9@;@T(Zc1q1(0ksKoB~)D24cC3i|s7!s59rsL%T&Xy_A(gCA|V9y~x8U_f9tq;-cQ2Z_?C z<){-bRi*QeZ1N0_XhOHEP;TJ?p5K~-j&?=3@UU$E2bQ8N33k#ZDuOyFB#Lm9Pz6<*XGFkA4SJJ5z-TLArVISjR7u_t$wXp&#==0SZgGNeWV8!bQKMi?0ccp14v~PIl{p(8bjs~G+D6%OORPNe zFh|~#2w5gB)gUa^;UEhMvaHOG=-?;-G^FI0c4V^Im&yPV9UR0ePMFAN(U5W)7tp&G zp8G%mF4LKCiD1-hypW7^X1}RdxP6m5XTJ%6d4PLvV6wS9&q+i~9LP$iFt=6xH<)FK z^@M;1f9^B#T>PCKc3FAmG}#4gy5G2@am@NDsGucr#AN_(ea`Jb&X15Ickal7LefuD zxDINU08U9l>pyk|F}P;wH~6)0Lx!iM>jE-J~ukA%l_N5`o}DAgd=AQ`E2!Vo0w2PJGY2arcw)ila?gM3yv3t`K0g7%K6s9~VqmOaL;fOQ`Pl3;QM*i9hMrd6ta+ck!R4#DnXSCB1&M9^B zppHT!Agjt8fSt`WUBv)e#j~b^CprabiBi-OU5@c%B2trAt#EFq%Zzo5nJ!hA3tFYu zUjVNYMmls@_rUW!0J2=3Q^Y(^%Fr!bx=Lhfs36-rG8KUy4S^nJI1U&od!98ZXpP_T z3Nn5S2FMX4lIMh}-@vd_lOX#79|i^Dpo2r>lTld7^@EN!kU_o}!AuG9(1wpCYdhWs zO_bp!qfN*`YG761%$g%69zT@TR^um0HVh#K$t=@~aA-V@*JOB%y&XtgA^<+Sez$M& zJX}&X@z4jFq#k1cA`)tpRfm)l+Ptkr+cO;_Cj}Lvs{)i0p>ez^lsXC|8NEb;Hab73 z%_`dOHaK4E(!H-jiM_n9ukT9eryKzqJ1O&lAt?KTp)}mBQzgZKl1gaZSx~85rPps2 zMP6z!SuC5o0s<7DXrmZSKWV%|`3+hSk~+y<0AvskTuD-)vboAUIb4`YS&*w84vbQ> zkqMaViX9$k(wJ=1rL;P5fu~G-s{kQZ*(zG_l#_V@`sk90Rw=@#|Cv-_CcVi=8S=~& zl}(@t1wuZsk$+^ClGHi5nE;w9Wx(krGSdx7R7zYXi*bQez|B|FLYC;hv(o|>hFq-% z52ga=bz4aRAs~Zo05AuoszjdY2NDn&1hT*7+!^))7ee$4{liZdsuaM5$Mr;7!0bcY zNTs|Y16uGIks?ou5#PWAKbT^HI#M|-C+L(u<2NyB2A(2c-?S@1!U^Gv=YQlE;?R9` zS_t89PBH350j_|Pf>*!=LM2XlT%NBM$Ps1w05LfNcX};pa}Wlcd?Kp}0uCRAD|h-l zgh`GRZYCzF)Xt1ff+NQY^W~WaNM_$jl}eDPQxG}{2$htz!)0oq$NHU$MsPi;0I2~6 zAB`V)lIdiJs(OTyBokpAQZ;_)C#4aHE**%%Lp#Z>{3M|PnLM+fgCA-@WA;*Rv|SLU z0=_vo@4phbEb!CLjFpzUUuKEf4?9hP`36W#l;L=RT2b|DogmQBIMEIT2@8y-PR2#{ z6P4#324tt^vc&%3PDUZZ?MhOn|M@&H1U#Hp+-CH{N2 zHl+dsuR`&yJirQ=Uy#MJ<$bbIEW4cyWDI6pUh3-?URe*JW5_FIz?n}Lu+&Z`n7?F& z4RB~drxJ}q&m5YZ*UKPN(ijHNf()$6m*qr&p2<7~twAt|ybO@nT#j-Wz1gCyMkz|8 ze(;+x<|vcL3}7Z-0(1G40%G7KBV5YJQ+AY@gcmUZRw<0fS}7-27$6oOB+s*wN;OSU zCg@au7JorTHpL4K=!{nV6iM{O{mb~F19mTz+nfDFp0MVU%gcb!Bp>{ll~^< z2Kt=gkRg#jDJwMjwt=2NSoBr3N=UGUi2?FmS3)I4@lJfp_zRxUevExh@ob80P4-!_fBa zvPP73g)j}ujYp8L@*qT{0D+=>v?z5}K&55C8GllOIPs6fDnM;fBJHS&Ts4=ryBOs3 zgMchXiWjBw4+?KN_Y+XJi8iP9(q!RLXK1Sut1J_WisIZN3xNOns4oCQSAL+W%PoMOa!UK)%q=c1WMwVSR0Act;rC!HefkB0^w{ z2{uVu_5SCQEf@N9yEYmDK7@fuWudLqf9D5*;$-i*krTqqfxb&NZXNoNDA$|4jW%f$ z6QG)4WYWH>+rJ$_PuwzTP=PxNq%;ixp(B+=7?T7B`rrTt9JG?*qKWGOR% z_P8wXz|2AEbdVrrz+pYXCQHle6UxA157O>8boMq}3JXlBvS>WM+28KM6sQpS{zF41d*(3zL z*}*Wdt||cMUZA3nWky476M(Z5Dr}jZGyrndw)ry`g*k)sI5|L0^vCEx<#1RZ?e{Wl ziXY*ZKO|7%;VOT?%HfI}mLH~#VXN%%i3wv!-Y=4$6i6i?;ew%*iQE##l@xtqU|H&_ z*@+;s$WQ;a%^VuM#Hn&T&-}zIFC7j;=Mb6d69DayJjZ}~LPx&zi@nDIdBT(rGO?_m z-ai;-$_zbw#vC>TIKkyQy_`vM2q;0T7z7(-&xwQ(CpQ7C3Y?vRxgpSr4XBL|30X$~ zj7CuarSpq15?1*)OHcqUAV|ufws|d~RifOt`UFov#|9LUkmLNOO)>)$$1kGHNF#$F zwci+Mo6)!cphN&!ypTzaC5;WJG^wp#bC}9O%|#*C%ZR2w0od+n#K2OIJ!?|l{@P;JNiO}A_a+cs~K31TSEC^a2FEgZWU^d1Mn%JzJMuO%vHV81gs(K*Y z6nZW-?MyH$b~+Hnx)jJ39f%SXu6Bcj{G?@#Iw1;4J1>#ZPrx(EhW*k5C_aeo(MOtU z`jr7nm0RjA+wCU_zeptVEV6(h2{<+#>jDs+DhB|KA>}1J>MsR@C??Yq{X+aT=KAXv z2~jZi=vyLA?eEd{6Ys>bf-72w|LR6YQ>-)S#y=oCZ{Z`aPveBJdBdaf`T&_6cF5|1 zDU)ab&CrfX!)csVcS`5yCi?q^FG}IL31PRTGrxS-gBuZ|Mb2@cX6<}wrnQHq5ER8T{vIc(Bc0*?e5Eh|o; zkUvrFhghi2%tyeYZLmQAq@$Vmf_^fpL4=b`*~A|MNgp=)M5fAWv;9m`=CNvr2G`*w zs(|Scla-77I7c>XE{5a+@ogw<-mqTYNan9A6bTH1y2o#62YTWYgDZ#9n1rvD^Ao7Xy ziUu=bPV1oo5OVkpCLq9X(2O0pkxA*4A7wQk-%^V#I)GV)FD53#3k*PfQN7YfZQzN- ztdI_pQd!2X;gbqQMqRK+sbdZb7a#>MiUyXw4iTxejMC{;HsN4y(tf0lz97cRPx-Ky z4s@seXoE$7{Re!$CNS z>z3a)DOa zlo$L;NwE16V=K5AKZtQ+FDrx=fuCTIB_)jyfe@x~1_gB)9L%&^Z2`*djQT-Jcs8&I zGT3CcpY{Z3he_tO_+X_Bmf)QZc6xa%`~$LM*Zf7x!~7*H!+<}IpJ?Wa&BiC>$7III zT^ApXFe|v-IrzC3UGNQQgi{@uo!JD0-NiC3!zphxP(bJmxk9jb_AWIO> zA3HE*n_rPfePq0-S^dcSXSOMdc2lm@)hzYE(Fl?1Rr{kKPGEk)E(jnucnnXliA?2K z=p{?y0v@9^c4iLBw;v>H%KPU~%grwJBQ{ec(s+sn3#{rgCaNg-?eZXjcrlsnB6NVo zws5O6n9^mj0XfA*9^mqW7&Hzm=D;C2yjUhO!8@JjMSLrMTuIuz{$V*0DTfpMMW@Fq zCi#VjPxATZC9nD9(_M$>BUT7N$XHMHaq;35$!l19>@m*qM<$V?Ce?j1{D z8C{}@MUzV!VNYcOZ%N0G*hHC{yCe*n6i!WkjR%lxiVy~yUsx{8kCbI{bo8qw| ze?m)NJdR?cm=tXRFKUEFgc&Uu#48=Bc{&qh(jvQoQFohIw0e;a4rJ|Ol;*Pg;znn5 z9!<$vG{2;*&5+0h-V$)M$%7_2*$Eb80tcPS%DixPFwr)0t8lM-uA1@#K82-p&EQ3v zW^~QqRs6W0X4AU0atU(_*kh7az_pjW`l90^ASslt5P%=<3l}DIY_DY1At;1df-M1F zHhV=_J!dza3;+j;ISW!|m;sEb90F)EPl{|nvQ7fD$&3QDj=-=p5HB!*QI>!5J0I>%4Td`GG*;DR74^#q1?F;NEPzr0 z5d?Ni}Z*y>a8FI2Zpk71g(O)Ze01$d|5~-6z>Kr6m zQ!3I37M)0u!~)5V37E^V+-0c%uqFCa+UT3CeNOaL{iI+5kE0ZqaFy8XOyV$>NU#080clkwMXl)^|*LgPFst+#aw zn=JlK>*V~xmJK&v`l^eLaGk}x=?VdavcdT45d*)H0GK+|2utPgVCC%9LW3v7tP`T+ zk^+=j;Ix)~XEegVcxwkmk%Ll!9LVGnrO=BMJ2%VHTwqd0M`|uGUkYdXl$PU#c&S_B zAmTs~fD2`A1kfQ#Rhcyg13cA%P6Sk@9~7P}R#GKibWo6@APfmQ{Z|@J z9!8%8gOZ@feImOGk2)Y)2{Kub?|*6^iAYLzDIv!&)>HRT3UDFiD7bSO} zJa_+5XIm$CMP=Xo#ii;W-ouV=mc`vuc;)yfG0lrv{E{!*M-gATWB#`3Ug_9|S3 z5R3q{$3%f}9v$4BXU?ALVKGugumX$+lY;}j+mq0N9gwWk8#QGBE?6N_8q;q$W>$8Q z`CRF##B8TLSY*ta!-mW+mjM|5kfMH;@&=G1bAa}`Tr#_jLZkiwDnR@jA@!t8f>WIo z$M`@+ELpBD+Tk00)$&-| z4+;jobmJQ~z zkkcv%1`m^#0dh;Vzf z0H(jltgHo#74(V?+9nB%o`?ZtN^GES_a51 z)so{?URDFE{y7Yyv`rnN5?lr3GFdj2_~q%|H-Geux3A4SD=)dPvqnX#M}4uuDE#oIXlE)i!_go^DG$}NXU1q`{unth-uYZsoD5vQ2S5di4)vPf z#E~#{Kw@T-BdKGQ5`WYHx=*=~s*y2_aJpQ$r8s~nTMBM3ut-J`eWX~@D;~T|PAJMz zWCG4BUUqsT@hq|fKnE0)`7*lpOXFWwcD-deJSgKy;bnXdOX-@Gowh7*#*@M$U!(Ee zi_U)MiPFD3(h*fGv|J&80fPF%;EScS2Cc`2u}0HI(w0{R8fFXn~CJnGNdAbADQwyFR-u^v?O6c%18opQ!|}_fy*SI zOdf4F`fOOnB~pS%lj}weWseK$C_6qaJIr~IBTXfK3Fn%D>BBFUxMaalH%hfY$E1qs|rqvdFb z2!#q-K{?c79Y}des}iKB2H+dXtkMejDM>pGfkvoOsYRG1CoPKTYzjhwHi8jGS@Kwr z*7($D_yk!(2sz}}I@w(W;E?6CQq=gsTJV|Oo`cqTQMLpb08>^hWl-3u0}*s4fQEp{ zB4YvorgpNIx1XtHmeDF-s$ON8Pw)}R^|FjFN-(=L<_<-!sige`;l7w;lG4}6rM@am zshkHSUha8*8LN%H;g@~<^mpBDuC>hCo)94E1J8WRW%5A&`%|gfEi^PSKYYv?pkqfdLN*HYkXczM2||&aH>pFT>r?G2H;ORXWT%kq zORdZX2#tpt{-FRVmZHwAPQPhy4o;YS;U8swiDV#APWW|F0gZk#9R?$NqCfHq z0^QqWQ!F9&s{(nRoJZ&hHXM9aU%XrBKy>?@*4Wj4$P@(QMD^fNAboKkjSjNNFEsGY zWtjx^o3v__`_I_PmrjswaB3%*lwH*uKVlM-!1$lU4?JdswucgvTfXRvSCI3Auij`s zwKhhN<^jey(MqN8dLEa>hV4hbJiSx&D!;Vdbx)YxFJpCdY19+K+n@Hd?E?eD&y(K5 zWrzkwI{|`+0OdN8*@F(m;7XtI&g{JCn}BJ@Q+}mU3bZEcR?RwNBFp(jAN7+c3kGyM z$izTxF3~=LfIp>2H==!{Rvfy%3xpiVrhFjc$Oe%lw_l_JrG5h88WraJN&{??1gSAe z`6)teCAD$Te(*}2hPo`5h+Gj70{QYc*7k$*>euMo4>mBq3;@Ch+uSlKvIhBH&gWVK zhZ1P}IW)^1kKDo%c|hg(sm?FA1<2T(@w~S`?d`H_@aU4qWprFZ{f4i+_kiu&wtZK^ zxR?R-)^bVSrk10r*wKL(+8mFM0HLKA$;roczvAoL90uwbjd6eB4(P zZEP+IIa4GPh$zkUXJsc%!bhQ$1)o6B!|fOCZ=>LGY=g9vq!;<6iPjAFHIDzUvoGX( z7D^4T0FHWv;Ick&_M3kpJ5--71AC)(O!PKQ+G)IoPDF?fARF z!lgb7PtUbq;xC+$Jol~F%WQO> z^oi}-Q3QxS0wliV;~m)RKoQOYzPz(Z?u^DuEYUrt@yc%8 z+DQ_4Y-oo;h@{kh1G$JS7i~&s%tDA2P#i3jq;(b{*9z_)2b(Kkp6GY6@Z8GEo>g2< z5e`imm6t3RJ<)F(Al!l?7GLs7{f~kGS4HxzCDJ*g@q$Ff5}_PYWNqB-r{eJKZC%WP zgMSWBX*2tG68=VGdt09zL1ML841at%+ zBpe)GM<+yQupD$!v|ge--U*dX@n}Go#~l3B0}Q(u^Qc>J#RMD@a&!{NQCP+=K&A3r z=+#!}C%YEFB6YO|aFHl5*1-#6d_YGB6{a)_qC9?)9YVrdeVQ$0eO2!IO6U`~DTO9%i*-T1oSesqzxYAO5H7^okJou@opp$>BzxIFb^Eafa(W8qGCUVrJk&Kw>Z`kV-yW&J3_T1R3piyex6Out}- z_Tj8^X57|5PL$8V#sNbe2~$atw8BpNB0lNl5oU#yHm_Fg6jpW`^NCy-JUM5CLRDmW zs>hJU!S5Z>J7>m{$%j8k3PBB}k;yyu2wR1eT*9W4jc8?A5UHqw1E3`xRJq#J7{HUH zK0shftaXLx#gpQuI=?i;M!9Y9yos0$5SMYU5Ine8DagAOPm!L) zyBXR0(UA%rUON*yfN*B5!48Nj5@?771Np~z1@l8{JY>Wlvh8`f-xC7RrpsFPsD z>$iCT9fd#sn$s(&g+V4$GI9Y#`&E(|Pa7Fz#KicJ>*_$5L2hapBNaH z5EEk{(wI#qf|>Fv#LF%PP{5pxKMGP;I5Xn4q_inc%Tt?Qyjmlhpqw&MlL2Dl@kDt- z(i^_=&I7h>Z(Je9?n;5NBS}rPK_UA_L38YAO2(!ot(Qy=BzWgk5!$(^tK+Uyv19+4M+rSdJqPU#)YjbVp3I_r;+Ae{n0 z?Z;YTb;Os`rIclZ!%cBn7zZrJFW0GqUk42g0HJZgXcTF@RvblG<^b*FU=;pR8|fp+ z6iaEw?`jfdq=RBmt9pLh;HEmk>Mm5q&}$BRv}0UQ;`gx3rKt+NckX( za^NXJ=-?y}D_mIKAIB;bHKo&%^83ITVQXF#HD%_Dgjf-o6l*Z>adOa%V%$8-$JBlz z$i-0RD8Hza5)i&@vTs*R%9EC-8o$JF4IWe)?XwB(`ss9NtB$8XyW+xKH*XsHlqiz@ z6gVzo=VN!Vj)<}jAW)?PXJn^B;{vLk4P~UH>&1?*7z_lL4RvaTx*t1=R7nFlRwg&e z@a1~c{D`CdBvJ%)TZ*!!?q%Ap=97x{2#ab^MA7`zHS)WHG#3F$D4{S~9ObDJvqhMV z2VznhM7C(Bt6~&VMM>FX48f_Lrq)H6en7Lh6w5?5`GRa;1vD!+VI{a3PYUlDe%a3e zk1&tssl_VWt8m&PRTLA1laA8(qc2@}fwba#<%N}t+50G42SBkSu>%Q;omA-3h8j^8 zBJi_!CyXl7aRo=*b9QE>@uf0l`RK5mg8&+Y&sZqX%aKQ*sor#TAij@CX0`aIiRQDW z18U@yXYlB=@L8GS6Z zHY)_93||I=h7^uEQVR33=gshBw68MSGFVZT%P6BQgN=q?yjmkKdVTXJ&U)v^q>a3b zxXO;?+ABIDx?Jd=e(fI@ZP~K^J;R~zRdU~g_z4r>t9GPvt~@l0jPhmJk(da{)TlaP zVuRVhfD8_56aeE$x6Gmx2R~?#9H2Gj7h3;yO$QgC!XO{d^EHJ!-UO1P@JlGRMLR*} z;v|PT1bLY_0lJT7uTBD)`NpOOQGm+9H+2cWs!>}IHz>|Jd{)mmTbGn8qbt^d$#i6N zUMkWT>r<9rLMsvf2=+j1XWKK6$3*04=dPqb`qJMWHQdQP!enop%iF zjOgQqfswNNfH2-TXh>rNEYd(}k{A&~dgipianwlxWmfSkijvtwlnxd^HGx3&r0fO} zoCVvp4Wa^xg2+UQocJE!H{Z70Zo2{<%d9Xm?&mMS#TC~ECqvc3s_zw z5qX^DFnGdi=hht^l970iz~?o+{Rif2WU9}15~vw8holN$3_Cd z68A{aTBw@ZT-TxvoD)kI(-%b&GAGLkQo_%=kTWOCVP}8r=I{F-@s7jGhxsO>yxxP# zDHRS%IU3xh?ai0=XTyg`z*nLWn3BAq<8;f3S#K;+Y^69{VF>}HCAQhCT#C$H+Dx`1 zj)|$FXDsfkK9f>sQ+qIZ(8lM_wq;G^*{ry-rz`OBhj+QFV)6r4UKSF$L&b4XRf4a4P z`3LU7vYV&HvcstJU%c|k3rMDSkWp{Vy5UKyj-2c;sxWF{N8VO1khn4fs<&hV(CWgn zReak3D+05qaG(tO$fpk?aaA#BKc_C;~*m~Ey5bElPKEZzw z2O=J9#V==%0A#|IASs2@D9o}}QZ0f;H;Oyha&LYy4;e9+i5_1ppu}k#Vh9}qwm^*w z2E$6%D+AiN5yA*hl=MEXVFv(l=~Y162O#tuXSub9E&A5J%6xoP`#o&kRb=EhXQpSj zzj*zF@mDg(Vwc=UPAoZ$#nZpL{n=CfaOX{I=6U?c@;uPb)FN)Us=$)%mdu2(;@P}7 z#245K%@aN70uv4cl$cv|E6YGdKPuA^LKafR52PjiyhDI-`kZuRv61a`#S@sKOgJ7K zwLq)E!k25K`ypWJn1uuSSDBAjWWNpFYzJ>O-Z?#-`0mT~ zjX&D;9k;P()Nu=IaXc6C3sm=UF!Zwl2SoQgisf1K{0eFnaHiV|J-LyErQQrnpeus| zN0zK^FaM^d)(in0`wT5173c&(L9c~sFW*`Cx#gHrVMfd)R`OhFGe9oBlTX>|1UyV) zUhBD_0y4q;NC%!&C6e$Ib8(#I*52A;9R2@^k0*>7cH>w4yznR7oa@-Mox}dcquAf0 z?3t=7-!`sqJod}&{pb4q;T&$nxqd)D>7T~J){uNp;FMT{er=fbYj}UhDdu@;p7i*5 zc|9pw`WLGU0m{8hRTEOntwm#nz~W6sYv^(iC527L<<(A5J2iaB?* zrEy%FTg_3`9#pEnb=V!0S8#}Ta_Yp~gQZ{=2>*5df9Cgl2yqvMzRMmP{uefR7hit- vJGi&_7yl`E>*Sfof8Kg|n_ z>Evwy&1^;NcX0YMOgBO|;!itcyW zmoEU`3|TyNXW|+xm?m|5QQEsz{9+l<$pgk8-~kk%bVH87(oCIJz1aqn-6xAlg1dF? z@_CI4uN4Rcx|{9i<}{uPfHNIjW$wumsHANGR|e{lK;aHgD^DOD^BY)9t3DLSC2)ZU z1DH*MKsGo%1A-TU!#u#uLT@eu?*(vy223V^8v|HTz|kqCyF74X3HY*rEmbo|AfL1j z&=lD?t_YqZ9<>VmS>X7TPy`1Sz9KKR6HV?=90%Z*3fdNc#V9IEFf#Z1 z7j;cCl?}Woz;7D3j05XI)eM1B8h?txl}Y+t|6{4Fn++mqfH)7_rhxs3>XY^FQ>zLY zoKM3mqyaV*$BZhT1EEy?q?r?`6yP}qoQ42;aDH(eL0rlE%o0ytfW^^?<+Q-U*~?F7 z{K=6ZEE`w5BZRmxOPXYRty ztKOSC@^BVS7&Sd zcP}FBl7r=O6V2U!$+BlD6Fna*UgteYBLus#S#;_wWvHvEskXM@d3tPYB-Y=}!Pxka z$_is<^y`;~^77K6f`9HO;Uc^|T|B5UnE(j&Tb(#+f8iq|)63retVH`ryU>uPO5(_W zQIkwieNKpm3zb_IY9Nx|5)$91r^7Wg{tgQd|9QAOa9q_w^SBCWHmNKJPbFdVJ)h%z{k`?L)vj(AN7(L0jvM2k!mrb>Sq|PO&#Y zt1IZ`Z?)5OMxB^{tENKt!Z)~W_vjZ9_KzP!bz&1sUu<#cA4)@4jN1mgx;|aSqmx&S z)_oBda>hH}n@lPxDqc;`f%U(IcS_%SU^y}(h%Pv4< z6Pw!7p1r$oCVl;&ey$9c8_zw?A=On^!)lC-484-aMgD5}>UxHUS$TKGS4T&=ryAO@ zx$eI1m9e#I$bMX-p-q}$d5Jt5FO#5N1qJxfb-nKp!v~D7)7;9*bE6F;}+uO z{V63xsjnW)?l6Vy{i?w%Ym9w*Rch+3VDr}B_RHei+}&GU>%6}gpO1mPA-qJ+D<4+$ z$(r+h6U@6BEQ7<(5?aweyG=0DbjhX{m9ZWi%VCiL@->65=0{se`mS|ybf!4IHGlYX z-_q}G>TYFfYb~-RZFuD@XoT(zlQcPW_2rF#+dE{Y3s2XdHkU&-Cn9@TV*VoI(h+zVhIH?maj&p@KJ9 z$rw;yZ2PG6xI#ET6J0B0Z7G^R=9*o(1>vdtl5KM9=?@%MG~t@3PzP3#MfgbPPP@!> zn{!{oq@}UzTQ0ac8oop09j|OV_~nb$a%TJ|>C(V`Uviyu@mOB41E@`4Fg`4w4awJ% ztwfJqT=V@%H50hUA<7RyTpALdJsWw%QQg~CTJikN!%q)gMpXV9xrMZp$3hVziRKT; z%6s-~-%k2@{(-zm#PCtQ9C}i3L79$mjt+a54@wAW0QF1a*HX@HT3kUip2ykX0*czHsRWpkjMH=12fqD@%z zfj-}gQKl-iJ&|PP--N$uVW4J8^H-o08{RjW=@{sXPe5YtmR;1^O<*_%`Q<-&xT8E@ z#csLPxMt9s?HD)K)0mz7iMRtRFnq$wkX6-(xyZGyq&%6L*VenY(9Neu4@(q68g-hU zrNq-AV}oA{a~{uuRS7ZA3L~;35*ZN2Mxsnc%kJI9=d>=$3U}_bEb=hh2YYekz!{h3 z92Q}!KZ2z)cQdfLgG!Mg1eMt5-?Jpq)1oA$UcESZtzo%irkOryaa>}(MAlCuU8)r5 zXgsfuVl;OREJOC(Nkt+jNCyqdE?w3_!DSq6`{t9dB+2a@I#sGML>oSH+Sc}mUH}wfKkrgCvyNQl6WNx2=s{Uwx4D z15=js<90tEQ~R@JL=xd|{%oVYmR-ML$;F0KjxMIk4Oh<>|J+|vB9-)tH^z4-pr%h{ zv=rj4m*&qqI~2Lpoa!v@@A7+e(5^5&code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control-plaintext~label::after,.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.form-floating>.form-control:disabled~label::after,.form-floating>:disabled~label::after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color:#86b7fe;--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;--bs-btn-close-white-filter:invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color: ;--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} -/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/static/bootstrap/icons/bootstrap-icons.css b/static/bootstrap/icons/bootstrap-icons.css deleted file mode 100644 index 6d3e532c..00000000 --- a/static/bootstrap/icons/bootstrap-icons.css +++ /dev/null @@ -1,8227 +0,0 @@ -/*! - * Bootstrap Icons v1.11.2 (https://icons.getbootstrap.com/) - * Copyright 2019-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) - */ - -@font-face { - font-display: block; - font-family: "bootstrap-icons"; - src: url("./fonts/bootstrap-icons.woff2?7141511ac37f13e1a387fb9fc6646256") format("woff2"), - url("./fonts/bootstrap-icons.woff?7141511ac37f13e1a387fb9fc6646256") format("woff"); -} - -.bi::before, -[class^="bi-"]::before, -[class*=" bi-"]::before { - display: inline-block; - font-family: bootstrap-icons !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -.125em; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.bi-123::before { - content: "\f67f"; -} - -.bi-alarm-fill::before { - content: "\f101"; -} - -.bi-alarm::before { - content: "\f102"; -} - -.bi-align-bottom::before { - content: "\f103"; -} - -.bi-align-center::before { - content: "\f104"; -} - -.bi-align-end::before { - content: "\f105"; -} - -.bi-align-middle::before { - content: "\f106"; -} - -.bi-align-start::before { - content: "\f107"; -} - -.bi-align-top::before { - content: "\f108"; -} - -.bi-alt::before { - content: "\f109"; -} - -.bi-app-indicator::before { - content: "\f10a"; -} - -.bi-app::before { - content: "\f10b"; -} - -.bi-archive-fill::before { - content: "\f10c"; -} - -.bi-archive::before { - content: "\f10d"; -} - -.bi-arrow-90deg-down::before { - content: "\f10e"; -} - -.bi-arrow-90deg-left::before { - content: "\f10f"; -} - -.bi-arrow-90deg-right::before { - content: "\f110"; -} - -.bi-arrow-90deg-up::before { - content: "\f111"; -} - -.bi-arrow-bar-down::before { - content: "\f112"; -} - -.bi-arrow-bar-left::before { - content: "\f113"; -} - -.bi-arrow-bar-right::before { - content: "\f114"; -} - -.bi-arrow-bar-up::before { - content: "\f115"; -} - -.bi-arrow-clockwise::before { - content: "\f116"; -} - -.bi-arrow-counterclockwise::before { - content: "\f117"; -} - -.bi-arrow-down-circle-fill::before { - content: "\f118"; -} - -.bi-arrow-down-circle::before { - content: "\f119"; -} - -.bi-arrow-down-left-circle-fill::before { - content: "\f11a"; -} - -.bi-arrow-down-left-circle::before { - content: "\f11b"; -} - -.bi-arrow-down-left-square-fill::before { - content: "\f11c"; -} - -.bi-arrow-down-left-square::before { - content: "\f11d"; -} - -.bi-arrow-down-left::before { - content: "\f11e"; -} - -.bi-arrow-down-right-circle-fill::before { - content: "\f11f"; -} - -.bi-arrow-down-right-circle::before { - content: "\f120"; -} - -.bi-arrow-down-right-square-fill::before { - content: "\f121"; -} - -.bi-arrow-down-right-square::before { - content: "\f122"; -} - -.bi-arrow-down-right::before { - content: "\f123"; -} - -.bi-arrow-down-short::before { - content: "\f124"; -} - -.bi-arrow-down-square-fill::before { - content: "\f125"; -} - -.bi-arrow-down-square::before { - content: "\f126"; -} - -.bi-arrow-down-up::before { - content: "\f127"; -} - -.bi-arrow-down::before { - content: "\f128"; -} - -.bi-arrow-left-circle-fill::before { - content: "\f129"; -} - -.bi-arrow-left-circle::before { - content: "\f12a"; -} - -.bi-arrow-left-right::before { - content: "\f12b"; -} - -.bi-arrow-left-short::before { - content: "\f12c"; -} - -.bi-arrow-left-square-fill::before { - content: "\f12d"; -} - -.bi-arrow-left-square::before { - content: "\f12e"; -} - -.bi-arrow-left::before { - content: "\f12f"; -} - -.bi-arrow-repeat::before { - content: "\f130"; -} - -.bi-arrow-return-left::before { - content: "\f131"; -} - -.bi-arrow-return-right::before { - content: "\f132"; -} - -.bi-arrow-right-circle-fill::before { - content: "\f133"; -} - -.bi-arrow-right-circle::before { - content: "\f134"; -} - -.bi-arrow-right-short::before { - content: "\f135"; -} - -.bi-arrow-right-square-fill::before { - content: "\f136"; -} - -.bi-arrow-right-square::before { - content: "\f137"; -} - -.bi-arrow-right::before { - content: "\f138"; -} - -.bi-arrow-up-circle-fill::before { - content: "\f139"; -} - -.bi-arrow-up-circle::before { - content: "\f13a"; -} - -.bi-arrow-up-left-circle-fill::before { - content: "\f13b"; -} - -.bi-arrow-up-left-circle::before { - content: "\f13c"; -} - -.bi-arrow-up-left-square-fill::before { - content: "\f13d"; -} - -.bi-arrow-up-left-square::before { - content: "\f13e"; -} - -.bi-arrow-up-left::before { - content: "\f13f"; -} - -.bi-arrow-up-right-circle-fill::before { - content: "\f140"; -} - -.bi-arrow-up-right-circle::before { - content: "\f141"; -} - -.bi-arrow-up-right-square-fill::before { - content: "\f142"; -} - -.bi-arrow-up-right-square::before { - content: "\f143"; -} - -.bi-arrow-up-right::before { - content: "\f144"; -} - -.bi-arrow-up-short::before { - content: "\f145"; -} - -.bi-arrow-up-square-fill::before { - content: "\f146"; -} - -.bi-arrow-up-square::before { - content: "\f147"; -} - -.bi-arrow-up::before { - content: "\f148"; -} - -.bi-arrows-angle-contract::before { - content: "\f149"; -} - -.bi-arrows-angle-expand::before { - content: "\f14a"; -} - -.bi-arrows-collapse::before { - content: "\f14b"; -} - -.bi-arrows-expand::before { - content: "\f14c"; -} - -.bi-arrows-fullscreen::before { - content: "\f14d"; -} - -.bi-arrows-move::before { - content: "\f14e"; -} - -.bi-aspect-ratio-fill::before { - content: "\f14f"; -} - -.bi-aspect-ratio::before { - content: "\f150"; -} - -.bi-asterisk::before { - content: "\f151"; -} - -.bi-at::before { - content: "\f152"; -} - -.bi-award-fill::before { - content: "\f153"; -} - -.bi-award::before { - content: "\f154"; -} - -.bi-back::before { - content: "\f155"; -} - -.bi-backspace-fill::before { - content: "\f156"; -} - -.bi-backspace-reverse-fill::before { - content: "\f157"; -} - -.bi-backspace-reverse::before { - content: "\f158"; -} - -.bi-backspace::before { - content: "\f159"; -} - -.bi-badge-3d-fill::before { - content: "\f15a"; -} - -.bi-badge-3d::before { - content: "\f15b"; -} - -.bi-badge-4k-fill::before { - content: "\f15c"; -} - -.bi-badge-4k::before { - content: "\f15d"; -} - -.bi-badge-8k-fill::before { - content: "\f15e"; -} - -.bi-badge-8k::before { - content: "\f15f"; -} - -.bi-badge-ad-fill::before { - content: "\f160"; -} - -.bi-badge-ad::before { - content: "\f161"; -} - -.bi-badge-ar-fill::before { - content: "\f162"; -} - -.bi-badge-ar::before { - content: "\f163"; -} - -.bi-badge-cc-fill::before { - content: "\f164"; -} - -.bi-badge-cc::before { - content: "\f165"; -} - -.bi-badge-hd-fill::before { - content: "\f166"; -} - -.bi-badge-hd::before { - content: "\f167"; -} - -.bi-badge-tm-fill::before { - content: "\f168"; -} - -.bi-badge-tm::before { - content: "\f169"; -} - -.bi-badge-vo-fill::before { - content: "\f16a"; -} - -.bi-badge-vo::before { - content: "\f16b"; -} - -.bi-badge-vr-fill::before { - content: "\f16c"; -} - -.bi-badge-vr::before { - content: "\f16d"; -} - -.bi-badge-wc-fill::before { - content: "\f16e"; -} - -.bi-badge-wc::before { - content: "\f16f"; -} - -.bi-bag-check-fill::before { - content: "\f170"; -} - -.bi-bag-check::before { - content: "\f171"; -} - -.bi-bag-dash-fill::before { - content: "\f172"; -} - -.bi-bag-dash::before { - content: "\f173"; -} - -.bi-bag-fill::before { - content: "\f174"; -} - -.bi-bag-plus-fill::before { - content: "\f175"; -} - -.bi-bag-plus::before { - content: "\f176"; -} - -.bi-bag-x-fill::before { - content: "\f177"; -} - -.bi-bag-x::before { - content: "\f178"; -} - -.bi-bag::before { - content: "\f179"; -} - -.bi-bar-chart-fill::before { - content: "\f17a"; -} - -.bi-bar-chart-line-fill::before { - content: "\f17b"; -} - -.bi-bar-chart-line::before { - content: "\f17c"; -} - -.bi-bar-chart-steps::before { - content: "\f17d"; -} - -.bi-bar-chart::before { - content: "\f17e"; -} - -.bi-basket-fill::before { - content: "\f17f"; -} - -.bi-basket::before { - content: "\f180"; -} - -.bi-basket2-fill::before { - content: "\f181"; -} - -.bi-basket2::before { - content: "\f182"; -} - -.bi-basket3-fill::before { - content: "\f183"; -} - -.bi-basket3::before { - content: "\f184"; -} - -.bi-battery-charging::before { - content: "\f185"; -} - -.bi-battery-full::before { - content: "\f186"; -} - -.bi-battery-half::before { - content: "\f187"; -} - -.bi-battery::before { - content: "\f188"; -} - -.bi-bell-fill::before { - content: "\f189"; -} - -.bi-bell::before { - content: "\f18a"; -} - -.bi-bezier::before { - content: "\f18b"; -} - -.bi-bezier2::before { - content: "\f18c"; -} - -.bi-bicycle::before { - content: "\f18d"; -} - -.bi-binoculars-fill::before { - content: "\f18e"; -} - -.bi-binoculars::before { - content: "\f18f"; -} - -.bi-blockquote-left::before { - content: "\f190"; -} - -.bi-blockquote-right::before { - content: "\f191"; -} - -.bi-book-fill::before { - content: "\f192"; -} - -.bi-book-half::before { - content: "\f193"; -} - -.bi-book::before { - content: "\f194"; -} - -.bi-bookmark-check-fill::before { - content: "\f195"; -} - -.bi-bookmark-check::before { - content: "\f196"; -} - -.bi-bookmark-dash-fill::before { - content: "\f197"; -} - -.bi-bookmark-dash::before { - content: "\f198"; -} - -.bi-bookmark-fill::before { - content: "\f199"; -} - -.bi-bookmark-heart-fill::before { - content: "\f19a"; -} - -.bi-bookmark-heart::before { - content: "\f19b"; -} - -.bi-bookmark-plus-fill::before { - content: "\f19c"; -} - -.bi-bookmark-plus::before { - content: "\f19d"; -} - -.bi-bookmark-star-fill::before { - content: "\f19e"; -} - -.bi-bookmark-star::before { - content: "\f19f"; -} - -.bi-bookmark-x-fill::before { - content: "\f1a0"; -} - -.bi-bookmark-x::before { - content: "\f1a1"; -} - -.bi-bookmark::before { - content: "\f1a2"; -} - -.bi-bookmarks-fill::before { - content: "\f1a3"; -} - -.bi-bookmarks::before { - content: "\f1a4"; -} - -.bi-bookshelf::before { - content: "\f1a5"; -} - -.bi-bootstrap-fill::before { - content: "\f1a6"; -} - -.bi-bootstrap-reboot::before { - content: "\f1a7"; -} - -.bi-bootstrap::before { - content: "\f1a8"; -} - -.bi-border-all::before { - content: "\f1a9"; -} - -.bi-border-bottom::before { - content: "\f1aa"; -} - -.bi-border-center::before { - content: "\f1ab"; -} - -.bi-border-inner::before { - content: "\f1ac"; -} - -.bi-border-left::before { - content: "\f1ad"; -} - -.bi-border-middle::before { - content: "\f1ae"; -} - -.bi-border-outer::before { - content: "\f1af"; -} - -.bi-border-right::before { - content: "\f1b0"; -} - -.bi-border-style::before { - content: "\f1b1"; -} - -.bi-border-top::before { - content: "\f1b2"; -} - -.bi-border-width::before { - content: "\f1b3"; -} - -.bi-border::before { - content: "\f1b4"; -} - -.bi-bounding-box-circles::before { - content: "\f1b5"; -} - -.bi-bounding-box::before { - content: "\f1b6"; -} - -.bi-box-arrow-down-left::before { - content: "\f1b7"; -} - -.bi-box-arrow-down-right::before { - content: "\f1b8"; -} - -.bi-box-arrow-down::before { - content: "\f1b9"; -} - -.bi-box-arrow-in-down-left::before { - content: "\f1ba"; -} - -.bi-box-arrow-in-down-right::before { - content: "\f1bb"; -} - -.bi-box-arrow-in-down::before { - content: "\f1bc"; -} - -.bi-box-arrow-in-left::before { - content: "\f1bd"; -} - -.bi-box-arrow-in-right::before { - content: "\f1be"; -} - -.bi-box-arrow-in-up-left::before { - content: "\f1bf"; -} - -.bi-box-arrow-in-up-right::before { - content: "\f1c0"; -} - -.bi-box-arrow-in-up::before { - content: "\f1c1"; -} - -.bi-box-arrow-left::before { - content: "\f1c2"; -} - -.bi-box-arrow-right::before { - content: "\f1c3"; -} - -.bi-box-arrow-up-left::before { - content: "\f1c4"; -} - -.bi-box-arrow-up-right::before { - content: "\f1c5"; -} - -.bi-box-arrow-up::before { - content: "\f1c6"; -} - -.bi-box-seam::before { - content: "\f1c7"; -} - -.bi-box::before { - content: "\f1c8"; -} - -.bi-braces::before { - content: "\f1c9"; -} - -.bi-bricks::before { - content: "\f1ca"; -} - -.bi-briefcase-fill::before { - content: "\f1cb"; -} - -.bi-briefcase::before { - content: "\f1cc"; -} - -.bi-brightness-alt-high-fill::before { - content: "\f1cd"; -} - -.bi-brightness-alt-high::before { - content: "\f1ce"; -} - -.bi-brightness-alt-low-fill::before { - content: "\f1cf"; -} - -.bi-brightness-alt-low::before { - content: "\f1d0"; -} - -.bi-brightness-high-fill::before { - content: "\f1d1"; -} - -.bi-brightness-high::before { - content: "\f1d2"; -} - -.bi-brightness-low-fill::before { - content: "\f1d3"; -} - -.bi-brightness-low::before { - content: "\f1d4"; -} - -.bi-broadcast-pin::before { - content: "\f1d5"; -} - -.bi-broadcast::before { - content: "\f1d6"; -} - -.bi-brush-fill::before { - content: "\f1d7"; -} - -.bi-brush::before { - content: "\f1d8"; -} - -.bi-bucket-fill::before { - content: "\f1d9"; -} - -.bi-bucket::before { - content: "\f1da"; -} - -.bi-bug-fill::before { - content: "\f1db"; -} - -.bi-bug::before { - content: "\f1dc"; -} - -.bi-building::before { - content: "\f1dd"; -} - -.bi-bullseye::before { - content: "\f1de"; -} - -.bi-calculator-fill::before { - content: "\f1df"; -} - -.bi-calculator::before { - content: "\f1e0"; -} - -.bi-calendar-check-fill::before { - content: "\f1e1"; -} - -.bi-calendar-check::before { - content: "\f1e2"; -} - -.bi-calendar-date-fill::before { - content: "\f1e3"; -} - -.bi-calendar-date::before { - content: "\f1e4"; -} - -.bi-calendar-day-fill::before { - content: "\f1e5"; -} - -.bi-calendar-day::before { - content: "\f1e6"; -} - -.bi-calendar-event-fill::before { - content: "\f1e7"; -} - -.bi-calendar-event::before { - content: "\f1e8"; -} - -.bi-calendar-fill::before { - content: "\f1e9"; -} - -.bi-calendar-minus-fill::before { - content: "\f1ea"; -} - -.bi-calendar-minus::before { - content: "\f1eb"; -} - -.bi-calendar-month-fill::before { - content: "\f1ec"; -} - -.bi-calendar-month::before { - content: "\f1ed"; -} - -.bi-calendar-plus-fill::before { - content: "\f1ee"; -} - -.bi-calendar-plus::before { - content: "\f1ef"; -} - -.bi-calendar-range-fill::before { - content: "\f1f0"; -} - -.bi-calendar-range::before { - content: "\f1f1"; -} - -.bi-calendar-week-fill::before { - content: "\f1f2"; -} - -.bi-calendar-week::before { - content: "\f1f3"; -} - -.bi-calendar-x-fill::before { - content: "\f1f4"; -} - -.bi-calendar-x::before { - content: "\f1f5"; -} - -.bi-calendar::before { - content: "\f1f6"; -} - -.bi-calendar2-check-fill::before { - content: "\f1f7"; -} - -.bi-calendar2-check::before { - content: "\f1f8"; -} - -.bi-calendar2-date-fill::before { - content: "\f1f9"; -} - -.bi-calendar2-date::before { - content: "\f1fa"; -} - -.bi-calendar2-day-fill::before { - content: "\f1fb"; -} - -.bi-calendar2-day::before { - content: "\f1fc"; -} - -.bi-calendar2-event-fill::before { - content: "\f1fd"; -} - -.bi-calendar2-event::before { - content: "\f1fe"; -} - -.bi-calendar2-fill::before { - content: "\f1ff"; -} - -.bi-calendar2-minus-fill::before { - content: "\f200"; -} - -.bi-calendar2-minus::before { - content: "\f201"; -} - -.bi-calendar2-month-fill::before { - content: "\f202"; -} - -.bi-calendar2-month::before { - content: "\f203"; -} - -.bi-calendar2-plus-fill::before { - content: "\f204"; -} - -.bi-calendar2-plus::before { - content: "\f205"; -} - -.bi-calendar2-range-fill::before { - content: "\f206"; -} - -.bi-calendar2-range::before { - content: "\f207"; -} - -.bi-calendar2-week-fill::before { - content: "\f208"; -} - -.bi-calendar2-week::before { - content: "\f209"; -} - -.bi-calendar2-x-fill::before { - content: "\f20a"; -} - -.bi-calendar2-x::before { - content: "\f20b"; -} - -.bi-calendar2::before { - content: "\f20c"; -} - -.bi-calendar3-event-fill::before { - content: "\f20d"; -} - -.bi-calendar3-event::before { - content: "\f20e"; -} - -.bi-calendar3-fill::before { - content: "\f20f"; -} - -.bi-calendar3-range-fill::before { - content: "\f210"; -} - -.bi-calendar3-range::before { - content: "\f211"; -} - -.bi-calendar3-week-fill::before { - content: "\f212"; -} - -.bi-calendar3-week::before { - content: "\f213"; -} - -.bi-calendar3::before { - content: "\f214"; -} - -.bi-calendar4-event::before { - content: "\f215"; -} - -.bi-calendar4-range::before { - content: "\f216"; -} - -.bi-calendar4-week::before { - content: "\f217"; -} - -.bi-calendar4::before { - content: "\f218"; -} - -.bi-camera-fill::before { - content: "\f219"; -} - -.bi-camera-reels-fill::before { - content: "\f21a"; -} - -.bi-camera-reels::before { - content: "\f21b"; -} - -.bi-camera-video-fill::before { - content: "\f21c"; -} - -.bi-camera-video-off-fill::before { - content: "\f21d"; -} - -.bi-camera-video-off::before { - content: "\f21e"; -} - -.bi-camera-video::before { - content: "\f21f"; -} - -.bi-camera::before { - content: "\f220"; -} - -.bi-camera2::before { - content: "\f221"; -} - -.bi-capslock-fill::before { - content: "\f222"; -} - -.bi-capslock::before { - content: "\f223"; -} - -.bi-card-checklist::before { - content: "\f224"; -} - -.bi-card-heading::before { - content: "\f225"; -} - -.bi-card-image::before { - content: "\f226"; -} - -.bi-card-list::before { - content: "\f227"; -} - -.bi-card-text::before { - content: "\f228"; -} - -.bi-caret-down-fill::before { - content: "\f229"; -} - -.bi-caret-down-square-fill::before { - content: "\f22a"; -} - -.bi-caret-down-square::before { - content: "\f22b"; -} - -.bi-caret-down::before { - content: "\f22c"; -} - -.bi-caret-left-fill::before { - content: "\f22d"; -} - -.bi-caret-left-square-fill::before { - content: "\f22e"; -} - -.bi-caret-left-square::before { - content: "\f22f"; -} - -.bi-caret-left::before { - content: "\f230"; -} - -.bi-caret-right-fill::before { - content: "\f231"; -} - -.bi-caret-right-square-fill::before { - content: "\f232"; -} - -.bi-caret-right-square::before { - content: "\f233"; -} - -.bi-caret-right::before { - content: "\f234"; -} - -.bi-caret-up-fill::before { - content: "\f235"; -} - -.bi-caret-up-square-fill::before { - content: "\f236"; -} - -.bi-caret-up-square::before { - content: "\f237"; -} - -.bi-caret-up::before { - content: "\f238"; -} - -.bi-cart-check-fill::before { - content: "\f239"; -} - -.bi-cart-check::before { - content: "\f23a"; -} - -.bi-cart-dash-fill::before { - content: "\f23b"; -} - -.bi-cart-dash::before { - content: "\f23c"; -} - -.bi-cart-fill::before { - content: "\f23d"; -} - -.bi-cart-plus-fill::before { - content: "\f23e"; -} - -.bi-cart-plus::before { - content: "\f23f"; -} - -.bi-cart-x-fill::before { - content: "\f240"; -} - -.bi-cart-x::before { - content: "\f241"; -} - -.bi-cart::before { - content: "\f242"; -} - -.bi-cart2::before { - content: "\f243"; -} - -.bi-cart3::before { - content: "\f244"; -} - -.bi-cart4::before { - content: "\f245"; -} - -.bi-cash-stack::before { - content: "\f246"; -} - -.bi-cash::before { - content: "\f247"; -} - -.bi-cast::before { - content: "\f248"; -} - -.bi-chat-dots-fill::before { - content: "\f249"; -} - -.bi-chat-dots::before { - content: "\f24a"; -} - -.bi-chat-fill::before { - content: "\f24b"; -} - -.bi-chat-left-dots-fill::before { - content: "\f24c"; -} - -.bi-chat-left-dots::before { - content: "\f24d"; -} - -.bi-chat-left-fill::before { - content: "\f24e"; -} - -.bi-chat-left-quote-fill::before { - content: "\f24f"; -} - -.bi-chat-left-quote::before { - content: "\f250"; -} - -.bi-chat-left-text-fill::before { - content: "\f251"; -} - -.bi-chat-left-text::before { - content: "\f252"; -} - -.bi-chat-left::before { - content: "\f253"; -} - -.bi-chat-quote-fill::before { - content: "\f254"; -} - -.bi-chat-quote::before { - content: "\f255"; -} - -.bi-chat-right-dots-fill::before { - content: "\f256"; -} - -.bi-chat-right-dots::before { - content: "\f257"; -} - -.bi-chat-right-fill::before { - content: "\f258"; -} - -.bi-chat-right-quote-fill::before { - content: "\f259"; -} - -.bi-chat-right-quote::before { - content: "\f25a"; -} - -.bi-chat-right-text-fill::before { - content: "\f25b"; -} - -.bi-chat-right-text::before { - content: "\f25c"; -} - -.bi-chat-right::before { - content: "\f25d"; -} - -.bi-chat-square-dots-fill::before { - content: "\f25e"; -} - -.bi-chat-square-dots::before { - content: "\f25f"; -} - -.bi-chat-square-fill::before { - content: "\f260"; -} - -.bi-chat-square-quote-fill::before { - content: "\f261"; -} - -.bi-chat-square-quote::before { - content: "\f262"; -} - -.bi-chat-square-text-fill::before { - content: "\f263"; -} - -.bi-chat-square-text::before { - content: "\f264"; -} - -.bi-chat-square::before { - content: "\f265"; -} - -.bi-chat-text-fill::before { - content: "\f266"; -} - -.bi-chat-text::before { - content: "\f267"; -} - -.bi-chat::before { - content: "\f268"; -} - -.bi-check-all::before { - content: "\f269"; -} - -.bi-check-circle-fill::before { - content: "\f26a"; -} - -.bi-check-circle::before { - content: "\f26b"; -} - -.bi-check-square-fill::before { - content: "\f26c"; -} - -.bi-check-square::before { - content: "\f26d"; -} - -.bi-check::before { - content: "\f26e"; -} - -.bi-check2-all::before { - content: "\f26f"; -} - -.bi-check2-circle::before { - content: "\f270"; -} - -.bi-check2-square::before { - content: "\f271"; -} - -.bi-check2::before { - content: "\f272"; -} - -.bi-chevron-bar-contract::before { - content: "\f273"; -} - -.bi-chevron-bar-down::before { - content: "\f274"; -} - -.bi-chevron-bar-expand::before { - content: "\f275"; -} - -.bi-chevron-bar-left::before { - content: "\f276"; -} - -.bi-chevron-bar-right::before { - content: "\f277"; -} - -.bi-chevron-bar-up::before { - content: "\f278"; -} - -.bi-chevron-compact-down::before { - content: "\f279"; -} - -.bi-chevron-compact-left::before { - content: "\f27a"; -} - -.bi-chevron-compact-right::before { - content: "\f27b"; -} - -.bi-chevron-compact-up::before { - content: "\f27c"; -} - -.bi-chevron-contract::before { - content: "\f27d"; -} - -.bi-chevron-double-down::before { - content: "\f27e"; -} - -.bi-chevron-double-left::before { - content: "\f27f"; -} - -.bi-chevron-double-right::before { - content: "\f280"; -} - -.bi-chevron-double-up::before { - content: "\f281"; -} - -.bi-chevron-down::before { - content: "\f282"; -} - -.bi-chevron-expand::before { - content: "\f283"; -} - -.bi-chevron-left::before { - content: "\f284"; -} - -.bi-chevron-right::before { - content: "\f285"; -} - -.bi-chevron-up::before { - content: "\f286"; -} - -.bi-circle-fill::before { - content: "\f287"; -} - -.bi-circle-half::before { - content: "\f288"; -} - -.bi-circle-square::before { - content: "\f289"; -} - -.bi-circle::before { - content: "\f28a"; -} - -.bi-clipboard-check::before { - content: "\f28b"; -} - -.bi-clipboard-data::before { - content: "\f28c"; -} - -.bi-clipboard-minus::before { - content: "\f28d"; -} - -.bi-clipboard-plus::before { - content: "\f28e"; -} - -.bi-clipboard-x::before { - content: "\f28f"; -} - -.bi-clipboard::before { - content: "\f290"; -} - -.bi-clock-fill::before { - content: "\f291"; -} - -.bi-clock-history::before { - content: "\f292"; -} - -.bi-clock::before { - content: "\f293"; -} - -.bi-cloud-arrow-down-fill::before { - content: "\f294"; -} - -.bi-cloud-arrow-down::before { - content: "\f295"; -} - -.bi-cloud-arrow-up-fill::before { - content: "\f296"; -} - -.bi-cloud-arrow-up::before { - content: "\f297"; -} - -.bi-cloud-check-fill::before { - content: "\f298"; -} - -.bi-cloud-check::before { - content: "\f299"; -} - -.bi-cloud-download-fill::before { - content: "\f29a"; -} - -.bi-cloud-download::before { - content: "\f29b"; -} - -.bi-cloud-drizzle-fill::before { - content: "\f29c"; -} - -.bi-cloud-drizzle::before { - content: "\f29d"; -} - -.bi-cloud-fill::before { - content: "\f29e"; -} - -.bi-cloud-fog-fill::before { - content: "\f29f"; -} - -.bi-cloud-fog::before { - content: "\f2a0"; -} - -.bi-cloud-fog2-fill::before { - content: "\f2a1"; -} - -.bi-cloud-fog2::before { - content: "\f2a2"; -} - -.bi-cloud-hail-fill::before { - content: "\f2a3"; -} - -.bi-cloud-hail::before { - content: "\f2a4"; -} - -.bi-cloud-haze-fill::before { - content: "\f2a6"; -} - -.bi-cloud-haze::before { - content: "\f2a7"; -} - -.bi-cloud-haze2-fill::before { - content: "\f2a8"; -} - -.bi-cloud-lightning-fill::before { - content: "\f2a9"; -} - -.bi-cloud-lightning-rain-fill::before { - content: "\f2aa"; -} - -.bi-cloud-lightning-rain::before { - content: "\f2ab"; -} - -.bi-cloud-lightning::before { - content: "\f2ac"; -} - -.bi-cloud-minus-fill::before { - content: "\f2ad"; -} - -.bi-cloud-minus::before { - content: "\f2ae"; -} - -.bi-cloud-moon-fill::before { - content: "\f2af"; -} - -.bi-cloud-moon::before { - content: "\f2b0"; -} - -.bi-cloud-plus-fill::before { - content: "\f2b1"; -} - -.bi-cloud-plus::before { - content: "\f2b2"; -} - -.bi-cloud-rain-fill::before { - content: "\f2b3"; -} - -.bi-cloud-rain-heavy-fill::before { - content: "\f2b4"; -} - -.bi-cloud-rain-heavy::before { - content: "\f2b5"; -} - -.bi-cloud-rain::before { - content: "\f2b6"; -} - -.bi-cloud-slash-fill::before { - content: "\f2b7"; -} - -.bi-cloud-slash::before { - content: "\f2b8"; -} - -.bi-cloud-sleet-fill::before { - content: "\f2b9"; -} - -.bi-cloud-sleet::before { - content: "\f2ba"; -} - -.bi-cloud-snow-fill::before { - content: "\f2bb"; -} - -.bi-cloud-snow::before { - content: "\f2bc"; -} - -.bi-cloud-sun-fill::before { - content: "\f2bd"; -} - -.bi-cloud-sun::before { - content: "\f2be"; -} - -.bi-cloud-upload-fill::before { - content: "\f2bf"; -} - -.bi-cloud-upload::before { - content: "\f2c0"; -} - -.bi-cloud::before { - content: "\f2c1"; -} - -.bi-clouds-fill::before { - content: "\f2c2"; -} - -.bi-clouds::before { - content: "\f2c3"; -} - -.bi-cloudy-fill::before { - content: "\f2c4"; -} - -.bi-cloudy::before { - content: "\f2c5"; -} - -.bi-code-slash::before { - content: "\f2c6"; -} - -.bi-code-square::before { - content: "\f2c7"; -} - -.bi-code::before { - content: "\f2c8"; -} - -.bi-collection-fill::before { - content: "\f2c9"; -} - -.bi-collection-play-fill::before { - content: "\f2ca"; -} - -.bi-collection-play::before { - content: "\f2cb"; -} - -.bi-collection::before { - content: "\f2cc"; -} - -.bi-columns-gap::before { - content: "\f2cd"; -} - -.bi-columns::before { - content: "\f2ce"; -} - -.bi-command::before { - content: "\f2cf"; -} - -.bi-compass-fill::before { - content: "\f2d0"; -} - -.bi-compass::before { - content: "\f2d1"; -} - -.bi-cone-striped::before { - content: "\f2d2"; -} - -.bi-cone::before { - content: "\f2d3"; -} - -.bi-controller::before { - content: "\f2d4"; -} - -.bi-cpu-fill::before { - content: "\f2d5"; -} - -.bi-cpu::before { - content: "\f2d6"; -} - -.bi-credit-card-2-back-fill::before { - content: "\f2d7"; -} - -.bi-credit-card-2-back::before { - content: "\f2d8"; -} - -.bi-credit-card-2-front-fill::before { - content: "\f2d9"; -} - -.bi-credit-card-2-front::before { - content: "\f2da"; -} - -.bi-credit-card-fill::before { - content: "\f2db"; -} - -.bi-credit-card::before { - content: "\f2dc"; -} - -.bi-crop::before { - content: "\f2dd"; -} - -.bi-cup-fill::before { - content: "\f2de"; -} - -.bi-cup-straw::before { - content: "\f2df"; -} - -.bi-cup::before { - content: "\f2e0"; -} - -.bi-cursor-fill::before { - content: "\f2e1"; -} - -.bi-cursor-text::before { - content: "\f2e2"; -} - -.bi-cursor::before { - content: "\f2e3"; -} - -.bi-dash-circle-dotted::before { - content: "\f2e4"; -} - -.bi-dash-circle-fill::before { - content: "\f2e5"; -} - -.bi-dash-circle::before { - content: "\f2e6"; -} - -.bi-dash-square-dotted::before { - content: "\f2e7"; -} - -.bi-dash-square-fill::before { - content: "\f2e8"; -} - -.bi-dash-square::before { - content: "\f2e9"; -} - -.bi-dash::before { - content: "\f2ea"; -} - -.bi-diagram-2-fill::before { - content: "\f2eb"; -} - -.bi-diagram-2::before { - content: "\f2ec"; -} - -.bi-diagram-3-fill::before { - content: "\f2ed"; -} - -.bi-diagram-3::before { - content: "\f2ee"; -} - -.bi-diamond-fill::before { - content: "\f2ef"; -} - -.bi-diamond-half::before { - content: "\f2f0"; -} - -.bi-diamond::before { - content: "\f2f1"; -} - -.bi-dice-1-fill::before { - content: "\f2f2"; -} - -.bi-dice-1::before { - content: "\f2f3"; -} - -.bi-dice-2-fill::before { - content: "\f2f4"; -} - -.bi-dice-2::before { - content: "\f2f5"; -} - -.bi-dice-3-fill::before { - content: "\f2f6"; -} - -.bi-dice-3::before { - content: "\f2f7"; -} - -.bi-dice-4-fill::before { - content: "\f2f8"; -} - -.bi-dice-4::before { - content: "\f2f9"; -} - -.bi-dice-5-fill::before { - content: "\f2fa"; -} - -.bi-dice-5::before { - content: "\f2fb"; -} - -.bi-dice-6-fill::before { - content: "\f2fc"; -} - -.bi-dice-6::before { - content: "\f2fd"; -} - -.bi-disc-fill::before { - content: "\f2fe"; -} - -.bi-disc::before { - content: "\f2ff"; -} - -.bi-discord::before { - content: "\f300"; -} - -.bi-display-fill::before { - content: "\f301"; -} - -.bi-display::before { - content: "\f302"; -} - -.bi-distribute-horizontal::before { - content: "\f303"; -} - -.bi-distribute-vertical::before { - content: "\f304"; -} - -.bi-door-closed-fill::before { - content: "\f305"; -} - -.bi-door-closed::before { - content: "\f306"; -} - -.bi-door-open-fill::before { - content: "\f307"; -} - -.bi-door-open::before { - content: "\f308"; -} - -.bi-dot::before { - content: "\f309"; -} - -.bi-download::before { - content: "\f30a"; -} - -.bi-droplet-fill::before { - content: "\f30b"; -} - -.bi-droplet-half::before { - content: "\f30c"; -} - -.bi-droplet::before { - content: "\f30d"; -} - -.bi-earbuds::before { - content: "\f30e"; -} - -.bi-easel-fill::before { - content: "\f30f"; -} - -.bi-easel::before { - content: "\f310"; -} - -.bi-egg-fill::before { - content: "\f311"; -} - -.bi-egg-fried::before { - content: "\f312"; -} - -.bi-egg::before { - content: "\f313"; -} - -.bi-eject-fill::before { - content: "\f314"; -} - -.bi-eject::before { - content: "\f315"; -} - -.bi-emoji-angry-fill::before { - content: "\f316"; -} - -.bi-emoji-angry::before { - content: "\f317"; -} - -.bi-emoji-dizzy-fill::before { - content: "\f318"; -} - -.bi-emoji-dizzy::before { - content: "\f319"; -} - -.bi-emoji-expressionless-fill::before { - content: "\f31a"; -} - -.bi-emoji-expressionless::before { - content: "\f31b"; -} - -.bi-emoji-frown-fill::before { - content: "\f31c"; -} - -.bi-emoji-frown::before { - content: "\f31d"; -} - -.bi-emoji-heart-eyes-fill::before { - content: "\f31e"; -} - -.bi-emoji-heart-eyes::before { - content: "\f31f"; -} - -.bi-emoji-laughing-fill::before { - content: "\f320"; -} - -.bi-emoji-laughing::before { - content: "\f321"; -} - -.bi-emoji-neutral-fill::before { - content: "\f322"; -} - -.bi-emoji-neutral::before { - content: "\f323"; -} - -.bi-emoji-smile-fill::before { - content: "\f324"; -} - -.bi-emoji-smile-upside-down-fill::before { - content: "\f325"; -} - -.bi-emoji-smile-upside-down::before { - content: "\f326"; -} - -.bi-emoji-smile::before { - content: "\f327"; -} - -.bi-emoji-sunglasses-fill::before { - content: "\f328"; -} - -.bi-emoji-sunglasses::before { - content: "\f329"; -} - -.bi-emoji-wink-fill::before { - content: "\f32a"; -} - -.bi-emoji-wink::before { - content: "\f32b"; -} - -.bi-envelope-fill::before { - content: "\f32c"; -} - -.bi-envelope-open-fill::before { - content: "\f32d"; -} - -.bi-envelope-open::before { - content: "\f32e"; -} - -.bi-envelope::before { - content: "\f32f"; -} - -.bi-eraser-fill::before { - content: "\f330"; -} - -.bi-eraser::before { - content: "\f331"; -} - -.bi-exclamation-circle-fill::before { - content: "\f332"; -} - -.bi-exclamation-circle::before { - content: "\f333"; -} - -.bi-exclamation-diamond-fill::before { - content: "\f334"; -} - -.bi-exclamation-diamond::before { - content: "\f335"; -} - -.bi-exclamation-octagon-fill::before { - content: "\f336"; -} - -.bi-exclamation-octagon::before { - content: "\f337"; -} - -.bi-exclamation-square-fill::before { - content: "\f338"; -} - -.bi-exclamation-square::before { - content: "\f339"; -} - -.bi-exclamation-triangle-fill::before { - content: "\f33a"; -} - -.bi-exclamation-triangle::before { - content: "\f33b"; -} - -.bi-exclamation::before { - content: "\f33c"; -} - -.bi-exclude::before { - content: "\f33d"; -} - -.bi-eye-fill::before { - content: "\f33e"; -} - -.bi-eye-slash-fill::before { - content: "\f33f"; -} - -.bi-eye-slash::before { - content: "\f340"; -} - -.bi-eye::before { - content: "\f341"; -} - -.bi-eyedropper::before { - content: "\f342"; -} - -.bi-eyeglasses::before { - content: "\f343"; -} - -.bi-facebook::before { - content: "\f344"; -} - -.bi-file-arrow-down-fill::before { - content: "\f345"; -} - -.bi-file-arrow-down::before { - content: "\f346"; -} - -.bi-file-arrow-up-fill::before { - content: "\f347"; -} - -.bi-file-arrow-up::before { - content: "\f348"; -} - -.bi-file-bar-graph-fill::before { - content: "\f349"; -} - -.bi-file-bar-graph::before { - content: "\f34a"; -} - -.bi-file-binary-fill::before { - content: "\f34b"; -} - -.bi-file-binary::before { - content: "\f34c"; -} - -.bi-file-break-fill::before { - content: "\f34d"; -} - -.bi-file-break::before { - content: "\f34e"; -} - -.bi-file-check-fill::before { - content: "\f34f"; -} - -.bi-file-check::before { - content: "\f350"; -} - -.bi-file-code-fill::before { - content: "\f351"; -} - -.bi-file-code::before { - content: "\f352"; -} - -.bi-file-diff-fill::before { - content: "\f353"; -} - -.bi-file-diff::before { - content: "\f354"; -} - -.bi-file-earmark-arrow-down-fill::before { - content: "\f355"; -} - -.bi-file-earmark-arrow-down::before { - content: "\f356"; -} - -.bi-file-earmark-arrow-up-fill::before { - content: "\f357"; -} - -.bi-file-earmark-arrow-up::before { - content: "\f358"; -} - -.bi-file-earmark-bar-graph-fill::before { - content: "\f359"; -} - -.bi-file-earmark-bar-graph::before { - content: "\f35a"; -} - -.bi-file-earmark-binary-fill::before { - content: "\f35b"; -} - -.bi-file-earmark-binary::before { - content: "\f35c"; -} - -.bi-file-earmark-break-fill::before { - content: "\f35d"; -} - -.bi-file-earmark-break::before { - content: "\f35e"; -} - -.bi-file-earmark-check-fill::before { - content: "\f35f"; -} - -.bi-file-earmark-check::before { - content: "\f360"; -} - -.bi-file-earmark-code-fill::before { - content: "\f361"; -} - -.bi-file-earmark-code::before { - content: "\f362"; -} - -.bi-file-earmark-diff-fill::before { - content: "\f363"; -} - -.bi-file-earmark-diff::before { - content: "\f364"; -} - -.bi-file-earmark-easel-fill::before { - content: "\f365"; -} - -.bi-file-earmark-easel::before { - content: "\f366"; -} - -.bi-file-earmark-excel-fill::before { - content: "\f367"; -} - -.bi-file-earmark-excel::before { - content: "\f368"; -} - -.bi-file-earmark-fill::before { - content: "\f369"; -} - -.bi-file-earmark-font-fill::before { - content: "\f36a"; -} - -.bi-file-earmark-font::before { - content: "\f36b"; -} - -.bi-file-earmark-image-fill::before { - content: "\f36c"; -} - -.bi-file-earmark-image::before { - content: "\f36d"; -} - -.bi-file-earmark-lock-fill::before { - content: "\f36e"; -} - -.bi-file-earmark-lock::before { - content: "\f36f"; -} - -.bi-file-earmark-lock2-fill::before { - content: "\f370"; -} - -.bi-file-earmark-lock2::before { - content: "\f371"; -} - -.bi-file-earmark-medical-fill::before { - content: "\f372"; -} - -.bi-file-earmark-medical::before { - content: "\f373"; -} - -.bi-file-earmark-minus-fill::before { - content: "\f374"; -} - -.bi-file-earmark-minus::before { - content: "\f375"; -} - -.bi-file-earmark-music-fill::before { - content: "\f376"; -} - -.bi-file-earmark-music::before { - content: "\f377"; -} - -.bi-file-earmark-person-fill::before { - content: "\f378"; -} - -.bi-file-earmark-person::before { - content: "\f379"; -} - -.bi-file-earmark-play-fill::before { - content: "\f37a"; -} - -.bi-file-earmark-play::before { - content: "\f37b"; -} - -.bi-file-earmark-plus-fill::before { - content: "\f37c"; -} - -.bi-file-earmark-plus::before { - content: "\f37d"; -} - -.bi-file-earmark-post-fill::before { - content: "\f37e"; -} - -.bi-file-earmark-post::before { - content: "\f37f"; -} - -.bi-file-earmark-ppt-fill::before { - content: "\f380"; -} - -.bi-file-earmark-ppt::before { - content: "\f381"; -} - -.bi-file-earmark-richtext-fill::before { - content: "\f382"; -} - -.bi-file-earmark-richtext::before { - content: "\f383"; -} - -.bi-file-earmark-ruled-fill::before { - content: "\f384"; -} - -.bi-file-earmark-ruled::before { - content: "\f385"; -} - -.bi-file-earmark-slides-fill::before { - content: "\f386"; -} - -.bi-file-earmark-slides::before { - content: "\f387"; -} - -.bi-file-earmark-spreadsheet-fill::before { - content: "\f388"; -} - -.bi-file-earmark-spreadsheet::before { - content: "\f389"; -} - -.bi-file-earmark-text-fill::before { - content: "\f38a"; -} - -.bi-file-earmark-text::before { - content: "\f38b"; -} - -.bi-file-earmark-word-fill::before { - content: "\f38c"; -} - -.bi-file-earmark-word::before { - content: "\f38d"; -} - -.bi-file-earmark-x-fill::before { - content: "\f38e"; -} - -.bi-file-earmark-x::before { - content: "\f38f"; -} - -.bi-file-earmark-zip-fill::before { - content: "\f390"; -} - -.bi-file-earmark-zip::before { - content: "\f391"; -} - -.bi-file-earmark::before { - content: "\f392"; -} - -.bi-file-easel-fill::before { - content: "\f393"; -} - -.bi-file-easel::before { - content: "\f394"; -} - -.bi-file-excel-fill::before { - content: "\f395"; -} - -.bi-file-excel::before { - content: "\f396"; -} - -.bi-file-fill::before { - content: "\f397"; -} - -.bi-file-font-fill::before { - content: "\f398"; -} - -.bi-file-font::before { - content: "\f399"; -} - -.bi-file-image-fill::before { - content: "\f39a"; -} - -.bi-file-image::before { - content: "\f39b"; -} - -.bi-file-lock-fill::before { - content: "\f39c"; -} - -.bi-file-lock::before { - content: "\f39d"; -} - -.bi-file-lock2-fill::before { - content: "\f39e"; -} - -.bi-file-lock2::before { - content: "\f39f"; -} - -.bi-file-medical-fill::before { - content: "\f3a0"; -} - -.bi-file-medical::before { - content: "\f3a1"; -} - -.bi-file-minus-fill::before { - content: "\f3a2"; -} - -.bi-file-minus::before { - content: "\f3a3"; -} - -.bi-file-music-fill::before { - content: "\f3a4"; -} - -.bi-file-music::before { - content: "\f3a5"; -} - -.bi-file-person-fill::before { - content: "\f3a6"; -} - -.bi-file-person::before { - content: "\f3a7"; -} - -.bi-file-play-fill::before { - content: "\f3a8"; -} - -.bi-file-play::before { - content: "\f3a9"; -} - -.bi-file-plus-fill::before { - content: "\f3aa"; -} - -.bi-file-plus::before { - content: "\f3ab"; -} - -.bi-file-post-fill::before { - content: "\f3ac"; -} - -.bi-file-post::before { - content: "\f3ad"; -} - -.bi-file-ppt-fill::before { - content: "\f3ae"; -} - -.bi-file-ppt::before { - content: "\f3af"; -} - -.bi-file-richtext-fill::before { - content: "\f3b0"; -} - -.bi-file-richtext::before { - content: "\f3b1"; -} - -.bi-file-ruled-fill::before { - content: "\f3b2"; -} - -.bi-file-ruled::before { - content: "\f3b3"; -} - -.bi-file-slides-fill::before { - content: "\f3b4"; -} - -.bi-file-slides::before { - content: "\f3b5"; -} - -.bi-file-spreadsheet-fill::before { - content: "\f3b6"; -} - -.bi-file-spreadsheet::before { - content: "\f3b7"; -} - -.bi-file-text-fill::before { - content: "\f3b8"; -} - -.bi-file-text::before { - content: "\f3b9"; -} - -.bi-file-word-fill::before { - content: "\f3ba"; -} - -.bi-file-word::before { - content: "\f3bb"; -} - -.bi-file-x-fill::before { - content: "\f3bc"; -} - -.bi-file-x::before { - content: "\f3bd"; -} - -.bi-file-zip-fill::before { - content: "\f3be"; -} - -.bi-file-zip::before { - content: "\f3bf"; -} - -.bi-file::before { - content: "\f3c0"; -} - -.bi-files-alt::before { - content: "\f3c1"; -} - -.bi-files::before { - content: "\f3c2"; -} - -.bi-film::before { - content: "\f3c3"; -} - -.bi-filter-circle-fill::before { - content: "\f3c4"; -} - -.bi-filter-circle::before { - content: "\f3c5"; -} - -.bi-filter-left::before { - content: "\f3c6"; -} - -.bi-filter-right::before { - content: "\f3c7"; -} - -.bi-filter-square-fill::before { - content: "\f3c8"; -} - -.bi-filter-square::before { - content: "\f3c9"; -} - -.bi-filter::before { - content: "\f3ca"; -} - -.bi-flag-fill::before { - content: "\f3cb"; -} - -.bi-flag::before { - content: "\f3cc"; -} - -.bi-flower1::before { - content: "\f3cd"; -} - -.bi-flower2::before { - content: "\f3ce"; -} - -.bi-flower3::before { - content: "\f3cf"; -} - -.bi-folder-check::before { - content: "\f3d0"; -} - -.bi-folder-fill::before { - content: "\f3d1"; -} - -.bi-folder-minus::before { - content: "\f3d2"; -} - -.bi-folder-plus::before { - content: "\f3d3"; -} - -.bi-folder-symlink-fill::before { - content: "\f3d4"; -} - -.bi-folder-symlink::before { - content: "\f3d5"; -} - -.bi-folder-x::before { - content: "\f3d6"; -} - -.bi-folder::before { - content: "\f3d7"; -} - -.bi-folder2-open::before { - content: "\f3d8"; -} - -.bi-folder2::before { - content: "\f3d9"; -} - -.bi-fonts::before { - content: "\f3da"; -} - -.bi-forward-fill::before { - content: "\f3db"; -} - -.bi-forward::before { - content: "\f3dc"; -} - -.bi-front::before { - content: "\f3dd"; -} - -.bi-fullscreen-exit::before { - content: "\f3de"; -} - -.bi-fullscreen::before { - content: "\f3df"; -} - -.bi-funnel-fill::before { - content: "\f3e0"; -} - -.bi-funnel::before { - content: "\f3e1"; -} - -.bi-gear-fill::before { - content: "\f3e2"; -} - -.bi-gear-wide-connected::before { - content: "\f3e3"; -} - -.bi-gear-wide::before { - content: "\f3e4"; -} - -.bi-gear::before { - content: "\f3e5"; -} - -.bi-gem::before { - content: "\f3e6"; -} - -.bi-geo-alt-fill::before { - content: "\f3e7"; -} - -.bi-geo-alt::before { - content: "\f3e8"; -} - -.bi-geo-fill::before { - content: "\f3e9"; -} - -.bi-geo::before { - content: "\f3ea"; -} - -.bi-gift-fill::before { - content: "\f3eb"; -} - -.bi-gift::before { - content: "\f3ec"; -} - -.bi-github::before { - content: "\f3ed"; -} - -.bi-globe::before { - content: "\f3ee"; -} - -.bi-globe2::before { - content: "\f3ef"; -} - -.bi-google::before { - content: "\f3f0"; -} - -.bi-graph-down::before { - content: "\f3f1"; -} - -.bi-graph-up::before { - content: "\f3f2"; -} - -.bi-grid-1x2-fill::before { - content: "\f3f3"; -} - -.bi-grid-1x2::before { - content: "\f3f4"; -} - -.bi-grid-3x2-gap-fill::before { - content: "\f3f5"; -} - -.bi-grid-3x2-gap::before { - content: "\f3f6"; -} - -.bi-grid-3x2::before { - content: "\f3f7"; -} - -.bi-grid-3x3-gap-fill::before { - content: "\f3f8"; -} - -.bi-grid-3x3-gap::before { - content: "\f3f9"; -} - -.bi-grid-3x3::before { - content: "\f3fa"; -} - -.bi-grid-fill::before { - content: "\f3fb"; -} - -.bi-grid::before { - content: "\f3fc"; -} - -.bi-grip-horizontal::before { - content: "\f3fd"; -} - -.bi-grip-vertical::before { - content: "\f3fe"; -} - -.bi-hammer::before { - content: "\f3ff"; -} - -.bi-hand-index-fill::before { - content: "\f400"; -} - -.bi-hand-index-thumb-fill::before { - content: "\f401"; -} - -.bi-hand-index-thumb::before { - content: "\f402"; -} - -.bi-hand-index::before { - content: "\f403"; -} - -.bi-hand-thumbs-down-fill::before { - content: "\f404"; -} - -.bi-hand-thumbs-down::before { - content: "\f405"; -} - -.bi-hand-thumbs-up-fill::before { - content: "\f406"; -} - -.bi-hand-thumbs-up::before { - content: "\f407"; -} - -.bi-handbag-fill::before { - content: "\f408"; -} - -.bi-handbag::before { - content: "\f409"; -} - -.bi-hash::before { - content: "\f40a"; -} - -.bi-hdd-fill::before { - content: "\f40b"; -} - -.bi-hdd-network-fill::before { - content: "\f40c"; -} - -.bi-hdd-network::before { - content: "\f40d"; -} - -.bi-hdd-rack-fill::before { - content: "\f40e"; -} - -.bi-hdd-rack::before { - content: "\f40f"; -} - -.bi-hdd-stack-fill::before { - content: "\f410"; -} - -.bi-hdd-stack::before { - content: "\f411"; -} - -.bi-hdd::before { - content: "\f412"; -} - -.bi-headphones::before { - content: "\f413"; -} - -.bi-headset::before { - content: "\f414"; -} - -.bi-heart-fill::before { - content: "\f415"; -} - -.bi-heart-half::before { - content: "\f416"; -} - -.bi-heart::before { - content: "\f417"; -} - -.bi-heptagon-fill::before { - content: "\f418"; -} - -.bi-heptagon-half::before { - content: "\f419"; -} - -.bi-heptagon::before { - content: "\f41a"; -} - -.bi-hexagon-fill::before { - content: "\f41b"; -} - -.bi-hexagon-half::before { - content: "\f41c"; -} - -.bi-hexagon::before { - content: "\f41d"; -} - -.bi-hourglass-bottom::before { - content: "\f41e"; -} - -.bi-hourglass-split::before { - content: "\f41f"; -} - -.bi-hourglass-top::before { - content: "\f420"; -} - -.bi-hourglass::before { - content: "\f421"; -} - -.bi-house-door-fill::before { - content: "\f422"; -} - -.bi-house-door::before { - content: "\f423"; -} - -.bi-house-fill::before { - content: "\f424"; -} - -.bi-house::before { - content: "\f425"; -} - -.bi-hr::before { - content: "\f426"; -} - -.bi-hurricane::before { - content: "\f427"; -} - -.bi-image-alt::before { - content: "\f428"; -} - -.bi-image-fill::before { - content: "\f429"; -} - -.bi-image::before { - content: "\f42a"; -} - -.bi-images::before { - content: "\f42b"; -} - -.bi-inbox-fill::before { - content: "\f42c"; -} - -.bi-inbox::before { - content: "\f42d"; -} - -.bi-inboxes-fill::before { - content: "\f42e"; -} - -.bi-inboxes::before { - content: "\f42f"; -} - -.bi-info-circle-fill::before { - content: "\f430"; -} - -.bi-info-circle::before { - content: "\f431"; -} - -.bi-info-square-fill::before { - content: "\f432"; -} - -.bi-info-square::before { - content: "\f433"; -} - -.bi-info::before { - content: "\f434"; -} - -.bi-input-cursor-text::before { - content: "\f435"; -} - -.bi-input-cursor::before { - content: "\f436"; -} - -.bi-instagram::before { - content: "\f437"; -} - -.bi-intersect::before { - content: "\f438"; -} - -.bi-journal-album::before { - content: "\f439"; -} - -.bi-journal-arrow-down::before { - content: "\f43a"; -} - -.bi-journal-arrow-up::before { - content: "\f43b"; -} - -.bi-journal-bookmark-fill::before { - content: "\f43c"; -} - -.bi-journal-bookmark::before { - content: "\f43d"; -} - -.bi-journal-check::before { - content: "\f43e"; -} - -.bi-journal-code::before { - content: "\f43f"; -} - -.bi-journal-medical::before { - content: "\f440"; -} - -.bi-journal-minus::before { - content: "\f441"; -} - -.bi-journal-plus::before { - content: "\f442"; -} - -.bi-journal-richtext::before { - content: "\f443"; -} - -.bi-journal-text::before { - content: "\f444"; -} - -.bi-journal-x::before { - content: "\f445"; -} - -.bi-journal::before { - content: "\f446"; -} - -.bi-journals::before { - content: "\f447"; -} - -.bi-joystick::before { - content: "\f448"; -} - -.bi-justify-left::before { - content: "\f449"; -} - -.bi-justify-right::before { - content: "\f44a"; -} - -.bi-justify::before { - content: "\f44b"; -} - -.bi-kanban-fill::before { - content: "\f44c"; -} - -.bi-kanban::before { - content: "\f44d"; -} - -.bi-key-fill::before { - content: "\f44e"; -} - -.bi-key::before { - content: "\f44f"; -} - -.bi-keyboard-fill::before { - content: "\f450"; -} - -.bi-keyboard::before { - content: "\f451"; -} - -.bi-ladder::before { - content: "\f452"; -} - -.bi-lamp-fill::before { - content: "\f453"; -} - -.bi-lamp::before { - content: "\f454"; -} - -.bi-laptop-fill::before { - content: "\f455"; -} - -.bi-laptop::before { - content: "\f456"; -} - -.bi-layer-backward::before { - content: "\f457"; -} - -.bi-layer-forward::before { - content: "\f458"; -} - -.bi-layers-fill::before { - content: "\f459"; -} - -.bi-layers-half::before { - content: "\f45a"; -} - -.bi-layers::before { - content: "\f45b"; -} - -.bi-layout-sidebar-inset-reverse::before { - content: "\f45c"; -} - -.bi-layout-sidebar-inset::before { - content: "\f45d"; -} - -.bi-layout-sidebar-reverse::before { - content: "\f45e"; -} - -.bi-layout-sidebar::before { - content: "\f45f"; -} - -.bi-layout-split::before { - content: "\f460"; -} - -.bi-layout-text-sidebar-reverse::before { - content: "\f461"; -} - -.bi-layout-text-sidebar::before { - content: "\f462"; -} - -.bi-layout-text-window-reverse::before { - content: "\f463"; -} - -.bi-layout-text-window::before { - content: "\f464"; -} - -.bi-layout-three-columns::before { - content: "\f465"; -} - -.bi-layout-wtf::before { - content: "\f466"; -} - -.bi-life-preserver::before { - content: "\f467"; -} - -.bi-lightbulb-fill::before { - content: "\f468"; -} - -.bi-lightbulb-off-fill::before { - content: "\f469"; -} - -.bi-lightbulb-off::before { - content: "\f46a"; -} - -.bi-lightbulb::before { - content: "\f46b"; -} - -.bi-lightning-charge-fill::before { - content: "\f46c"; -} - -.bi-lightning-charge::before { - content: "\f46d"; -} - -.bi-lightning-fill::before { - content: "\f46e"; -} - -.bi-lightning::before { - content: "\f46f"; -} - -.bi-link-45deg::before { - content: "\f470"; -} - -.bi-link::before { - content: "\f471"; -} - -.bi-linkedin::before { - content: "\f472"; -} - -.bi-list-check::before { - content: "\f473"; -} - -.bi-list-nested::before { - content: "\f474"; -} - -.bi-list-ol::before { - content: "\f475"; -} - -.bi-list-stars::before { - content: "\f476"; -} - -.bi-list-task::before { - content: "\f477"; -} - -.bi-list-ul::before { - content: "\f478"; -} - -.bi-list::before { - content: "\f479"; -} - -.bi-lock-fill::before { - content: "\f47a"; -} - -.bi-lock::before { - content: "\f47b"; -} - -.bi-mailbox::before { - content: "\f47c"; -} - -.bi-mailbox2::before { - content: "\f47d"; -} - -.bi-map-fill::before { - content: "\f47e"; -} - -.bi-map::before { - content: "\f47f"; -} - -.bi-markdown-fill::before { - content: "\f480"; -} - -.bi-markdown::before { - content: "\f481"; -} - -.bi-mask::before { - content: "\f482"; -} - -.bi-megaphone-fill::before { - content: "\f483"; -} - -.bi-megaphone::before { - content: "\f484"; -} - -.bi-menu-app-fill::before { - content: "\f485"; -} - -.bi-menu-app::before { - content: "\f486"; -} - -.bi-menu-button-fill::before { - content: "\f487"; -} - -.bi-menu-button-wide-fill::before { - content: "\f488"; -} - -.bi-menu-button-wide::before { - content: "\f489"; -} - -.bi-menu-button::before { - content: "\f48a"; -} - -.bi-menu-down::before { - content: "\f48b"; -} - -.bi-menu-up::before { - content: "\f48c"; -} - -.bi-mic-fill::before { - content: "\f48d"; -} - -.bi-mic-mute-fill::before { - content: "\f48e"; -} - -.bi-mic-mute::before { - content: "\f48f"; -} - -.bi-mic::before { - content: "\f490"; -} - -.bi-minecart-loaded::before { - content: "\f491"; -} - -.bi-minecart::before { - content: "\f492"; -} - -.bi-moisture::before { - content: "\f493"; -} - -.bi-moon-fill::before { - content: "\f494"; -} - -.bi-moon-stars-fill::before { - content: "\f495"; -} - -.bi-moon-stars::before { - content: "\f496"; -} - -.bi-moon::before { - content: "\f497"; -} - -.bi-mouse-fill::before { - content: "\f498"; -} - -.bi-mouse::before { - content: "\f499"; -} - -.bi-mouse2-fill::before { - content: "\f49a"; -} - -.bi-mouse2::before { - content: "\f49b"; -} - -.bi-mouse3-fill::before { - content: "\f49c"; -} - -.bi-mouse3::before { - content: "\f49d"; -} - -.bi-music-note-beamed::before { - content: "\f49e"; -} - -.bi-music-note-list::before { - content: "\f49f"; -} - -.bi-music-note::before { - content: "\f4a0"; -} - -.bi-music-player-fill::before { - content: "\f4a1"; -} - -.bi-music-player::before { - content: "\f4a2"; -} - -.bi-newspaper::before { - content: "\f4a3"; -} - -.bi-node-minus-fill::before { - content: "\f4a4"; -} - -.bi-node-minus::before { - content: "\f4a5"; -} - -.bi-node-plus-fill::before { - content: "\f4a6"; -} - -.bi-node-plus::before { - content: "\f4a7"; -} - -.bi-nut-fill::before { - content: "\f4a8"; -} - -.bi-nut::before { - content: "\f4a9"; -} - -.bi-octagon-fill::before { - content: "\f4aa"; -} - -.bi-octagon-half::before { - content: "\f4ab"; -} - -.bi-octagon::before { - content: "\f4ac"; -} - -.bi-option::before { - content: "\f4ad"; -} - -.bi-outlet::before { - content: "\f4ae"; -} - -.bi-paint-bucket::before { - content: "\f4af"; -} - -.bi-palette-fill::before { - content: "\f4b0"; -} - -.bi-palette::before { - content: "\f4b1"; -} - -.bi-palette2::before { - content: "\f4b2"; -} - -.bi-paperclip::before { - content: "\f4b3"; -} - -.bi-paragraph::before { - content: "\f4b4"; -} - -.bi-patch-check-fill::before { - content: "\f4b5"; -} - -.bi-patch-check::before { - content: "\f4b6"; -} - -.bi-patch-exclamation-fill::before { - content: "\f4b7"; -} - -.bi-patch-exclamation::before { - content: "\f4b8"; -} - -.bi-patch-minus-fill::before { - content: "\f4b9"; -} - -.bi-patch-minus::before { - content: "\f4ba"; -} - -.bi-patch-plus-fill::before { - content: "\f4bb"; -} - -.bi-patch-plus::before { - content: "\f4bc"; -} - -.bi-patch-question-fill::before { - content: "\f4bd"; -} - -.bi-patch-question::before { - content: "\f4be"; -} - -.bi-pause-btn-fill::before { - content: "\f4bf"; -} - -.bi-pause-btn::before { - content: "\f4c0"; -} - -.bi-pause-circle-fill::before { - content: "\f4c1"; -} - -.bi-pause-circle::before { - content: "\f4c2"; -} - -.bi-pause-fill::before { - content: "\f4c3"; -} - -.bi-pause::before { - content: "\f4c4"; -} - -.bi-peace-fill::before { - content: "\f4c5"; -} - -.bi-peace::before { - content: "\f4c6"; -} - -.bi-pen-fill::before { - content: "\f4c7"; -} - -.bi-pen::before { - content: "\f4c8"; -} - -.bi-pencil-fill::before { - content: "\f4c9"; -} - -.bi-pencil-square::before { - content: "\f4ca"; -} - -.bi-pencil::before { - content: "\f4cb"; -} - -.bi-pentagon-fill::before { - content: "\f4cc"; -} - -.bi-pentagon-half::before { - content: "\f4cd"; -} - -.bi-pentagon::before { - content: "\f4ce"; -} - -.bi-people-fill::before { - content: "\f4cf"; -} - -.bi-people::before { - content: "\f4d0"; -} - -.bi-percent::before { - content: "\f4d1"; -} - -.bi-person-badge-fill::before { - content: "\f4d2"; -} - -.bi-person-badge::before { - content: "\f4d3"; -} - -.bi-person-bounding-box::before { - content: "\f4d4"; -} - -.bi-person-check-fill::before { - content: "\f4d5"; -} - -.bi-person-check::before { - content: "\f4d6"; -} - -.bi-person-circle::before { - content: "\f4d7"; -} - -.bi-person-dash-fill::before { - content: "\f4d8"; -} - -.bi-person-dash::before { - content: "\f4d9"; -} - -.bi-person-fill::before { - content: "\f4da"; -} - -.bi-person-lines-fill::before { - content: "\f4db"; -} - -.bi-person-plus-fill::before { - content: "\f4dc"; -} - -.bi-person-plus::before { - content: "\f4dd"; -} - -.bi-person-square::before { - content: "\f4de"; -} - -.bi-person-x-fill::before { - content: "\f4df"; -} - -.bi-person-x::before { - content: "\f4e0"; -} - -.bi-person::before { - content: "\f4e1"; -} - -.bi-phone-fill::before { - content: "\f4e2"; -} - -.bi-phone-landscape-fill::before { - content: "\f4e3"; -} - -.bi-phone-landscape::before { - content: "\f4e4"; -} - -.bi-phone-vibrate-fill::before { - content: "\f4e5"; -} - -.bi-phone-vibrate::before { - content: "\f4e6"; -} - -.bi-phone::before { - content: "\f4e7"; -} - -.bi-pie-chart-fill::before { - content: "\f4e8"; -} - -.bi-pie-chart::before { - content: "\f4e9"; -} - -.bi-pin-angle-fill::before { - content: "\f4ea"; -} - -.bi-pin-angle::before { - content: "\f4eb"; -} - -.bi-pin-fill::before { - content: "\f4ec"; -} - -.bi-pin::before { - content: "\f4ed"; -} - -.bi-pip-fill::before { - content: "\f4ee"; -} - -.bi-pip::before { - content: "\f4ef"; -} - -.bi-play-btn-fill::before { - content: "\f4f0"; -} - -.bi-play-btn::before { - content: "\f4f1"; -} - -.bi-play-circle-fill::before { - content: "\f4f2"; -} - -.bi-play-circle::before { - content: "\f4f3"; -} - -.bi-play-fill::before { - content: "\f4f4"; -} - -.bi-play::before { - content: "\f4f5"; -} - -.bi-plug-fill::before { - content: "\f4f6"; -} - -.bi-plug::before { - content: "\f4f7"; -} - -.bi-plus-circle-dotted::before { - content: "\f4f8"; -} - -.bi-plus-circle-fill::before { - content: "\f4f9"; -} - -.bi-plus-circle::before { - content: "\f4fa"; -} - -.bi-plus-square-dotted::before { - content: "\f4fb"; -} - -.bi-plus-square-fill::before { - content: "\f4fc"; -} - -.bi-plus-square::before { - content: "\f4fd"; -} - -.bi-plus::before { - content: "\f4fe"; -} - -.bi-power::before { - content: "\f4ff"; -} - -.bi-printer-fill::before { - content: "\f500"; -} - -.bi-printer::before { - content: "\f501"; -} - -.bi-puzzle-fill::before { - content: "\f502"; -} - -.bi-puzzle::before { - content: "\f503"; -} - -.bi-question-circle-fill::before { - content: "\f504"; -} - -.bi-question-circle::before { - content: "\f505"; -} - -.bi-question-diamond-fill::before { - content: "\f506"; -} - -.bi-question-diamond::before { - content: "\f507"; -} - -.bi-question-octagon-fill::before { - content: "\f508"; -} - -.bi-question-octagon::before { - content: "\f509"; -} - -.bi-question-square-fill::before { - content: "\f50a"; -} - -.bi-question-square::before { - content: "\f50b"; -} - -.bi-question::before { - content: "\f50c"; -} - -.bi-rainbow::before { - content: "\f50d"; -} - -.bi-receipt-cutoff::before { - content: "\f50e"; -} - -.bi-receipt::before { - content: "\f50f"; -} - -.bi-reception-0::before { - content: "\f510"; -} - -.bi-reception-1::before { - content: "\f511"; -} - -.bi-reception-2::before { - content: "\f512"; -} - -.bi-reception-3::before { - content: "\f513"; -} - -.bi-reception-4::before { - content: "\f514"; -} - -.bi-record-btn-fill::before { - content: "\f515"; -} - -.bi-record-btn::before { - content: "\f516"; -} - -.bi-record-circle-fill::before { - content: "\f517"; -} - -.bi-record-circle::before { - content: "\f518"; -} - -.bi-record-fill::before { - content: "\f519"; -} - -.bi-record::before { - content: "\f51a"; -} - -.bi-record2-fill::before { - content: "\f51b"; -} - -.bi-record2::before { - content: "\f51c"; -} - -.bi-reply-all-fill::before { - content: "\f51d"; -} - -.bi-reply-all::before { - content: "\f51e"; -} - -.bi-reply-fill::before { - content: "\f51f"; -} - -.bi-reply::before { - content: "\f520"; -} - -.bi-rss-fill::before { - content: "\f521"; -} - -.bi-rss::before { - content: "\f522"; -} - -.bi-rulers::before { - content: "\f523"; -} - -.bi-save-fill::before { - content: "\f524"; -} - -.bi-save::before { - content: "\f525"; -} - -.bi-save2-fill::before { - content: "\f526"; -} - -.bi-save2::before { - content: "\f527"; -} - -.bi-scissors::before { - content: "\f528"; -} - -.bi-screwdriver::before { - content: "\f529"; -} - -.bi-search::before { - content: "\f52a"; -} - -.bi-segmented-nav::before { - content: "\f52b"; -} - -.bi-server::before { - content: "\f52c"; -} - -.bi-share-fill::before { - content: "\f52d"; -} - -.bi-share::before { - content: "\f52e"; -} - -.bi-shield-check::before { - content: "\f52f"; -} - -.bi-shield-exclamation::before { - content: "\f530"; -} - -.bi-shield-fill-check::before { - content: "\f531"; -} - -.bi-shield-fill-exclamation::before { - content: "\f532"; -} - -.bi-shield-fill-minus::before { - content: "\f533"; -} - -.bi-shield-fill-plus::before { - content: "\f534"; -} - -.bi-shield-fill-x::before { - content: "\f535"; -} - -.bi-shield-fill::before { - content: "\f536"; -} - -.bi-shield-lock-fill::before { - content: "\f537"; -} - -.bi-shield-lock::before { - content: "\f538"; -} - -.bi-shield-minus::before { - content: "\f539"; -} - -.bi-shield-plus::before { - content: "\f53a"; -} - -.bi-shield-shaded::before { - content: "\f53b"; -} - -.bi-shield-slash-fill::before { - content: "\f53c"; -} - -.bi-shield-slash::before { - content: "\f53d"; -} - -.bi-shield-x::before { - content: "\f53e"; -} - -.bi-shield::before { - content: "\f53f"; -} - -.bi-shift-fill::before { - content: "\f540"; -} - -.bi-shift::before { - content: "\f541"; -} - -.bi-shop-window::before { - content: "\f542"; -} - -.bi-shop::before { - content: "\f543"; -} - -.bi-shuffle::before { - content: "\f544"; -} - -.bi-signpost-2-fill::before { - content: "\f545"; -} - -.bi-signpost-2::before { - content: "\f546"; -} - -.bi-signpost-fill::before { - content: "\f547"; -} - -.bi-signpost-split-fill::before { - content: "\f548"; -} - -.bi-signpost-split::before { - content: "\f549"; -} - -.bi-signpost::before { - content: "\f54a"; -} - -.bi-sim-fill::before { - content: "\f54b"; -} - -.bi-sim::before { - content: "\f54c"; -} - -.bi-skip-backward-btn-fill::before { - content: "\f54d"; -} - -.bi-skip-backward-btn::before { - content: "\f54e"; -} - -.bi-skip-backward-circle-fill::before { - content: "\f54f"; -} - -.bi-skip-backward-circle::before { - content: "\f550"; -} - -.bi-skip-backward-fill::before { - content: "\f551"; -} - -.bi-skip-backward::before { - content: "\f552"; -} - -.bi-skip-end-btn-fill::before { - content: "\f553"; -} - -.bi-skip-end-btn::before { - content: "\f554"; -} - -.bi-skip-end-circle-fill::before { - content: "\f555"; -} - -.bi-skip-end-circle::before { - content: "\f556"; -} - -.bi-skip-end-fill::before { - content: "\f557"; -} - -.bi-skip-end::before { - content: "\f558"; -} - -.bi-skip-forward-btn-fill::before { - content: "\f559"; -} - -.bi-skip-forward-btn::before { - content: "\f55a"; -} - -.bi-skip-forward-circle-fill::before { - content: "\f55b"; -} - -.bi-skip-forward-circle::before { - content: "\f55c"; -} - -.bi-skip-forward-fill::before { - content: "\f55d"; -} - -.bi-skip-forward::before { - content: "\f55e"; -} - -.bi-skip-start-btn-fill::before { - content: "\f55f"; -} - -.bi-skip-start-btn::before { - content: "\f560"; -} - -.bi-skip-start-circle-fill::before { - content: "\f561"; -} - -.bi-skip-start-circle::before { - content: "\f562"; -} - -.bi-skip-start-fill::before { - content: "\f563"; -} - -.bi-skip-start::before { - content: "\f564"; -} - -.bi-slack::before { - content: "\f565"; -} - -.bi-slash-circle-fill::before { - content: "\f566"; -} - -.bi-slash-circle::before { - content: "\f567"; -} - -.bi-slash-square-fill::before { - content: "\f568"; -} - -.bi-slash-square::before { - content: "\f569"; -} - -.bi-slash::before { - content: "\f56a"; -} - -.bi-sliders::before { - content: "\f56b"; -} - -.bi-smartwatch::before { - content: "\f56c"; -} - -.bi-snow::before { - content: "\f56d"; -} - -.bi-snow2::before { - content: "\f56e"; -} - -.bi-snow3::before { - content: "\f56f"; -} - -.bi-sort-alpha-down-alt::before { - content: "\f570"; -} - -.bi-sort-alpha-down::before { - content: "\f571"; -} - -.bi-sort-alpha-up-alt::before { - content: "\f572"; -} - -.bi-sort-alpha-up::before { - content: "\f573"; -} - -.bi-sort-down-alt::before { - content: "\f574"; -} - -.bi-sort-down::before { - content: "\f575"; -} - -.bi-sort-numeric-down-alt::before { - content: "\f576"; -} - -.bi-sort-numeric-down::before { - content: "\f577"; -} - -.bi-sort-numeric-up-alt::before { - content: "\f578"; -} - -.bi-sort-numeric-up::before { - content: "\f579"; -} - -.bi-sort-up-alt::before { - content: "\f57a"; -} - -.bi-sort-up::before { - content: "\f57b"; -} - -.bi-soundwave::before { - content: "\f57c"; -} - -.bi-speaker-fill::before { - content: "\f57d"; -} - -.bi-speaker::before { - content: "\f57e"; -} - -.bi-speedometer::before { - content: "\f57f"; -} - -.bi-speedometer2::before { - content: "\f580"; -} - -.bi-spellcheck::before { - content: "\f581"; -} - -.bi-square-fill::before { - content: "\f582"; -} - -.bi-square-half::before { - content: "\f583"; -} - -.bi-square::before { - content: "\f584"; -} - -.bi-stack::before { - content: "\f585"; -} - -.bi-star-fill::before { - content: "\f586"; -} - -.bi-star-half::before { - content: "\f587"; -} - -.bi-star::before { - content: "\f588"; -} - -.bi-stars::before { - content: "\f589"; -} - -.bi-stickies-fill::before { - content: "\f58a"; -} - -.bi-stickies::before { - content: "\f58b"; -} - -.bi-sticky-fill::before { - content: "\f58c"; -} - -.bi-sticky::before { - content: "\f58d"; -} - -.bi-stop-btn-fill::before { - content: "\f58e"; -} - -.bi-stop-btn::before { - content: "\f58f"; -} - -.bi-stop-circle-fill::before { - content: "\f590"; -} - -.bi-stop-circle::before { - content: "\f591"; -} - -.bi-stop-fill::before { - content: "\f592"; -} - -.bi-stop::before { - content: "\f593"; -} - -.bi-stoplights-fill::before { - content: "\f594"; -} - -.bi-stoplights::before { - content: "\f595"; -} - -.bi-stopwatch-fill::before { - content: "\f596"; -} - -.bi-stopwatch::before { - content: "\f597"; -} - -.bi-subtract::before { - content: "\f598"; -} - -.bi-suit-club-fill::before { - content: "\f599"; -} - -.bi-suit-club::before { - content: "\f59a"; -} - -.bi-suit-diamond-fill::before { - content: "\f59b"; -} - -.bi-suit-diamond::before { - content: "\f59c"; -} - -.bi-suit-heart-fill::before { - content: "\f59d"; -} - -.bi-suit-heart::before { - content: "\f59e"; -} - -.bi-suit-spade-fill::before { - content: "\f59f"; -} - -.bi-suit-spade::before { - content: "\f5a0"; -} - -.bi-sun-fill::before { - content: "\f5a1"; -} - -.bi-sun::before { - content: "\f5a2"; -} - -.bi-sunglasses::before { - content: "\f5a3"; -} - -.bi-sunrise-fill::before { - content: "\f5a4"; -} - -.bi-sunrise::before { - content: "\f5a5"; -} - -.bi-sunset-fill::before { - content: "\f5a6"; -} - -.bi-sunset::before { - content: "\f5a7"; -} - -.bi-symmetry-horizontal::before { - content: "\f5a8"; -} - -.bi-symmetry-vertical::before { - content: "\f5a9"; -} - -.bi-table::before { - content: "\f5aa"; -} - -.bi-tablet-fill::before { - content: "\f5ab"; -} - -.bi-tablet-landscape-fill::before { - content: "\f5ac"; -} - -.bi-tablet-landscape::before { - content: "\f5ad"; -} - -.bi-tablet::before { - content: "\f5ae"; -} - -.bi-tag-fill::before { - content: "\f5af"; -} - -.bi-tag::before { - content: "\f5b0"; -} - -.bi-tags-fill::before { - content: "\f5b1"; -} - -.bi-tags::before { - content: "\f5b2"; -} - -.bi-telegram::before { - content: "\f5b3"; -} - -.bi-telephone-fill::before { - content: "\f5b4"; -} - -.bi-telephone-forward-fill::before { - content: "\f5b5"; -} - -.bi-telephone-forward::before { - content: "\f5b6"; -} - -.bi-telephone-inbound-fill::before { - content: "\f5b7"; -} - -.bi-telephone-inbound::before { - content: "\f5b8"; -} - -.bi-telephone-minus-fill::before { - content: "\f5b9"; -} - -.bi-telephone-minus::before { - content: "\f5ba"; -} - -.bi-telephone-outbound-fill::before { - content: "\f5bb"; -} - -.bi-telephone-outbound::before { - content: "\f5bc"; -} - -.bi-telephone-plus-fill::before { - content: "\f5bd"; -} - -.bi-telephone-plus::before { - content: "\f5be"; -} - -.bi-telephone-x-fill::before { - content: "\f5bf"; -} - -.bi-telephone-x::before { - content: "\f5c0"; -} - -.bi-telephone::before { - content: "\f5c1"; -} - -.bi-terminal-fill::before { - content: "\f5c2"; -} - -.bi-terminal::before { - content: "\f5c3"; -} - -.bi-text-center::before { - content: "\f5c4"; -} - -.bi-text-indent-left::before { - content: "\f5c5"; -} - -.bi-text-indent-right::before { - content: "\f5c6"; -} - -.bi-text-left::before { - content: "\f5c7"; -} - -.bi-text-paragraph::before { - content: "\f5c8"; -} - -.bi-text-right::before { - content: "\f5c9"; -} - -.bi-textarea-resize::before { - content: "\f5ca"; -} - -.bi-textarea-t::before { - content: "\f5cb"; -} - -.bi-textarea::before { - content: "\f5cc"; -} - -.bi-thermometer-half::before { - content: "\f5cd"; -} - -.bi-thermometer-high::before { - content: "\f5ce"; -} - -.bi-thermometer-low::before { - content: "\f5cf"; -} - -.bi-thermometer-snow::before { - content: "\f5d0"; -} - -.bi-thermometer-sun::before { - content: "\f5d1"; -} - -.bi-thermometer::before { - content: "\f5d2"; -} - -.bi-three-dots-vertical::before { - content: "\f5d3"; -} - -.bi-three-dots::before { - content: "\f5d4"; -} - -.bi-toggle-off::before { - content: "\f5d5"; -} - -.bi-toggle-on::before { - content: "\f5d6"; -} - -.bi-toggle2-off::before { - content: "\f5d7"; -} - -.bi-toggle2-on::before { - content: "\f5d8"; -} - -.bi-toggles::before { - content: "\f5d9"; -} - -.bi-toggles2::before { - content: "\f5da"; -} - -.bi-tools::before { - content: "\f5db"; -} - -.bi-tornado::before { - content: "\f5dc"; -} - -.bi-trash-fill::before { - content: "\f5dd"; -} - -.bi-trash::before { - content: "\f5de"; -} - -.bi-trash2-fill::before { - content: "\f5df"; -} - -.bi-trash2::before { - content: "\f5e0"; -} - -.bi-tree-fill::before { - content: "\f5e1"; -} - -.bi-tree::before { - content: "\f5e2"; -} - -.bi-triangle-fill::before { - content: "\f5e3"; -} - -.bi-triangle-half::before { - content: "\f5e4"; -} - -.bi-triangle::before { - content: "\f5e5"; -} - -.bi-trophy-fill::before { - content: "\f5e6"; -} - -.bi-trophy::before { - content: "\f5e7"; -} - -.bi-tropical-storm::before { - content: "\f5e8"; -} - -.bi-truck-flatbed::before { - content: "\f5e9"; -} - -.bi-truck::before { - content: "\f5ea"; -} - -.bi-tsunami::before { - content: "\f5eb"; -} - -.bi-tv-fill::before { - content: "\f5ec"; -} - -.bi-tv::before { - content: "\f5ed"; -} - -.bi-twitch::before { - content: "\f5ee"; -} - -.bi-twitter::before { - content: "\f5ef"; -} - -.bi-type-bold::before { - content: "\f5f0"; -} - -.bi-type-h1::before { - content: "\f5f1"; -} - -.bi-type-h2::before { - content: "\f5f2"; -} - -.bi-type-h3::before { - content: "\f5f3"; -} - -.bi-type-italic::before { - content: "\f5f4"; -} - -.bi-type-strikethrough::before { - content: "\f5f5"; -} - -.bi-type-underline::before { - content: "\f5f6"; -} - -.bi-type::before { - content: "\f5f7"; -} - -.bi-ui-checks-grid::before { - content: "\f5f8"; -} - -.bi-ui-checks::before { - content: "\f5f9"; -} - -.bi-ui-radios-grid::before { - content: "\f5fa"; -} - -.bi-ui-radios::before { - content: "\f5fb"; -} - -.bi-umbrella-fill::before { - content: "\f5fc"; -} - -.bi-umbrella::before { - content: "\f5fd"; -} - -.bi-union::before { - content: "\f5fe"; -} - -.bi-unlock-fill::before { - content: "\f5ff"; -} - -.bi-unlock::before { - content: "\f600"; -} - -.bi-upc-scan::before { - content: "\f601"; -} - -.bi-upc::before { - content: "\f602"; -} - -.bi-upload::before { - content: "\f603"; -} - -.bi-vector-pen::before { - content: "\f604"; -} - -.bi-view-list::before { - content: "\f605"; -} - -.bi-view-stacked::before { - content: "\f606"; -} - -.bi-vinyl-fill::before { - content: "\f607"; -} - -.bi-vinyl::before { - content: "\f608"; -} - -.bi-voicemail::before { - content: "\f609"; -} - -.bi-volume-down-fill::before { - content: "\f60a"; -} - -.bi-volume-down::before { - content: "\f60b"; -} - -.bi-volume-mute-fill::before { - content: "\f60c"; -} - -.bi-volume-mute::before { - content: "\f60d"; -} - -.bi-volume-off-fill::before { - content: "\f60e"; -} - -.bi-volume-off::before { - content: "\f60f"; -} - -.bi-volume-up-fill::before { - content: "\f610"; -} - -.bi-volume-up::before { - content: "\f611"; -} - -.bi-vr::before { - content: "\f612"; -} - -.bi-wallet-fill::before { - content: "\f613"; -} - -.bi-wallet::before { - content: "\f614"; -} - -.bi-wallet2::before { - content: "\f615"; -} - -.bi-watch::before { - content: "\f616"; -} - -.bi-water::before { - content: "\f617"; -} - -.bi-whatsapp::before { - content: "\f618"; -} - -.bi-wifi-1::before { - content: "\f619"; -} - -.bi-wifi-2::before { - content: "\f61a"; -} - -.bi-wifi-off::before { - content: "\f61b"; -} - -.bi-wifi::before { - content: "\f61c"; -} - -.bi-wind::before { - content: "\f61d"; -} - -.bi-window-dock::before { - content: "\f61e"; -} - -.bi-window-sidebar::before { - content: "\f61f"; -} - -.bi-window::before { - content: "\f620"; -} - -.bi-wrench::before { - content: "\f621"; -} - -.bi-x-circle-fill::before { - content: "\f622"; -} - -.bi-x-circle::before { - content: "\f623"; -} - -.bi-x-diamond-fill::before { - content: "\f624"; -} - -.bi-x-diamond::before { - content: "\f625"; -} - -.bi-x-octagon-fill::before { - content: "\f626"; -} - -.bi-x-octagon::before { - content: "\f627"; -} - -.bi-x-square-fill::before { - content: "\f628"; -} - -.bi-x-square::before { - content: "\f629"; -} - -.bi-x::before { - content: "\f62a"; -} - -.bi-youtube::before { - content: "\f62b"; -} - -.bi-zoom-in::before { - content: "\f62c"; -} - -.bi-zoom-out::before { - content: "\f62d"; -} - -.bi-bank::before { - content: "\f62e"; -} - -.bi-bank2::before { - content: "\f62f"; -} - -.bi-bell-slash-fill::before { - content: "\f630"; -} - -.bi-bell-slash::before { - content: "\f631"; -} - -.bi-cash-coin::before { - content: "\f632"; -} - -.bi-check-lg::before { - content: "\f633"; -} - -.bi-coin::before { - content: "\f634"; -} - -.bi-currency-bitcoin::before { - content: "\f635"; -} - -.bi-currency-dollar::before { - content: "\f636"; -} - -.bi-currency-euro::before { - content: "\f637"; -} - -.bi-currency-exchange::before { - content: "\f638"; -} - -.bi-currency-pound::before { - content: "\f639"; -} - -.bi-currency-yen::before { - content: "\f63a"; -} - -.bi-dash-lg::before { - content: "\f63b"; -} - -.bi-exclamation-lg::before { - content: "\f63c"; -} - -.bi-file-earmark-pdf-fill::before { - content: "\f63d"; -} - -.bi-file-earmark-pdf::before { - content: "\f63e"; -} - -.bi-file-pdf-fill::before { - content: "\f63f"; -} - -.bi-file-pdf::before { - content: "\f640"; -} - -.bi-gender-ambiguous::before { - content: "\f641"; -} - -.bi-gender-female::before { - content: "\f642"; -} - -.bi-gender-male::before { - content: "\f643"; -} - -.bi-gender-trans::before { - content: "\f644"; -} - -.bi-headset-vr::before { - content: "\f645"; -} - -.bi-info-lg::before { - content: "\f646"; -} - -.bi-mastodon::before { - content: "\f647"; -} - -.bi-messenger::before { - content: "\f648"; -} - -.bi-piggy-bank-fill::before { - content: "\f649"; -} - -.bi-piggy-bank::before { - content: "\f64a"; -} - -.bi-pin-map-fill::before { - content: "\f64b"; -} - -.bi-pin-map::before { - content: "\f64c"; -} - -.bi-plus-lg::before { - content: "\f64d"; -} - -.bi-question-lg::before { - content: "\f64e"; -} - -.bi-recycle::before { - content: "\f64f"; -} - -.bi-reddit::before { - content: "\f650"; -} - -.bi-safe-fill::before { - content: "\f651"; -} - -.bi-safe2-fill::before { - content: "\f652"; -} - -.bi-safe2::before { - content: "\f653"; -} - -.bi-sd-card-fill::before { - content: "\f654"; -} - -.bi-sd-card::before { - content: "\f655"; -} - -.bi-skype::before { - content: "\f656"; -} - -.bi-slash-lg::before { - content: "\f657"; -} - -.bi-translate::before { - content: "\f658"; -} - -.bi-x-lg::before { - content: "\f659"; -} - -.bi-safe::before { - content: "\f65a"; -} - -.bi-apple::before { - content: "\f65b"; -} - -.bi-microsoft::before { - content: "\f65d"; -} - -.bi-windows::before { - content: "\f65e"; -} - -.bi-behance::before { - content: "\f65c"; -} - -.bi-dribbble::before { - content: "\f65f"; -} - -.bi-line::before { - content: "\f660"; -} - -.bi-medium::before { - content: "\f661"; -} - -.bi-paypal::before { - content: "\f662"; -} - -.bi-pinterest::before { - content: "\f663"; -} - -.bi-signal::before { - content: "\f664"; -} - -.bi-snapchat::before { - content: "\f665"; -} - -.bi-spotify::before { - content: "\f666"; -} - -.bi-stack-overflow::before { - content: "\f667"; -} - -.bi-strava::before { - content: "\f668"; -} - -.bi-wordpress::before { - content: "\f669"; -} - -.bi-vimeo::before { - content: "\f66a"; -} - -.bi-activity::before { - content: "\f66b"; -} - -.bi-easel2-fill::before { - content: "\f66c"; -} - -.bi-easel2::before { - content: "\f66d"; -} - -.bi-easel3-fill::before { - content: "\f66e"; -} - -.bi-easel3::before { - content: "\f66f"; -} - -.bi-fan::before { - content: "\f670"; -} - -.bi-fingerprint::before { - content: "\f671"; -} - -.bi-graph-down-arrow::before { - content: "\f672"; -} - -.bi-graph-up-arrow::before { - content: "\f673"; -} - -.bi-hypnotize::before { - content: "\f674"; -} - -.bi-magic::before { - content: "\f675"; -} - -.bi-person-rolodex::before { - content: "\f676"; -} - -.bi-person-video::before { - content: "\f677"; -} - -.bi-person-video2::before { - content: "\f678"; -} - -.bi-person-video3::before { - content: "\f679"; -} - -.bi-person-workspace::before { - content: "\f67a"; -} - -.bi-radioactive::before { - content: "\f67b"; -} - -.bi-webcam-fill::before { - content: "\f67c"; -} - -.bi-webcam::before { - content: "\f67d"; -} - -.bi-yin-yang::before { - content: "\f67e"; -} - -.bi-bandaid-fill::before { - content: "\f680"; -} - -.bi-bandaid::before { - content: "\f681"; -} - -.bi-bluetooth::before { - content: "\f682"; -} - -.bi-body-text::before { - content: "\f683"; -} - -.bi-boombox::before { - content: "\f684"; -} - -.bi-boxes::before { - content: "\f685"; -} - -.bi-dpad-fill::before { - content: "\f686"; -} - -.bi-dpad::before { - content: "\f687"; -} - -.bi-ear-fill::before { - content: "\f688"; -} - -.bi-ear::before { - content: "\f689"; -} - -.bi-envelope-check-fill::before { - content: "\f68b"; -} - -.bi-envelope-check::before { - content: "\f68c"; -} - -.bi-envelope-dash-fill::before { - content: "\f68e"; -} - -.bi-envelope-dash::before { - content: "\f68f"; -} - -.bi-envelope-exclamation-fill::before { - content: "\f691"; -} - -.bi-envelope-exclamation::before { - content: "\f692"; -} - -.bi-envelope-plus-fill::before { - content: "\f693"; -} - -.bi-envelope-plus::before { - content: "\f694"; -} - -.bi-envelope-slash-fill::before { - content: "\f696"; -} - -.bi-envelope-slash::before { - content: "\f697"; -} - -.bi-envelope-x-fill::before { - content: "\f699"; -} - -.bi-envelope-x::before { - content: "\f69a"; -} - -.bi-explicit-fill::before { - content: "\f69b"; -} - -.bi-explicit::before { - content: "\f69c"; -} - -.bi-git::before { - content: "\f69d"; -} - -.bi-infinity::before { - content: "\f69e"; -} - -.bi-list-columns-reverse::before { - content: "\f69f"; -} - -.bi-list-columns::before { - content: "\f6a0"; -} - -.bi-meta::before { - content: "\f6a1"; -} - -.bi-nintendo-switch::before { - content: "\f6a4"; -} - -.bi-pc-display-horizontal::before { - content: "\f6a5"; -} - -.bi-pc-display::before { - content: "\f6a6"; -} - -.bi-pc-horizontal::before { - content: "\f6a7"; -} - -.bi-pc::before { - content: "\f6a8"; -} - -.bi-playstation::before { - content: "\f6a9"; -} - -.bi-plus-slash-minus::before { - content: "\f6aa"; -} - -.bi-projector-fill::before { - content: "\f6ab"; -} - -.bi-projector::before { - content: "\f6ac"; -} - -.bi-qr-code-scan::before { - content: "\f6ad"; -} - -.bi-qr-code::before { - content: "\f6ae"; -} - -.bi-quora::before { - content: "\f6af"; -} - -.bi-quote::before { - content: "\f6b0"; -} - -.bi-robot::before { - content: "\f6b1"; -} - -.bi-send-check-fill::before { - content: "\f6b2"; -} - -.bi-send-check::before { - content: "\f6b3"; -} - -.bi-send-dash-fill::before { - content: "\f6b4"; -} - -.bi-send-dash::before { - content: "\f6b5"; -} - -.bi-send-exclamation-fill::before { - content: "\f6b7"; -} - -.bi-send-exclamation::before { - content: "\f6b8"; -} - -.bi-send-fill::before { - content: "\f6b9"; -} - -.bi-send-plus-fill::before { - content: "\f6ba"; -} - -.bi-send-plus::before { - content: "\f6bb"; -} - -.bi-send-slash-fill::before { - content: "\f6bc"; -} - -.bi-send-slash::before { - content: "\f6bd"; -} - -.bi-send-x-fill::before { - content: "\f6be"; -} - -.bi-send-x::before { - content: "\f6bf"; -} - -.bi-send::before { - content: "\f6c0"; -} - -.bi-steam::before { - content: "\f6c1"; -} - -.bi-terminal-dash::before { - content: "\f6c3"; -} - -.bi-terminal-plus::before { - content: "\f6c4"; -} - -.bi-terminal-split::before { - content: "\f6c5"; -} - -.bi-ticket-detailed-fill::before { - content: "\f6c6"; -} - -.bi-ticket-detailed::before { - content: "\f6c7"; -} - -.bi-ticket-fill::before { - content: "\f6c8"; -} - -.bi-ticket-perforated-fill::before { - content: "\f6c9"; -} - -.bi-ticket-perforated::before { - content: "\f6ca"; -} - -.bi-ticket::before { - content: "\f6cb"; -} - -.bi-tiktok::before { - content: "\f6cc"; -} - -.bi-window-dash::before { - content: "\f6cd"; -} - -.bi-window-desktop::before { - content: "\f6ce"; -} - -.bi-window-fullscreen::before { - content: "\f6cf"; -} - -.bi-window-plus::before { - content: "\f6d0"; -} - -.bi-window-split::before { - content: "\f6d1"; -} - -.bi-window-stack::before { - content: "\f6d2"; -} - -.bi-window-x::before { - content: "\f6d3"; -} - -.bi-xbox::before { - content: "\f6d4"; -} - -.bi-ethernet::before { - content: "\f6d5"; -} - -.bi-hdmi-fill::before { - content: "\f6d6"; -} - -.bi-hdmi::before { - content: "\f6d7"; -} - -.bi-usb-c-fill::before { - content: "\f6d8"; -} - -.bi-usb-c::before { - content: "\f6d9"; -} - -.bi-usb-fill::before { - content: "\f6da"; -} - -.bi-usb-plug-fill::before { - content: "\f6db"; -} - -.bi-usb-plug::before { - content: "\f6dc"; -} - -.bi-usb-symbol::before { - content: "\f6dd"; -} - -.bi-usb::before { - content: "\f6de"; -} - -.bi-boombox-fill::before { - content: "\f6df"; -} - -.bi-displayport::before { - content: "\f6e1"; -} - -.bi-gpu-card::before { - content: "\f6e2"; -} - -.bi-memory::before { - content: "\f6e3"; -} - -.bi-modem-fill::before { - content: "\f6e4"; -} - -.bi-modem::before { - content: "\f6e5"; -} - -.bi-motherboard-fill::before { - content: "\f6e6"; -} - -.bi-motherboard::before { - content: "\f6e7"; -} - -.bi-optical-audio-fill::before { - content: "\f6e8"; -} - -.bi-optical-audio::before { - content: "\f6e9"; -} - -.bi-pci-card::before { - content: "\f6ea"; -} - -.bi-router-fill::before { - content: "\f6eb"; -} - -.bi-router::before { - content: "\f6ec"; -} - -.bi-thunderbolt-fill::before { - content: "\f6ef"; -} - -.bi-thunderbolt::before { - content: "\f6f0"; -} - -.bi-usb-drive-fill::before { - content: "\f6f1"; -} - -.bi-usb-drive::before { - content: "\f6f2"; -} - -.bi-usb-micro-fill::before { - content: "\f6f3"; -} - -.bi-usb-micro::before { - content: "\f6f4"; -} - -.bi-usb-mini-fill::before { - content: "\f6f5"; -} - -.bi-usb-mini::before { - content: "\f6f6"; -} - -.bi-cloud-haze2::before { - content: "\f6f7"; -} - -.bi-device-hdd-fill::before { - content: "\f6f8"; -} - -.bi-device-hdd::before { - content: "\f6f9"; -} - -.bi-device-ssd-fill::before { - content: "\f6fa"; -} - -.bi-device-ssd::before { - content: "\f6fb"; -} - -.bi-displayport-fill::before { - content: "\f6fc"; -} - -.bi-mortarboard-fill::before { - content: "\f6fd"; -} - -.bi-mortarboard::before { - content: "\f6fe"; -} - -.bi-terminal-x::before { - content: "\f6ff"; -} - -.bi-arrow-through-heart-fill::before { - content: "\f700"; -} - -.bi-arrow-through-heart::before { - content: "\f701"; -} - -.bi-badge-sd-fill::before { - content: "\f702"; -} - -.bi-badge-sd::before { - content: "\f703"; -} - -.bi-bag-heart-fill::before { - content: "\f704"; -} - -.bi-bag-heart::before { - content: "\f705"; -} - -.bi-balloon-fill::before { - content: "\f706"; -} - -.bi-balloon-heart-fill::before { - content: "\f707"; -} - -.bi-balloon-heart::before { - content: "\f708"; -} - -.bi-balloon::before { - content: "\f709"; -} - -.bi-box2-fill::before { - content: "\f70a"; -} - -.bi-box2-heart-fill::before { - content: "\f70b"; -} - -.bi-box2-heart::before { - content: "\f70c"; -} - -.bi-box2::before { - content: "\f70d"; -} - -.bi-braces-asterisk::before { - content: "\f70e"; -} - -.bi-calendar-heart-fill::before { - content: "\f70f"; -} - -.bi-calendar-heart::before { - content: "\f710"; -} - -.bi-calendar2-heart-fill::before { - content: "\f711"; -} - -.bi-calendar2-heart::before { - content: "\f712"; -} - -.bi-chat-heart-fill::before { - content: "\f713"; -} - -.bi-chat-heart::before { - content: "\f714"; -} - -.bi-chat-left-heart-fill::before { - content: "\f715"; -} - -.bi-chat-left-heart::before { - content: "\f716"; -} - -.bi-chat-right-heart-fill::before { - content: "\f717"; -} - -.bi-chat-right-heart::before { - content: "\f718"; -} - -.bi-chat-square-heart-fill::before { - content: "\f719"; -} - -.bi-chat-square-heart::before { - content: "\f71a"; -} - -.bi-clipboard-check-fill::before { - content: "\f71b"; -} - -.bi-clipboard-data-fill::before { - content: "\f71c"; -} - -.bi-clipboard-fill::before { - content: "\f71d"; -} - -.bi-clipboard-heart-fill::before { - content: "\f71e"; -} - -.bi-clipboard-heart::before { - content: "\f71f"; -} - -.bi-clipboard-minus-fill::before { - content: "\f720"; -} - -.bi-clipboard-plus-fill::before { - content: "\f721"; -} - -.bi-clipboard-pulse::before { - content: "\f722"; -} - -.bi-clipboard-x-fill::before { - content: "\f723"; -} - -.bi-clipboard2-check-fill::before { - content: "\f724"; -} - -.bi-clipboard2-check::before { - content: "\f725"; -} - -.bi-clipboard2-data-fill::before { - content: "\f726"; -} - -.bi-clipboard2-data::before { - content: "\f727"; -} - -.bi-clipboard2-fill::before { - content: "\f728"; -} - -.bi-clipboard2-heart-fill::before { - content: "\f729"; -} - -.bi-clipboard2-heart::before { - content: "\f72a"; -} - -.bi-clipboard2-minus-fill::before { - content: "\f72b"; -} - -.bi-clipboard2-minus::before { - content: "\f72c"; -} - -.bi-clipboard2-plus-fill::before { - content: "\f72d"; -} - -.bi-clipboard2-plus::before { - content: "\f72e"; -} - -.bi-clipboard2-pulse-fill::before { - content: "\f72f"; -} - -.bi-clipboard2-pulse::before { - content: "\f730"; -} - -.bi-clipboard2-x-fill::before { - content: "\f731"; -} - -.bi-clipboard2-x::before { - content: "\f732"; -} - -.bi-clipboard2::before { - content: "\f733"; -} - -.bi-emoji-kiss-fill::before { - content: "\f734"; -} - -.bi-emoji-kiss::before { - content: "\f735"; -} - -.bi-envelope-heart-fill::before { - content: "\f736"; -} - -.bi-envelope-heart::before { - content: "\f737"; -} - -.bi-envelope-open-heart-fill::before { - content: "\f738"; -} - -.bi-envelope-open-heart::before { - content: "\f739"; -} - -.bi-envelope-paper-fill::before { - content: "\f73a"; -} - -.bi-envelope-paper-heart-fill::before { - content: "\f73b"; -} - -.bi-envelope-paper-heart::before { - content: "\f73c"; -} - -.bi-envelope-paper::before { - content: "\f73d"; -} - -.bi-filetype-aac::before { - content: "\f73e"; -} - -.bi-filetype-ai::before { - content: "\f73f"; -} - -.bi-filetype-bmp::before { - content: "\f740"; -} - -.bi-filetype-cs::before { - content: "\f741"; -} - -.bi-filetype-css::before { - content: "\f742"; -} - -.bi-filetype-csv::before { - content: "\f743"; -} - -.bi-filetype-doc::before { - content: "\f744"; -} - -.bi-filetype-docx::before { - content: "\f745"; -} - -.bi-filetype-exe::before { - content: "\f746"; -} - -.bi-filetype-gif::before { - content: "\f747"; -} - -.bi-filetype-heic::before { - content: "\f748"; -} - -.bi-filetype-html::before { - content: "\f749"; -} - -.bi-filetype-java::before { - content: "\f74a"; -} - -.bi-filetype-jpg::before { - content: "\f74b"; -} - -.bi-filetype-js::before { - content: "\f74c"; -} - -.bi-filetype-jsx::before { - content: "\f74d"; -} - -.bi-filetype-key::before { - content: "\f74e"; -} - -.bi-filetype-m4p::before { - content: "\f74f"; -} - -.bi-filetype-md::before { - content: "\f750"; -} - -.bi-filetype-mdx::before { - content: "\f751"; -} - -.bi-filetype-mov::before { - content: "\f752"; -} - -.bi-filetype-mp3::before { - content: "\f753"; -} - -.bi-filetype-mp4::before { - content: "\f754"; -} - -.bi-filetype-otf::before { - content: "\f755"; -} - -.bi-filetype-pdf::before { - content: "\f756"; -} - -.bi-filetype-php::before { - content: "\f757"; -} - -.bi-filetype-png::before { - content: "\f758"; -} - -.bi-filetype-ppt::before { - content: "\f75a"; -} - -.bi-filetype-psd::before { - content: "\f75b"; -} - -.bi-filetype-py::before { - content: "\f75c"; -} - -.bi-filetype-raw::before { - content: "\f75d"; -} - -.bi-filetype-rb::before { - content: "\f75e"; -} - -.bi-filetype-sass::before { - content: "\f75f"; -} - -.bi-filetype-scss::before { - content: "\f760"; -} - -.bi-filetype-sh::before { - content: "\f761"; -} - -.bi-filetype-svg::before { - content: "\f762"; -} - -.bi-filetype-tiff::before { - content: "\f763"; -} - -.bi-filetype-tsx::before { - content: "\f764"; -} - -.bi-filetype-ttf::before { - content: "\f765"; -} - -.bi-filetype-txt::before { - content: "\f766"; -} - -.bi-filetype-wav::before { - content: "\f767"; -} - -.bi-filetype-woff::before { - content: "\f768"; -} - -.bi-filetype-xls::before { - content: "\f76a"; -} - -.bi-filetype-xml::before { - content: "\f76b"; -} - -.bi-filetype-yml::before { - content: "\f76c"; -} - -.bi-heart-arrow::before { - content: "\f76d"; -} - -.bi-heart-pulse-fill::before { - content: "\f76e"; -} - -.bi-heart-pulse::before { - content: "\f76f"; -} - -.bi-heartbreak-fill::before { - content: "\f770"; -} - -.bi-heartbreak::before { - content: "\f771"; -} - -.bi-hearts::before { - content: "\f772"; -} - -.bi-hospital-fill::before { - content: "\f773"; -} - -.bi-hospital::before { - content: "\f774"; -} - -.bi-house-heart-fill::before { - content: "\f775"; -} - -.bi-house-heart::before { - content: "\f776"; -} - -.bi-incognito::before { - content: "\f777"; -} - -.bi-magnet-fill::before { - content: "\f778"; -} - -.bi-magnet::before { - content: "\f779"; -} - -.bi-person-heart::before { - content: "\f77a"; -} - -.bi-person-hearts::before { - content: "\f77b"; -} - -.bi-phone-flip::before { - content: "\f77c"; -} - -.bi-plugin::before { - content: "\f77d"; -} - -.bi-postage-fill::before { - content: "\f77e"; -} - -.bi-postage-heart-fill::before { - content: "\f77f"; -} - -.bi-postage-heart::before { - content: "\f780"; -} - -.bi-postage::before { - content: "\f781"; -} - -.bi-postcard-fill::before { - content: "\f782"; -} - -.bi-postcard-heart-fill::before { - content: "\f783"; -} - -.bi-postcard-heart::before { - content: "\f784"; -} - -.bi-postcard::before { - content: "\f785"; -} - -.bi-search-heart-fill::before { - content: "\f786"; -} - -.bi-search-heart::before { - content: "\f787"; -} - -.bi-sliders2-vertical::before { - content: "\f788"; -} - -.bi-sliders2::before { - content: "\f789"; -} - -.bi-trash3-fill::before { - content: "\f78a"; -} - -.bi-trash3::before { - content: "\f78b"; -} - -.bi-valentine::before { - content: "\f78c"; -} - -.bi-valentine2::before { - content: "\f78d"; -} - -.bi-wrench-adjustable-circle-fill::before { - content: "\f78e"; -} - -.bi-wrench-adjustable-circle::before { - content: "\f78f"; -} - -.bi-wrench-adjustable::before { - content: "\f790"; -} - -.bi-filetype-json::before { - content: "\f791"; -} - -.bi-filetype-pptx::before { - content: "\f792"; -} - -.bi-filetype-xlsx::before { - content: "\f793"; -} - -.bi-1-circle-fill::before { - content: "\f796"; -} - -.bi-1-circle::before { - content: "\f797"; -} - -.bi-1-square-fill::before { - content: "\f798"; -} - -.bi-1-square::before { - content: "\f799"; -} - -.bi-2-circle-fill::before { - content: "\f79c"; -} - -.bi-2-circle::before { - content: "\f79d"; -} - -.bi-2-square-fill::before { - content: "\f79e"; -} - -.bi-2-square::before { - content: "\f79f"; -} - -.bi-3-circle-fill::before { - content: "\f7a2"; -} - -.bi-3-circle::before { - content: "\f7a3"; -} - -.bi-3-square-fill::before { - content: "\f7a4"; -} - -.bi-3-square::before { - content: "\f7a5"; -} - -.bi-4-circle-fill::before { - content: "\f7a8"; -} - -.bi-4-circle::before { - content: "\f7a9"; -} - -.bi-4-square-fill::before { - content: "\f7aa"; -} - -.bi-4-square::before { - content: "\f7ab"; -} - -.bi-5-circle-fill::before { - content: "\f7ae"; -} - -.bi-5-circle::before { - content: "\f7af"; -} - -.bi-5-square-fill::before { - content: "\f7b0"; -} - -.bi-5-square::before { - content: "\f7b1"; -} - -.bi-6-circle-fill::before { - content: "\f7b4"; -} - -.bi-6-circle::before { - content: "\f7b5"; -} - -.bi-6-square-fill::before { - content: "\f7b6"; -} - -.bi-6-square::before { - content: "\f7b7"; -} - -.bi-7-circle-fill::before { - content: "\f7ba"; -} - -.bi-7-circle::before { - content: "\f7bb"; -} - -.bi-7-square-fill::before { - content: "\f7bc"; -} - -.bi-7-square::before { - content: "\f7bd"; -} - -.bi-8-circle-fill::before { - content: "\f7c0"; -} - -.bi-8-circle::before { - content: "\f7c1"; -} - -.bi-8-square-fill::before { - content: "\f7c2"; -} - -.bi-8-square::before { - content: "\f7c3"; -} - -.bi-9-circle-fill::before { - content: "\f7c6"; -} - -.bi-9-circle::before { - content: "\f7c7"; -} - -.bi-9-square-fill::before { - content: "\f7c8"; -} - -.bi-9-square::before { - content: "\f7c9"; -} - -.bi-airplane-engines-fill::before { - content: "\f7ca"; -} - -.bi-airplane-engines::before { - content: "\f7cb"; -} - -.bi-airplane-fill::before { - content: "\f7cc"; -} - -.bi-airplane::before { - content: "\f7cd"; -} - -.bi-alexa::before { - content: "\f7ce"; -} - -.bi-alipay::before { - content: "\f7cf"; -} - -.bi-android::before { - content: "\f7d0"; -} - -.bi-android2::before { - content: "\f7d1"; -} - -.bi-box-fill::before { - content: "\f7d2"; -} - -.bi-box-seam-fill::before { - content: "\f7d3"; -} - -.bi-browser-chrome::before { - content: "\f7d4"; -} - -.bi-browser-edge::before { - content: "\f7d5"; -} - -.bi-browser-firefox::before { - content: "\f7d6"; -} - -.bi-browser-safari::before { - content: "\f7d7"; -} - -.bi-c-circle-fill::before { - content: "\f7da"; -} - -.bi-c-circle::before { - content: "\f7db"; -} - -.bi-c-square-fill::before { - content: "\f7dc"; -} - -.bi-c-square::before { - content: "\f7dd"; -} - -.bi-capsule-pill::before { - content: "\f7de"; -} - -.bi-capsule::before { - content: "\f7df"; -} - -.bi-car-front-fill::before { - content: "\f7e0"; -} - -.bi-car-front::before { - content: "\f7e1"; -} - -.bi-cassette-fill::before { - content: "\f7e2"; -} - -.bi-cassette::before { - content: "\f7e3"; -} - -.bi-cc-circle-fill::before { - content: "\f7e6"; -} - -.bi-cc-circle::before { - content: "\f7e7"; -} - -.bi-cc-square-fill::before { - content: "\f7e8"; -} - -.bi-cc-square::before { - content: "\f7e9"; -} - -.bi-cup-hot-fill::before { - content: "\f7ea"; -} - -.bi-cup-hot::before { - content: "\f7eb"; -} - -.bi-currency-rupee::before { - content: "\f7ec"; -} - -.bi-dropbox::before { - content: "\f7ed"; -} - -.bi-escape::before { - content: "\f7ee"; -} - -.bi-fast-forward-btn-fill::before { - content: "\f7ef"; -} - -.bi-fast-forward-btn::before { - content: "\f7f0"; -} - -.bi-fast-forward-circle-fill::before { - content: "\f7f1"; -} - -.bi-fast-forward-circle::before { - content: "\f7f2"; -} - -.bi-fast-forward-fill::before { - content: "\f7f3"; -} - -.bi-fast-forward::before { - content: "\f7f4"; -} - -.bi-filetype-sql::before { - content: "\f7f5"; -} - -.bi-fire::before { - content: "\f7f6"; -} - -.bi-google-play::before { - content: "\f7f7"; -} - -.bi-h-circle-fill::before { - content: "\f7fa"; -} - -.bi-h-circle::before { - content: "\f7fb"; -} - -.bi-h-square-fill::before { - content: "\f7fc"; -} - -.bi-h-square::before { - content: "\f7fd"; -} - -.bi-indent::before { - content: "\f7fe"; -} - -.bi-lungs-fill::before { - content: "\f7ff"; -} - -.bi-lungs::before { - content: "\f800"; -} - -.bi-microsoft-teams::before { - content: "\f801"; -} - -.bi-p-circle-fill::before { - content: "\f804"; -} - -.bi-p-circle::before { - content: "\f805"; -} - -.bi-p-square-fill::before { - content: "\f806"; -} - -.bi-p-square::before { - content: "\f807"; -} - -.bi-pass-fill::before { - content: "\f808"; -} - -.bi-pass::before { - content: "\f809"; -} - -.bi-prescription::before { - content: "\f80a"; -} - -.bi-prescription2::before { - content: "\f80b"; -} - -.bi-r-circle-fill::before { - content: "\f80e"; -} - -.bi-r-circle::before { - content: "\f80f"; -} - -.bi-r-square-fill::before { - content: "\f810"; -} - -.bi-r-square::before { - content: "\f811"; -} - -.bi-repeat-1::before { - content: "\f812"; -} - -.bi-repeat::before { - content: "\f813"; -} - -.bi-rewind-btn-fill::before { - content: "\f814"; -} - -.bi-rewind-btn::before { - content: "\f815"; -} - -.bi-rewind-circle-fill::before { - content: "\f816"; -} - -.bi-rewind-circle::before { - content: "\f817"; -} - -.bi-rewind-fill::before { - content: "\f818"; -} - -.bi-rewind::before { - content: "\f819"; -} - -.bi-train-freight-front-fill::before { - content: "\f81a"; -} - -.bi-train-freight-front::before { - content: "\f81b"; -} - -.bi-train-front-fill::before { - content: "\f81c"; -} - -.bi-train-front::before { - content: "\f81d"; -} - -.bi-train-lightrail-front-fill::before { - content: "\f81e"; -} - -.bi-train-lightrail-front::before { - content: "\f81f"; -} - -.bi-truck-front-fill::before { - content: "\f820"; -} - -.bi-truck-front::before { - content: "\f821"; -} - -.bi-ubuntu::before { - content: "\f822"; -} - -.bi-unindent::before { - content: "\f823"; -} - -.bi-unity::before { - content: "\f824"; -} - -.bi-universal-access-circle::before { - content: "\f825"; -} - -.bi-universal-access::before { - content: "\f826"; -} - -.bi-virus::before { - content: "\f827"; -} - -.bi-virus2::before { - content: "\f828"; -} - -.bi-wechat::before { - content: "\f829"; -} - -.bi-yelp::before { - content: "\f82a"; -} - -.bi-sign-stop-fill::before { - content: "\f82b"; -} - -.bi-sign-stop-lights-fill::before { - content: "\f82c"; -} - -.bi-sign-stop-lights::before { - content: "\f82d"; -} - -.bi-sign-stop::before { - content: "\f82e"; -} - -.bi-sign-turn-left-fill::before { - content: "\f82f"; -} - -.bi-sign-turn-left::before { - content: "\f830"; -} - -.bi-sign-turn-right-fill::before { - content: "\f831"; -} - -.bi-sign-turn-right::before { - content: "\f832"; -} - -.bi-sign-turn-slight-left-fill::before { - content: "\f833"; -} - -.bi-sign-turn-slight-left::before { - content: "\f834"; -} - -.bi-sign-turn-slight-right-fill::before { - content: "\f835"; -} - -.bi-sign-turn-slight-right::before { - content: "\f836"; -} - -.bi-sign-yield-fill::before { - content: "\f837"; -} - -.bi-sign-yield::before { - content: "\f838"; -} - -.bi-ev-station-fill::before { - content: "\f839"; -} - -.bi-ev-station::before { - content: "\f83a"; -} - -.bi-fuel-pump-diesel-fill::before { - content: "\f83b"; -} - -.bi-fuel-pump-diesel::before { - content: "\f83c"; -} - -.bi-fuel-pump-fill::before { - content: "\f83d"; -} - -.bi-fuel-pump::before { - content: "\f83e"; -} - -.bi-0-circle-fill::before { - content: "\f83f"; -} - -.bi-0-circle::before { - content: "\f840"; -} - -.bi-0-square-fill::before { - content: "\f841"; -} - -.bi-0-square::before { - content: "\f842"; -} - -.bi-rocket-fill::before { - content: "\f843"; -} - -.bi-rocket-takeoff-fill::before { - content: "\f844"; -} - -.bi-rocket-takeoff::before { - content: "\f845"; -} - -.bi-rocket::before { - content: "\f846"; -} - -.bi-stripe::before { - content: "\f847"; -} - -.bi-subscript::before { - content: "\f848"; -} - -.bi-superscript::before { - content: "\f849"; -} - -.bi-trello::before { - content: "\f84a"; -} - -.bi-envelope-at-fill::before { - content: "\f84b"; -} - -.bi-envelope-at::before { - content: "\f84c"; -} - -.bi-regex::before { - content: "\f84d"; -} - -.bi-text-wrap::before { - content: "\f84e"; -} - -.bi-sign-dead-end-fill::before { - content: "\f84f"; -} - -.bi-sign-dead-end::before { - content: "\f850"; -} - -.bi-sign-do-not-enter-fill::before { - content: "\f851"; -} - -.bi-sign-do-not-enter::before { - content: "\f852"; -} - -.bi-sign-intersection-fill::before { - content: "\f853"; -} - -.bi-sign-intersection-side-fill::before { - content: "\f854"; -} - -.bi-sign-intersection-side::before { - content: "\f855"; -} - -.bi-sign-intersection-t-fill::before { - content: "\f856"; -} - -.bi-sign-intersection-t::before { - content: "\f857"; -} - -.bi-sign-intersection-y-fill::before { - content: "\f858"; -} - -.bi-sign-intersection-y::before { - content: "\f859"; -} - -.bi-sign-intersection::before { - content: "\f85a"; -} - -.bi-sign-merge-left-fill::before { - content: "\f85b"; -} - -.bi-sign-merge-left::before { - content: "\f85c"; -} - -.bi-sign-merge-right-fill::before { - content: "\f85d"; -} - -.bi-sign-merge-right::before { - content: "\f85e"; -} - -.bi-sign-no-left-turn-fill::before { - content: "\f85f"; -} - -.bi-sign-no-left-turn::before { - content: "\f860"; -} - -.bi-sign-no-parking-fill::before { - content: "\f861"; -} - -.bi-sign-no-parking::before { - content: "\f862"; -} - -.bi-sign-no-right-turn-fill::before { - content: "\f863"; -} - -.bi-sign-no-right-turn::before { - content: "\f864"; -} - -.bi-sign-railroad-fill::before { - content: "\f865"; -} - -.bi-sign-railroad::before { - content: "\f866"; -} - -.bi-building-add::before { - content: "\f867"; -} - -.bi-building-check::before { - content: "\f868"; -} - -.bi-building-dash::before { - content: "\f869"; -} - -.bi-building-down::before { - content: "\f86a"; -} - -.bi-building-exclamation::before { - content: "\f86b"; -} - -.bi-building-fill-add::before { - content: "\f86c"; -} - -.bi-building-fill-check::before { - content: "\f86d"; -} - -.bi-building-fill-dash::before { - content: "\f86e"; -} - -.bi-building-fill-down::before { - content: "\f86f"; -} - -.bi-building-fill-exclamation::before { - content: "\f870"; -} - -.bi-building-fill-gear::before { - content: "\f871"; -} - -.bi-building-fill-lock::before { - content: "\f872"; -} - -.bi-building-fill-slash::before { - content: "\f873"; -} - -.bi-building-fill-up::before { - content: "\f874"; -} - -.bi-building-fill-x::before { - content: "\f875"; -} - -.bi-building-fill::before { - content: "\f876"; -} - -.bi-building-gear::before { - content: "\f877"; -} - -.bi-building-lock::before { - content: "\f878"; -} - -.bi-building-slash::before { - content: "\f879"; -} - -.bi-building-up::before { - content: "\f87a"; -} - -.bi-building-x::before { - content: "\f87b"; -} - -.bi-buildings-fill::before { - content: "\f87c"; -} - -.bi-buildings::before { - content: "\f87d"; -} - -.bi-bus-front-fill::before { - content: "\f87e"; -} - -.bi-bus-front::before { - content: "\f87f"; -} - -.bi-ev-front-fill::before { - content: "\f880"; -} - -.bi-ev-front::before { - content: "\f881"; -} - -.bi-globe-americas::before { - content: "\f882"; -} - -.bi-globe-asia-australia::before { - content: "\f883"; -} - -.bi-globe-central-south-asia::before { - content: "\f884"; -} - -.bi-globe-europe-africa::before { - content: "\f885"; -} - -.bi-house-add-fill::before { - content: "\f886"; -} - -.bi-house-add::before { - content: "\f887"; -} - -.bi-house-check-fill::before { - content: "\f888"; -} - -.bi-house-check::before { - content: "\f889"; -} - -.bi-house-dash-fill::before { - content: "\f88a"; -} - -.bi-house-dash::before { - content: "\f88b"; -} - -.bi-house-down-fill::before { - content: "\f88c"; -} - -.bi-house-down::before { - content: "\f88d"; -} - -.bi-house-exclamation-fill::before { - content: "\f88e"; -} - -.bi-house-exclamation::before { - content: "\f88f"; -} - -.bi-house-gear-fill::before { - content: "\f890"; -} - -.bi-house-gear::before { - content: "\f891"; -} - -.bi-house-lock-fill::before { - content: "\f892"; -} - -.bi-house-lock::before { - content: "\f893"; -} - -.bi-house-slash-fill::before { - content: "\f894"; -} - -.bi-house-slash::before { - content: "\f895"; -} - -.bi-house-up-fill::before { - content: "\f896"; -} - -.bi-house-up::before { - content: "\f897"; -} - -.bi-house-x-fill::before { - content: "\f898"; -} - -.bi-house-x::before { - content: "\f899"; -} - -.bi-person-add::before { - content: "\f89a"; -} - -.bi-person-down::before { - content: "\f89b"; -} - -.bi-person-exclamation::before { - content: "\f89c"; -} - -.bi-person-fill-add::before { - content: "\f89d"; -} - -.bi-person-fill-check::before { - content: "\f89e"; -} - -.bi-person-fill-dash::before { - content: "\f89f"; -} - -.bi-person-fill-down::before { - content: "\f8a0"; -} - -.bi-person-fill-exclamation::before { - content: "\f8a1"; -} - -.bi-person-fill-gear::before { - content: "\f8a2"; -} - -.bi-person-fill-lock::before { - content: "\f8a3"; -} - -.bi-person-fill-slash::before { - content: "\f8a4"; -} - -.bi-person-fill-up::before { - content: "\f8a5"; -} - -.bi-person-fill-x::before { - content: "\f8a6"; -} - -.bi-person-gear::before { - content: "\f8a7"; -} - -.bi-person-lock::before { - content: "\f8a8"; -} - -.bi-person-slash::before { - content: "\f8a9"; -} - -.bi-person-up::before { - content: "\f8aa"; -} - -.bi-scooter::before { - content: "\f8ab"; -} - -.bi-taxi-front-fill::before { - content: "\f8ac"; -} - -.bi-taxi-front::before { - content: "\f8ad"; -} - -.bi-amd::before { - content: "\f8ae"; -} - -.bi-database-add::before { - content: "\f8af"; -} - -.bi-database-check::before { - content: "\f8b0"; -} - -.bi-database-dash::before { - content: "\f8b1"; -} - -.bi-database-down::before { - content: "\f8b2"; -} - -.bi-database-exclamation::before { - content: "\f8b3"; -} - -.bi-database-fill-add::before { - content: "\f8b4"; -} - -.bi-database-fill-check::before { - content: "\f8b5"; -} - -.bi-database-fill-dash::before { - content: "\f8b6"; -} - -.bi-database-fill-down::before { - content: "\f8b7"; -} - -.bi-database-fill-exclamation::before { - content: "\f8b8"; -} - -.bi-database-fill-gear::before { - content: "\f8b9"; -} - -.bi-database-fill-lock::before { - content: "\f8ba"; -} - -.bi-database-fill-slash::before { - content: "\f8bb"; -} - -.bi-database-fill-up::before { - content: "\f8bc"; -} - -.bi-database-fill-x::before { - content: "\f8bd"; -} - -.bi-database-fill::before { - content: "\f8be"; -} - -.bi-database-gear::before { - content: "\f8bf"; -} - -.bi-database-lock::before { - content: "\f8c0"; -} - -.bi-database-slash::before { - content: "\f8c1"; -} - -.bi-database-up::before { - content: "\f8c2"; -} - -.bi-database-x::before { - content: "\f8c3"; -} - -.bi-database::before { - content: "\f8c4"; -} - -.bi-houses-fill::before { - content: "\f8c5"; -} - -.bi-houses::before { - content: "\f8c6"; -} - -.bi-nvidia::before { - content: "\f8c7"; -} - -.bi-person-vcard-fill::before { - content: "\f8c8"; -} - -.bi-person-vcard::before { - content: "\f8c9"; -} - -.bi-sina-weibo::before { - content: "\f8ca"; -} - -.bi-tencent-qq::before { - content: "\f8cb"; -} - -.bi-wikipedia::before { - content: "\f8cc"; -} - -.bi-alphabet-uppercase::before { - content: "\f2a5"; -} - -.bi-alphabet::before { - content: "\f68a"; -} - -.bi-amazon::before { - content: "\f68d"; -} - -.bi-arrows-collapse-vertical::before { - content: "\f690"; -} - -.bi-arrows-expand-vertical::before { - content: "\f695"; -} - -.bi-arrows-vertical::before { - content: "\f698"; -} - -.bi-arrows::before { - content: "\f6a2"; -} - -.bi-ban-fill::before { - content: "\f6a3"; -} - -.bi-ban::before { - content: "\f6b6"; -} - -.bi-bing::before { - content: "\f6c2"; -} - -.bi-cake::before { - content: "\f6e0"; -} - -.bi-cake2::before { - content: "\f6ed"; -} - -.bi-cookie::before { - content: "\f6ee"; -} - -.bi-copy::before { - content: "\f759"; -} - -.bi-crosshair::before { - content: "\f769"; -} - -.bi-crosshair2::before { - content: "\f794"; -} - -.bi-emoji-astonished-fill::before { - content: "\f795"; -} - -.bi-emoji-astonished::before { - content: "\f79a"; -} - -.bi-emoji-grimace-fill::before { - content: "\f79b"; -} - -.bi-emoji-grimace::before { - content: "\f7a0"; -} - -.bi-emoji-grin-fill::before { - content: "\f7a1"; -} - -.bi-emoji-grin::before { - content: "\f7a6"; -} - -.bi-emoji-surprise-fill::before { - content: "\f7a7"; -} - -.bi-emoji-surprise::before { - content: "\f7ac"; -} - -.bi-emoji-tear-fill::before { - content: "\f7ad"; -} - -.bi-emoji-tear::before { - content: "\f7b2"; -} - -.bi-envelope-arrow-down-fill::before { - content: "\f7b3"; -} - -.bi-envelope-arrow-down::before { - content: "\f7b8"; -} - -.bi-envelope-arrow-up-fill::before { - content: "\f7b9"; -} - -.bi-envelope-arrow-up::before { - content: "\f7be"; -} - -.bi-feather::before { - content: "\f7bf"; -} - -.bi-feather2::before { - content: "\f7c4"; -} - -.bi-floppy-fill::before { - content: "\f7c5"; -} - -.bi-floppy::before { - content: "\f7d8"; -} - -.bi-floppy2-fill::before { - content: "\f7d9"; -} - -.bi-floppy2::before { - content: "\f7e4"; -} - -.bi-gitlab::before { - content: "\f7e5"; -} - -.bi-highlighter::before { - content: "\f7f8"; -} - -.bi-marker-tip::before { - content: "\f802"; -} - -.bi-nvme-fill::before { - content: "\f803"; -} - -.bi-nvme::before { - content: "\f80c"; -} - -.bi-opencollective::before { - content: "\f80d"; -} - -.bi-pci-card-network::before { - content: "\f8cd"; -} - -.bi-pci-card-sound::before { - content: "\f8ce"; -} - -.bi-radar::before { - content: "\f8cf"; -} - -.bi-send-arrow-down-fill::before { - content: "\f8d0"; -} - -.bi-send-arrow-down::before { - content: "\f8d1"; -} - -.bi-send-arrow-up-fill::before { - content: "\f8d2"; -} - -.bi-send-arrow-up::before { - content: "\f8d3"; -} - -.bi-sim-slash-fill::before { - content: "\f8d4"; -} - -.bi-sim-slash::before { - content: "\f8d5"; -} - -.bi-sourceforge::before { - content: "\f8d6"; -} - -.bi-substack::before { - content: "\f8d7"; -} - -.bi-threads-fill::before { - content: "\f8d8"; -} - -.bi-threads::before { - content: "\f8d9"; -} - -.bi-transparency::before { - content: "\f8da"; -} - -.bi-twitter-x::before { - content: "\f8db"; -} - -.bi-type-h4::before { - content: "\f8dc"; -} - -.bi-type-h5::before { - content: "\f8dd"; -} - -.bi-type-h6::before { - content: "\f8de"; -} - -.bi-backpack-fill::before { - content: "\f8df"; -} - -.bi-backpack::before { - content: "\f8e0"; -} - -.bi-backpack2-fill::before { - content: "\f8e1"; -} - -.bi-backpack2::before { - content: "\f8e2"; -} - -.bi-backpack3-fill::before { - content: "\f8e3"; -} - -.bi-backpack3::before { - content: "\f8e4"; -} - -.bi-backpack4-fill::before { - content: "\f8e5"; -} - -.bi-backpack4::before { - content: "\f8e6"; -} - -.bi-brilliance::before { - content: "\f8e7"; -} - -.bi-cake-fill::before { - content: "\f8e8"; -} - -.bi-cake2-fill::before { - content: "\f8e9"; -} - -.bi-duffle-fill::before { - content: "\f8ea"; -} - -.bi-duffle::before { - content: "\f8eb"; -} - -.bi-exposure::before { - content: "\f8ec"; -} - -.bi-gender-neuter::before { - content: "\f8ed"; -} - -.bi-highlights::before { - content: "\f8ee"; -} - -.bi-luggage-fill::before { - content: "\f8ef"; -} - -.bi-luggage::before { - content: "\f8f0"; -} - -.bi-mailbox-flag::before { - content: "\f8f1"; -} - -.bi-mailbox2-flag::before { - content: "\f8f2"; -} - -.bi-noise-reduction::before { - content: "\f8f3"; -} - -.bi-passport-fill::before { - content: "\f8f4"; -} - -.bi-passport::before { - content: "\f8f5"; -} - -.bi-person-arms-up::before { - content: "\f8f6"; -} - -.bi-person-raised-hand::before { - content: "\f8f7"; -} - -.bi-person-standing-dress::before { - content: "\f8f8"; -} - -.bi-person-standing::before { - content: "\f8f9"; -} - -.bi-person-walking::before { - content: "\f8fa"; -} - -.bi-person-wheelchair::before { - content: "\f8fb"; -} - -.bi-shadows::before { - content: "\f8fc"; -} - -.bi-suitcase-fill::before { - content: "\f8fd"; -} - -.bi-suitcase-lg-fill::before { - content: "\f8fe"; -} - -.bi-suitcase-lg::before { - content: "\f8ff"; -} - -.bi-suitcase::before { - content: "\f900"; -} - -.bi-suitcase2-fill::before { - content: "\f901"; -} - -.bi-suitcase2::before { - content: "\f902"; -} - -.bi-vignette::before { - content: "\f903"; -} diff --git a/static/bootstrap/icons/bootstrap-icons.json b/static/bootstrap/icons/bootstrap-icons.json deleted file mode 100644 index 56247e50..00000000 --- a/static/bootstrap/icons/bootstrap-icons.json +++ /dev/null @@ -1,2052 +0,0 @@ -{ - "123": 63103, - "alarm-fill": 61697, - "alarm": 61698, - "align-bottom": 61699, - "align-center": 61700, - "align-end": 61701, - "align-middle": 61702, - "align-start": 61703, - "align-top": 61704, - "alt": 61705, - "app-indicator": 61706, - "app": 61707, - "archive-fill": 61708, - "archive": 61709, - "arrow-90deg-down": 61710, - "arrow-90deg-left": 61711, - "arrow-90deg-right": 61712, - "arrow-90deg-up": 61713, - "arrow-bar-down": 61714, - "arrow-bar-left": 61715, - "arrow-bar-right": 61716, - "arrow-bar-up": 61717, - "arrow-clockwise": 61718, - "arrow-counterclockwise": 61719, - "arrow-down-circle-fill": 61720, - "arrow-down-circle": 61721, - "arrow-down-left-circle-fill": 61722, - "arrow-down-left-circle": 61723, - "arrow-down-left-square-fill": 61724, - "arrow-down-left-square": 61725, - "arrow-down-left": 61726, - "arrow-down-right-circle-fill": 61727, - "arrow-down-right-circle": 61728, - "arrow-down-right-square-fill": 61729, - "arrow-down-right-square": 61730, - "arrow-down-right": 61731, - "arrow-down-short": 61732, - "arrow-down-square-fill": 61733, - "arrow-down-square": 61734, - "arrow-down-up": 61735, - "arrow-down": 61736, - "arrow-left-circle-fill": 61737, - "arrow-left-circle": 61738, - "arrow-left-right": 61739, - "arrow-left-short": 61740, - "arrow-left-square-fill": 61741, - "arrow-left-square": 61742, - "arrow-left": 61743, - "arrow-repeat": 61744, - "arrow-return-left": 61745, - "arrow-return-right": 61746, - "arrow-right-circle-fill": 61747, - "arrow-right-circle": 61748, - "arrow-right-short": 61749, - "arrow-right-square-fill": 61750, - "arrow-right-square": 61751, - "arrow-right": 61752, - "arrow-up-circle-fill": 61753, - "arrow-up-circle": 61754, - "arrow-up-left-circle-fill": 61755, - "arrow-up-left-circle": 61756, - "arrow-up-left-square-fill": 61757, - "arrow-up-left-square": 61758, - "arrow-up-left": 61759, - "arrow-up-right-circle-fill": 61760, - "arrow-up-right-circle": 61761, - "arrow-up-right-square-fill": 61762, - "arrow-up-right-square": 61763, - "arrow-up-right": 61764, - "arrow-up-short": 61765, - "arrow-up-square-fill": 61766, - "arrow-up-square": 61767, - "arrow-up": 61768, - "arrows-angle-contract": 61769, - "arrows-angle-expand": 61770, - "arrows-collapse": 61771, - "arrows-expand": 61772, - "arrows-fullscreen": 61773, - "arrows-move": 61774, - "aspect-ratio-fill": 61775, - "aspect-ratio": 61776, - "asterisk": 61777, - "at": 61778, - "award-fill": 61779, - "award": 61780, - "back": 61781, - "backspace-fill": 61782, - "backspace-reverse-fill": 61783, - "backspace-reverse": 61784, - "backspace": 61785, - "badge-3d-fill": 61786, - "badge-3d": 61787, - "badge-4k-fill": 61788, - "badge-4k": 61789, - "badge-8k-fill": 61790, - "badge-8k": 61791, - "badge-ad-fill": 61792, - "badge-ad": 61793, - "badge-ar-fill": 61794, - "badge-ar": 61795, - "badge-cc-fill": 61796, - "badge-cc": 61797, - "badge-hd-fill": 61798, - "badge-hd": 61799, - "badge-tm-fill": 61800, - "badge-tm": 61801, - "badge-vo-fill": 61802, - "badge-vo": 61803, - "badge-vr-fill": 61804, - "badge-vr": 61805, - "badge-wc-fill": 61806, - "badge-wc": 61807, - "bag-check-fill": 61808, - "bag-check": 61809, - "bag-dash-fill": 61810, - "bag-dash": 61811, - "bag-fill": 61812, - "bag-plus-fill": 61813, - "bag-plus": 61814, - "bag-x-fill": 61815, - "bag-x": 61816, - "bag": 61817, - "bar-chart-fill": 61818, - "bar-chart-line-fill": 61819, - "bar-chart-line": 61820, - "bar-chart-steps": 61821, - "bar-chart": 61822, - "basket-fill": 61823, - "basket": 61824, - "basket2-fill": 61825, - "basket2": 61826, - "basket3-fill": 61827, - "basket3": 61828, - "battery-charging": 61829, - "battery-full": 61830, - "battery-half": 61831, - "battery": 61832, - "bell-fill": 61833, - "bell": 61834, - "bezier": 61835, - "bezier2": 61836, - "bicycle": 61837, - "binoculars-fill": 61838, - "binoculars": 61839, - "blockquote-left": 61840, - "blockquote-right": 61841, - "book-fill": 61842, - "book-half": 61843, - "book": 61844, - "bookmark-check-fill": 61845, - "bookmark-check": 61846, - "bookmark-dash-fill": 61847, - "bookmark-dash": 61848, - "bookmark-fill": 61849, - "bookmark-heart-fill": 61850, - "bookmark-heart": 61851, - "bookmark-plus-fill": 61852, - "bookmark-plus": 61853, - "bookmark-star-fill": 61854, - "bookmark-star": 61855, - "bookmark-x-fill": 61856, - "bookmark-x": 61857, - "bookmark": 61858, - "bookmarks-fill": 61859, - "bookmarks": 61860, - "bookshelf": 61861, - "bootstrap-fill": 61862, - "bootstrap-reboot": 61863, - "bootstrap": 61864, - "border-all": 61865, - "border-bottom": 61866, - "border-center": 61867, - "border-inner": 61868, - "border-left": 61869, - "border-middle": 61870, - "border-outer": 61871, - "border-right": 61872, - "border-style": 61873, - "border-top": 61874, - "border-width": 61875, - "border": 61876, - "bounding-box-circles": 61877, - "bounding-box": 61878, - "box-arrow-down-left": 61879, - "box-arrow-down-right": 61880, - "box-arrow-down": 61881, - "box-arrow-in-down-left": 61882, - "box-arrow-in-down-right": 61883, - "box-arrow-in-down": 61884, - "box-arrow-in-left": 61885, - "box-arrow-in-right": 61886, - "box-arrow-in-up-left": 61887, - "box-arrow-in-up-right": 61888, - "box-arrow-in-up": 61889, - "box-arrow-left": 61890, - "box-arrow-right": 61891, - "box-arrow-up-left": 61892, - "box-arrow-up-right": 61893, - "box-arrow-up": 61894, - "box-seam": 61895, - "box": 61896, - "braces": 61897, - "bricks": 61898, - "briefcase-fill": 61899, - "briefcase": 61900, - "brightness-alt-high-fill": 61901, - "brightness-alt-high": 61902, - "brightness-alt-low-fill": 61903, - "brightness-alt-low": 61904, - "brightness-high-fill": 61905, - "brightness-high": 61906, - "brightness-low-fill": 61907, - "brightness-low": 61908, - "broadcast-pin": 61909, - "broadcast": 61910, - "brush-fill": 61911, - "brush": 61912, - "bucket-fill": 61913, - "bucket": 61914, - "bug-fill": 61915, - "bug": 61916, - "building": 61917, - "bullseye": 61918, - "calculator-fill": 61919, - "calculator": 61920, - "calendar-check-fill": 61921, - "calendar-check": 61922, - "calendar-date-fill": 61923, - "calendar-date": 61924, - "calendar-day-fill": 61925, - "calendar-day": 61926, - "calendar-event-fill": 61927, - "calendar-event": 61928, - "calendar-fill": 61929, - "calendar-minus-fill": 61930, - "calendar-minus": 61931, - "calendar-month-fill": 61932, - "calendar-month": 61933, - "calendar-plus-fill": 61934, - "calendar-plus": 61935, - "calendar-range-fill": 61936, - "calendar-range": 61937, - "calendar-week-fill": 61938, - "calendar-week": 61939, - "calendar-x-fill": 61940, - "calendar-x": 61941, - "calendar": 61942, - "calendar2-check-fill": 61943, - "calendar2-check": 61944, - "calendar2-date-fill": 61945, - "calendar2-date": 61946, - "calendar2-day-fill": 61947, - "calendar2-day": 61948, - "calendar2-event-fill": 61949, - "calendar2-event": 61950, - "calendar2-fill": 61951, - "calendar2-minus-fill": 61952, - "calendar2-minus": 61953, - "calendar2-month-fill": 61954, - "calendar2-month": 61955, - "calendar2-plus-fill": 61956, - "calendar2-plus": 61957, - "calendar2-range-fill": 61958, - "calendar2-range": 61959, - "calendar2-week-fill": 61960, - "calendar2-week": 61961, - "calendar2-x-fill": 61962, - "calendar2-x": 61963, - "calendar2": 61964, - "calendar3-event-fill": 61965, - "calendar3-event": 61966, - "calendar3-fill": 61967, - "calendar3-range-fill": 61968, - "calendar3-range": 61969, - "calendar3-week-fill": 61970, - "calendar3-week": 61971, - "calendar3": 61972, - "calendar4-event": 61973, - "calendar4-range": 61974, - "calendar4-week": 61975, - "calendar4": 61976, - "camera-fill": 61977, - "camera-reels-fill": 61978, - "camera-reels": 61979, - "camera-video-fill": 61980, - "camera-video-off-fill": 61981, - "camera-video-off": 61982, - "camera-video": 61983, - "camera": 61984, - "camera2": 61985, - "capslock-fill": 61986, - "capslock": 61987, - "card-checklist": 61988, - "card-heading": 61989, - "card-image": 61990, - "card-list": 61991, - "card-text": 61992, - "caret-down-fill": 61993, - "caret-down-square-fill": 61994, - "caret-down-square": 61995, - "caret-down": 61996, - "caret-left-fill": 61997, - "caret-left-square-fill": 61998, - "caret-left-square": 61999, - "caret-left": 62000, - "caret-right-fill": 62001, - "caret-right-square-fill": 62002, - "caret-right-square": 62003, - "caret-right": 62004, - "caret-up-fill": 62005, - "caret-up-square-fill": 62006, - "caret-up-square": 62007, - "caret-up": 62008, - "cart-check-fill": 62009, - "cart-check": 62010, - "cart-dash-fill": 62011, - "cart-dash": 62012, - "cart-fill": 62013, - "cart-plus-fill": 62014, - "cart-plus": 62015, - "cart-x-fill": 62016, - "cart-x": 62017, - "cart": 62018, - "cart2": 62019, - "cart3": 62020, - "cart4": 62021, - "cash-stack": 62022, - "cash": 62023, - "cast": 62024, - "chat-dots-fill": 62025, - "chat-dots": 62026, - "chat-fill": 62027, - "chat-left-dots-fill": 62028, - "chat-left-dots": 62029, - "chat-left-fill": 62030, - "chat-left-quote-fill": 62031, - "chat-left-quote": 62032, - "chat-left-text-fill": 62033, - "chat-left-text": 62034, - "chat-left": 62035, - "chat-quote-fill": 62036, - "chat-quote": 62037, - "chat-right-dots-fill": 62038, - "chat-right-dots": 62039, - "chat-right-fill": 62040, - "chat-right-quote-fill": 62041, - "chat-right-quote": 62042, - "chat-right-text-fill": 62043, - "chat-right-text": 62044, - "chat-right": 62045, - "chat-square-dots-fill": 62046, - "chat-square-dots": 62047, - "chat-square-fill": 62048, - "chat-square-quote-fill": 62049, - "chat-square-quote": 62050, - "chat-square-text-fill": 62051, - "chat-square-text": 62052, - "chat-square": 62053, - "chat-text-fill": 62054, - "chat-text": 62055, - "chat": 62056, - "check-all": 62057, - "check-circle-fill": 62058, - "check-circle": 62059, - "check-square-fill": 62060, - "check-square": 62061, - "check": 62062, - "check2-all": 62063, - "check2-circle": 62064, - "check2-square": 62065, - "check2": 62066, - "chevron-bar-contract": 62067, - "chevron-bar-down": 62068, - "chevron-bar-expand": 62069, - "chevron-bar-left": 62070, - "chevron-bar-right": 62071, - "chevron-bar-up": 62072, - "chevron-compact-down": 62073, - "chevron-compact-left": 62074, - "chevron-compact-right": 62075, - "chevron-compact-up": 62076, - "chevron-contract": 62077, - "chevron-double-down": 62078, - "chevron-double-left": 62079, - "chevron-double-right": 62080, - "chevron-double-up": 62081, - "chevron-down": 62082, - "chevron-expand": 62083, - "chevron-left": 62084, - "chevron-right": 62085, - "chevron-up": 62086, - "circle-fill": 62087, - "circle-half": 62088, - "circle-square": 62089, - "circle": 62090, - "clipboard-check": 62091, - "clipboard-data": 62092, - "clipboard-minus": 62093, - "clipboard-plus": 62094, - "clipboard-x": 62095, - "clipboard": 62096, - "clock-fill": 62097, - "clock-history": 62098, - "clock": 62099, - "cloud-arrow-down-fill": 62100, - "cloud-arrow-down": 62101, - "cloud-arrow-up-fill": 62102, - "cloud-arrow-up": 62103, - "cloud-check-fill": 62104, - "cloud-check": 62105, - "cloud-download-fill": 62106, - "cloud-download": 62107, - "cloud-drizzle-fill": 62108, - "cloud-drizzle": 62109, - "cloud-fill": 62110, - "cloud-fog-fill": 62111, - "cloud-fog": 62112, - "cloud-fog2-fill": 62113, - "cloud-fog2": 62114, - "cloud-hail-fill": 62115, - "cloud-hail": 62116, - "cloud-haze-fill": 62118, - "cloud-haze": 62119, - "cloud-haze2-fill": 62120, - "cloud-lightning-fill": 62121, - "cloud-lightning-rain-fill": 62122, - "cloud-lightning-rain": 62123, - "cloud-lightning": 62124, - "cloud-minus-fill": 62125, - "cloud-minus": 62126, - "cloud-moon-fill": 62127, - "cloud-moon": 62128, - "cloud-plus-fill": 62129, - "cloud-plus": 62130, - "cloud-rain-fill": 62131, - "cloud-rain-heavy-fill": 62132, - "cloud-rain-heavy": 62133, - "cloud-rain": 62134, - "cloud-slash-fill": 62135, - "cloud-slash": 62136, - "cloud-sleet-fill": 62137, - "cloud-sleet": 62138, - "cloud-snow-fill": 62139, - "cloud-snow": 62140, - "cloud-sun-fill": 62141, - "cloud-sun": 62142, - "cloud-upload-fill": 62143, - "cloud-upload": 62144, - "cloud": 62145, - "clouds-fill": 62146, - "clouds": 62147, - "cloudy-fill": 62148, - "cloudy": 62149, - "code-slash": 62150, - "code-square": 62151, - "code": 62152, - "collection-fill": 62153, - "collection-play-fill": 62154, - "collection-play": 62155, - "collection": 62156, - "columns-gap": 62157, - "columns": 62158, - "command": 62159, - "compass-fill": 62160, - "compass": 62161, - "cone-striped": 62162, - "cone": 62163, - "controller": 62164, - "cpu-fill": 62165, - "cpu": 62166, - "credit-card-2-back-fill": 62167, - "credit-card-2-back": 62168, - "credit-card-2-front-fill": 62169, - "credit-card-2-front": 62170, - "credit-card-fill": 62171, - "credit-card": 62172, - "crop": 62173, - "cup-fill": 62174, - "cup-straw": 62175, - "cup": 62176, - "cursor-fill": 62177, - "cursor-text": 62178, - "cursor": 62179, - "dash-circle-dotted": 62180, - "dash-circle-fill": 62181, - "dash-circle": 62182, - "dash-square-dotted": 62183, - "dash-square-fill": 62184, - "dash-square": 62185, - "dash": 62186, - "diagram-2-fill": 62187, - "diagram-2": 62188, - "diagram-3-fill": 62189, - "diagram-3": 62190, - "diamond-fill": 62191, - "diamond-half": 62192, - "diamond": 62193, - "dice-1-fill": 62194, - "dice-1": 62195, - "dice-2-fill": 62196, - "dice-2": 62197, - "dice-3-fill": 62198, - "dice-3": 62199, - "dice-4-fill": 62200, - "dice-4": 62201, - "dice-5-fill": 62202, - "dice-5": 62203, - "dice-6-fill": 62204, - "dice-6": 62205, - "disc-fill": 62206, - "disc": 62207, - "discord": 62208, - "display-fill": 62209, - "display": 62210, - "distribute-horizontal": 62211, - "distribute-vertical": 62212, - "door-closed-fill": 62213, - "door-closed": 62214, - "door-open-fill": 62215, - "door-open": 62216, - "dot": 62217, - "download": 62218, - "droplet-fill": 62219, - "droplet-half": 62220, - "droplet": 62221, - "earbuds": 62222, - "easel-fill": 62223, - "easel": 62224, - "egg-fill": 62225, - "egg-fried": 62226, - "egg": 62227, - "eject-fill": 62228, - "eject": 62229, - "emoji-angry-fill": 62230, - "emoji-angry": 62231, - "emoji-dizzy-fill": 62232, - "emoji-dizzy": 62233, - "emoji-expressionless-fill": 62234, - "emoji-expressionless": 62235, - "emoji-frown-fill": 62236, - "emoji-frown": 62237, - "emoji-heart-eyes-fill": 62238, - "emoji-heart-eyes": 62239, - "emoji-laughing-fill": 62240, - "emoji-laughing": 62241, - "emoji-neutral-fill": 62242, - "emoji-neutral": 62243, - "emoji-smile-fill": 62244, - "emoji-smile-upside-down-fill": 62245, - "emoji-smile-upside-down": 62246, - "emoji-smile": 62247, - "emoji-sunglasses-fill": 62248, - "emoji-sunglasses": 62249, - "emoji-wink-fill": 62250, - "emoji-wink": 62251, - "envelope-fill": 62252, - "envelope-open-fill": 62253, - "envelope-open": 62254, - "envelope": 62255, - "eraser-fill": 62256, - "eraser": 62257, - "exclamation-circle-fill": 62258, - "exclamation-circle": 62259, - "exclamation-diamond-fill": 62260, - "exclamation-diamond": 62261, - "exclamation-octagon-fill": 62262, - "exclamation-octagon": 62263, - "exclamation-square-fill": 62264, - "exclamation-square": 62265, - "exclamation-triangle-fill": 62266, - "exclamation-triangle": 62267, - "exclamation": 62268, - "exclude": 62269, - "eye-fill": 62270, - "eye-slash-fill": 62271, - "eye-slash": 62272, - "eye": 62273, - "eyedropper": 62274, - "eyeglasses": 62275, - "facebook": 62276, - "file-arrow-down-fill": 62277, - "file-arrow-down": 62278, - "file-arrow-up-fill": 62279, - "file-arrow-up": 62280, - "file-bar-graph-fill": 62281, - "file-bar-graph": 62282, - "file-binary-fill": 62283, - "file-binary": 62284, - "file-break-fill": 62285, - "file-break": 62286, - "file-check-fill": 62287, - "file-check": 62288, - "file-code-fill": 62289, - "file-code": 62290, - "file-diff-fill": 62291, - "file-diff": 62292, - "file-earmark-arrow-down-fill": 62293, - "file-earmark-arrow-down": 62294, - "file-earmark-arrow-up-fill": 62295, - "file-earmark-arrow-up": 62296, - "file-earmark-bar-graph-fill": 62297, - "file-earmark-bar-graph": 62298, - "file-earmark-binary-fill": 62299, - "file-earmark-binary": 62300, - "file-earmark-break-fill": 62301, - "file-earmark-break": 62302, - "file-earmark-check-fill": 62303, - "file-earmark-check": 62304, - "file-earmark-code-fill": 62305, - "file-earmark-code": 62306, - "file-earmark-diff-fill": 62307, - "file-earmark-diff": 62308, - "file-earmark-easel-fill": 62309, - "file-earmark-easel": 62310, - "file-earmark-excel-fill": 62311, - "file-earmark-excel": 62312, - "file-earmark-fill": 62313, - "file-earmark-font-fill": 62314, - "file-earmark-font": 62315, - "file-earmark-image-fill": 62316, - "file-earmark-image": 62317, - "file-earmark-lock-fill": 62318, - "file-earmark-lock": 62319, - "file-earmark-lock2-fill": 62320, - "file-earmark-lock2": 62321, - "file-earmark-medical-fill": 62322, - "file-earmark-medical": 62323, - "file-earmark-minus-fill": 62324, - "file-earmark-minus": 62325, - "file-earmark-music-fill": 62326, - "file-earmark-music": 62327, - "file-earmark-person-fill": 62328, - "file-earmark-person": 62329, - "file-earmark-play-fill": 62330, - "file-earmark-play": 62331, - "file-earmark-plus-fill": 62332, - "file-earmark-plus": 62333, - "file-earmark-post-fill": 62334, - "file-earmark-post": 62335, - "file-earmark-ppt-fill": 62336, - "file-earmark-ppt": 62337, - "file-earmark-richtext-fill": 62338, - "file-earmark-richtext": 62339, - "file-earmark-ruled-fill": 62340, - "file-earmark-ruled": 62341, - "file-earmark-slides-fill": 62342, - "file-earmark-slides": 62343, - "file-earmark-spreadsheet-fill": 62344, - "file-earmark-spreadsheet": 62345, - "file-earmark-text-fill": 62346, - "file-earmark-text": 62347, - "file-earmark-word-fill": 62348, - "file-earmark-word": 62349, - "file-earmark-x-fill": 62350, - "file-earmark-x": 62351, - "file-earmark-zip-fill": 62352, - "file-earmark-zip": 62353, - "file-earmark": 62354, - "file-easel-fill": 62355, - "file-easel": 62356, - "file-excel-fill": 62357, - "file-excel": 62358, - "file-fill": 62359, - "file-font-fill": 62360, - "file-font": 62361, - "file-image-fill": 62362, - "file-image": 62363, - "file-lock-fill": 62364, - "file-lock": 62365, - "file-lock2-fill": 62366, - "file-lock2": 62367, - "file-medical-fill": 62368, - "file-medical": 62369, - "file-minus-fill": 62370, - "file-minus": 62371, - "file-music-fill": 62372, - "file-music": 62373, - "file-person-fill": 62374, - "file-person": 62375, - "file-play-fill": 62376, - "file-play": 62377, - "file-plus-fill": 62378, - "file-plus": 62379, - "file-post-fill": 62380, - "file-post": 62381, - "file-ppt-fill": 62382, - "file-ppt": 62383, - "file-richtext-fill": 62384, - "file-richtext": 62385, - "file-ruled-fill": 62386, - "file-ruled": 62387, - "file-slides-fill": 62388, - "file-slides": 62389, - "file-spreadsheet-fill": 62390, - "file-spreadsheet": 62391, - "file-text-fill": 62392, - "file-text": 62393, - "file-word-fill": 62394, - "file-word": 62395, - "file-x-fill": 62396, - "file-x": 62397, - "file-zip-fill": 62398, - "file-zip": 62399, - "file": 62400, - "files-alt": 62401, - "files": 62402, - "film": 62403, - "filter-circle-fill": 62404, - "filter-circle": 62405, - "filter-left": 62406, - "filter-right": 62407, - "filter-square-fill": 62408, - "filter-square": 62409, - "filter": 62410, - "flag-fill": 62411, - "flag": 62412, - "flower1": 62413, - "flower2": 62414, - "flower3": 62415, - "folder-check": 62416, - "folder-fill": 62417, - "folder-minus": 62418, - "folder-plus": 62419, - "folder-symlink-fill": 62420, - "folder-symlink": 62421, - "folder-x": 62422, - "folder": 62423, - "folder2-open": 62424, - "folder2": 62425, - "fonts": 62426, - "forward-fill": 62427, - "forward": 62428, - "front": 62429, - "fullscreen-exit": 62430, - "fullscreen": 62431, - "funnel-fill": 62432, - "funnel": 62433, - "gear-fill": 62434, - "gear-wide-connected": 62435, - "gear-wide": 62436, - "gear": 62437, - "gem": 62438, - "geo-alt-fill": 62439, - "geo-alt": 62440, - "geo-fill": 62441, - "geo": 62442, - "gift-fill": 62443, - "gift": 62444, - "github": 62445, - "globe": 62446, - "globe2": 62447, - "google": 62448, - "graph-down": 62449, - "graph-up": 62450, - "grid-1x2-fill": 62451, - "grid-1x2": 62452, - "grid-3x2-gap-fill": 62453, - "grid-3x2-gap": 62454, - "grid-3x2": 62455, - "grid-3x3-gap-fill": 62456, - "grid-3x3-gap": 62457, - "grid-3x3": 62458, - "grid-fill": 62459, - "grid": 62460, - "grip-horizontal": 62461, - "grip-vertical": 62462, - "hammer": 62463, - "hand-index-fill": 62464, - "hand-index-thumb-fill": 62465, - "hand-index-thumb": 62466, - "hand-index": 62467, - "hand-thumbs-down-fill": 62468, - "hand-thumbs-down": 62469, - "hand-thumbs-up-fill": 62470, - "hand-thumbs-up": 62471, - "handbag-fill": 62472, - "handbag": 62473, - "hash": 62474, - "hdd-fill": 62475, - "hdd-network-fill": 62476, - "hdd-network": 62477, - "hdd-rack-fill": 62478, - "hdd-rack": 62479, - "hdd-stack-fill": 62480, - "hdd-stack": 62481, - "hdd": 62482, - "headphones": 62483, - "headset": 62484, - "heart-fill": 62485, - "heart-half": 62486, - "heart": 62487, - "heptagon-fill": 62488, - "heptagon-half": 62489, - "heptagon": 62490, - "hexagon-fill": 62491, - "hexagon-half": 62492, - "hexagon": 62493, - "hourglass-bottom": 62494, - "hourglass-split": 62495, - "hourglass-top": 62496, - "hourglass": 62497, - "house-door-fill": 62498, - "house-door": 62499, - "house-fill": 62500, - "house": 62501, - "hr": 62502, - "hurricane": 62503, - "image-alt": 62504, - "image-fill": 62505, - "image": 62506, - "images": 62507, - "inbox-fill": 62508, - "inbox": 62509, - "inboxes-fill": 62510, - "inboxes": 62511, - "info-circle-fill": 62512, - "info-circle": 62513, - "info-square-fill": 62514, - "info-square": 62515, - "info": 62516, - "input-cursor-text": 62517, - "input-cursor": 62518, - "instagram": 62519, - "intersect": 62520, - "journal-album": 62521, - "journal-arrow-down": 62522, - "journal-arrow-up": 62523, - "journal-bookmark-fill": 62524, - "journal-bookmark": 62525, - "journal-check": 62526, - "journal-code": 62527, - "journal-medical": 62528, - "journal-minus": 62529, - "journal-plus": 62530, - "journal-richtext": 62531, - "journal-text": 62532, - "journal-x": 62533, - "journal": 62534, - "journals": 62535, - "joystick": 62536, - "justify-left": 62537, - "justify-right": 62538, - "justify": 62539, - "kanban-fill": 62540, - "kanban": 62541, - "key-fill": 62542, - "key": 62543, - "keyboard-fill": 62544, - "keyboard": 62545, - "ladder": 62546, - "lamp-fill": 62547, - "lamp": 62548, - "laptop-fill": 62549, - "laptop": 62550, - "layer-backward": 62551, - "layer-forward": 62552, - "layers-fill": 62553, - "layers-half": 62554, - "layers": 62555, - "layout-sidebar-inset-reverse": 62556, - "layout-sidebar-inset": 62557, - "layout-sidebar-reverse": 62558, - "layout-sidebar": 62559, - "layout-split": 62560, - "layout-text-sidebar-reverse": 62561, - "layout-text-sidebar": 62562, - "layout-text-window-reverse": 62563, - "layout-text-window": 62564, - "layout-three-columns": 62565, - "layout-wtf": 62566, - "life-preserver": 62567, - "lightbulb-fill": 62568, - "lightbulb-off-fill": 62569, - "lightbulb-off": 62570, - "lightbulb": 62571, - "lightning-charge-fill": 62572, - "lightning-charge": 62573, - "lightning-fill": 62574, - "lightning": 62575, - "link-45deg": 62576, - "link": 62577, - "linkedin": 62578, - "list-check": 62579, - "list-nested": 62580, - "list-ol": 62581, - "list-stars": 62582, - "list-task": 62583, - "list-ul": 62584, - "list": 62585, - "lock-fill": 62586, - "lock": 62587, - "mailbox": 62588, - "mailbox2": 62589, - "map-fill": 62590, - "map": 62591, - "markdown-fill": 62592, - "markdown": 62593, - "mask": 62594, - "megaphone-fill": 62595, - "megaphone": 62596, - "menu-app-fill": 62597, - "menu-app": 62598, - "menu-button-fill": 62599, - "menu-button-wide-fill": 62600, - "menu-button-wide": 62601, - "menu-button": 62602, - "menu-down": 62603, - "menu-up": 62604, - "mic-fill": 62605, - "mic-mute-fill": 62606, - "mic-mute": 62607, - "mic": 62608, - "minecart-loaded": 62609, - "minecart": 62610, - "moisture": 62611, - "moon-fill": 62612, - "moon-stars-fill": 62613, - "moon-stars": 62614, - "moon": 62615, - "mouse-fill": 62616, - "mouse": 62617, - "mouse2-fill": 62618, - "mouse2": 62619, - "mouse3-fill": 62620, - "mouse3": 62621, - "music-note-beamed": 62622, - "music-note-list": 62623, - "music-note": 62624, - "music-player-fill": 62625, - "music-player": 62626, - "newspaper": 62627, - "node-minus-fill": 62628, - "node-minus": 62629, - "node-plus-fill": 62630, - "node-plus": 62631, - "nut-fill": 62632, - "nut": 62633, - "octagon-fill": 62634, - "octagon-half": 62635, - "octagon": 62636, - "option": 62637, - "outlet": 62638, - "paint-bucket": 62639, - "palette-fill": 62640, - "palette": 62641, - "palette2": 62642, - "paperclip": 62643, - "paragraph": 62644, - "patch-check-fill": 62645, - "patch-check": 62646, - "patch-exclamation-fill": 62647, - "patch-exclamation": 62648, - "patch-minus-fill": 62649, - "patch-minus": 62650, - "patch-plus-fill": 62651, - "patch-plus": 62652, - "patch-question-fill": 62653, - "patch-question": 62654, - "pause-btn-fill": 62655, - "pause-btn": 62656, - "pause-circle-fill": 62657, - "pause-circle": 62658, - "pause-fill": 62659, - "pause": 62660, - "peace-fill": 62661, - "peace": 62662, - "pen-fill": 62663, - "pen": 62664, - "pencil-fill": 62665, - "pencil-square": 62666, - "pencil": 62667, - "pentagon-fill": 62668, - "pentagon-half": 62669, - "pentagon": 62670, - "people-fill": 62671, - "people": 62672, - "percent": 62673, - "person-badge-fill": 62674, - "person-badge": 62675, - "person-bounding-box": 62676, - "person-check-fill": 62677, - "person-check": 62678, - "person-circle": 62679, - "person-dash-fill": 62680, - "person-dash": 62681, - "person-fill": 62682, - "person-lines-fill": 62683, - "person-plus-fill": 62684, - "person-plus": 62685, - "person-square": 62686, - "person-x-fill": 62687, - "person-x": 62688, - "person": 62689, - "phone-fill": 62690, - "phone-landscape-fill": 62691, - "phone-landscape": 62692, - "phone-vibrate-fill": 62693, - "phone-vibrate": 62694, - "phone": 62695, - "pie-chart-fill": 62696, - "pie-chart": 62697, - "pin-angle-fill": 62698, - "pin-angle": 62699, - "pin-fill": 62700, - "pin": 62701, - "pip-fill": 62702, - "pip": 62703, - "play-btn-fill": 62704, - "play-btn": 62705, - "play-circle-fill": 62706, - "play-circle": 62707, - "play-fill": 62708, - "play": 62709, - "plug-fill": 62710, - "plug": 62711, - "plus-circle-dotted": 62712, - "plus-circle-fill": 62713, - "plus-circle": 62714, - "plus-square-dotted": 62715, - "plus-square-fill": 62716, - "plus-square": 62717, - "plus": 62718, - "power": 62719, - "printer-fill": 62720, - "printer": 62721, - "puzzle-fill": 62722, - "puzzle": 62723, - "question-circle-fill": 62724, - "question-circle": 62725, - "question-diamond-fill": 62726, - "question-diamond": 62727, - "question-octagon-fill": 62728, - "question-octagon": 62729, - "question-square-fill": 62730, - "question-square": 62731, - "question": 62732, - "rainbow": 62733, - "receipt-cutoff": 62734, - "receipt": 62735, - "reception-0": 62736, - "reception-1": 62737, - "reception-2": 62738, - "reception-3": 62739, - "reception-4": 62740, - "record-btn-fill": 62741, - "record-btn": 62742, - "record-circle-fill": 62743, - "record-circle": 62744, - "record-fill": 62745, - "record": 62746, - "record2-fill": 62747, - "record2": 62748, - "reply-all-fill": 62749, - "reply-all": 62750, - "reply-fill": 62751, - "reply": 62752, - "rss-fill": 62753, - "rss": 62754, - "rulers": 62755, - "save-fill": 62756, - "save": 62757, - "save2-fill": 62758, - "save2": 62759, - "scissors": 62760, - "screwdriver": 62761, - "search": 62762, - "segmented-nav": 62763, - "server": 62764, - "share-fill": 62765, - "share": 62766, - "shield-check": 62767, - "shield-exclamation": 62768, - "shield-fill-check": 62769, - "shield-fill-exclamation": 62770, - "shield-fill-minus": 62771, - "shield-fill-plus": 62772, - "shield-fill-x": 62773, - "shield-fill": 62774, - "shield-lock-fill": 62775, - "shield-lock": 62776, - "shield-minus": 62777, - "shield-plus": 62778, - "shield-shaded": 62779, - "shield-slash-fill": 62780, - "shield-slash": 62781, - "shield-x": 62782, - "shield": 62783, - "shift-fill": 62784, - "shift": 62785, - "shop-window": 62786, - "shop": 62787, - "shuffle": 62788, - "signpost-2-fill": 62789, - "signpost-2": 62790, - "signpost-fill": 62791, - "signpost-split-fill": 62792, - "signpost-split": 62793, - "signpost": 62794, - "sim-fill": 62795, - "sim": 62796, - "skip-backward-btn-fill": 62797, - "skip-backward-btn": 62798, - "skip-backward-circle-fill": 62799, - "skip-backward-circle": 62800, - "skip-backward-fill": 62801, - "skip-backward": 62802, - "skip-end-btn-fill": 62803, - "skip-end-btn": 62804, - "skip-end-circle-fill": 62805, - "skip-end-circle": 62806, - "skip-end-fill": 62807, - "skip-end": 62808, - "skip-forward-btn-fill": 62809, - "skip-forward-btn": 62810, - "skip-forward-circle-fill": 62811, - "skip-forward-circle": 62812, - "skip-forward-fill": 62813, - "skip-forward": 62814, - "skip-start-btn-fill": 62815, - "skip-start-btn": 62816, - "skip-start-circle-fill": 62817, - "skip-start-circle": 62818, - "skip-start-fill": 62819, - "skip-start": 62820, - "slack": 62821, - "slash-circle-fill": 62822, - "slash-circle": 62823, - "slash-square-fill": 62824, - "slash-square": 62825, - "slash": 62826, - "sliders": 62827, - "smartwatch": 62828, - "snow": 62829, - "snow2": 62830, - "snow3": 62831, - "sort-alpha-down-alt": 62832, - "sort-alpha-down": 62833, - "sort-alpha-up-alt": 62834, - "sort-alpha-up": 62835, - "sort-down-alt": 62836, - "sort-down": 62837, - "sort-numeric-down-alt": 62838, - "sort-numeric-down": 62839, - "sort-numeric-up-alt": 62840, - "sort-numeric-up": 62841, - "sort-up-alt": 62842, - "sort-up": 62843, - "soundwave": 62844, - "speaker-fill": 62845, - "speaker": 62846, - "speedometer": 62847, - "speedometer2": 62848, - "spellcheck": 62849, - "square-fill": 62850, - "square-half": 62851, - "square": 62852, - "stack": 62853, - "star-fill": 62854, - "star-half": 62855, - "star": 62856, - "stars": 62857, - "stickies-fill": 62858, - "stickies": 62859, - "sticky-fill": 62860, - "sticky": 62861, - "stop-btn-fill": 62862, - "stop-btn": 62863, - "stop-circle-fill": 62864, - "stop-circle": 62865, - "stop-fill": 62866, - "stop": 62867, - "stoplights-fill": 62868, - "stoplights": 62869, - "stopwatch-fill": 62870, - "stopwatch": 62871, - "subtract": 62872, - "suit-club-fill": 62873, - "suit-club": 62874, - "suit-diamond-fill": 62875, - "suit-diamond": 62876, - "suit-heart-fill": 62877, - "suit-heart": 62878, - "suit-spade-fill": 62879, - "suit-spade": 62880, - "sun-fill": 62881, - "sun": 62882, - "sunglasses": 62883, - "sunrise-fill": 62884, - "sunrise": 62885, - "sunset-fill": 62886, - "sunset": 62887, - "symmetry-horizontal": 62888, - "symmetry-vertical": 62889, - "table": 62890, - "tablet-fill": 62891, - "tablet-landscape-fill": 62892, - "tablet-landscape": 62893, - "tablet": 62894, - "tag-fill": 62895, - "tag": 62896, - "tags-fill": 62897, - "tags": 62898, - "telegram": 62899, - "telephone-fill": 62900, - "telephone-forward-fill": 62901, - "telephone-forward": 62902, - "telephone-inbound-fill": 62903, - "telephone-inbound": 62904, - "telephone-minus-fill": 62905, - "telephone-minus": 62906, - "telephone-outbound-fill": 62907, - "telephone-outbound": 62908, - "telephone-plus-fill": 62909, - "telephone-plus": 62910, - "telephone-x-fill": 62911, - "telephone-x": 62912, - "telephone": 62913, - "terminal-fill": 62914, - "terminal": 62915, - "text-center": 62916, - "text-indent-left": 62917, - "text-indent-right": 62918, - "text-left": 62919, - "text-paragraph": 62920, - "text-right": 62921, - "textarea-resize": 62922, - "textarea-t": 62923, - "textarea": 62924, - "thermometer-half": 62925, - "thermometer-high": 62926, - "thermometer-low": 62927, - "thermometer-snow": 62928, - "thermometer-sun": 62929, - "thermometer": 62930, - "three-dots-vertical": 62931, - "three-dots": 62932, - "toggle-off": 62933, - "toggle-on": 62934, - "toggle2-off": 62935, - "toggle2-on": 62936, - "toggles": 62937, - "toggles2": 62938, - "tools": 62939, - "tornado": 62940, - "trash-fill": 62941, - "trash": 62942, - "trash2-fill": 62943, - "trash2": 62944, - "tree-fill": 62945, - "tree": 62946, - "triangle-fill": 62947, - "triangle-half": 62948, - "triangle": 62949, - "trophy-fill": 62950, - "trophy": 62951, - "tropical-storm": 62952, - "truck-flatbed": 62953, - "truck": 62954, - "tsunami": 62955, - "tv-fill": 62956, - "tv": 62957, - "twitch": 62958, - "twitter": 62959, - "type-bold": 62960, - "type-h1": 62961, - "type-h2": 62962, - "type-h3": 62963, - "type-italic": 62964, - "type-strikethrough": 62965, - "type-underline": 62966, - "type": 62967, - "ui-checks-grid": 62968, - "ui-checks": 62969, - "ui-radios-grid": 62970, - "ui-radios": 62971, - "umbrella-fill": 62972, - "umbrella": 62973, - "union": 62974, - "unlock-fill": 62975, - "unlock": 62976, - "upc-scan": 62977, - "upc": 62978, - "upload": 62979, - "vector-pen": 62980, - "view-list": 62981, - "view-stacked": 62982, - "vinyl-fill": 62983, - "vinyl": 62984, - "voicemail": 62985, - "volume-down-fill": 62986, - "volume-down": 62987, - "volume-mute-fill": 62988, - "volume-mute": 62989, - "volume-off-fill": 62990, - "volume-off": 62991, - "volume-up-fill": 62992, - "volume-up": 62993, - "vr": 62994, - "wallet-fill": 62995, - "wallet": 62996, - "wallet2": 62997, - "watch": 62998, - "water": 62999, - "whatsapp": 63000, - "wifi-1": 63001, - "wifi-2": 63002, - "wifi-off": 63003, - "wifi": 63004, - "wind": 63005, - "window-dock": 63006, - "window-sidebar": 63007, - "window": 63008, - "wrench": 63009, - "x-circle-fill": 63010, - "x-circle": 63011, - "x-diamond-fill": 63012, - "x-diamond": 63013, - "x-octagon-fill": 63014, - "x-octagon": 63015, - "x-square-fill": 63016, - "x-square": 63017, - "x": 63018, - "youtube": 63019, - "zoom-in": 63020, - "zoom-out": 63021, - "bank": 63022, - "bank2": 63023, - "bell-slash-fill": 63024, - "bell-slash": 63025, - "cash-coin": 63026, - "check-lg": 63027, - "coin": 63028, - "currency-bitcoin": 63029, - "currency-dollar": 63030, - "currency-euro": 63031, - "currency-exchange": 63032, - "currency-pound": 63033, - "currency-yen": 63034, - "dash-lg": 63035, - "exclamation-lg": 63036, - "file-earmark-pdf-fill": 63037, - "file-earmark-pdf": 63038, - "file-pdf-fill": 63039, - "file-pdf": 63040, - "gender-ambiguous": 63041, - "gender-female": 63042, - "gender-male": 63043, - "gender-trans": 63044, - "headset-vr": 63045, - "info-lg": 63046, - "mastodon": 63047, - "messenger": 63048, - "piggy-bank-fill": 63049, - "piggy-bank": 63050, - "pin-map-fill": 63051, - "pin-map": 63052, - "plus-lg": 63053, - "question-lg": 63054, - "recycle": 63055, - "reddit": 63056, - "safe-fill": 63057, - "safe2-fill": 63058, - "safe2": 63059, - "sd-card-fill": 63060, - "sd-card": 63061, - "skype": 63062, - "slash-lg": 63063, - "translate": 63064, - "x-lg": 63065, - "safe": 63066, - "apple": 63067, - "microsoft": 63069, - "windows": 63070, - "behance": 63068, - "dribbble": 63071, - "line": 63072, - "medium": 63073, - "paypal": 63074, - "pinterest": 63075, - "signal": 63076, - "snapchat": 63077, - "spotify": 63078, - "stack-overflow": 63079, - "strava": 63080, - "wordpress": 63081, - "vimeo": 63082, - "activity": 63083, - "easel2-fill": 63084, - "easel2": 63085, - "easel3-fill": 63086, - "easel3": 63087, - "fan": 63088, - "fingerprint": 63089, - "graph-down-arrow": 63090, - "graph-up-arrow": 63091, - "hypnotize": 63092, - "magic": 63093, - "person-rolodex": 63094, - "person-video": 63095, - "person-video2": 63096, - "person-video3": 63097, - "person-workspace": 63098, - "radioactive": 63099, - "webcam-fill": 63100, - "webcam": 63101, - "yin-yang": 63102, - "bandaid-fill": 63104, - "bandaid": 63105, - "bluetooth": 63106, - "body-text": 63107, - "boombox": 63108, - "boxes": 63109, - "dpad-fill": 63110, - "dpad": 63111, - "ear-fill": 63112, - "ear": 63113, - "envelope-check-fill": 63115, - "envelope-check": 63116, - "envelope-dash-fill": 63118, - "envelope-dash": 63119, - "envelope-exclamation-fill": 63121, - "envelope-exclamation": 63122, - "envelope-plus-fill": 63123, - "envelope-plus": 63124, - "envelope-slash-fill": 63126, - "envelope-slash": 63127, - "envelope-x-fill": 63129, - "envelope-x": 63130, - "explicit-fill": 63131, - "explicit": 63132, - "git": 63133, - "infinity": 63134, - "list-columns-reverse": 63135, - "list-columns": 63136, - "meta": 63137, - "nintendo-switch": 63140, - "pc-display-horizontal": 63141, - "pc-display": 63142, - "pc-horizontal": 63143, - "pc": 63144, - "playstation": 63145, - "plus-slash-minus": 63146, - "projector-fill": 63147, - "projector": 63148, - "qr-code-scan": 63149, - "qr-code": 63150, - "quora": 63151, - "quote": 63152, - "robot": 63153, - "send-check-fill": 63154, - "send-check": 63155, - "send-dash-fill": 63156, - "send-dash": 63157, - "send-exclamation-fill": 63159, - "send-exclamation": 63160, - "send-fill": 63161, - "send-plus-fill": 63162, - "send-plus": 63163, - "send-slash-fill": 63164, - "send-slash": 63165, - "send-x-fill": 63166, - "send-x": 63167, - "send": 63168, - "steam": 63169, - "terminal-dash": 63171, - "terminal-plus": 63172, - "terminal-split": 63173, - "ticket-detailed-fill": 63174, - "ticket-detailed": 63175, - "ticket-fill": 63176, - "ticket-perforated-fill": 63177, - "ticket-perforated": 63178, - "ticket": 63179, - "tiktok": 63180, - "window-dash": 63181, - "window-desktop": 63182, - "window-fullscreen": 63183, - "window-plus": 63184, - "window-split": 63185, - "window-stack": 63186, - "window-x": 63187, - "xbox": 63188, - "ethernet": 63189, - "hdmi-fill": 63190, - "hdmi": 63191, - "usb-c-fill": 63192, - "usb-c": 63193, - "usb-fill": 63194, - "usb-plug-fill": 63195, - "usb-plug": 63196, - "usb-symbol": 63197, - "usb": 63198, - "boombox-fill": 63199, - "displayport": 63201, - "gpu-card": 63202, - "memory": 63203, - "modem-fill": 63204, - "modem": 63205, - "motherboard-fill": 63206, - "motherboard": 63207, - "optical-audio-fill": 63208, - "optical-audio": 63209, - "pci-card": 63210, - "router-fill": 63211, - "router": 63212, - "thunderbolt-fill": 63215, - "thunderbolt": 63216, - "usb-drive-fill": 63217, - "usb-drive": 63218, - "usb-micro-fill": 63219, - "usb-micro": 63220, - "usb-mini-fill": 63221, - "usb-mini": 63222, - "cloud-haze2": 63223, - "device-hdd-fill": 63224, - "device-hdd": 63225, - "device-ssd-fill": 63226, - "device-ssd": 63227, - "displayport-fill": 63228, - "mortarboard-fill": 63229, - "mortarboard": 63230, - "terminal-x": 63231, - "arrow-through-heart-fill": 63232, - "arrow-through-heart": 63233, - "badge-sd-fill": 63234, - "badge-sd": 63235, - "bag-heart-fill": 63236, - "bag-heart": 63237, - "balloon-fill": 63238, - "balloon-heart-fill": 63239, - "balloon-heart": 63240, - "balloon": 63241, - "box2-fill": 63242, - "box2-heart-fill": 63243, - "box2-heart": 63244, - "box2": 63245, - "braces-asterisk": 63246, - "calendar-heart-fill": 63247, - "calendar-heart": 63248, - "calendar2-heart-fill": 63249, - "calendar2-heart": 63250, - "chat-heart-fill": 63251, - "chat-heart": 63252, - "chat-left-heart-fill": 63253, - "chat-left-heart": 63254, - "chat-right-heart-fill": 63255, - "chat-right-heart": 63256, - "chat-square-heart-fill": 63257, - "chat-square-heart": 63258, - "clipboard-check-fill": 63259, - "clipboard-data-fill": 63260, - "clipboard-fill": 63261, - "clipboard-heart-fill": 63262, - "clipboard-heart": 63263, - "clipboard-minus-fill": 63264, - "clipboard-plus-fill": 63265, - "clipboard-pulse": 63266, - "clipboard-x-fill": 63267, - "clipboard2-check-fill": 63268, - "clipboard2-check": 63269, - "clipboard2-data-fill": 63270, - "clipboard2-data": 63271, - "clipboard2-fill": 63272, - "clipboard2-heart-fill": 63273, - "clipboard2-heart": 63274, - "clipboard2-minus-fill": 63275, - "clipboard2-minus": 63276, - "clipboard2-plus-fill": 63277, - "clipboard2-plus": 63278, - "clipboard2-pulse-fill": 63279, - "clipboard2-pulse": 63280, - "clipboard2-x-fill": 63281, - "clipboard2-x": 63282, - "clipboard2": 63283, - "emoji-kiss-fill": 63284, - "emoji-kiss": 63285, - "envelope-heart-fill": 63286, - "envelope-heart": 63287, - "envelope-open-heart-fill": 63288, - "envelope-open-heart": 63289, - "envelope-paper-fill": 63290, - "envelope-paper-heart-fill": 63291, - "envelope-paper-heart": 63292, - "envelope-paper": 63293, - "filetype-aac": 63294, - "filetype-ai": 63295, - "filetype-bmp": 63296, - "filetype-cs": 63297, - "filetype-css": 63298, - "filetype-csv": 63299, - "filetype-doc": 63300, - "filetype-docx": 63301, - "filetype-exe": 63302, - "filetype-gif": 63303, - "filetype-heic": 63304, - "filetype-html": 63305, - "filetype-java": 63306, - "filetype-jpg": 63307, - "filetype-js": 63308, - "filetype-jsx": 63309, - "filetype-key": 63310, - "filetype-m4p": 63311, - "filetype-md": 63312, - "filetype-mdx": 63313, - "filetype-mov": 63314, - "filetype-mp3": 63315, - "filetype-mp4": 63316, - "filetype-otf": 63317, - "filetype-pdf": 63318, - "filetype-php": 63319, - "filetype-png": 63320, - "filetype-ppt": 63322, - "filetype-psd": 63323, - "filetype-py": 63324, - "filetype-raw": 63325, - "filetype-rb": 63326, - "filetype-sass": 63327, - "filetype-scss": 63328, - "filetype-sh": 63329, - "filetype-svg": 63330, - "filetype-tiff": 63331, - "filetype-tsx": 63332, - "filetype-ttf": 63333, - "filetype-txt": 63334, - "filetype-wav": 63335, - "filetype-woff": 63336, - "filetype-xls": 63338, - "filetype-xml": 63339, - "filetype-yml": 63340, - "heart-arrow": 63341, - "heart-pulse-fill": 63342, - "heart-pulse": 63343, - "heartbreak-fill": 63344, - "heartbreak": 63345, - "hearts": 63346, - "hospital-fill": 63347, - "hospital": 63348, - "house-heart-fill": 63349, - "house-heart": 63350, - "incognito": 63351, - "magnet-fill": 63352, - "magnet": 63353, - "person-heart": 63354, - "person-hearts": 63355, - "phone-flip": 63356, - "plugin": 63357, - "postage-fill": 63358, - "postage-heart-fill": 63359, - "postage-heart": 63360, - "postage": 63361, - "postcard-fill": 63362, - "postcard-heart-fill": 63363, - "postcard-heart": 63364, - "postcard": 63365, - "search-heart-fill": 63366, - "search-heart": 63367, - "sliders2-vertical": 63368, - "sliders2": 63369, - "trash3-fill": 63370, - "trash3": 63371, - "valentine": 63372, - "valentine2": 63373, - "wrench-adjustable-circle-fill": 63374, - "wrench-adjustable-circle": 63375, - "wrench-adjustable": 63376, - "filetype-json": 63377, - "filetype-pptx": 63378, - "filetype-xlsx": 63379, - "1-circle-fill": 63382, - "1-circle": 63383, - "1-square-fill": 63384, - "1-square": 63385, - "2-circle-fill": 63388, - "2-circle": 63389, - "2-square-fill": 63390, - "2-square": 63391, - "3-circle-fill": 63394, - "3-circle": 63395, - "3-square-fill": 63396, - "3-square": 63397, - "4-circle-fill": 63400, - "4-circle": 63401, - "4-square-fill": 63402, - "4-square": 63403, - "5-circle-fill": 63406, - "5-circle": 63407, - "5-square-fill": 63408, - "5-square": 63409, - "6-circle-fill": 63412, - "6-circle": 63413, - "6-square-fill": 63414, - "6-square": 63415, - "7-circle-fill": 63418, - "7-circle": 63419, - "7-square-fill": 63420, - "7-square": 63421, - "8-circle-fill": 63424, - "8-circle": 63425, - "8-square-fill": 63426, - "8-square": 63427, - "9-circle-fill": 63430, - "9-circle": 63431, - "9-square-fill": 63432, - "9-square": 63433, - "airplane-engines-fill": 63434, - "airplane-engines": 63435, - "airplane-fill": 63436, - "airplane": 63437, - "alexa": 63438, - "alipay": 63439, - "android": 63440, - "android2": 63441, - "box-fill": 63442, - "box-seam-fill": 63443, - "browser-chrome": 63444, - "browser-edge": 63445, - "browser-firefox": 63446, - "browser-safari": 63447, - "c-circle-fill": 63450, - "c-circle": 63451, - "c-square-fill": 63452, - "c-square": 63453, - "capsule-pill": 63454, - "capsule": 63455, - "car-front-fill": 63456, - "car-front": 63457, - "cassette-fill": 63458, - "cassette": 63459, - "cc-circle-fill": 63462, - "cc-circle": 63463, - "cc-square-fill": 63464, - "cc-square": 63465, - "cup-hot-fill": 63466, - "cup-hot": 63467, - "currency-rupee": 63468, - "dropbox": 63469, - "escape": 63470, - "fast-forward-btn-fill": 63471, - "fast-forward-btn": 63472, - "fast-forward-circle-fill": 63473, - "fast-forward-circle": 63474, - "fast-forward-fill": 63475, - "fast-forward": 63476, - "filetype-sql": 63477, - "fire": 63478, - "google-play": 63479, - "h-circle-fill": 63482, - "h-circle": 63483, - "h-square-fill": 63484, - "h-square": 63485, - "indent": 63486, - "lungs-fill": 63487, - "lungs": 63488, - "microsoft-teams": 63489, - "p-circle-fill": 63492, - "p-circle": 63493, - "p-square-fill": 63494, - "p-square": 63495, - "pass-fill": 63496, - "pass": 63497, - "prescription": 63498, - "prescription2": 63499, - "r-circle-fill": 63502, - "r-circle": 63503, - "r-square-fill": 63504, - "r-square": 63505, - "repeat-1": 63506, - "repeat": 63507, - "rewind-btn-fill": 63508, - "rewind-btn": 63509, - "rewind-circle-fill": 63510, - "rewind-circle": 63511, - "rewind-fill": 63512, - "rewind": 63513, - "train-freight-front-fill": 63514, - "train-freight-front": 63515, - "train-front-fill": 63516, - "train-front": 63517, - "train-lightrail-front-fill": 63518, - "train-lightrail-front": 63519, - "truck-front-fill": 63520, - "truck-front": 63521, - "ubuntu": 63522, - "unindent": 63523, - "unity": 63524, - "universal-access-circle": 63525, - "universal-access": 63526, - "virus": 63527, - "virus2": 63528, - "wechat": 63529, - "yelp": 63530, - "sign-stop-fill": 63531, - "sign-stop-lights-fill": 63532, - "sign-stop-lights": 63533, - "sign-stop": 63534, - "sign-turn-left-fill": 63535, - "sign-turn-left": 63536, - "sign-turn-right-fill": 63537, - "sign-turn-right": 63538, - "sign-turn-slight-left-fill": 63539, - "sign-turn-slight-left": 63540, - "sign-turn-slight-right-fill": 63541, - "sign-turn-slight-right": 63542, - "sign-yield-fill": 63543, - "sign-yield": 63544, - "ev-station-fill": 63545, - "ev-station": 63546, - "fuel-pump-diesel-fill": 63547, - "fuel-pump-diesel": 63548, - "fuel-pump-fill": 63549, - "fuel-pump": 63550, - "0-circle-fill": 63551, - "0-circle": 63552, - "0-square-fill": 63553, - "0-square": 63554, - "rocket-fill": 63555, - "rocket-takeoff-fill": 63556, - "rocket-takeoff": 63557, - "rocket": 63558, - "stripe": 63559, - "subscript": 63560, - "superscript": 63561, - "trello": 63562, - "envelope-at-fill": 63563, - "envelope-at": 63564, - "regex": 63565, - "text-wrap": 63566, - "sign-dead-end-fill": 63567, - "sign-dead-end": 63568, - "sign-do-not-enter-fill": 63569, - "sign-do-not-enter": 63570, - "sign-intersection-fill": 63571, - "sign-intersection-side-fill": 63572, - "sign-intersection-side": 63573, - "sign-intersection-t-fill": 63574, - "sign-intersection-t": 63575, - "sign-intersection-y-fill": 63576, - "sign-intersection-y": 63577, - "sign-intersection": 63578, - "sign-merge-left-fill": 63579, - "sign-merge-left": 63580, - "sign-merge-right-fill": 63581, - "sign-merge-right": 63582, - "sign-no-left-turn-fill": 63583, - "sign-no-left-turn": 63584, - "sign-no-parking-fill": 63585, - "sign-no-parking": 63586, - "sign-no-right-turn-fill": 63587, - "sign-no-right-turn": 63588, - "sign-railroad-fill": 63589, - "sign-railroad": 63590, - "building-add": 63591, - "building-check": 63592, - "building-dash": 63593, - "building-down": 63594, - "building-exclamation": 63595, - "building-fill-add": 63596, - "building-fill-check": 63597, - "building-fill-dash": 63598, - "building-fill-down": 63599, - "building-fill-exclamation": 63600, - "building-fill-gear": 63601, - "building-fill-lock": 63602, - "building-fill-slash": 63603, - "building-fill-up": 63604, - "building-fill-x": 63605, - "building-fill": 63606, - "building-gear": 63607, - "building-lock": 63608, - "building-slash": 63609, - "building-up": 63610, - "building-x": 63611, - "buildings-fill": 63612, - "buildings": 63613, - "bus-front-fill": 63614, - "bus-front": 63615, - "ev-front-fill": 63616, - "ev-front": 63617, - "globe-americas": 63618, - "globe-asia-australia": 63619, - "globe-central-south-asia": 63620, - "globe-europe-africa": 63621, - "house-add-fill": 63622, - "house-add": 63623, - "house-check-fill": 63624, - "house-check": 63625, - "house-dash-fill": 63626, - "house-dash": 63627, - "house-down-fill": 63628, - "house-down": 63629, - "house-exclamation-fill": 63630, - "house-exclamation": 63631, - "house-gear-fill": 63632, - "house-gear": 63633, - "house-lock-fill": 63634, - "house-lock": 63635, - "house-slash-fill": 63636, - "house-slash": 63637, - "house-up-fill": 63638, - "house-up": 63639, - "house-x-fill": 63640, - "house-x": 63641, - "person-add": 63642, - "person-down": 63643, - "person-exclamation": 63644, - "person-fill-add": 63645, - "person-fill-check": 63646, - "person-fill-dash": 63647, - "person-fill-down": 63648, - "person-fill-exclamation": 63649, - "person-fill-gear": 63650, - "person-fill-lock": 63651, - "person-fill-slash": 63652, - "person-fill-up": 63653, - "person-fill-x": 63654, - "person-gear": 63655, - "person-lock": 63656, - "person-slash": 63657, - "person-up": 63658, - "scooter": 63659, - "taxi-front-fill": 63660, - "taxi-front": 63661, - "amd": 63662, - "database-add": 63663, - "database-check": 63664, - "database-dash": 63665, - "database-down": 63666, - "database-exclamation": 63667, - "database-fill-add": 63668, - "database-fill-check": 63669, - "database-fill-dash": 63670, - "database-fill-down": 63671, - "database-fill-exclamation": 63672, - "database-fill-gear": 63673, - "database-fill-lock": 63674, - "database-fill-slash": 63675, - "database-fill-up": 63676, - "database-fill-x": 63677, - "database-fill": 63678, - "database-gear": 63679, - "database-lock": 63680, - "database-slash": 63681, - "database-up": 63682, - "database-x": 63683, - "database": 63684, - "houses-fill": 63685, - "houses": 63686, - "nvidia": 63687, - "person-vcard-fill": 63688, - "person-vcard": 63689, - "sina-weibo": 63690, - "tencent-qq": 63691, - "wikipedia": 63692, - "alphabet-uppercase": 62117, - "alphabet": 63114, - "amazon": 63117, - "arrows-collapse-vertical": 63120, - "arrows-expand-vertical": 63125, - "arrows-vertical": 63128, - "arrows": 63138, - "ban-fill": 63139, - "ban": 63158, - "bing": 63170, - "cake": 63200, - "cake2": 63213, - "cookie": 63214, - "copy": 63321, - "crosshair": 63337, - "crosshair2": 63380, - "emoji-astonished-fill": 63381, - "emoji-astonished": 63386, - "emoji-grimace-fill": 63387, - "emoji-grimace": 63392, - "emoji-grin-fill": 63393, - "emoji-grin": 63398, - "emoji-surprise-fill": 63399, - "emoji-surprise": 63404, - "emoji-tear-fill": 63405, - "emoji-tear": 63410, - "envelope-arrow-down-fill": 63411, - "envelope-arrow-down": 63416, - "envelope-arrow-up-fill": 63417, - "envelope-arrow-up": 63422, - "feather": 63423, - "feather2": 63428, - "floppy-fill": 63429, - "floppy": 63448, - "floppy2-fill": 63449, - "floppy2": 63460, - "gitlab": 63461, - "highlighter": 63480, - "marker-tip": 63490, - "nvme-fill": 63491, - "nvme": 63500, - "opencollective": 63501, - "pci-card-network": 63693, - "pci-card-sound": 63694, - "radar": 63695, - "send-arrow-down-fill": 63696, - "send-arrow-down": 63697, - "send-arrow-up-fill": 63698, - "send-arrow-up": 63699, - "sim-slash-fill": 63700, - "sim-slash": 63701, - "sourceforge": 63702, - "substack": 63703, - "threads-fill": 63704, - "threads": 63705, - "transparency": 63706, - "twitter-x": 63707, - "type-h4": 63708, - "type-h5": 63709, - "type-h6": 63710, - "backpack-fill": 63711, - "backpack": 63712, - "backpack2-fill": 63713, - "backpack2": 63714, - "backpack3-fill": 63715, - "backpack3": 63716, - "backpack4-fill": 63717, - "backpack4": 63718, - "brilliance": 63719, - "cake-fill": 63720, - "cake2-fill": 63721, - "duffle-fill": 63722, - "duffle": 63723, - "exposure": 63724, - "gender-neuter": 63725, - "highlights": 63726, - "luggage-fill": 63727, - "luggage": 63728, - "mailbox-flag": 63729, - "mailbox2-flag": 63730, - "noise-reduction": 63731, - "passport-fill": 63732, - "passport": 63733, - "person-arms-up": 63734, - "person-raised-hand": 63735, - "person-standing-dress": 63736, - "person-standing": 63737, - "person-walking": 63738, - "person-wheelchair": 63739, - "shadows": 63740, - "suitcase-fill": 63741, - "suitcase-lg-fill": 63742, - "suitcase-lg": 63743, - "suitcase": 63744, - "suitcase2-fill": 63745, - "suitcase2": 63746, - "vignette": 63747 -} \ No newline at end of file diff --git a/static/bootstrap/icons/bootstrap-icons.min.css b/static/bootstrap/icons/bootstrap-icons.min.css deleted file mode 100644 index b882fd5a..00000000 --- a/static/bootstrap/icons/bootstrap-icons.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Bootstrap Icons v1.11.2 (https://icons.getbootstrap.com/) - * Copyright 2019-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) - */@font-face{font-display:block;font-family:bootstrap-icons;src:url("fonts/bootstrap-icons.woff2?7141511ac37f13e1a387fb9fc6646256") format("woff2"),url("fonts/bootstrap-icons.woff?7141511ac37f13e1a387fb9fc6646256") format("woff")}.bi::before,[class*=" bi-"]::before,[class^=bi-]::before{display:inline-block;font-family:bootstrap-icons!important;font-style:normal;font-weight:400!important;font-variant:normal;text-transform:none;line-height:1;vertical-align:-.125em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.bi-123::before{content:"\f67f"}.bi-alarm-fill::before{content:"\f101"}.bi-alarm::before{content:"\f102"}.bi-align-bottom::before{content:"\f103"}.bi-align-center::before{content:"\f104"}.bi-align-end::before{content:"\f105"}.bi-align-middle::before{content:"\f106"}.bi-align-start::before{content:"\f107"}.bi-align-top::before{content:"\f108"}.bi-alt::before{content:"\f109"}.bi-app-indicator::before{content:"\f10a"}.bi-app::before{content:"\f10b"}.bi-archive-fill::before{content:"\f10c"}.bi-archive::before{content:"\f10d"}.bi-arrow-90deg-down::before{content:"\f10e"}.bi-arrow-90deg-left::before{content:"\f10f"}.bi-arrow-90deg-right::before{content:"\f110"}.bi-arrow-90deg-up::before{content:"\f111"}.bi-arrow-bar-down::before{content:"\f112"}.bi-arrow-bar-left::before{content:"\f113"}.bi-arrow-bar-right::before{content:"\f114"}.bi-arrow-bar-up::before{content:"\f115"}.bi-arrow-clockwise::before{content:"\f116"}.bi-arrow-counterclockwise::before{content:"\f117"}.bi-arrow-down-circle-fill::before{content:"\f118"}.bi-arrow-down-circle::before{content:"\f119"}.bi-arrow-down-left-circle-fill::before{content:"\f11a"}.bi-arrow-down-left-circle::before{content:"\f11b"}.bi-arrow-down-left-square-fill::before{content:"\f11c"}.bi-arrow-down-left-square::before{content:"\f11d"}.bi-arrow-down-left::before{content:"\f11e"}.bi-arrow-down-right-circle-fill::before{content:"\f11f"}.bi-arrow-down-right-circle::before{content:"\f120"}.bi-arrow-down-right-square-fill::before{content:"\f121"}.bi-arrow-down-right-square::before{content:"\f122"}.bi-arrow-down-right::before{content:"\f123"}.bi-arrow-down-short::before{content:"\f124"}.bi-arrow-down-square-fill::before{content:"\f125"}.bi-arrow-down-square::before{content:"\f126"}.bi-arrow-down-up::before{content:"\f127"}.bi-arrow-down::before{content:"\f128"}.bi-arrow-left-circle-fill::before{content:"\f129"}.bi-arrow-left-circle::before{content:"\f12a"}.bi-arrow-left-right::before{content:"\f12b"}.bi-arrow-left-short::before{content:"\f12c"}.bi-arrow-left-square-fill::before{content:"\f12d"}.bi-arrow-left-square::before{content:"\f12e"}.bi-arrow-left::before{content:"\f12f"}.bi-arrow-repeat::before{content:"\f130"}.bi-arrow-return-left::before{content:"\f131"}.bi-arrow-return-right::before{content:"\f132"}.bi-arrow-right-circle-fill::before{content:"\f133"}.bi-arrow-right-circle::before{content:"\f134"}.bi-arrow-right-short::before{content:"\f135"}.bi-arrow-right-square-fill::before{content:"\f136"}.bi-arrow-right-square::before{content:"\f137"}.bi-arrow-right::before{content:"\f138"}.bi-arrow-up-circle-fill::before{content:"\f139"}.bi-arrow-up-circle::before{content:"\f13a"}.bi-arrow-up-left-circle-fill::before{content:"\f13b"}.bi-arrow-up-left-circle::before{content:"\f13c"}.bi-arrow-up-left-square-fill::before{content:"\f13d"}.bi-arrow-up-left-square::before{content:"\f13e"}.bi-arrow-up-left::before{content:"\f13f"}.bi-arrow-up-right-circle-fill::before{content:"\f140"}.bi-arrow-up-right-circle::before{content:"\f141"}.bi-arrow-up-right-square-fill::before{content:"\f142"}.bi-arrow-up-right-square::before{content:"\f143"}.bi-arrow-up-right::before{content:"\f144"}.bi-arrow-up-short::before{content:"\f145"}.bi-arrow-up-square-fill::before{content:"\f146"}.bi-arrow-up-square::before{content:"\f147"}.bi-arrow-up::before{content:"\f148"}.bi-arrows-angle-contract::before{content:"\f149"}.bi-arrows-angle-expand::before{content:"\f14a"}.bi-arrows-collapse::before{content:"\f14b"}.bi-arrows-expand::before{content:"\f14c"}.bi-arrows-fullscreen::before{content:"\f14d"}.bi-arrows-move::before{content:"\f14e"}.bi-aspect-ratio-fill::before{content:"\f14f"}.bi-aspect-ratio::before{content:"\f150"}.bi-asterisk::before{content:"\f151"}.bi-at::before{content:"\f152"}.bi-award-fill::before{content:"\f153"}.bi-award::before{content:"\f154"}.bi-back::before{content:"\f155"}.bi-backspace-fill::before{content:"\f156"}.bi-backspace-reverse-fill::before{content:"\f157"}.bi-backspace-reverse::before{content:"\f158"}.bi-backspace::before{content:"\f159"}.bi-badge-3d-fill::before{content:"\f15a"}.bi-badge-3d::before{content:"\f15b"}.bi-badge-4k-fill::before{content:"\f15c"}.bi-badge-4k::before{content:"\f15d"}.bi-badge-8k-fill::before{content:"\f15e"}.bi-badge-8k::before{content:"\f15f"}.bi-badge-ad-fill::before{content:"\f160"}.bi-badge-ad::before{content:"\f161"}.bi-badge-ar-fill::before{content:"\f162"}.bi-badge-ar::before{content:"\f163"}.bi-badge-cc-fill::before{content:"\f164"}.bi-badge-cc::before{content:"\f165"}.bi-badge-hd-fill::before{content:"\f166"}.bi-badge-hd::before{content:"\f167"}.bi-badge-tm-fill::before{content:"\f168"}.bi-badge-tm::before{content:"\f169"}.bi-badge-vo-fill::before{content:"\f16a"}.bi-badge-vo::before{content:"\f16b"}.bi-badge-vr-fill::before{content:"\f16c"}.bi-badge-vr::before{content:"\f16d"}.bi-badge-wc-fill::before{content:"\f16e"}.bi-badge-wc::before{content:"\f16f"}.bi-bag-check-fill::before{content:"\f170"}.bi-bag-check::before{content:"\f171"}.bi-bag-dash-fill::before{content:"\f172"}.bi-bag-dash::before{content:"\f173"}.bi-bag-fill::before{content:"\f174"}.bi-bag-plus-fill::before{content:"\f175"}.bi-bag-plus::before{content:"\f176"}.bi-bag-x-fill::before{content:"\f177"}.bi-bag-x::before{content:"\f178"}.bi-bag::before{content:"\f179"}.bi-bar-chart-fill::before{content:"\f17a"}.bi-bar-chart-line-fill::before{content:"\f17b"}.bi-bar-chart-line::before{content:"\f17c"}.bi-bar-chart-steps::before{content:"\f17d"}.bi-bar-chart::before{content:"\f17e"}.bi-basket-fill::before{content:"\f17f"}.bi-basket::before{content:"\f180"}.bi-basket2-fill::before{content:"\f181"}.bi-basket2::before{content:"\f182"}.bi-basket3-fill::before{content:"\f183"}.bi-basket3::before{content:"\f184"}.bi-battery-charging::before{content:"\f185"}.bi-battery-full::before{content:"\f186"}.bi-battery-half::before{content:"\f187"}.bi-battery::before{content:"\f188"}.bi-bell-fill::before{content:"\f189"}.bi-bell::before{content:"\f18a"}.bi-bezier::before{content:"\f18b"}.bi-bezier2::before{content:"\f18c"}.bi-bicycle::before{content:"\f18d"}.bi-binoculars-fill::before{content:"\f18e"}.bi-binoculars::before{content:"\f18f"}.bi-blockquote-left::before{content:"\f190"}.bi-blockquote-right::before{content:"\f191"}.bi-book-fill::before{content:"\f192"}.bi-book-half::before{content:"\f193"}.bi-book::before{content:"\f194"}.bi-bookmark-check-fill::before{content:"\f195"}.bi-bookmark-check::before{content:"\f196"}.bi-bookmark-dash-fill::before{content:"\f197"}.bi-bookmark-dash::before{content:"\f198"}.bi-bookmark-fill::before{content:"\f199"}.bi-bookmark-heart-fill::before{content:"\f19a"}.bi-bookmark-heart::before{content:"\f19b"}.bi-bookmark-plus-fill::before{content:"\f19c"}.bi-bookmark-plus::before{content:"\f19d"}.bi-bookmark-star-fill::before{content:"\f19e"}.bi-bookmark-star::before{content:"\f19f"}.bi-bookmark-x-fill::before{content:"\f1a0"}.bi-bookmark-x::before{content:"\f1a1"}.bi-bookmark::before{content:"\f1a2"}.bi-bookmarks-fill::before{content:"\f1a3"}.bi-bookmarks::before{content:"\f1a4"}.bi-bookshelf::before{content:"\f1a5"}.bi-bootstrap-fill::before{content:"\f1a6"}.bi-bootstrap-reboot::before{content:"\f1a7"}.bi-bootstrap::before{content:"\f1a8"}.bi-border-all::before{content:"\f1a9"}.bi-border-bottom::before{content:"\f1aa"}.bi-border-center::before{content:"\f1ab"}.bi-border-inner::before{content:"\f1ac"}.bi-border-left::before{content:"\f1ad"}.bi-border-middle::before{content:"\f1ae"}.bi-border-outer::before{content:"\f1af"}.bi-border-right::before{content:"\f1b0"}.bi-border-style::before{content:"\f1b1"}.bi-border-top::before{content:"\f1b2"}.bi-border-width::before{content:"\f1b3"}.bi-border::before{content:"\f1b4"}.bi-bounding-box-circles::before{content:"\f1b5"}.bi-bounding-box::before{content:"\f1b6"}.bi-box-arrow-down-left::before{content:"\f1b7"}.bi-box-arrow-down-right::before{content:"\f1b8"}.bi-box-arrow-down::before{content:"\f1b9"}.bi-box-arrow-in-down-left::before{content:"\f1ba"}.bi-box-arrow-in-down-right::before{content:"\f1bb"}.bi-box-arrow-in-down::before{content:"\f1bc"}.bi-box-arrow-in-left::before{content:"\f1bd"}.bi-box-arrow-in-right::before{content:"\f1be"}.bi-box-arrow-in-up-left::before{content:"\f1bf"}.bi-box-arrow-in-up-right::before{content:"\f1c0"}.bi-box-arrow-in-up::before{content:"\f1c1"}.bi-box-arrow-left::before{content:"\f1c2"}.bi-box-arrow-right::before{content:"\f1c3"}.bi-box-arrow-up-left::before{content:"\f1c4"}.bi-box-arrow-up-right::before{content:"\f1c5"}.bi-box-arrow-up::before{content:"\f1c6"}.bi-box-seam::before{content:"\f1c7"}.bi-box::before{content:"\f1c8"}.bi-braces::before{content:"\f1c9"}.bi-bricks::before{content:"\f1ca"}.bi-briefcase-fill::before{content:"\f1cb"}.bi-briefcase::before{content:"\f1cc"}.bi-brightness-alt-high-fill::before{content:"\f1cd"}.bi-brightness-alt-high::before{content:"\f1ce"}.bi-brightness-alt-low-fill::before{content:"\f1cf"}.bi-brightness-alt-low::before{content:"\f1d0"}.bi-brightness-high-fill::before{content:"\f1d1"}.bi-brightness-high::before{content:"\f1d2"}.bi-brightness-low-fill::before{content:"\f1d3"}.bi-brightness-low::before{content:"\f1d4"}.bi-broadcast-pin::before{content:"\f1d5"}.bi-broadcast::before{content:"\f1d6"}.bi-brush-fill::before{content:"\f1d7"}.bi-brush::before{content:"\f1d8"}.bi-bucket-fill::before{content:"\f1d9"}.bi-bucket::before{content:"\f1da"}.bi-bug-fill::before{content:"\f1db"}.bi-bug::before{content:"\f1dc"}.bi-building::before{content:"\f1dd"}.bi-bullseye::before{content:"\f1de"}.bi-calculator-fill::before{content:"\f1df"}.bi-calculator::before{content:"\f1e0"}.bi-calendar-check-fill::before{content:"\f1e1"}.bi-calendar-check::before{content:"\f1e2"}.bi-calendar-date-fill::before{content:"\f1e3"}.bi-calendar-date::before{content:"\f1e4"}.bi-calendar-day-fill::before{content:"\f1e5"}.bi-calendar-day::before{content:"\f1e6"}.bi-calendar-event-fill::before{content:"\f1e7"}.bi-calendar-event::before{content:"\f1e8"}.bi-calendar-fill::before{content:"\f1e9"}.bi-calendar-minus-fill::before{content:"\f1ea"}.bi-calendar-minus::before{content:"\f1eb"}.bi-calendar-month-fill::before{content:"\f1ec"}.bi-calendar-month::before{content:"\f1ed"}.bi-calendar-plus-fill::before{content:"\f1ee"}.bi-calendar-plus::before{content:"\f1ef"}.bi-calendar-range-fill::before{content:"\f1f0"}.bi-calendar-range::before{content:"\f1f1"}.bi-calendar-week-fill::before{content:"\f1f2"}.bi-calendar-week::before{content:"\f1f3"}.bi-calendar-x-fill::before{content:"\f1f4"}.bi-calendar-x::before{content:"\f1f5"}.bi-calendar::before{content:"\f1f6"}.bi-calendar2-check-fill::before{content:"\f1f7"}.bi-calendar2-check::before{content:"\f1f8"}.bi-calendar2-date-fill::before{content:"\f1f9"}.bi-calendar2-date::before{content:"\f1fa"}.bi-calendar2-day-fill::before{content:"\f1fb"}.bi-calendar2-day::before{content:"\f1fc"}.bi-calendar2-event-fill::before{content:"\f1fd"}.bi-calendar2-event::before{content:"\f1fe"}.bi-calendar2-fill::before{content:"\f1ff"}.bi-calendar2-minus-fill::before{content:"\f200"}.bi-calendar2-minus::before{content:"\f201"}.bi-calendar2-month-fill::before{content:"\f202"}.bi-calendar2-month::before{content:"\f203"}.bi-calendar2-plus-fill::before{content:"\f204"}.bi-calendar2-plus::before{content:"\f205"}.bi-calendar2-range-fill::before{content:"\f206"}.bi-calendar2-range::before{content:"\f207"}.bi-calendar2-week-fill::before{content:"\f208"}.bi-calendar2-week::before{content:"\f209"}.bi-calendar2-x-fill::before{content:"\f20a"}.bi-calendar2-x::before{content:"\f20b"}.bi-calendar2::before{content:"\f20c"}.bi-calendar3-event-fill::before{content:"\f20d"}.bi-calendar3-event::before{content:"\f20e"}.bi-calendar3-fill::before{content:"\f20f"}.bi-calendar3-range-fill::before{content:"\f210"}.bi-calendar3-range::before{content:"\f211"}.bi-calendar3-week-fill::before{content:"\f212"}.bi-calendar3-week::before{content:"\f213"}.bi-calendar3::before{content:"\f214"}.bi-calendar4-event::before{content:"\f215"}.bi-calendar4-range::before{content:"\f216"}.bi-calendar4-week::before{content:"\f217"}.bi-calendar4::before{content:"\f218"}.bi-camera-fill::before{content:"\f219"}.bi-camera-reels-fill::before{content:"\f21a"}.bi-camera-reels::before{content:"\f21b"}.bi-camera-video-fill::before{content:"\f21c"}.bi-camera-video-off-fill::before{content:"\f21d"}.bi-camera-video-off::before{content:"\f21e"}.bi-camera-video::before{content:"\f21f"}.bi-camera::before{content:"\f220"}.bi-camera2::before{content:"\f221"}.bi-capslock-fill::before{content:"\f222"}.bi-capslock::before{content:"\f223"}.bi-card-checklist::before{content:"\f224"}.bi-card-heading::before{content:"\f225"}.bi-card-image::before{content:"\f226"}.bi-card-list::before{content:"\f227"}.bi-card-text::before{content:"\f228"}.bi-caret-down-fill::before{content:"\f229"}.bi-caret-down-square-fill::before{content:"\f22a"}.bi-caret-down-square::before{content:"\f22b"}.bi-caret-down::before{content:"\f22c"}.bi-caret-left-fill::before{content:"\f22d"}.bi-caret-left-square-fill::before{content:"\f22e"}.bi-caret-left-square::before{content:"\f22f"}.bi-caret-left::before{content:"\f230"}.bi-caret-right-fill::before{content:"\f231"}.bi-caret-right-square-fill::before{content:"\f232"}.bi-caret-right-square::before{content:"\f233"}.bi-caret-right::before{content:"\f234"}.bi-caret-up-fill::before{content:"\f235"}.bi-caret-up-square-fill::before{content:"\f236"}.bi-caret-up-square::before{content:"\f237"}.bi-caret-up::before{content:"\f238"}.bi-cart-check-fill::before{content:"\f239"}.bi-cart-check::before{content:"\f23a"}.bi-cart-dash-fill::before{content:"\f23b"}.bi-cart-dash::before{content:"\f23c"}.bi-cart-fill::before{content:"\f23d"}.bi-cart-plus-fill::before{content:"\f23e"}.bi-cart-plus::before{content:"\f23f"}.bi-cart-x-fill::before{content:"\f240"}.bi-cart-x::before{content:"\f241"}.bi-cart::before{content:"\f242"}.bi-cart2::before{content:"\f243"}.bi-cart3::before{content:"\f244"}.bi-cart4::before{content:"\f245"}.bi-cash-stack::before{content:"\f246"}.bi-cash::before{content:"\f247"}.bi-cast::before{content:"\f248"}.bi-chat-dots-fill::before{content:"\f249"}.bi-chat-dots::before{content:"\f24a"}.bi-chat-fill::before{content:"\f24b"}.bi-chat-left-dots-fill::before{content:"\f24c"}.bi-chat-left-dots::before{content:"\f24d"}.bi-chat-left-fill::before{content:"\f24e"}.bi-chat-left-quote-fill::before{content:"\f24f"}.bi-chat-left-quote::before{content:"\f250"}.bi-chat-left-text-fill::before{content:"\f251"}.bi-chat-left-text::before{content:"\f252"}.bi-chat-left::before{content:"\f253"}.bi-chat-quote-fill::before{content:"\f254"}.bi-chat-quote::before{content:"\f255"}.bi-chat-right-dots-fill::before{content:"\f256"}.bi-chat-right-dots::before{content:"\f257"}.bi-chat-right-fill::before{content:"\f258"}.bi-chat-right-quote-fill::before{content:"\f259"}.bi-chat-right-quote::before{content:"\f25a"}.bi-chat-right-text-fill::before{content:"\f25b"}.bi-chat-right-text::before{content:"\f25c"}.bi-chat-right::before{content:"\f25d"}.bi-chat-square-dots-fill::before{content:"\f25e"}.bi-chat-square-dots::before{content:"\f25f"}.bi-chat-square-fill::before{content:"\f260"}.bi-chat-square-quote-fill::before{content:"\f261"}.bi-chat-square-quote::before{content:"\f262"}.bi-chat-square-text-fill::before{content:"\f263"}.bi-chat-square-text::before{content:"\f264"}.bi-chat-square::before{content:"\f265"}.bi-chat-text-fill::before{content:"\f266"}.bi-chat-text::before{content:"\f267"}.bi-chat::before{content:"\f268"}.bi-check-all::before{content:"\f269"}.bi-check-circle-fill::before{content:"\f26a"}.bi-check-circle::before{content:"\f26b"}.bi-check-square-fill::before{content:"\f26c"}.bi-check-square::before{content:"\f26d"}.bi-check::before{content:"\f26e"}.bi-check2-all::before{content:"\f26f"}.bi-check2-circle::before{content:"\f270"}.bi-check2-square::before{content:"\f271"}.bi-check2::before{content:"\f272"}.bi-chevron-bar-contract::before{content:"\f273"}.bi-chevron-bar-down::before{content:"\f274"}.bi-chevron-bar-expand::before{content:"\f275"}.bi-chevron-bar-left::before{content:"\f276"}.bi-chevron-bar-right::before{content:"\f277"}.bi-chevron-bar-up::before{content:"\f278"}.bi-chevron-compact-down::before{content:"\f279"}.bi-chevron-compact-left::before{content:"\f27a"}.bi-chevron-compact-right::before{content:"\f27b"}.bi-chevron-compact-up::before{content:"\f27c"}.bi-chevron-contract::before{content:"\f27d"}.bi-chevron-double-down::before{content:"\f27e"}.bi-chevron-double-left::before{content:"\f27f"}.bi-chevron-double-right::before{content:"\f280"}.bi-chevron-double-up::before{content:"\f281"}.bi-chevron-down::before{content:"\f282"}.bi-chevron-expand::before{content:"\f283"}.bi-chevron-left::before{content:"\f284"}.bi-chevron-right::before{content:"\f285"}.bi-chevron-up::before{content:"\f286"}.bi-circle-fill::before{content:"\f287"}.bi-circle-half::before{content:"\f288"}.bi-circle-square::before{content:"\f289"}.bi-circle::before{content:"\f28a"}.bi-clipboard-check::before{content:"\f28b"}.bi-clipboard-data::before{content:"\f28c"}.bi-clipboard-minus::before{content:"\f28d"}.bi-clipboard-plus::before{content:"\f28e"}.bi-clipboard-x::before{content:"\f28f"}.bi-clipboard::before{content:"\f290"}.bi-clock-fill::before{content:"\f291"}.bi-clock-history::before{content:"\f292"}.bi-clock::before{content:"\f293"}.bi-cloud-arrow-down-fill::before{content:"\f294"}.bi-cloud-arrow-down::before{content:"\f295"}.bi-cloud-arrow-up-fill::before{content:"\f296"}.bi-cloud-arrow-up::before{content:"\f297"}.bi-cloud-check-fill::before{content:"\f298"}.bi-cloud-check::before{content:"\f299"}.bi-cloud-download-fill::before{content:"\f29a"}.bi-cloud-download::before{content:"\f29b"}.bi-cloud-drizzle-fill::before{content:"\f29c"}.bi-cloud-drizzle::before{content:"\f29d"}.bi-cloud-fill::before{content:"\f29e"}.bi-cloud-fog-fill::before{content:"\f29f"}.bi-cloud-fog::before{content:"\f2a0"}.bi-cloud-fog2-fill::before{content:"\f2a1"}.bi-cloud-fog2::before{content:"\f2a2"}.bi-cloud-hail-fill::before{content:"\f2a3"}.bi-cloud-hail::before{content:"\f2a4"}.bi-cloud-haze-fill::before{content:"\f2a6"}.bi-cloud-haze::before{content:"\f2a7"}.bi-cloud-haze2-fill::before{content:"\f2a8"}.bi-cloud-lightning-fill::before{content:"\f2a9"}.bi-cloud-lightning-rain-fill::before{content:"\f2aa"}.bi-cloud-lightning-rain::before{content:"\f2ab"}.bi-cloud-lightning::before{content:"\f2ac"}.bi-cloud-minus-fill::before{content:"\f2ad"}.bi-cloud-minus::before{content:"\f2ae"}.bi-cloud-moon-fill::before{content:"\f2af"}.bi-cloud-moon::before{content:"\f2b0"}.bi-cloud-plus-fill::before{content:"\f2b1"}.bi-cloud-plus::before{content:"\f2b2"}.bi-cloud-rain-fill::before{content:"\f2b3"}.bi-cloud-rain-heavy-fill::before{content:"\f2b4"}.bi-cloud-rain-heavy::before{content:"\f2b5"}.bi-cloud-rain::before{content:"\f2b6"}.bi-cloud-slash-fill::before{content:"\f2b7"}.bi-cloud-slash::before{content:"\f2b8"}.bi-cloud-sleet-fill::before{content:"\f2b9"}.bi-cloud-sleet::before{content:"\f2ba"}.bi-cloud-snow-fill::before{content:"\f2bb"}.bi-cloud-snow::before{content:"\f2bc"}.bi-cloud-sun-fill::before{content:"\f2bd"}.bi-cloud-sun::before{content:"\f2be"}.bi-cloud-upload-fill::before{content:"\f2bf"}.bi-cloud-upload::before{content:"\f2c0"}.bi-cloud::before{content:"\f2c1"}.bi-clouds-fill::before{content:"\f2c2"}.bi-clouds::before{content:"\f2c3"}.bi-cloudy-fill::before{content:"\f2c4"}.bi-cloudy::before{content:"\f2c5"}.bi-code-slash::before{content:"\f2c6"}.bi-code-square::before{content:"\f2c7"}.bi-code::before{content:"\f2c8"}.bi-collection-fill::before{content:"\f2c9"}.bi-collection-play-fill::before{content:"\f2ca"}.bi-collection-play::before{content:"\f2cb"}.bi-collection::before{content:"\f2cc"}.bi-columns-gap::before{content:"\f2cd"}.bi-columns::before{content:"\f2ce"}.bi-command::before{content:"\f2cf"}.bi-compass-fill::before{content:"\f2d0"}.bi-compass::before{content:"\f2d1"}.bi-cone-striped::before{content:"\f2d2"}.bi-cone::before{content:"\f2d3"}.bi-controller::before{content:"\f2d4"}.bi-cpu-fill::before{content:"\f2d5"}.bi-cpu::before{content:"\f2d6"}.bi-credit-card-2-back-fill::before{content:"\f2d7"}.bi-credit-card-2-back::before{content:"\f2d8"}.bi-credit-card-2-front-fill::before{content:"\f2d9"}.bi-credit-card-2-front::before{content:"\f2da"}.bi-credit-card-fill::before{content:"\f2db"}.bi-credit-card::before{content:"\f2dc"}.bi-crop::before{content:"\f2dd"}.bi-cup-fill::before{content:"\f2de"}.bi-cup-straw::before{content:"\f2df"}.bi-cup::before{content:"\f2e0"}.bi-cursor-fill::before{content:"\f2e1"}.bi-cursor-text::before{content:"\f2e2"}.bi-cursor::before{content:"\f2e3"}.bi-dash-circle-dotted::before{content:"\f2e4"}.bi-dash-circle-fill::before{content:"\f2e5"}.bi-dash-circle::before{content:"\f2e6"}.bi-dash-square-dotted::before{content:"\f2e7"}.bi-dash-square-fill::before{content:"\f2e8"}.bi-dash-square::before{content:"\f2e9"}.bi-dash::before{content:"\f2ea"}.bi-diagram-2-fill::before{content:"\f2eb"}.bi-diagram-2::before{content:"\f2ec"}.bi-diagram-3-fill::before{content:"\f2ed"}.bi-diagram-3::before{content:"\f2ee"}.bi-diamond-fill::before{content:"\f2ef"}.bi-diamond-half::before{content:"\f2f0"}.bi-diamond::before{content:"\f2f1"}.bi-dice-1-fill::before{content:"\f2f2"}.bi-dice-1::before{content:"\f2f3"}.bi-dice-2-fill::before{content:"\f2f4"}.bi-dice-2::before{content:"\f2f5"}.bi-dice-3-fill::before{content:"\f2f6"}.bi-dice-3::before{content:"\f2f7"}.bi-dice-4-fill::before{content:"\f2f8"}.bi-dice-4::before{content:"\f2f9"}.bi-dice-5-fill::before{content:"\f2fa"}.bi-dice-5::before{content:"\f2fb"}.bi-dice-6-fill::before{content:"\f2fc"}.bi-dice-6::before{content:"\f2fd"}.bi-disc-fill::before{content:"\f2fe"}.bi-disc::before{content:"\f2ff"}.bi-discord::before{content:"\f300"}.bi-display-fill::before{content:"\f301"}.bi-display::before{content:"\f302"}.bi-distribute-horizontal::before{content:"\f303"}.bi-distribute-vertical::before{content:"\f304"}.bi-door-closed-fill::before{content:"\f305"}.bi-door-closed::before{content:"\f306"}.bi-door-open-fill::before{content:"\f307"}.bi-door-open::before{content:"\f308"}.bi-dot::before{content:"\f309"}.bi-download::before{content:"\f30a"}.bi-droplet-fill::before{content:"\f30b"}.bi-droplet-half::before{content:"\f30c"}.bi-droplet::before{content:"\f30d"}.bi-earbuds::before{content:"\f30e"}.bi-easel-fill::before{content:"\f30f"}.bi-easel::before{content:"\f310"}.bi-egg-fill::before{content:"\f311"}.bi-egg-fried::before{content:"\f312"}.bi-egg::before{content:"\f313"}.bi-eject-fill::before{content:"\f314"}.bi-eject::before{content:"\f315"}.bi-emoji-angry-fill::before{content:"\f316"}.bi-emoji-angry::before{content:"\f317"}.bi-emoji-dizzy-fill::before{content:"\f318"}.bi-emoji-dizzy::before{content:"\f319"}.bi-emoji-expressionless-fill::before{content:"\f31a"}.bi-emoji-expressionless::before{content:"\f31b"}.bi-emoji-frown-fill::before{content:"\f31c"}.bi-emoji-frown::before{content:"\f31d"}.bi-emoji-heart-eyes-fill::before{content:"\f31e"}.bi-emoji-heart-eyes::before{content:"\f31f"}.bi-emoji-laughing-fill::before{content:"\f320"}.bi-emoji-laughing::before{content:"\f321"}.bi-emoji-neutral-fill::before{content:"\f322"}.bi-emoji-neutral::before{content:"\f323"}.bi-emoji-smile-fill::before{content:"\f324"}.bi-emoji-smile-upside-down-fill::before{content:"\f325"}.bi-emoji-smile-upside-down::before{content:"\f326"}.bi-emoji-smile::before{content:"\f327"}.bi-emoji-sunglasses-fill::before{content:"\f328"}.bi-emoji-sunglasses::before{content:"\f329"}.bi-emoji-wink-fill::before{content:"\f32a"}.bi-emoji-wink::before{content:"\f32b"}.bi-envelope-fill::before{content:"\f32c"}.bi-envelope-open-fill::before{content:"\f32d"}.bi-envelope-open::before{content:"\f32e"}.bi-envelope::before{content:"\f32f"}.bi-eraser-fill::before{content:"\f330"}.bi-eraser::before{content:"\f331"}.bi-exclamation-circle-fill::before{content:"\f332"}.bi-exclamation-circle::before{content:"\f333"}.bi-exclamation-diamond-fill::before{content:"\f334"}.bi-exclamation-diamond::before{content:"\f335"}.bi-exclamation-octagon-fill::before{content:"\f336"}.bi-exclamation-octagon::before{content:"\f337"}.bi-exclamation-square-fill::before{content:"\f338"}.bi-exclamation-square::before{content:"\f339"}.bi-exclamation-triangle-fill::before{content:"\f33a"}.bi-exclamation-triangle::before{content:"\f33b"}.bi-exclamation::before{content:"\f33c"}.bi-exclude::before{content:"\f33d"}.bi-eye-fill::before{content:"\f33e"}.bi-eye-slash-fill::before{content:"\f33f"}.bi-eye-slash::before{content:"\f340"}.bi-eye::before{content:"\f341"}.bi-eyedropper::before{content:"\f342"}.bi-eyeglasses::before{content:"\f343"}.bi-facebook::before{content:"\f344"}.bi-file-arrow-down-fill::before{content:"\f345"}.bi-file-arrow-down::before{content:"\f346"}.bi-file-arrow-up-fill::before{content:"\f347"}.bi-file-arrow-up::before{content:"\f348"}.bi-file-bar-graph-fill::before{content:"\f349"}.bi-file-bar-graph::before{content:"\f34a"}.bi-file-binary-fill::before{content:"\f34b"}.bi-file-binary::before{content:"\f34c"}.bi-file-break-fill::before{content:"\f34d"}.bi-file-break::before{content:"\f34e"}.bi-file-check-fill::before{content:"\f34f"}.bi-file-check::before{content:"\f350"}.bi-file-code-fill::before{content:"\f351"}.bi-file-code::before{content:"\f352"}.bi-file-diff-fill::before{content:"\f353"}.bi-file-diff::before{content:"\f354"}.bi-file-earmark-arrow-down-fill::before{content:"\f355"}.bi-file-earmark-arrow-down::before{content:"\f356"}.bi-file-earmark-arrow-up-fill::before{content:"\f357"}.bi-file-earmark-arrow-up::before{content:"\f358"}.bi-file-earmark-bar-graph-fill::before{content:"\f359"}.bi-file-earmark-bar-graph::before{content:"\f35a"}.bi-file-earmark-binary-fill::before{content:"\f35b"}.bi-file-earmark-binary::before{content:"\f35c"}.bi-file-earmark-break-fill::before{content:"\f35d"}.bi-file-earmark-break::before{content:"\f35e"}.bi-file-earmark-check-fill::before{content:"\f35f"}.bi-file-earmark-check::before{content:"\f360"}.bi-file-earmark-code-fill::before{content:"\f361"}.bi-file-earmark-code::before{content:"\f362"}.bi-file-earmark-diff-fill::before{content:"\f363"}.bi-file-earmark-diff::before{content:"\f364"}.bi-file-earmark-easel-fill::before{content:"\f365"}.bi-file-earmark-easel::before{content:"\f366"}.bi-file-earmark-excel-fill::before{content:"\f367"}.bi-file-earmark-excel::before{content:"\f368"}.bi-file-earmark-fill::before{content:"\f369"}.bi-file-earmark-font-fill::before{content:"\f36a"}.bi-file-earmark-font::before{content:"\f36b"}.bi-file-earmark-image-fill::before{content:"\f36c"}.bi-file-earmark-image::before{content:"\f36d"}.bi-file-earmark-lock-fill::before{content:"\f36e"}.bi-file-earmark-lock::before{content:"\f36f"}.bi-file-earmark-lock2-fill::before{content:"\f370"}.bi-file-earmark-lock2::before{content:"\f371"}.bi-file-earmark-medical-fill::before{content:"\f372"}.bi-file-earmark-medical::before{content:"\f373"}.bi-file-earmark-minus-fill::before{content:"\f374"}.bi-file-earmark-minus::before{content:"\f375"}.bi-file-earmark-music-fill::before{content:"\f376"}.bi-file-earmark-music::before{content:"\f377"}.bi-file-earmark-person-fill::before{content:"\f378"}.bi-file-earmark-person::before{content:"\f379"}.bi-file-earmark-play-fill::before{content:"\f37a"}.bi-file-earmark-play::before{content:"\f37b"}.bi-file-earmark-plus-fill::before{content:"\f37c"}.bi-file-earmark-plus::before{content:"\f37d"}.bi-file-earmark-post-fill::before{content:"\f37e"}.bi-file-earmark-post::before{content:"\f37f"}.bi-file-earmark-ppt-fill::before{content:"\f380"}.bi-file-earmark-ppt::before{content:"\f381"}.bi-file-earmark-richtext-fill::before{content:"\f382"}.bi-file-earmark-richtext::before{content:"\f383"}.bi-file-earmark-ruled-fill::before{content:"\f384"}.bi-file-earmark-ruled::before{content:"\f385"}.bi-file-earmark-slides-fill::before{content:"\f386"}.bi-file-earmark-slides::before{content:"\f387"}.bi-file-earmark-spreadsheet-fill::before{content:"\f388"}.bi-file-earmark-spreadsheet::before{content:"\f389"}.bi-file-earmark-text-fill::before{content:"\f38a"}.bi-file-earmark-text::before{content:"\f38b"}.bi-file-earmark-word-fill::before{content:"\f38c"}.bi-file-earmark-word::before{content:"\f38d"}.bi-file-earmark-x-fill::before{content:"\f38e"}.bi-file-earmark-x::before{content:"\f38f"}.bi-file-earmark-zip-fill::before{content:"\f390"}.bi-file-earmark-zip::before{content:"\f391"}.bi-file-earmark::before{content:"\f392"}.bi-file-easel-fill::before{content:"\f393"}.bi-file-easel::before{content:"\f394"}.bi-file-excel-fill::before{content:"\f395"}.bi-file-excel::before{content:"\f396"}.bi-file-fill::before{content:"\f397"}.bi-file-font-fill::before{content:"\f398"}.bi-file-font::before{content:"\f399"}.bi-file-image-fill::before{content:"\f39a"}.bi-file-image::before{content:"\f39b"}.bi-file-lock-fill::before{content:"\f39c"}.bi-file-lock::before{content:"\f39d"}.bi-file-lock2-fill::before{content:"\f39e"}.bi-file-lock2::before{content:"\f39f"}.bi-file-medical-fill::before{content:"\f3a0"}.bi-file-medical::before{content:"\f3a1"}.bi-file-minus-fill::before{content:"\f3a2"}.bi-file-minus::before{content:"\f3a3"}.bi-file-music-fill::before{content:"\f3a4"}.bi-file-music::before{content:"\f3a5"}.bi-file-person-fill::before{content:"\f3a6"}.bi-file-person::before{content:"\f3a7"}.bi-file-play-fill::before{content:"\f3a8"}.bi-file-play::before{content:"\f3a9"}.bi-file-plus-fill::before{content:"\f3aa"}.bi-file-plus::before{content:"\f3ab"}.bi-file-post-fill::before{content:"\f3ac"}.bi-file-post::before{content:"\f3ad"}.bi-file-ppt-fill::before{content:"\f3ae"}.bi-file-ppt::before{content:"\f3af"}.bi-file-richtext-fill::before{content:"\f3b0"}.bi-file-richtext::before{content:"\f3b1"}.bi-file-ruled-fill::before{content:"\f3b2"}.bi-file-ruled::before{content:"\f3b3"}.bi-file-slides-fill::before{content:"\f3b4"}.bi-file-slides::before{content:"\f3b5"}.bi-file-spreadsheet-fill::before{content:"\f3b6"}.bi-file-spreadsheet::before{content:"\f3b7"}.bi-file-text-fill::before{content:"\f3b8"}.bi-file-text::before{content:"\f3b9"}.bi-file-word-fill::before{content:"\f3ba"}.bi-file-word::before{content:"\f3bb"}.bi-file-x-fill::before{content:"\f3bc"}.bi-file-x::before{content:"\f3bd"}.bi-file-zip-fill::before{content:"\f3be"}.bi-file-zip::before{content:"\f3bf"}.bi-file::before{content:"\f3c0"}.bi-files-alt::before{content:"\f3c1"}.bi-files::before{content:"\f3c2"}.bi-film::before{content:"\f3c3"}.bi-filter-circle-fill::before{content:"\f3c4"}.bi-filter-circle::before{content:"\f3c5"}.bi-filter-left::before{content:"\f3c6"}.bi-filter-right::before{content:"\f3c7"}.bi-filter-square-fill::before{content:"\f3c8"}.bi-filter-square::before{content:"\f3c9"}.bi-filter::before{content:"\f3ca"}.bi-flag-fill::before{content:"\f3cb"}.bi-flag::before{content:"\f3cc"}.bi-flower1::before{content:"\f3cd"}.bi-flower2::before{content:"\f3ce"}.bi-flower3::before{content:"\f3cf"}.bi-folder-check::before{content:"\f3d0"}.bi-folder-fill::before{content:"\f3d1"}.bi-folder-minus::before{content:"\f3d2"}.bi-folder-plus::before{content:"\f3d3"}.bi-folder-symlink-fill::before{content:"\f3d4"}.bi-folder-symlink::before{content:"\f3d5"}.bi-folder-x::before{content:"\f3d6"}.bi-folder::before{content:"\f3d7"}.bi-folder2-open::before{content:"\f3d8"}.bi-folder2::before{content:"\f3d9"}.bi-fonts::before{content:"\f3da"}.bi-forward-fill::before{content:"\f3db"}.bi-forward::before{content:"\f3dc"}.bi-front::before{content:"\f3dd"}.bi-fullscreen-exit::before{content:"\f3de"}.bi-fullscreen::before{content:"\f3df"}.bi-funnel-fill::before{content:"\f3e0"}.bi-funnel::before{content:"\f3e1"}.bi-gear-fill::before{content:"\f3e2"}.bi-gear-wide-connected::before{content:"\f3e3"}.bi-gear-wide::before{content:"\f3e4"}.bi-gear::before{content:"\f3e5"}.bi-gem::before{content:"\f3e6"}.bi-geo-alt-fill::before{content:"\f3e7"}.bi-geo-alt::before{content:"\f3e8"}.bi-geo-fill::before{content:"\f3e9"}.bi-geo::before{content:"\f3ea"}.bi-gift-fill::before{content:"\f3eb"}.bi-gift::before{content:"\f3ec"}.bi-github::before{content:"\f3ed"}.bi-globe::before{content:"\f3ee"}.bi-globe2::before{content:"\f3ef"}.bi-google::before{content:"\f3f0"}.bi-graph-down::before{content:"\f3f1"}.bi-graph-up::before{content:"\f3f2"}.bi-grid-1x2-fill::before{content:"\f3f3"}.bi-grid-1x2::before{content:"\f3f4"}.bi-grid-3x2-gap-fill::before{content:"\f3f5"}.bi-grid-3x2-gap::before{content:"\f3f6"}.bi-grid-3x2::before{content:"\f3f7"}.bi-grid-3x3-gap-fill::before{content:"\f3f8"}.bi-grid-3x3-gap::before{content:"\f3f9"}.bi-grid-3x3::before{content:"\f3fa"}.bi-grid-fill::before{content:"\f3fb"}.bi-grid::before{content:"\f3fc"}.bi-grip-horizontal::before{content:"\f3fd"}.bi-grip-vertical::before{content:"\f3fe"}.bi-hammer::before{content:"\f3ff"}.bi-hand-index-fill::before{content:"\f400"}.bi-hand-index-thumb-fill::before{content:"\f401"}.bi-hand-index-thumb::before{content:"\f402"}.bi-hand-index::before{content:"\f403"}.bi-hand-thumbs-down-fill::before{content:"\f404"}.bi-hand-thumbs-down::before{content:"\f405"}.bi-hand-thumbs-up-fill::before{content:"\f406"}.bi-hand-thumbs-up::before{content:"\f407"}.bi-handbag-fill::before{content:"\f408"}.bi-handbag::before{content:"\f409"}.bi-hash::before{content:"\f40a"}.bi-hdd-fill::before{content:"\f40b"}.bi-hdd-network-fill::before{content:"\f40c"}.bi-hdd-network::before{content:"\f40d"}.bi-hdd-rack-fill::before{content:"\f40e"}.bi-hdd-rack::before{content:"\f40f"}.bi-hdd-stack-fill::before{content:"\f410"}.bi-hdd-stack::before{content:"\f411"}.bi-hdd::before{content:"\f412"}.bi-headphones::before{content:"\f413"}.bi-headset::before{content:"\f414"}.bi-heart-fill::before{content:"\f415"}.bi-heart-half::before{content:"\f416"}.bi-heart::before{content:"\f417"}.bi-heptagon-fill::before{content:"\f418"}.bi-heptagon-half::before{content:"\f419"}.bi-heptagon::before{content:"\f41a"}.bi-hexagon-fill::before{content:"\f41b"}.bi-hexagon-half::before{content:"\f41c"}.bi-hexagon::before{content:"\f41d"}.bi-hourglass-bottom::before{content:"\f41e"}.bi-hourglass-split::before{content:"\f41f"}.bi-hourglass-top::before{content:"\f420"}.bi-hourglass::before{content:"\f421"}.bi-house-door-fill::before{content:"\f422"}.bi-house-door::before{content:"\f423"}.bi-house-fill::before{content:"\f424"}.bi-house::before{content:"\f425"}.bi-hr::before{content:"\f426"}.bi-hurricane::before{content:"\f427"}.bi-image-alt::before{content:"\f428"}.bi-image-fill::before{content:"\f429"}.bi-image::before{content:"\f42a"}.bi-images::before{content:"\f42b"}.bi-inbox-fill::before{content:"\f42c"}.bi-inbox::before{content:"\f42d"}.bi-inboxes-fill::before{content:"\f42e"}.bi-inboxes::before{content:"\f42f"}.bi-info-circle-fill::before{content:"\f430"}.bi-info-circle::before{content:"\f431"}.bi-info-square-fill::before{content:"\f432"}.bi-info-square::before{content:"\f433"}.bi-info::before{content:"\f434"}.bi-input-cursor-text::before{content:"\f435"}.bi-input-cursor::before{content:"\f436"}.bi-instagram::before{content:"\f437"}.bi-intersect::before{content:"\f438"}.bi-journal-album::before{content:"\f439"}.bi-journal-arrow-down::before{content:"\f43a"}.bi-journal-arrow-up::before{content:"\f43b"}.bi-journal-bookmark-fill::before{content:"\f43c"}.bi-journal-bookmark::before{content:"\f43d"}.bi-journal-check::before{content:"\f43e"}.bi-journal-code::before{content:"\f43f"}.bi-journal-medical::before{content:"\f440"}.bi-journal-minus::before{content:"\f441"}.bi-journal-plus::before{content:"\f442"}.bi-journal-richtext::before{content:"\f443"}.bi-journal-text::before{content:"\f444"}.bi-journal-x::before{content:"\f445"}.bi-journal::before{content:"\f446"}.bi-journals::before{content:"\f447"}.bi-joystick::before{content:"\f448"}.bi-justify-left::before{content:"\f449"}.bi-justify-right::before{content:"\f44a"}.bi-justify::before{content:"\f44b"}.bi-kanban-fill::before{content:"\f44c"}.bi-kanban::before{content:"\f44d"}.bi-key-fill::before{content:"\f44e"}.bi-key::before{content:"\f44f"}.bi-keyboard-fill::before{content:"\f450"}.bi-keyboard::before{content:"\f451"}.bi-ladder::before{content:"\f452"}.bi-lamp-fill::before{content:"\f453"}.bi-lamp::before{content:"\f454"}.bi-laptop-fill::before{content:"\f455"}.bi-laptop::before{content:"\f456"}.bi-layer-backward::before{content:"\f457"}.bi-layer-forward::before{content:"\f458"}.bi-layers-fill::before{content:"\f459"}.bi-layers-half::before{content:"\f45a"}.bi-layers::before{content:"\f45b"}.bi-layout-sidebar-inset-reverse::before{content:"\f45c"}.bi-layout-sidebar-inset::before{content:"\f45d"}.bi-layout-sidebar-reverse::before{content:"\f45e"}.bi-layout-sidebar::before{content:"\f45f"}.bi-layout-split::before{content:"\f460"}.bi-layout-text-sidebar-reverse::before{content:"\f461"}.bi-layout-text-sidebar::before{content:"\f462"}.bi-layout-text-window-reverse::before{content:"\f463"}.bi-layout-text-window::before{content:"\f464"}.bi-layout-three-columns::before{content:"\f465"}.bi-layout-wtf::before{content:"\f466"}.bi-life-preserver::before{content:"\f467"}.bi-lightbulb-fill::before{content:"\f468"}.bi-lightbulb-off-fill::before{content:"\f469"}.bi-lightbulb-off::before{content:"\f46a"}.bi-lightbulb::before{content:"\f46b"}.bi-lightning-charge-fill::before{content:"\f46c"}.bi-lightning-charge::before{content:"\f46d"}.bi-lightning-fill::before{content:"\f46e"}.bi-lightning::before{content:"\f46f"}.bi-link-45deg::before{content:"\f470"}.bi-link::before{content:"\f471"}.bi-linkedin::before{content:"\f472"}.bi-list-check::before{content:"\f473"}.bi-list-nested::before{content:"\f474"}.bi-list-ol::before{content:"\f475"}.bi-list-stars::before{content:"\f476"}.bi-list-task::before{content:"\f477"}.bi-list-ul::before{content:"\f478"}.bi-list::before{content:"\f479"}.bi-lock-fill::before{content:"\f47a"}.bi-lock::before{content:"\f47b"}.bi-mailbox::before{content:"\f47c"}.bi-mailbox2::before{content:"\f47d"}.bi-map-fill::before{content:"\f47e"}.bi-map::before{content:"\f47f"}.bi-markdown-fill::before{content:"\f480"}.bi-markdown::before{content:"\f481"}.bi-mask::before{content:"\f482"}.bi-megaphone-fill::before{content:"\f483"}.bi-megaphone::before{content:"\f484"}.bi-menu-app-fill::before{content:"\f485"}.bi-menu-app::before{content:"\f486"}.bi-menu-button-fill::before{content:"\f487"}.bi-menu-button-wide-fill::before{content:"\f488"}.bi-menu-button-wide::before{content:"\f489"}.bi-menu-button::before{content:"\f48a"}.bi-menu-down::before{content:"\f48b"}.bi-menu-up::before{content:"\f48c"}.bi-mic-fill::before{content:"\f48d"}.bi-mic-mute-fill::before{content:"\f48e"}.bi-mic-mute::before{content:"\f48f"}.bi-mic::before{content:"\f490"}.bi-minecart-loaded::before{content:"\f491"}.bi-minecart::before{content:"\f492"}.bi-moisture::before{content:"\f493"}.bi-moon-fill::before{content:"\f494"}.bi-moon-stars-fill::before{content:"\f495"}.bi-moon-stars::before{content:"\f496"}.bi-moon::before{content:"\f497"}.bi-mouse-fill::before{content:"\f498"}.bi-mouse::before{content:"\f499"}.bi-mouse2-fill::before{content:"\f49a"}.bi-mouse2::before{content:"\f49b"}.bi-mouse3-fill::before{content:"\f49c"}.bi-mouse3::before{content:"\f49d"}.bi-music-note-beamed::before{content:"\f49e"}.bi-music-note-list::before{content:"\f49f"}.bi-music-note::before{content:"\f4a0"}.bi-music-player-fill::before{content:"\f4a1"}.bi-music-player::before{content:"\f4a2"}.bi-newspaper::before{content:"\f4a3"}.bi-node-minus-fill::before{content:"\f4a4"}.bi-node-minus::before{content:"\f4a5"}.bi-node-plus-fill::before{content:"\f4a6"}.bi-node-plus::before{content:"\f4a7"}.bi-nut-fill::before{content:"\f4a8"}.bi-nut::before{content:"\f4a9"}.bi-octagon-fill::before{content:"\f4aa"}.bi-octagon-half::before{content:"\f4ab"}.bi-octagon::before{content:"\f4ac"}.bi-option::before{content:"\f4ad"}.bi-outlet::before{content:"\f4ae"}.bi-paint-bucket::before{content:"\f4af"}.bi-palette-fill::before{content:"\f4b0"}.bi-palette::before{content:"\f4b1"}.bi-palette2::before{content:"\f4b2"}.bi-paperclip::before{content:"\f4b3"}.bi-paragraph::before{content:"\f4b4"}.bi-patch-check-fill::before{content:"\f4b5"}.bi-patch-check::before{content:"\f4b6"}.bi-patch-exclamation-fill::before{content:"\f4b7"}.bi-patch-exclamation::before{content:"\f4b8"}.bi-patch-minus-fill::before{content:"\f4b9"}.bi-patch-minus::before{content:"\f4ba"}.bi-patch-plus-fill::before{content:"\f4bb"}.bi-patch-plus::before{content:"\f4bc"}.bi-patch-question-fill::before{content:"\f4bd"}.bi-patch-question::before{content:"\f4be"}.bi-pause-btn-fill::before{content:"\f4bf"}.bi-pause-btn::before{content:"\f4c0"}.bi-pause-circle-fill::before{content:"\f4c1"}.bi-pause-circle::before{content:"\f4c2"}.bi-pause-fill::before{content:"\f4c3"}.bi-pause::before{content:"\f4c4"}.bi-peace-fill::before{content:"\f4c5"}.bi-peace::before{content:"\f4c6"}.bi-pen-fill::before{content:"\f4c7"}.bi-pen::before{content:"\f4c8"}.bi-pencil-fill::before{content:"\f4c9"}.bi-pencil-square::before{content:"\f4ca"}.bi-pencil::before{content:"\f4cb"}.bi-pentagon-fill::before{content:"\f4cc"}.bi-pentagon-half::before{content:"\f4cd"}.bi-pentagon::before{content:"\f4ce"}.bi-people-fill::before{content:"\f4cf"}.bi-people::before{content:"\f4d0"}.bi-percent::before{content:"\f4d1"}.bi-person-badge-fill::before{content:"\f4d2"}.bi-person-badge::before{content:"\f4d3"}.bi-person-bounding-box::before{content:"\f4d4"}.bi-person-check-fill::before{content:"\f4d5"}.bi-person-check::before{content:"\f4d6"}.bi-person-circle::before{content:"\f4d7"}.bi-person-dash-fill::before{content:"\f4d8"}.bi-person-dash::before{content:"\f4d9"}.bi-person-fill::before{content:"\f4da"}.bi-person-lines-fill::before{content:"\f4db"}.bi-person-plus-fill::before{content:"\f4dc"}.bi-person-plus::before{content:"\f4dd"}.bi-person-square::before{content:"\f4de"}.bi-person-x-fill::before{content:"\f4df"}.bi-person-x::before{content:"\f4e0"}.bi-person::before{content:"\f4e1"}.bi-phone-fill::before{content:"\f4e2"}.bi-phone-landscape-fill::before{content:"\f4e3"}.bi-phone-landscape::before{content:"\f4e4"}.bi-phone-vibrate-fill::before{content:"\f4e5"}.bi-phone-vibrate::before{content:"\f4e6"}.bi-phone::before{content:"\f4e7"}.bi-pie-chart-fill::before{content:"\f4e8"}.bi-pie-chart::before{content:"\f4e9"}.bi-pin-angle-fill::before{content:"\f4ea"}.bi-pin-angle::before{content:"\f4eb"}.bi-pin-fill::before{content:"\f4ec"}.bi-pin::before{content:"\f4ed"}.bi-pip-fill::before{content:"\f4ee"}.bi-pip::before{content:"\f4ef"}.bi-play-btn-fill::before{content:"\f4f0"}.bi-play-btn::before{content:"\f4f1"}.bi-play-circle-fill::before{content:"\f4f2"}.bi-play-circle::before{content:"\f4f3"}.bi-play-fill::before{content:"\f4f4"}.bi-play::before{content:"\f4f5"}.bi-plug-fill::before{content:"\f4f6"}.bi-plug::before{content:"\f4f7"}.bi-plus-circle-dotted::before{content:"\f4f8"}.bi-plus-circle-fill::before{content:"\f4f9"}.bi-plus-circle::before{content:"\f4fa"}.bi-plus-square-dotted::before{content:"\f4fb"}.bi-plus-square-fill::before{content:"\f4fc"}.bi-plus-square::before{content:"\f4fd"}.bi-plus::before{content:"\f4fe"}.bi-power::before{content:"\f4ff"}.bi-printer-fill::before{content:"\f500"}.bi-printer::before{content:"\f501"}.bi-puzzle-fill::before{content:"\f502"}.bi-puzzle::before{content:"\f503"}.bi-question-circle-fill::before{content:"\f504"}.bi-question-circle::before{content:"\f505"}.bi-question-diamond-fill::before{content:"\f506"}.bi-question-diamond::before{content:"\f507"}.bi-question-octagon-fill::before{content:"\f508"}.bi-question-octagon::before{content:"\f509"}.bi-question-square-fill::before{content:"\f50a"}.bi-question-square::before{content:"\f50b"}.bi-question::before{content:"\f50c"}.bi-rainbow::before{content:"\f50d"}.bi-receipt-cutoff::before{content:"\f50e"}.bi-receipt::before{content:"\f50f"}.bi-reception-0::before{content:"\f510"}.bi-reception-1::before{content:"\f511"}.bi-reception-2::before{content:"\f512"}.bi-reception-3::before{content:"\f513"}.bi-reception-4::before{content:"\f514"}.bi-record-btn-fill::before{content:"\f515"}.bi-record-btn::before{content:"\f516"}.bi-record-circle-fill::before{content:"\f517"}.bi-record-circle::before{content:"\f518"}.bi-record-fill::before{content:"\f519"}.bi-record::before{content:"\f51a"}.bi-record2-fill::before{content:"\f51b"}.bi-record2::before{content:"\f51c"}.bi-reply-all-fill::before{content:"\f51d"}.bi-reply-all::before{content:"\f51e"}.bi-reply-fill::before{content:"\f51f"}.bi-reply::before{content:"\f520"}.bi-rss-fill::before{content:"\f521"}.bi-rss::before{content:"\f522"}.bi-rulers::before{content:"\f523"}.bi-save-fill::before{content:"\f524"}.bi-save::before{content:"\f525"}.bi-save2-fill::before{content:"\f526"}.bi-save2::before{content:"\f527"}.bi-scissors::before{content:"\f528"}.bi-screwdriver::before{content:"\f529"}.bi-search::before{content:"\f52a"}.bi-segmented-nav::before{content:"\f52b"}.bi-server::before{content:"\f52c"}.bi-share-fill::before{content:"\f52d"}.bi-share::before{content:"\f52e"}.bi-shield-check::before{content:"\f52f"}.bi-shield-exclamation::before{content:"\f530"}.bi-shield-fill-check::before{content:"\f531"}.bi-shield-fill-exclamation::before{content:"\f532"}.bi-shield-fill-minus::before{content:"\f533"}.bi-shield-fill-plus::before{content:"\f534"}.bi-shield-fill-x::before{content:"\f535"}.bi-shield-fill::before{content:"\f536"}.bi-shield-lock-fill::before{content:"\f537"}.bi-shield-lock::before{content:"\f538"}.bi-shield-minus::before{content:"\f539"}.bi-shield-plus::before{content:"\f53a"}.bi-shield-shaded::before{content:"\f53b"}.bi-shield-slash-fill::before{content:"\f53c"}.bi-shield-slash::before{content:"\f53d"}.bi-shield-x::before{content:"\f53e"}.bi-shield::before{content:"\f53f"}.bi-shift-fill::before{content:"\f540"}.bi-shift::before{content:"\f541"}.bi-shop-window::before{content:"\f542"}.bi-shop::before{content:"\f543"}.bi-shuffle::before{content:"\f544"}.bi-signpost-2-fill::before{content:"\f545"}.bi-signpost-2::before{content:"\f546"}.bi-signpost-fill::before{content:"\f547"}.bi-signpost-split-fill::before{content:"\f548"}.bi-signpost-split::before{content:"\f549"}.bi-signpost::before{content:"\f54a"}.bi-sim-fill::before{content:"\f54b"}.bi-sim::before{content:"\f54c"}.bi-skip-backward-btn-fill::before{content:"\f54d"}.bi-skip-backward-btn::before{content:"\f54e"}.bi-skip-backward-circle-fill::before{content:"\f54f"}.bi-skip-backward-circle::before{content:"\f550"}.bi-skip-backward-fill::before{content:"\f551"}.bi-skip-backward::before{content:"\f552"}.bi-skip-end-btn-fill::before{content:"\f553"}.bi-skip-end-btn::before{content:"\f554"}.bi-skip-end-circle-fill::before{content:"\f555"}.bi-skip-end-circle::before{content:"\f556"}.bi-skip-end-fill::before{content:"\f557"}.bi-skip-end::before{content:"\f558"}.bi-skip-forward-btn-fill::before{content:"\f559"}.bi-skip-forward-btn::before{content:"\f55a"}.bi-skip-forward-circle-fill::before{content:"\f55b"}.bi-skip-forward-circle::before{content:"\f55c"}.bi-skip-forward-fill::before{content:"\f55d"}.bi-skip-forward::before{content:"\f55e"}.bi-skip-start-btn-fill::before{content:"\f55f"}.bi-skip-start-btn::before{content:"\f560"}.bi-skip-start-circle-fill::before{content:"\f561"}.bi-skip-start-circle::before{content:"\f562"}.bi-skip-start-fill::before{content:"\f563"}.bi-skip-start::before{content:"\f564"}.bi-slack::before{content:"\f565"}.bi-slash-circle-fill::before{content:"\f566"}.bi-slash-circle::before{content:"\f567"}.bi-slash-square-fill::before{content:"\f568"}.bi-slash-square::before{content:"\f569"}.bi-slash::before{content:"\f56a"}.bi-sliders::before{content:"\f56b"}.bi-smartwatch::before{content:"\f56c"}.bi-snow::before{content:"\f56d"}.bi-snow2::before{content:"\f56e"}.bi-snow3::before{content:"\f56f"}.bi-sort-alpha-down-alt::before{content:"\f570"}.bi-sort-alpha-down::before{content:"\f571"}.bi-sort-alpha-up-alt::before{content:"\f572"}.bi-sort-alpha-up::before{content:"\f573"}.bi-sort-down-alt::before{content:"\f574"}.bi-sort-down::before{content:"\f575"}.bi-sort-numeric-down-alt::before{content:"\f576"}.bi-sort-numeric-down::before{content:"\f577"}.bi-sort-numeric-up-alt::before{content:"\f578"}.bi-sort-numeric-up::before{content:"\f579"}.bi-sort-up-alt::before{content:"\f57a"}.bi-sort-up::before{content:"\f57b"}.bi-soundwave::before{content:"\f57c"}.bi-speaker-fill::before{content:"\f57d"}.bi-speaker::before{content:"\f57e"}.bi-speedometer::before{content:"\f57f"}.bi-speedometer2::before{content:"\f580"}.bi-spellcheck::before{content:"\f581"}.bi-square-fill::before{content:"\f582"}.bi-square-half::before{content:"\f583"}.bi-square::before{content:"\f584"}.bi-stack::before{content:"\f585"}.bi-star-fill::before{content:"\f586"}.bi-star-half::before{content:"\f587"}.bi-star::before{content:"\f588"}.bi-stars::before{content:"\f589"}.bi-stickies-fill::before{content:"\f58a"}.bi-stickies::before{content:"\f58b"}.bi-sticky-fill::before{content:"\f58c"}.bi-sticky::before{content:"\f58d"}.bi-stop-btn-fill::before{content:"\f58e"}.bi-stop-btn::before{content:"\f58f"}.bi-stop-circle-fill::before{content:"\f590"}.bi-stop-circle::before{content:"\f591"}.bi-stop-fill::before{content:"\f592"}.bi-stop::before{content:"\f593"}.bi-stoplights-fill::before{content:"\f594"}.bi-stoplights::before{content:"\f595"}.bi-stopwatch-fill::before{content:"\f596"}.bi-stopwatch::before{content:"\f597"}.bi-subtract::before{content:"\f598"}.bi-suit-club-fill::before{content:"\f599"}.bi-suit-club::before{content:"\f59a"}.bi-suit-diamond-fill::before{content:"\f59b"}.bi-suit-diamond::before{content:"\f59c"}.bi-suit-heart-fill::before{content:"\f59d"}.bi-suit-heart::before{content:"\f59e"}.bi-suit-spade-fill::before{content:"\f59f"}.bi-suit-spade::before{content:"\f5a0"}.bi-sun-fill::before{content:"\f5a1"}.bi-sun::before{content:"\f5a2"}.bi-sunglasses::before{content:"\f5a3"}.bi-sunrise-fill::before{content:"\f5a4"}.bi-sunrise::before{content:"\f5a5"}.bi-sunset-fill::before{content:"\f5a6"}.bi-sunset::before{content:"\f5a7"}.bi-symmetry-horizontal::before{content:"\f5a8"}.bi-symmetry-vertical::before{content:"\f5a9"}.bi-table::before{content:"\f5aa"}.bi-tablet-fill::before{content:"\f5ab"}.bi-tablet-landscape-fill::before{content:"\f5ac"}.bi-tablet-landscape::before{content:"\f5ad"}.bi-tablet::before{content:"\f5ae"}.bi-tag-fill::before{content:"\f5af"}.bi-tag::before{content:"\f5b0"}.bi-tags-fill::before{content:"\f5b1"}.bi-tags::before{content:"\f5b2"}.bi-telegram::before{content:"\f5b3"}.bi-telephone-fill::before{content:"\f5b4"}.bi-telephone-forward-fill::before{content:"\f5b5"}.bi-telephone-forward::before{content:"\f5b6"}.bi-telephone-inbound-fill::before{content:"\f5b7"}.bi-telephone-inbound::before{content:"\f5b8"}.bi-telephone-minus-fill::before{content:"\f5b9"}.bi-telephone-minus::before{content:"\f5ba"}.bi-telephone-outbound-fill::before{content:"\f5bb"}.bi-telephone-outbound::before{content:"\f5bc"}.bi-telephone-plus-fill::before{content:"\f5bd"}.bi-telephone-plus::before{content:"\f5be"}.bi-telephone-x-fill::before{content:"\f5bf"}.bi-telephone-x::before{content:"\f5c0"}.bi-telephone::before{content:"\f5c1"}.bi-terminal-fill::before{content:"\f5c2"}.bi-terminal::before{content:"\f5c3"}.bi-text-center::before{content:"\f5c4"}.bi-text-indent-left::before{content:"\f5c5"}.bi-text-indent-right::before{content:"\f5c6"}.bi-text-left::before{content:"\f5c7"}.bi-text-paragraph::before{content:"\f5c8"}.bi-text-right::before{content:"\f5c9"}.bi-textarea-resize::before{content:"\f5ca"}.bi-textarea-t::before{content:"\f5cb"}.bi-textarea::before{content:"\f5cc"}.bi-thermometer-half::before{content:"\f5cd"}.bi-thermometer-high::before{content:"\f5ce"}.bi-thermometer-low::before{content:"\f5cf"}.bi-thermometer-snow::before{content:"\f5d0"}.bi-thermometer-sun::before{content:"\f5d1"}.bi-thermometer::before{content:"\f5d2"}.bi-three-dots-vertical::before{content:"\f5d3"}.bi-three-dots::before{content:"\f5d4"}.bi-toggle-off::before{content:"\f5d5"}.bi-toggle-on::before{content:"\f5d6"}.bi-toggle2-off::before{content:"\f5d7"}.bi-toggle2-on::before{content:"\f5d8"}.bi-toggles::before{content:"\f5d9"}.bi-toggles2::before{content:"\f5da"}.bi-tools::before{content:"\f5db"}.bi-tornado::before{content:"\f5dc"}.bi-trash-fill::before{content:"\f5dd"}.bi-trash::before{content:"\f5de"}.bi-trash2-fill::before{content:"\f5df"}.bi-trash2::before{content:"\f5e0"}.bi-tree-fill::before{content:"\f5e1"}.bi-tree::before{content:"\f5e2"}.bi-triangle-fill::before{content:"\f5e3"}.bi-triangle-half::before{content:"\f5e4"}.bi-triangle::before{content:"\f5e5"}.bi-trophy-fill::before{content:"\f5e6"}.bi-trophy::before{content:"\f5e7"}.bi-tropical-storm::before{content:"\f5e8"}.bi-truck-flatbed::before{content:"\f5e9"}.bi-truck::before{content:"\f5ea"}.bi-tsunami::before{content:"\f5eb"}.bi-tv-fill::before{content:"\f5ec"}.bi-tv::before{content:"\f5ed"}.bi-twitch::before{content:"\f5ee"}.bi-twitter::before{content:"\f5ef"}.bi-type-bold::before{content:"\f5f0"}.bi-type-h1::before{content:"\f5f1"}.bi-type-h2::before{content:"\f5f2"}.bi-type-h3::before{content:"\f5f3"}.bi-type-italic::before{content:"\f5f4"}.bi-type-strikethrough::before{content:"\f5f5"}.bi-type-underline::before{content:"\f5f6"}.bi-type::before{content:"\f5f7"}.bi-ui-checks-grid::before{content:"\f5f8"}.bi-ui-checks::before{content:"\f5f9"}.bi-ui-radios-grid::before{content:"\f5fa"}.bi-ui-radios::before{content:"\f5fb"}.bi-umbrella-fill::before{content:"\f5fc"}.bi-umbrella::before{content:"\f5fd"}.bi-union::before{content:"\f5fe"}.bi-unlock-fill::before{content:"\f5ff"}.bi-unlock::before{content:"\f600"}.bi-upc-scan::before{content:"\f601"}.bi-upc::before{content:"\f602"}.bi-upload::before{content:"\f603"}.bi-vector-pen::before{content:"\f604"}.bi-view-list::before{content:"\f605"}.bi-view-stacked::before{content:"\f606"}.bi-vinyl-fill::before{content:"\f607"}.bi-vinyl::before{content:"\f608"}.bi-voicemail::before{content:"\f609"}.bi-volume-down-fill::before{content:"\f60a"}.bi-volume-down::before{content:"\f60b"}.bi-volume-mute-fill::before{content:"\f60c"}.bi-volume-mute::before{content:"\f60d"}.bi-volume-off-fill::before{content:"\f60e"}.bi-volume-off::before{content:"\f60f"}.bi-volume-up-fill::before{content:"\f610"}.bi-volume-up::before{content:"\f611"}.bi-vr::before{content:"\f612"}.bi-wallet-fill::before{content:"\f613"}.bi-wallet::before{content:"\f614"}.bi-wallet2::before{content:"\f615"}.bi-watch::before{content:"\f616"}.bi-water::before{content:"\f617"}.bi-whatsapp::before{content:"\f618"}.bi-wifi-1::before{content:"\f619"}.bi-wifi-2::before{content:"\f61a"}.bi-wifi-off::before{content:"\f61b"}.bi-wifi::before{content:"\f61c"}.bi-wind::before{content:"\f61d"}.bi-window-dock::before{content:"\f61e"}.bi-window-sidebar::before{content:"\f61f"}.bi-window::before{content:"\f620"}.bi-wrench::before{content:"\f621"}.bi-x-circle-fill::before{content:"\f622"}.bi-x-circle::before{content:"\f623"}.bi-x-diamond-fill::before{content:"\f624"}.bi-x-diamond::before{content:"\f625"}.bi-x-octagon-fill::before{content:"\f626"}.bi-x-octagon::before{content:"\f627"}.bi-x-square-fill::before{content:"\f628"}.bi-x-square::before{content:"\f629"}.bi-x::before{content:"\f62a"}.bi-youtube::before{content:"\f62b"}.bi-zoom-in::before{content:"\f62c"}.bi-zoom-out::before{content:"\f62d"}.bi-bank::before{content:"\f62e"}.bi-bank2::before{content:"\f62f"}.bi-bell-slash-fill::before{content:"\f630"}.bi-bell-slash::before{content:"\f631"}.bi-cash-coin::before{content:"\f632"}.bi-check-lg::before{content:"\f633"}.bi-coin::before{content:"\f634"}.bi-currency-bitcoin::before{content:"\f635"}.bi-currency-dollar::before{content:"\f636"}.bi-currency-euro::before{content:"\f637"}.bi-currency-exchange::before{content:"\f638"}.bi-currency-pound::before{content:"\f639"}.bi-currency-yen::before{content:"\f63a"}.bi-dash-lg::before{content:"\f63b"}.bi-exclamation-lg::before{content:"\f63c"}.bi-file-earmark-pdf-fill::before{content:"\f63d"}.bi-file-earmark-pdf::before{content:"\f63e"}.bi-file-pdf-fill::before{content:"\f63f"}.bi-file-pdf::before{content:"\f640"}.bi-gender-ambiguous::before{content:"\f641"}.bi-gender-female::before{content:"\f642"}.bi-gender-male::before{content:"\f643"}.bi-gender-trans::before{content:"\f644"}.bi-headset-vr::before{content:"\f645"}.bi-info-lg::before{content:"\f646"}.bi-mastodon::before{content:"\f647"}.bi-messenger::before{content:"\f648"}.bi-piggy-bank-fill::before{content:"\f649"}.bi-piggy-bank::before{content:"\f64a"}.bi-pin-map-fill::before{content:"\f64b"}.bi-pin-map::before{content:"\f64c"}.bi-plus-lg::before{content:"\f64d"}.bi-question-lg::before{content:"\f64e"}.bi-recycle::before{content:"\f64f"}.bi-reddit::before{content:"\f650"}.bi-safe-fill::before{content:"\f651"}.bi-safe2-fill::before{content:"\f652"}.bi-safe2::before{content:"\f653"}.bi-sd-card-fill::before{content:"\f654"}.bi-sd-card::before{content:"\f655"}.bi-skype::before{content:"\f656"}.bi-slash-lg::before{content:"\f657"}.bi-translate::before{content:"\f658"}.bi-x-lg::before{content:"\f659"}.bi-safe::before{content:"\f65a"}.bi-apple::before{content:"\f65b"}.bi-microsoft::before{content:"\f65d"}.bi-windows::before{content:"\f65e"}.bi-behance::before{content:"\f65c"}.bi-dribbble::before{content:"\f65f"}.bi-line::before{content:"\f660"}.bi-medium::before{content:"\f661"}.bi-paypal::before{content:"\f662"}.bi-pinterest::before{content:"\f663"}.bi-signal::before{content:"\f664"}.bi-snapchat::before{content:"\f665"}.bi-spotify::before{content:"\f666"}.bi-stack-overflow::before{content:"\f667"}.bi-strava::before{content:"\f668"}.bi-wordpress::before{content:"\f669"}.bi-vimeo::before{content:"\f66a"}.bi-activity::before{content:"\f66b"}.bi-easel2-fill::before{content:"\f66c"}.bi-easel2::before{content:"\f66d"}.bi-easel3-fill::before{content:"\f66e"}.bi-easel3::before{content:"\f66f"}.bi-fan::before{content:"\f670"}.bi-fingerprint::before{content:"\f671"}.bi-graph-down-arrow::before{content:"\f672"}.bi-graph-up-arrow::before{content:"\f673"}.bi-hypnotize::before{content:"\f674"}.bi-magic::before{content:"\f675"}.bi-person-rolodex::before{content:"\f676"}.bi-person-video::before{content:"\f677"}.bi-person-video2::before{content:"\f678"}.bi-person-video3::before{content:"\f679"}.bi-person-workspace::before{content:"\f67a"}.bi-radioactive::before{content:"\f67b"}.bi-webcam-fill::before{content:"\f67c"}.bi-webcam::before{content:"\f67d"}.bi-yin-yang::before{content:"\f67e"}.bi-bandaid-fill::before{content:"\f680"}.bi-bandaid::before{content:"\f681"}.bi-bluetooth::before{content:"\f682"}.bi-body-text::before{content:"\f683"}.bi-boombox::before{content:"\f684"}.bi-boxes::before{content:"\f685"}.bi-dpad-fill::before{content:"\f686"}.bi-dpad::before{content:"\f687"}.bi-ear-fill::before{content:"\f688"}.bi-ear::before{content:"\f689"}.bi-envelope-check-fill::before{content:"\f68b"}.bi-envelope-check::before{content:"\f68c"}.bi-envelope-dash-fill::before{content:"\f68e"}.bi-envelope-dash::before{content:"\f68f"}.bi-envelope-exclamation-fill::before{content:"\f691"}.bi-envelope-exclamation::before{content:"\f692"}.bi-envelope-plus-fill::before{content:"\f693"}.bi-envelope-plus::before{content:"\f694"}.bi-envelope-slash-fill::before{content:"\f696"}.bi-envelope-slash::before{content:"\f697"}.bi-envelope-x-fill::before{content:"\f699"}.bi-envelope-x::before{content:"\f69a"}.bi-explicit-fill::before{content:"\f69b"}.bi-explicit::before{content:"\f69c"}.bi-git::before{content:"\f69d"}.bi-infinity::before{content:"\f69e"}.bi-list-columns-reverse::before{content:"\f69f"}.bi-list-columns::before{content:"\f6a0"}.bi-meta::before{content:"\f6a1"}.bi-nintendo-switch::before{content:"\f6a4"}.bi-pc-display-horizontal::before{content:"\f6a5"}.bi-pc-display::before{content:"\f6a6"}.bi-pc-horizontal::before{content:"\f6a7"}.bi-pc::before{content:"\f6a8"}.bi-playstation::before{content:"\f6a9"}.bi-plus-slash-minus::before{content:"\f6aa"}.bi-projector-fill::before{content:"\f6ab"}.bi-projector::before{content:"\f6ac"}.bi-qr-code-scan::before{content:"\f6ad"}.bi-qr-code::before{content:"\f6ae"}.bi-quora::before{content:"\f6af"}.bi-quote::before{content:"\f6b0"}.bi-robot::before{content:"\f6b1"}.bi-send-check-fill::before{content:"\f6b2"}.bi-send-check::before{content:"\f6b3"}.bi-send-dash-fill::before{content:"\f6b4"}.bi-send-dash::before{content:"\f6b5"}.bi-send-exclamation-fill::before{content:"\f6b7"}.bi-send-exclamation::before{content:"\f6b8"}.bi-send-fill::before{content:"\f6b9"}.bi-send-plus-fill::before{content:"\f6ba"}.bi-send-plus::before{content:"\f6bb"}.bi-send-slash-fill::before{content:"\f6bc"}.bi-send-slash::before{content:"\f6bd"}.bi-send-x-fill::before{content:"\f6be"}.bi-send-x::before{content:"\f6bf"}.bi-send::before{content:"\f6c0"}.bi-steam::before{content:"\f6c1"}.bi-terminal-dash::before{content:"\f6c3"}.bi-terminal-plus::before{content:"\f6c4"}.bi-terminal-split::before{content:"\f6c5"}.bi-ticket-detailed-fill::before{content:"\f6c6"}.bi-ticket-detailed::before{content:"\f6c7"}.bi-ticket-fill::before{content:"\f6c8"}.bi-ticket-perforated-fill::before{content:"\f6c9"}.bi-ticket-perforated::before{content:"\f6ca"}.bi-ticket::before{content:"\f6cb"}.bi-tiktok::before{content:"\f6cc"}.bi-window-dash::before{content:"\f6cd"}.bi-window-desktop::before{content:"\f6ce"}.bi-window-fullscreen::before{content:"\f6cf"}.bi-window-plus::before{content:"\f6d0"}.bi-window-split::before{content:"\f6d1"}.bi-window-stack::before{content:"\f6d2"}.bi-window-x::before{content:"\f6d3"}.bi-xbox::before{content:"\f6d4"}.bi-ethernet::before{content:"\f6d5"}.bi-hdmi-fill::before{content:"\f6d6"}.bi-hdmi::before{content:"\f6d7"}.bi-usb-c-fill::before{content:"\f6d8"}.bi-usb-c::before{content:"\f6d9"}.bi-usb-fill::before{content:"\f6da"}.bi-usb-plug-fill::before{content:"\f6db"}.bi-usb-plug::before{content:"\f6dc"}.bi-usb-symbol::before{content:"\f6dd"}.bi-usb::before{content:"\f6de"}.bi-boombox-fill::before{content:"\f6df"}.bi-displayport::before{content:"\f6e1"}.bi-gpu-card::before{content:"\f6e2"}.bi-memory::before{content:"\f6e3"}.bi-modem-fill::before{content:"\f6e4"}.bi-modem::before{content:"\f6e5"}.bi-motherboard-fill::before{content:"\f6e6"}.bi-motherboard::before{content:"\f6e7"}.bi-optical-audio-fill::before{content:"\f6e8"}.bi-optical-audio::before{content:"\f6e9"}.bi-pci-card::before{content:"\f6ea"}.bi-router-fill::before{content:"\f6eb"}.bi-router::before{content:"\f6ec"}.bi-thunderbolt-fill::before{content:"\f6ef"}.bi-thunderbolt::before{content:"\f6f0"}.bi-usb-drive-fill::before{content:"\f6f1"}.bi-usb-drive::before{content:"\f6f2"}.bi-usb-micro-fill::before{content:"\f6f3"}.bi-usb-micro::before{content:"\f6f4"}.bi-usb-mini-fill::before{content:"\f6f5"}.bi-usb-mini::before{content:"\f6f6"}.bi-cloud-haze2::before{content:"\f6f7"}.bi-device-hdd-fill::before{content:"\f6f8"}.bi-device-hdd::before{content:"\f6f9"}.bi-device-ssd-fill::before{content:"\f6fa"}.bi-device-ssd::before{content:"\f6fb"}.bi-displayport-fill::before{content:"\f6fc"}.bi-mortarboard-fill::before{content:"\f6fd"}.bi-mortarboard::before{content:"\f6fe"}.bi-terminal-x::before{content:"\f6ff"}.bi-arrow-through-heart-fill::before{content:"\f700"}.bi-arrow-through-heart::before{content:"\f701"}.bi-badge-sd-fill::before{content:"\f702"}.bi-badge-sd::before{content:"\f703"}.bi-bag-heart-fill::before{content:"\f704"}.bi-bag-heart::before{content:"\f705"}.bi-balloon-fill::before{content:"\f706"}.bi-balloon-heart-fill::before{content:"\f707"}.bi-balloon-heart::before{content:"\f708"}.bi-balloon::before{content:"\f709"}.bi-box2-fill::before{content:"\f70a"}.bi-box2-heart-fill::before{content:"\f70b"}.bi-box2-heart::before{content:"\f70c"}.bi-box2::before{content:"\f70d"}.bi-braces-asterisk::before{content:"\f70e"}.bi-calendar-heart-fill::before{content:"\f70f"}.bi-calendar-heart::before{content:"\f710"}.bi-calendar2-heart-fill::before{content:"\f711"}.bi-calendar2-heart::before{content:"\f712"}.bi-chat-heart-fill::before{content:"\f713"}.bi-chat-heart::before{content:"\f714"}.bi-chat-left-heart-fill::before{content:"\f715"}.bi-chat-left-heart::before{content:"\f716"}.bi-chat-right-heart-fill::before{content:"\f717"}.bi-chat-right-heart::before{content:"\f718"}.bi-chat-square-heart-fill::before{content:"\f719"}.bi-chat-square-heart::before{content:"\f71a"}.bi-clipboard-check-fill::before{content:"\f71b"}.bi-clipboard-data-fill::before{content:"\f71c"}.bi-clipboard-fill::before{content:"\f71d"}.bi-clipboard-heart-fill::before{content:"\f71e"}.bi-clipboard-heart::before{content:"\f71f"}.bi-clipboard-minus-fill::before{content:"\f720"}.bi-clipboard-plus-fill::before{content:"\f721"}.bi-clipboard-pulse::before{content:"\f722"}.bi-clipboard-x-fill::before{content:"\f723"}.bi-clipboard2-check-fill::before{content:"\f724"}.bi-clipboard2-check::before{content:"\f725"}.bi-clipboard2-data-fill::before{content:"\f726"}.bi-clipboard2-data::before{content:"\f727"}.bi-clipboard2-fill::before{content:"\f728"}.bi-clipboard2-heart-fill::before{content:"\f729"}.bi-clipboard2-heart::before{content:"\f72a"}.bi-clipboard2-minus-fill::before{content:"\f72b"}.bi-clipboard2-minus::before{content:"\f72c"}.bi-clipboard2-plus-fill::before{content:"\f72d"}.bi-clipboard2-plus::before{content:"\f72e"}.bi-clipboard2-pulse-fill::before{content:"\f72f"}.bi-clipboard2-pulse::before{content:"\f730"}.bi-clipboard2-x-fill::before{content:"\f731"}.bi-clipboard2-x::before{content:"\f732"}.bi-clipboard2::before{content:"\f733"}.bi-emoji-kiss-fill::before{content:"\f734"}.bi-emoji-kiss::before{content:"\f735"}.bi-envelope-heart-fill::before{content:"\f736"}.bi-envelope-heart::before{content:"\f737"}.bi-envelope-open-heart-fill::before{content:"\f738"}.bi-envelope-open-heart::before{content:"\f739"}.bi-envelope-paper-fill::before{content:"\f73a"}.bi-envelope-paper-heart-fill::before{content:"\f73b"}.bi-envelope-paper-heart::before{content:"\f73c"}.bi-envelope-paper::before{content:"\f73d"}.bi-filetype-aac::before{content:"\f73e"}.bi-filetype-ai::before{content:"\f73f"}.bi-filetype-bmp::before{content:"\f740"}.bi-filetype-cs::before{content:"\f741"}.bi-filetype-css::before{content:"\f742"}.bi-filetype-csv::before{content:"\f743"}.bi-filetype-doc::before{content:"\f744"}.bi-filetype-docx::before{content:"\f745"}.bi-filetype-exe::before{content:"\f746"}.bi-filetype-gif::before{content:"\f747"}.bi-filetype-heic::before{content:"\f748"}.bi-filetype-html::before{content:"\f749"}.bi-filetype-java::before{content:"\f74a"}.bi-filetype-jpg::before{content:"\f74b"}.bi-filetype-js::before{content:"\f74c"}.bi-filetype-jsx::before{content:"\f74d"}.bi-filetype-key::before{content:"\f74e"}.bi-filetype-m4p::before{content:"\f74f"}.bi-filetype-md::before{content:"\f750"}.bi-filetype-mdx::before{content:"\f751"}.bi-filetype-mov::before{content:"\f752"}.bi-filetype-mp3::before{content:"\f753"}.bi-filetype-mp4::before{content:"\f754"}.bi-filetype-otf::before{content:"\f755"}.bi-filetype-pdf::before{content:"\f756"}.bi-filetype-php::before{content:"\f757"}.bi-filetype-png::before{content:"\f758"}.bi-filetype-ppt::before{content:"\f75a"}.bi-filetype-psd::before{content:"\f75b"}.bi-filetype-py::before{content:"\f75c"}.bi-filetype-raw::before{content:"\f75d"}.bi-filetype-rb::before{content:"\f75e"}.bi-filetype-sass::before{content:"\f75f"}.bi-filetype-scss::before{content:"\f760"}.bi-filetype-sh::before{content:"\f761"}.bi-filetype-svg::before{content:"\f762"}.bi-filetype-tiff::before{content:"\f763"}.bi-filetype-tsx::before{content:"\f764"}.bi-filetype-ttf::before{content:"\f765"}.bi-filetype-txt::before{content:"\f766"}.bi-filetype-wav::before{content:"\f767"}.bi-filetype-woff::before{content:"\f768"}.bi-filetype-xls::before{content:"\f76a"}.bi-filetype-xml::before{content:"\f76b"}.bi-filetype-yml::before{content:"\f76c"}.bi-heart-arrow::before{content:"\f76d"}.bi-heart-pulse-fill::before{content:"\f76e"}.bi-heart-pulse::before{content:"\f76f"}.bi-heartbreak-fill::before{content:"\f770"}.bi-heartbreak::before{content:"\f771"}.bi-hearts::before{content:"\f772"}.bi-hospital-fill::before{content:"\f773"}.bi-hospital::before{content:"\f774"}.bi-house-heart-fill::before{content:"\f775"}.bi-house-heart::before{content:"\f776"}.bi-incognito::before{content:"\f777"}.bi-magnet-fill::before{content:"\f778"}.bi-magnet::before{content:"\f779"}.bi-person-heart::before{content:"\f77a"}.bi-person-hearts::before{content:"\f77b"}.bi-phone-flip::before{content:"\f77c"}.bi-plugin::before{content:"\f77d"}.bi-postage-fill::before{content:"\f77e"}.bi-postage-heart-fill::before{content:"\f77f"}.bi-postage-heart::before{content:"\f780"}.bi-postage::before{content:"\f781"}.bi-postcard-fill::before{content:"\f782"}.bi-postcard-heart-fill::before{content:"\f783"}.bi-postcard-heart::before{content:"\f784"}.bi-postcard::before{content:"\f785"}.bi-search-heart-fill::before{content:"\f786"}.bi-search-heart::before{content:"\f787"}.bi-sliders2-vertical::before{content:"\f788"}.bi-sliders2::before{content:"\f789"}.bi-trash3-fill::before{content:"\f78a"}.bi-trash3::before{content:"\f78b"}.bi-valentine::before{content:"\f78c"}.bi-valentine2::before{content:"\f78d"}.bi-wrench-adjustable-circle-fill::before{content:"\f78e"}.bi-wrench-adjustable-circle::before{content:"\f78f"}.bi-wrench-adjustable::before{content:"\f790"}.bi-filetype-json::before{content:"\f791"}.bi-filetype-pptx::before{content:"\f792"}.bi-filetype-xlsx::before{content:"\f793"}.bi-1-circle-fill::before{content:"\f796"}.bi-1-circle::before{content:"\f797"}.bi-1-square-fill::before{content:"\f798"}.bi-1-square::before{content:"\f799"}.bi-2-circle-fill::before{content:"\f79c"}.bi-2-circle::before{content:"\f79d"}.bi-2-square-fill::before{content:"\f79e"}.bi-2-square::before{content:"\f79f"}.bi-3-circle-fill::before{content:"\f7a2"}.bi-3-circle::before{content:"\f7a3"}.bi-3-square-fill::before{content:"\f7a4"}.bi-3-square::before{content:"\f7a5"}.bi-4-circle-fill::before{content:"\f7a8"}.bi-4-circle::before{content:"\f7a9"}.bi-4-square-fill::before{content:"\f7aa"}.bi-4-square::before{content:"\f7ab"}.bi-5-circle-fill::before{content:"\f7ae"}.bi-5-circle::before{content:"\f7af"}.bi-5-square-fill::before{content:"\f7b0"}.bi-5-square::before{content:"\f7b1"}.bi-6-circle-fill::before{content:"\f7b4"}.bi-6-circle::before{content:"\f7b5"}.bi-6-square-fill::before{content:"\f7b6"}.bi-6-square::before{content:"\f7b7"}.bi-7-circle-fill::before{content:"\f7ba"}.bi-7-circle::before{content:"\f7bb"}.bi-7-square-fill::before{content:"\f7bc"}.bi-7-square::before{content:"\f7bd"}.bi-8-circle-fill::before{content:"\f7c0"}.bi-8-circle::before{content:"\f7c1"}.bi-8-square-fill::before{content:"\f7c2"}.bi-8-square::before{content:"\f7c3"}.bi-9-circle-fill::before{content:"\f7c6"}.bi-9-circle::before{content:"\f7c7"}.bi-9-square-fill::before{content:"\f7c8"}.bi-9-square::before{content:"\f7c9"}.bi-airplane-engines-fill::before{content:"\f7ca"}.bi-airplane-engines::before{content:"\f7cb"}.bi-airplane-fill::before{content:"\f7cc"}.bi-airplane::before{content:"\f7cd"}.bi-alexa::before{content:"\f7ce"}.bi-alipay::before{content:"\f7cf"}.bi-android::before{content:"\f7d0"}.bi-android2::before{content:"\f7d1"}.bi-box-fill::before{content:"\f7d2"}.bi-box-seam-fill::before{content:"\f7d3"}.bi-browser-chrome::before{content:"\f7d4"}.bi-browser-edge::before{content:"\f7d5"}.bi-browser-firefox::before{content:"\f7d6"}.bi-browser-safari::before{content:"\f7d7"}.bi-c-circle-fill::before{content:"\f7da"}.bi-c-circle::before{content:"\f7db"}.bi-c-square-fill::before{content:"\f7dc"}.bi-c-square::before{content:"\f7dd"}.bi-capsule-pill::before{content:"\f7de"}.bi-capsule::before{content:"\f7df"}.bi-car-front-fill::before{content:"\f7e0"}.bi-car-front::before{content:"\f7e1"}.bi-cassette-fill::before{content:"\f7e2"}.bi-cassette::before{content:"\f7e3"}.bi-cc-circle-fill::before{content:"\f7e6"}.bi-cc-circle::before{content:"\f7e7"}.bi-cc-square-fill::before{content:"\f7e8"}.bi-cc-square::before{content:"\f7e9"}.bi-cup-hot-fill::before{content:"\f7ea"}.bi-cup-hot::before{content:"\f7eb"}.bi-currency-rupee::before{content:"\f7ec"}.bi-dropbox::before{content:"\f7ed"}.bi-escape::before{content:"\f7ee"}.bi-fast-forward-btn-fill::before{content:"\f7ef"}.bi-fast-forward-btn::before{content:"\f7f0"}.bi-fast-forward-circle-fill::before{content:"\f7f1"}.bi-fast-forward-circle::before{content:"\f7f2"}.bi-fast-forward-fill::before{content:"\f7f3"}.bi-fast-forward::before{content:"\f7f4"}.bi-filetype-sql::before{content:"\f7f5"}.bi-fire::before{content:"\f7f6"}.bi-google-play::before{content:"\f7f7"}.bi-h-circle-fill::before{content:"\f7fa"}.bi-h-circle::before{content:"\f7fb"}.bi-h-square-fill::before{content:"\f7fc"}.bi-h-square::before{content:"\f7fd"}.bi-indent::before{content:"\f7fe"}.bi-lungs-fill::before{content:"\f7ff"}.bi-lungs::before{content:"\f800"}.bi-microsoft-teams::before{content:"\f801"}.bi-p-circle-fill::before{content:"\f804"}.bi-p-circle::before{content:"\f805"}.bi-p-square-fill::before{content:"\f806"}.bi-p-square::before{content:"\f807"}.bi-pass-fill::before{content:"\f808"}.bi-pass::before{content:"\f809"}.bi-prescription::before{content:"\f80a"}.bi-prescription2::before{content:"\f80b"}.bi-r-circle-fill::before{content:"\f80e"}.bi-r-circle::before{content:"\f80f"}.bi-r-square-fill::before{content:"\f810"}.bi-r-square::before{content:"\f811"}.bi-repeat-1::before{content:"\f812"}.bi-repeat::before{content:"\f813"}.bi-rewind-btn-fill::before{content:"\f814"}.bi-rewind-btn::before{content:"\f815"}.bi-rewind-circle-fill::before{content:"\f816"}.bi-rewind-circle::before{content:"\f817"}.bi-rewind-fill::before{content:"\f818"}.bi-rewind::before{content:"\f819"}.bi-train-freight-front-fill::before{content:"\f81a"}.bi-train-freight-front::before{content:"\f81b"}.bi-train-front-fill::before{content:"\f81c"}.bi-train-front::before{content:"\f81d"}.bi-train-lightrail-front-fill::before{content:"\f81e"}.bi-train-lightrail-front::before{content:"\f81f"}.bi-truck-front-fill::before{content:"\f820"}.bi-truck-front::before{content:"\f821"}.bi-ubuntu::before{content:"\f822"}.bi-unindent::before{content:"\f823"}.bi-unity::before{content:"\f824"}.bi-universal-access-circle::before{content:"\f825"}.bi-universal-access::before{content:"\f826"}.bi-virus::before{content:"\f827"}.bi-virus2::before{content:"\f828"}.bi-wechat::before{content:"\f829"}.bi-yelp::before{content:"\f82a"}.bi-sign-stop-fill::before{content:"\f82b"}.bi-sign-stop-lights-fill::before{content:"\f82c"}.bi-sign-stop-lights::before{content:"\f82d"}.bi-sign-stop::before{content:"\f82e"}.bi-sign-turn-left-fill::before{content:"\f82f"}.bi-sign-turn-left::before{content:"\f830"}.bi-sign-turn-right-fill::before{content:"\f831"}.bi-sign-turn-right::before{content:"\f832"}.bi-sign-turn-slight-left-fill::before{content:"\f833"}.bi-sign-turn-slight-left::before{content:"\f834"}.bi-sign-turn-slight-right-fill::before{content:"\f835"}.bi-sign-turn-slight-right::before{content:"\f836"}.bi-sign-yield-fill::before{content:"\f837"}.bi-sign-yield::before{content:"\f838"}.bi-ev-station-fill::before{content:"\f839"}.bi-ev-station::before{content:"\f83a"}.bi-fuel-pump-diesel-fill::before{content:"\f83b"}.bi-fuel-pump-diesel::before{content:"\f83c"}.bi-fuel-pump-fill::before{content:"\f83d"}.bi-fuel-pump::before{content:"\f83e"}.bi-0-circle-fill::before{content:"\f83f"}.bi-0-circle::before{content:"\f840"}.bi-0-square-fill::before{content:"\f841"}.bi-0-square::before{content:"\f842"}.bi-rocket-fill::before{content:"\f843"}.bi-rocket-takeoff-fill::before{content:"\f844"}.bi-rocket-takeoff::before{content:"\f845"}.bi-rocket::before{content:"\f846"}.bi-stripe::before{content:"\f847"}.bi-subscript::before{content:"\f848"}.bi-superscript::before{content:"\f849"}.bi-trello::before{content:"\f84a"}.bi-envelope-at-fill::before{content:"\f84b"}.bi-envelope-at::before{content:"\f84c"}.bi-regex::before{content:"\f84d"}.bi-text-wrap::before{content:"\f84e"}.bi-sign-dead-end-fill::before{content:"\f84f"}.bi-sign-dead-end::before{content:"\f850"}.bi-sign-do-not-enter-fill::before{content:"\f851"}.bi-sign-do-not-enter::before{content:"\f852"}.bi-sign-intersection-fill::before{content:"\f853"}.bi-sign-intersection-side-fill::before{content:"\f854"}.bi-sign-intersection-side::before{content:"\f855"}.bi-sign-intersection-t-fill::before{content:"\f856"}.bi-sign-intersection-t::before{content:"\f857"}.bi-sign-intersection-y-fill::before{content:"\f858"}.bi-sign-intersection-y::before{content:"\f859"}.bi-sign-intersection::before{content:"\f85a"}.bi-sign-merge-left-fill::before{content:"\f85b"}.bi-sign-merge-left::before{content:"\f85c"}.bi-sign-merge-right-fill::before{content:"\f85d"}.bi-sign-merge-right::before{content:"\f85e"}.bi-sign-no-left-turn-fill::before{content:"\f85f"}.bi-sign-no-left-turn::before{content:"\f860"}.bi-sign-no-parking-fill::before{content:"\f861"}.bi-sign-no-parking::before{content:"\f862"}.bi-sign-no-right-turn-fill::before{content:"\f863"}.bi-sign-no-right-turn::before{content:"\f864"}.bi-sign-railroad-fill::before{content:"\f865"}.bi-sign-railroad::before{content:"\f866"}.bi-building-add::before{content:"\f867"}.bi-building-check::before{content:"\f868"}.bi-building-dash::before{content:"\f869"}.bi-building-down::before{content:"\f86a"}.bi-building-exclamation::before{content:"\f86b"}.bi-building-fill-add::before{content:"\f86c"}.bi-building-fill-check::before{content:"\f86d"}.bi-building-fill-dash::before{content:"\f86e"}.bi-building-fill-down::before{content:"\f86f"}.bi-building-fill-exclamation::before{content:"\f870"}.bi-building-fill-gear::before{content:"\f871"}.bi-building-fill-lock::before{content:"\f872"}.bi-building-fill-slash::before{content:"\f873"}.bi-building-fill-up::before{content:"\f874"}.bi-building-fill-x::before{content:"\f875"}.bi-building-fill::before{content:"\f876"}.bi-building-gear::before{content:"\f877"}.bi-building-lock::before{content:"\f878"}.bi-building-slash::before{content:"\f879"}.bi-building-up::before{content:"\f87a"}.bi-building-x::before{content:"\f87b"}.bi-buildings-fill::before{content:"\f87c"}.bi-buildings::before{content:"\f87d"}.bi-bus-front-fill::before{content:"\f87e"}.bi-bus-front::before{content:"\f87f"}.bi-ev-front-fill::before{content:"\f880"}.bi-ev-front::before{content:"\f881"}.bi-globe-americas::before{content:"\f882"}.bi-globe-asia-australia::before{content:"\f883"}.bi-globe-central-south-asia::before{content:"\f884"}.bi-globe-europe-africa::before{content:"\f885"}.bi-house-add-fill::before{content:"\f886"}.bi-house-add::before{content:"\f887"}.bi-house-check-fill::before{content:"\f888"}.bi-house-check::before{content:"\f889"}.bi-house-dash-fill::before{content:"\f88a"}.bi-house-dash::before{content:"\f88b"}.bi-house-down-fill::before{content:"\f88c"}.bi-house-down::before{content:"\f88d"}.bi-house-exclamation-fill::before{content:"\f88e"}.bi-house-exclamation::before{content:"\f88f"}.bi-house-gear-fill::before{content:"\f890"}.bi-house-gear::before{content:"\f891"}.bi-house-lock-fill::before{content:"\f892"}.bi-house-lock::before{content:"\f893"}.bi-house-slash-fill::before{content:"\f894"}.bi-house-slash::before{content:"\f895"}.bi-house-up-fill::before{content:"\f896"}.bi-house-up::before{content:"\f897"}.bi-house-x-fill::before{content:"\f898"}.bi-house-x::before{content:"\f899"}.bi-person-add::before{content:"\f89a"}.bi-person-down::before{content:"\f89b"}.bi-person-exclamation::before{content:"\f89c"}.bi-person-fill-add::before{content:"\f89d"}.bi-person-fill-check::before{content:"\f89e"}.bi-person-fill-dash::before{content:"\f89f"}.bi-person-fill-down::before{content:"\f8a0"}.bi-person-fill-exclamation::before{content:"\f8a1"}.bi-person-fill-gear::before{content:"\f8a2"}.bi-person-fill-lock::before{content:"\f8a3"}.bi-person-fill-slash::before{content:"\f8a4"}.bi-person-fill-up::before{content:"\f8a5"}.bi-person-fill-x::before{content:"\f8a6"}.bi-person-gear::before{content:"\f8a7"}.bi-person-lock::before{content:"\f8a8"}.bi-person-slash::before{content:"\f8a9"}.bi-person-up::before{content:"\f8aa"}.bi-scooter::before{content:"\f8ab"}.bi-taxi-front-fill::before{content:"\f8ac"}.bi-taxi-front::before{content:"\f8ad"}.bi-amd::before{content:"\f8ae"}.bi-database-add::before{content:"\f8af"}.bi-database-check::before{content:"\f8b0"}.bi-database-dash::before{content:"\f8b1"}.bi-database-down::before{content:"\f8b2"}.bi-database-exclamation::before{content:"\f8b3"}.bi-database-fill-add::before{content:"\f8b4"}.bi-database-fill-check::before{content:"\f8b5"}.bi-database-fill-dash::before{content:"\f8b6"}.bi-database-fill-down::before{content:"\f8b7"}.bi-database-fill-exclamation::before{content:"\f8b8"}.bi-database-fill-gear::before{content:"\f8b9"}.bi-database-fill-lock::before{content:"\f8ba"}.bi-database-fill-slash::before{content:"\f8bb"}.bi-database-fill-up::before{content:"\f8bc"}.bi-database-fill-x::before{content:"\f8bd"}.bi-database-fill::before{content:"\f8be"}.bi-database-gear::before{content:"\f8bf"}.bi-database-lock::before{content:"\f8c0"}.bi-database-slash::before{content:"\f8c1"}.bi-database-up::before{content:"\f8c2"}.bi-database-x::before{content:"\f8c3"}.bi-database::before{content:"\f8c4"}.bi-houses-fill::before{content:"\f8c5"}.bi-houses::before{content:"\f8c6"}.bi-nvidia::before{content:"\f8c7"}.bi-person-vcard-fill::before{content:"\f8c8"}.bi-person-vcard::before{content:"\f8c9"}.bi-sina-weibo::before{content:"\f8ca"}.bi-tencent-qq::before{content:"\f8cb"}.bi-wikipedia::before{content:"\f8cc"}.bi-alphabet-uppercase::before{content:"\f2a5"}.bi-alphabet::before{content:"\f68a"}.bi-amazon::before{content:"\f68d"}.bi-arrows-collapse-vertical::before{content:"\f690"}.bi-arrows-expand-vertical::before{content:"\f695"}.bi-arrows-vertical::before{content:"\f698"}.bi-arrows::before{content:"\f6a2"}.bi-ban-fill::before{content:"\f6a3"}.bi-ban::before{content:"\f6b6"}.bi-bing::before{content:"\f6c2"}.bi-cake::before{content:"\f6e0"}.bi-cake2::before{content:"\f6ed"}.bi-cookie::before{content:"\f6ee"}.bi-copy::before{content:"\f759"}.bi-crosshair::before{content:"\f769"}.bi-crosshair2::before{content:"\f794"}.bi-emoji-astonished-fill::before{content:"\f795"}.bi-emoji-astonished::before{content:"\f79a"}.bi-emoji-grimace-fill::before{content:"\f79b"}.bi-emoji-grimace::before{content:"\f7a0"}.bi-emoji-grin-fill::before{content:"\f7a1"}.bi-emoji-grin::before{content:"\f7a6"}.bi-emoji-surprise-fill::before{content:"\f7a7"}.bi-emoji-surprise::before{content:"\f7ac"}.bi-emoji-tear-fill::before{content:"\f7ad"}.bi-emoji-tear::before{content:"\f7b2"}.bi-envelope-arrow-down-fill::before{content:"\f7b3"}.bi-envelope-arrow-down::before{content:"\f7b8"}.bi-envelope-arrow-up-fill::before{content:"\f7b9"}.bi-envelope-arrow-up::before{content:"\f7be"}.bi-feather::before{content:"\f7bf"}.bi-feather2::before{content:"\f7c4"}.bi-floppy-fill::before{content:"\f7c5"}.bi-floppy::before{content:"\f7d8"}.bi-floppy2-fill::before{content:"\f7d9"}.bi-floppy2::before{content:"\f7e4"}.bi-gitlab::before{content:"\f7e5"}.bi-highlighter::before{content:"\f7f8"}.bi-marker-tip::before{content:"\f802"}.bi-nvme-fill::before{content:"\f803"}.bi-nvme::before{content:"\f80c"}.bi-opencollective::before{content:"\f80d"}.bi-pci-card-network::before{content:"\f8cd"}.bi-pci-card-sound::before{content:"\f8ce"}.bi-radar::before{content:"\f8cf"}.bi-send-arrow-down-fill::before{content:"\f8d0"}.bi-send-arrow-down::before{content:"\f8d1"}.bi-send-arrow-up-fill::before{content:"\f8d2"}.bi-send-arrow-up::before{content:"\f8d3"}.bi-sim-slash-fill::before{content:"\f8d4"}.bi-sim-slash::before{content:"\f8d5"}.bi-sourceforge::before{content:"\f8d6"}.bi-substack::before{content:"\f8d7"}.bi-threads-fill::before{content:"\f8d8"}.bi-threads::before{content:"\f8d9"}.bi-transparency::before{content:"\f8da"}.bi-twitter-x::before{content:"\f8db"}.bi-type-h4::before{content:"\f8dc"}.bi-type-h5::before{content:"\f8dd"}.bi-type-h6::before{content:"\f8de"}.bi-backpack-fill::before{content:"\f8df"}.bi-backpack::before{content:"\f8e0"}.bi-backpack2-fill::before{content:"\f8e1"}.bi-backpack2::before{content:"\f8e2"}.bi-backpack3-fill::before{content:"\f8e3"}.bi-backpack3::before{content:"\f8e4"}.bi-backpack4-fill::before{content:"\f8e5"}.bi-backpack4::before{content:"\f8e6"}.bi-brilliance::before{content:"\f8e7"}.bi-cake-fill::before{content:"\f8e8"}.bi-cake2-fill::before{content:"\f8e9"}.bi-duffle-fill::before{content:"\f8ea"}.bi-duffle::before{content:"\f8eb"}.bi-exposure::before{content:"\f8ec"}.bi-gender-neuter::before{content:"\f8ed"}.bi-highlights::before{content:"\f8ee"}.bi-luggage-fill::before{content:"\f8ef"}.bi-luggage::before{content:"\f8f0"}.bi-mailbox-flag::before{content:"\f8f1"}.bi-mailbox2-flag::before{content:"\f8f2"}.bi-noise-reduction::before{content:"\f8f3"}.bi-passport-fill::before{content:"\f8f4"}.bi-passport::before{content:"\f8f5"}.bi-person-arms-up::before{content:"\f8f6"}.bi-person-raised-hand::before{content:"\f8f7"}.bi-person-standing-dress::before{content:"\f8f8"}.bi-person-standing::before{content:"\f8f9"}.bi-person-walking::before{content:"\f8fa"}.bi-person-wheelchair::before{content:"\f8fb"}.bi-shadows::before{content:"\f8fc"}.bi-suitcase-fill::before{content:"\f8fd"}.bi-suitcase-lg-fill::before{content:"\f8fe"}.bi-suitcase-lg::before{content:"\f8ff"}.bi-suitcase::before{content:"\f900"}.bi-suitcase2-fill::before{content:"\f901"}.bi-suitcase2::before{content:"\f902"}.bi-vignette::before{content:"\f903"} \ No newline at end of file diff --git a/static/bootstrap/icons/bootstrap-icons.scss b/static/bootstrap/icons/bootstrap-icons.scss deleted file mode 100644 index a34d6ba8..00000000 --- a/static/bootstrap/icons/bootstrap-icons.scss +++ /dev/null @@ -1,2090 +0,0 @@ -/*! - * Bootstrap Icons v1.11.2 (https://icons.getbootstrap.com/) - * Copyright 2019-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/icons/blob/main/LICENSE) - */ - -$bootstrap-icons-font: "bootstrap-icons" !default; -$bootstrap-icons-font-dir: "./fonts" !default; -$bootstrap-icons-font-file: "#{$bootstrap-icons-font-dir}/#{$bootstrap-icons-font}" !default; -$bootstrap-icons-font-hash: "24e3eb84d0bcaf83d77f904c78ac1f47" !default; -$bootstrap-icons-font-src: url("#{$bootstrap-icons-font-file}.woff2?#{$bootstrap-icons-font-hash}") format("woff2"), - url("#{$bootstrap-icons-font-file}.woff?#{$bootstrap-icons-font-hash}") format("woff") !default; - -@font-face { - font-display: block; - font-family: $bootstrap-icons-font; - src: $bootstrap-icons-font-src; -} - -.bi::before, -[class^="bi-"]::before, -[class*=" bi-"]::before { - display: inline-block; - font-family: $bootstrap-icons-font !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -.125em; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -$bootstrap-icons-map: ( - "123": "\f67f", - "alarm-fill": "\f101", - "alarm": "\f102", - "align-bottom": "\f103", - "align-center": "\f104", - "align-end": "\f105", - "align-middle": "\f106", - "align-start": "\f107", - "align-top": "\f108", - "alt": "\f109", - "app-indicator": "\f10a", - "app": "\f10b", - "archive-fill": "\f10c", - "archive": "\f10d", - "arrow-90deg-down": "\f10e", - "arrow-90deg-left": "\f10f", - "arrow-90deg-right": "\f110", - "arrow-90deg-up": "\f111", - "arrow-bar-down": "\f112", - "arrow-bar-left": "\f113", - "arrow-bar-right": "\f114", - "arrow-bar-up": "\f115", - "arrow-clockwise": "\f116", - "arrow-counterclockwise": "\f117", - "arrow-down-circle-fill": "\f118", - "arrow-down-circle": "\f119", - "arrow-down-left-circle-fill": "\f11a", - "arrow-down-left-circle": "\f11b", - "arrow-down-left-square-fill": "\f11c", - "arrow-down-left-square": "\f11d", - "arrow-down-left": "\f11e", - "arrow-down-right-circle-fill": "\f11f", - "arrow-down-right-circle": "\f120", - "arrow-down-right-square-fill": "\f121", - "arrow-down-right-square": "\f122", - "arrow-down-right": "\f123", - "arrow-down-short": "\f124", - "arrow-down-square-fill": "\f125", - "arrow-down-square": "\f126", - "arrow-down-up": "\f127", - "arrow-down": "\f128", - "arrow-left-circle-fill": "\f129", - "arrow-left-circle": "\f12a", - "arrow-left-right": "\f12b", - "arrow-left-short": "\f12c", - "arrow-left-square-fill": "\f12d", - "arrow-left-square": "\f12e", - "arrow-left": "\f12f", - "arrow-repeat": "\f130", - "arrow-return-left": "\f131", - "arrow-return-right": "\f132", - "arrow-right-circle-fill": "\f133", - "arrow-right-circle": "\f134", - "arrow-right-short": "\f135", - "arrow-right-square-fill": "\f136", - "arrow-right-square": "\f137", - "arrow-right": "\f138", - "arrow-up-circle-fill": "\f139", - "arrow-up-circle": "\f13a", - "arrow-up-left-circle-fill": "\f13b", - "arrow-up-left-circle": "\f13c", - "arrow-up-left-square-fill": "\f13d", - "arrow-up-left-square": "\f13e", - "arrow-up-left": "\f13f", - "arrow-up-right-circle-fill": "\f140", - "arrow-up-right-circle": "\f141", - "arrow-up-right-square-fill": "\f142", - "arrow-up-right-square": "\f143", - "arrow-up-right": "\f144", - "arrow-up-short": "\f145", - "arrow-up-square-fill": "\f146", - "arrow-up-square": "\f147", - "arrow-up": "\f148", - "arrows-angle-contract": "\f149", - "arrows-angle-expand": "\f14a", - "arrows-collapse": "\f14b", - "arrows-expand": "\f14c", - "arrows-fullscreen": "\f14d", - "arrows-move": "\f14e", - "aspect-ratio-fill": "\f14f", - "aspect-ratio": "\f150", - "asterisk": "\f151", - "at": "\f152", - "award-fill": "\f153", - "award": "\f154", - "back": "\f155", - "backspace-fill": "\f156", - "backspace-reverse-fill": "\f157", - "backspace-reverse": "\f158", - "backspace": "\f159", - "badge-3d-fill": "\f15a", - "badge-3d": "\f15b", - "badge-4k-fill": "\f15c", - "badge-4k": "\f15d", - "badge-8k-fill": "\f15e", - "badge-8k": "\f15f", - "badge-ad-fill": "\f160", - "badge-ad": "\f161", - "badge-ar-fill": "\f162", - "badge-ar": "\f163", - "badge-cc-fill": "\f164", - "badge-cc": "\f165", - "badge-hd-fill": "\f166", - "badge-hd": "\f167", - "badge-tm-fill": "\f168", - "badge-tm": "\f169", - "badge-vo-fill": "\f16a", - "badge-vo": "\f16b", - "badge-vr-fill": "\f16c", - "badge-vr": "\f16d", - "badge-wc-fill": "\f16e", - "badge-wc": "\f16f", - "bag-check-fill": "\f170", - "bag-check": "\f171", - "bag-dash-fill": "\f172", - "bag-dash": "\f173", - "bag-fill": "\f174", - "bag-plus-fill": "\f175", - "bag-plus": "\f176", - "bag-x-fill": "\f177", - "bag-x": "\f178", - "bag": "\f179", - "bar-chart-fill": "\f17a", - "bar-chart-line-fill": "\f17b", - "bar-chart-line": "\f17c", - "bar-chart-steps": "\f17d", - "bar-chart": "\f17e", - "basket-fill": "\f17f", - "basket": "\f180", - "basket2-fill": "\f181", - "basket2": "\f182", - "basket3-fill": "\f183", - "basket3": "\f184", - "battery-charging": "\f185", - "battery-full": "\f186", - "battery-half": "\f187", - "battery": "\f188", - "bell-fill": "\f189", - "bell": "\f18a", - "bezier": "\f18b", - "bezier2": "\f18c", - "bicycle": "\f18d", - "binoculars-fill": "\f18e", - "binoculars": "\f18f", - "blockquote-left": "\f190", - "blockquote-right": "\f191", - "book-fill": "\f192", - "book-half": "\f193", - "book": "\f194", - "bookmark-check-fill": "\f195", - "bookmark-check": "\f196", - "bookmark-dash-fill": "\f197", - "bookmark-dash": "\f198", - "bookmark-fill": "\f199", - "bookmark-heart-fill": "\f19a", - "bookmark-heart": "\f19b", - "bookmark-plus-fill": "\f19c", - "bookmark-plus": "\f19d", - "bookmark-star-fill": "\f19e", - "bookmark-star": "\f19f", - "bookmark-x-fill": "\f1a0", - "bookmark-x": "\f1a1", - "bookmark": "\f1a2", - "bookmarks-fill": "\f1a3", - "bookmarks": "\f1a4", - "bookshelf": "\f1a5", - "bootstrap-fill": "\f1a6", - "bootstrap-reboot": "\f1a7", - "bootstrap": "\f1a8", - "border-all": "\f1a9", - "border-bottom": "\f1aa", - "border-center": "\f1ab", - "border-inner": "\f1ac", - "border-left": "\f1ad", - "border-middle": "\f1ae", - "border-outer": "\f1af", - "border-right": "\f1b0", - "border-style": "\f1b1", - "border-top": "\f1b2", - "border-width": "\f1b3", - "border": "\f1b4", - "bounding-box-circles": "\f1b5", - "bounding-box": "\f1b6", - "box-arrow-down-left": "\f1b7", - "box-arrow-down-right": "\f1b8", - "box-arrow-down": "\f1b9", - "box-arrow-in-down-left": "\f1ba", - "box-arrow-in-down-right": "\f1bb", - "box-arrow-in-down": "\f1bc", - "box-arrow-in-left": "\f1bd", - "box-arrow-in-right": "\f1be", - "box-arrow-in-up-left": "\f1bf", - "box-arrow-in-up-right": "\f1c0", - "box-arrow-in-up": "\f1c1", - "box-arrow-left": "\f1c2", - "box-arrow-right": "\f1c3", - "box-arrow-up-left": "\f1c4", - "box-arrow-up-right": "\f1c5", - "box-arrow-up": "\f1c6", - "box-seam": "\f1c7", - "box": "\f1c8", - "braces": "\f1c9", - "bricks": "\f1ca", - "briefcase-fill": "\f1cb", - "briefcase": "\f1cc", - "brightness-alt-high-fill": "\f1cd", - "brightness-alt-high": "\f1ce", - "brightness-alt-low-fill": "\f1cf", - "brightness-alt-low": "\f1d0", - "brightness-high-fill": "\f1d1", - "brightness-high": "\f1d2", - "brightness-low-fill": "\f1d3", - "brightness-low": "\f1d4", - "broadcast-pin": "\f1d5", - "broadcast": "\f1d6", - "brush-fill": "\f1d7", - "brush": "\f1d8", - "bucket-fill": "\f1d9", - "bucket": "\f1da", - "bug-fill": "\f1db", - "bug": "\f1dc", - "building": "\f1dd", - "bullseye": "\f1de", - "calculator-fill": "\f1df", - "calculator": "\f1e0", - "calendar-check-fill": "\f1e1", - "calendar-check": "\f1e2", - "calendar-date-fill": "\f1e3", - "calendar-date": "\f1e4", - "calendar-day-fill": "\f1e5", - "calendar-day": "\f1e6", - "calendar-event-fill": "\f1e7", - "calendar-event": "\f1e8", - "calendar-fill": "\f1e9", - "calendar-minus-fill": "\f1ea", - "calendar-minus": "\f1eb", - "calendar-month-fill": "\f1ec", - "calendar-month": "\f1ed", - "calendar-plus-fill": "\f1ee", - "calendar-plus": "\f1ef", - "calendar-range-fill": "\f1f0", - "calendar-range": "\f1f1", - "calendar-week-fill": "\f1f2", - "calendar-week": "\f1f3", - "calendar-x-fill": "\f1f4", - "calendar-x": "\f1f5", - "calendar": "\f1f6", - "calendar2-check-fill": "\f1f7", - "calendar2-check": "\f1f8", - "calendar2-date-fill": "\f1f9", - "calendar2-date": "\f1fa", - "calendar2-day-fill": "\f1fb", - "calendar2-day": "\f1fc", - "calendar2-event-fill": "\f1fd", - "calendar2-event": "\f1fe", - "calendar2-fill": "\f1ff", - "calendar2-minus-fill": "\f200", - "calendar2-minus": "\f201", - "calendar2-month-fill": "\f202", - "calendar2-month": "\f203", - "calendar2-plus-fill": "\f204", - "calendar2-plus": "\f205", - "calendar2-range-fill": "\f206", - "calendar2-range": "\f207", - "calendar2-week-fill": "\f208", - "calendar2-week": "\f209", - "calendar2-x-fill": "\f20a", - "calendar2-x": "\f20b", - "calendar2": "\f20c", - "calendar3-event-fill": "\f20d", - "calendar3-event": "\f20e", - "calendar3-fill": "\f20f", - "calendar3-range-fill": "\f210", - "calendar3-range": "\f211", - "calendar3-week-fill": "\f212", - "calendar3-week": "\f213", - "calendar3": "\f214", - "calendar4-event": "\f215", - "calendar4-range": "\f216", - "calendar4-week": "\f217", - "calendar4": "\f218", - "camera-fill": "\f219", - "camera-reels-fill": "\f21a", - "camera-reels": "\f21b", - "camera-video-fill": "\f21c", - "camera-video-off-fill": "\f21d", - "camera-video-off": "\f21e", - "camera-video": "\f21f", - "camera": "\f220", - "camera2": "\f221", - "capslock-fill": "\f222", - "capslock": "\f223", - "card-checklist": "\f224", - "card-heading": "\f225", - "card-image": "\f226", - "card-list": "\f227", - "card-text": "\f228", - "caret-down-fill": "\f229", - "caret-down-square-fill": "\f22a", - "caret-down-square": "\f22b", - "caret-down": "\f22c", - "caret-left-fill": "\f22d", - "caret-left-square-fill": "\f22e", - "caret-left-square": "\f22f", - "caret-left": "\f230", - "caret-right-fill": "\f231", - "caret-right-square-fill": "\f232", - "caret-right-square": "\f233", - "caret-right": "\f234", - "caret-up-fill": "\f235", - "caret-up-square-fill": "\f236", - "caret-up-square": "\f237", - "caret-up": "\f238", - "cart-check-fill": "\f239", - "cart-check": "\f23a", - "cart-dash-fill": "\f23b", - "cart-dash": "\f23c", - "cart-fill": "\f23d", - "cart-plus-fill": "\f23e", - "cart-plus": "\f23f", - "cart-x-fill": "\f240", - "cart-x": "\f241", - "cart": "\f242", - "cart2": "\f243", - "cart3": "\f244", - "cart4": "\f245", - "cash-stack": "\f246", - "cash": "\f247", - "cast": "\f248", - "chat-dots-fill": "\f249", - "chat-dots": "\f24a", - "chat-fill": "\f24b", - "chat-left-dots-fill": "\f24c", - "chat-left-dots": "\f24d", - "chat-left-fill": "\f24e", - "chat-left-quote-fill": "\f24f", - "chat-left-quote": "\f250", - "chat-left-text-fill": "\f251", - "chat-left-text": "\f252", - "chat-left": "\f253", - "chat-quote-fill": "\f254", - "chat-quote": "\f255", - "chat-right-dots-fill": "\f256", - "chat-right-dots": "\f257", - "chat-right-fill": "\f258", - "chat-right-quote-fill": "\f259", - "chat-right-quote": "\f25a", - "chat-right-text-fill": "\f25b", - "chat-right-text": "\f25c", - "chat-right": "\f25d", - "chat-square-dots-fill": "\f25e", - "chat-square-dots": "\f25f", - "chat-square-fill": "\f260", - "chat-square-quote-fill": "\f261", - "chat-square-quote": "\f262", - "chat-square-text-fill": "\f263", - "chat-square-text": "\f264", - "chat-square": "\f265", - "chat-text-fill": "\f266", - "chat-text": "\f267", - "chat": "\f268", - "check-all": "\f269", - "check-circle-fill": "\f26a", - "check-circle": "\f26b", - "check-square-fill": "\f26c", - "check-square": "\f26d", - "check": "\f26e", - "check2-all": "\f26f", - "check2-circle": "\f270", - "check2-square": "\f271", - "check2": "\f272", - "chevron-bar-contract": "\f273", - "chevron-bar-down": "\f274", - "chevron-bar-expand": "\f275", - "chevron-bar-left": "\f276", - "chevron-bar-right": "\f277", - "chevron-bar-up": "\f278", - "chevron-compact-down": "\f279", - "chevron-compact-left": "\f27a", - "chevron-compact-right": "\f27b", - "chevron-compact-up": "\f27c", - "chevron-contract": "\f27d", - "chevron-double-down": "\f27e", - "chevron-double-left": "\f27f", - "chevron-double-right": "\f280", - "chevron-double-up": "\f281", - "chevron-down": "\f282", - "chevron-expand": "\f283", - "chevron-left": "\f284", - "chevron-right": "\f285", - "chevron-up": "\f286", - "circle-fill": "\f287", - "circle-half": "\f288", - "circle-square": "\f289", - "circle": "\f28a", - "clipboard-check": "\f28b", - "clipboard-data": "\f28c", - "clipboard-minus": "\f28d", - "clipboard-plus": "\f28e", - "clipboard-x": "\f28f", - "clipboard": "\f290", - "clock-fill": "\f291", - "clock-history": "\f292", - "clock": "\f293", - "cloud-arrow-down-fill": "\f294", - "cloud-arrow-down": "\f295", - "cloud-arrow-up-fill": "\f296", - "cloud-arrow-up": "\f297", - "cloud-check-fill": "\f298", - "cloud-check": "\f299", - "cloud-download-fill": "\f29a", - "cloud-download": "\f29b", - "cloud-drizzle-fill": "\f29c", - "cloud-drizzle": "\f29d", - "cloud-fill": "\f29e", - "cloud-fog-fill": "\f29f", - "cloud-fog": "\f2a0", - "cloud-fog2-fill": "\f2a1", - "cloud-fog2": "\f2a2", - "cloud-hail-fill": "\f2a3", - "cloud-hail": "\f2a4", - "cloud-haze-fill": "\f2a6", - "cloud-haze": "\f2a7", - "cloud-haze2-fill": "\f2a8", - "cloud-lightning-fill": "\f2a9", - "cloud-lightning-rain-fill": "\f2aa", - "cloud-lightning-rain": "\f2ab", - "cloud-lightning": "\f2ac", - "cloud-minus-fill": "\f2ad", - "cloud-minus": "\f2ae", - "cloud-moon-fill": "\f2af", - "cloud-moon": "\f2b0", - "cloud-plus-fill": "\f2b1", - "cloud-plus": "\f2b2", - "cloud-rain-fill": "\f2b3", - "cloud-rain-heavy-fill": "\f2b4", - "cloud-rain-heavy": "\f2b5", - "cloud-rain": "\f2b6", - "cloud-slash-fill": "\f2b7", - "cloud-slash": "\f2b8", - "cloud-sleet-fill": "\f2b9", - "cloud-sleet": "\f2ba", - "cloud-snow-fill": "\f2bb", - "cloud-snow": "\f2bc", - "cloud-sun-fill": "\f2bd", - "cloud-sun": "\f2be", - "cloud-upload-fill": "\f2bf", - "cloud-upload": "\f2c0", - "cloud": "\f2c1", - "clouds-fill": "\f2c2", - "clouds": "\f2c3", - "cloudy-fill": "\f2c4", - "cloudy": "\f2c5", - "code-slash": "\f2c6", - "code-square": "\f2c7", - "code": "\f2c8", - "collection-fill": "\f2c9", - "collection-play-fill": "\f2ca", - "collection-play": "\f2cb", - "collection": "\f2cc", - "columns-gap": "\f2cd", - "columns": "\f2ce", - "command": "\f2cf", - "compass-fill": "\f2d0", - "compass": "\f2d1", - "cone-striped": "\f2d2", - "cone": "\f2d3", - "controller": "\f2d4", - "cpu-fill": "\f2d5", - "cpu": "\f2d6", - "credit-card-2-back-fill": "\f2d7", - "credit-card-2-back": "\f2d8", - "credit-card-2-front-fill": "\f2d9", - "credit-card-2-front": "\f2da", - "credit-card-fill": "\f2db", - "credit-card": "\f2dc", - "crop": "\f2dd", - "cup-fill": "\f2de", - "cup-straw": "\f2df", - "cup": "\f2e0", - "cursor-fill": "\f2e1", - "cursor-text": "\f2e2", - "cursor": "\f2e3", - "dash-circle-dotted": "\f2e4", - "dash-circle-fill": "\f2e5", - "dash-circle": "\f2e6", - "dash-square-dotted": "\f2e7", - "dash-square-fill": "\f2e8", - "dash-square": "\f2e9", - "dash": "\f2ea", - "diagram-2-fill": "\f2eb", - "diagram-2": "\f2ec", - "diagram-3-fill": "\f2ed", - "diagram-3": "\f2ee", - "diamond-fill": "\f2ef", - "diamond-half": "\f2f0", - "diamond": "\f2f1", - "dice-1-fill": "\f2f2", - "dice-1": "\f2f3", - "dice-2-fill": "\f2f4", - "dice-2": "\f2f5", - "dice-3-fill": "\f2f6", - "dice-3": "\f2f7", - "dice-4-fill": "\f2f8", - "dice-4": "\f2f9", - "dice-5-fill": "\f2fa", - "dice-5": "\f2fb", - "dice-6-fill": "\f2fc", - "dice-6": "\f2fd", - "disc-fill": "\f2fe", - "disc": "\f2ff", - "discord": "\f300", - "display-fill": "\f301", - "display": "\f302", - "distribute-horizontal": "\f303", - "distribute-vertical": "\f304", - "door-closed-fill": "\f305", - "door-closed": "\f306", - "door-open-fill": "\f307", - "door-open": "\f308", - "dot": "\f309", - "download": "\f30a", - "droplet-fill": "\f30b", - "droplet-half": "\f30c", - "droplet": "\f30d", - "earbuds": "\f30e", - "easel-fill": "\f30f", - "easel": "\f310", - "egg-fill": "\f311", - "egg-fried": "\f312", - "egg": "\f313", - "eject-fill": "\f314", - "eject": "\f315", - "emoji-angry-fill": "\f316", - "emoji-angry": "\f317", - "emoji-dizzy-fill": "\f318", - "emoji-dizzy": "\f319", - "emoji-expressionless-fill": "\f31a", - "emoji-expressionless": "\f31b", - "emoji-frown-fill": "\f31c", - "emoji-frown": "\f31d", - "emoji-heart-eyes-fill": "\f31e", - "emoji-heart-eyes": "\f31f", - "emoji-laughing-fill": "\f320", - "emoji-laughing": "\f321", - "emoji-neutral-fill": "\f322", - "emoji-neutral": "\f323", - "emoji-smile-fill": "\f324", - "emoji-smile-upside-down-fill": "\f325", - "emoji-smile-upside-down": "\f326", - "emoji-smile": "\f327", - "emoji-sunglasses-fill": "\f328", - "emoji-sunglasses": "\f329", - "emoji-wink-fill": "\f32a", - "emoji-wink": "\f32b", - "envelope-fill": "\f32c", - "envelope-open-fill": "\f32d", - "envelope-open": "\f32e", - "envelope": "\f32f", - "eraser-fill": "\f330", - "eraser": "\f331", - "exclamation-circle-fill": "\f332", - "exclamation-circle": "\f333", - "exclamation-diamond-fill": "\f334", - "exclamation-diamond": "\f335", - "exclamation-octagon-fill": "\f336", - "exclamation-octagon": "\f337", - "exclamation-square-fill": "\f338", - "exclamation-square": "\f339", - "exclamation-triangle-fill": "\f33a", - "exclamation-triangle": "\f33b", - "exclamation": "\f33c", - "exclude": "\f33d", - "eye-fill": "\f33e", - "eye-slash-fill": "\f33f", - "eye-slash": "\f340", - "eye": "\f341", - "eyedropper": "\f342", - "eyeglasses": "\f343", - "facebook": "\f344", - "file-arrow-down-fill": "\f345", - "file-arrow-down": "\f346", - "file-arrow-up-fill": "\f347", - "file-arrow-up": "\f348", - "file-bar-graph-fill": "\f349", - "file-bar-graph": "\f34a", - "file-binary-fill": "\f34b", - "file-binary": "\f34c", - "file-break-fill": "\f34d", - "file-break": "\f34e", - "file-check-fill": "\f34f", - "file-check": "\f350", - "file-code-fill": "\f351", - "file-code": "\f352", - "file-diff-fill": "\f353", - "file-diff": "\f354", - "file-earmark-arrow-down-fill": "\f355", - "file-earmark-arrow-down": "\f356", - "file-earmark-arrow-up-fill": "\f357", - "file-earmark-arrow-up": "\f358", - "file-earmark-bar-graph-fill": "\f359", - "file-earmark-bar-graph": "\f35a", - "file-earmark-binary-fill": "\f35b", - "file-earmark-binary": "\f35c", - "file-earmark-break-fill": "\f35d", - "file-earmark-break": "\f35e", - "file-earmark-check-fill": "\f35f", - "file-earmark-check": "\f360", - "file-earmark-code-fill": "\f361", - "file-earmark-code": "\f362", - "file-earmark-diff-fill": "\f363", - "file-earmark-diff": "\f364", - "file-earmark-easel-fill": "\f365", - "file-earmark-easel": "\f366", - "file-earmark-excel-fill": "\f367", - "file-earmark-excel": "\f368", - "file-earmark-fill": "\f369", - "file-earmark-font-fill": "\f36a", - "file-earmark-font": "\f36b", - "file-earmark-image-fill": "\f36c", - "file-earmark-image": "\f36d", - "file-earmark-lock-fill": "\f36e", - "file-earmark-lock": "\f36f", - "file-earmark-lock2-fill": "\f370", - "file-earmark-lock2": "\f371", - "file-earmark-medical-fill": "\f372", - "file-earmark-medical": "\f373", - "file-earmark-minus-fill": "\f374", - "file-earmark-minus": "\f375", - "file-earmark-music-fill": "\f376", - "file-earmark-music": "\f377", - "file-earmark-person-fill": "\f378", - "file-earmark-person": "\f379", - "file-earmark-play-fill": "\f37a", - "file-earmark-play": "\f37b", - "file-earmark-plus-fill": "\f37c", - "file-earmark-plus": "\f37d", - "file-earmark-post-fill": "\f37e", - "file-earmark-post": "\f37f", - "file-earmark-ppt-fill": "\f380", - "file-earmark-ppt": "\f381", - "file-earmark-richtext-fill": "\f382", - "file-earmark-richtext": "\f383", - "file-earmark-ruled-fill": "\f384", - "file-earmark-ruled": "\f385", - "file-earmark-slides-fill": "\f386", - "file-earmark-slides": "\f387", - "file-earmark-spreadsheet-fill": "\f388", - "file-earmark-spreadsheet": "\f389", - "file-earmark-text-fill": "\f38a", - "file-earmark-text": "\f38b", - "file-earmark-word-fill": "\f38c", - "file-earmark-word": "\f38d", - "file-earmark-x-fill": "\f38e", - "file-earmark-x": "\f38f", - "file-earmark-zip-fill": "\f390", - "file-earmark-zip": "\f391", - "file-earmark": "\f392", - "file-easel-fill": "\f393", - "file-easel": "\f394", - "file-excel-fill": "\f395", - "file-excel": "\f396", - "file-fill": "\f397", - "file-font-fill": "\f398", - "file-font": "\f399", - "file-image-fill": "\f39a", - "file-image": "\f39b", - "file-lock-fill": "\f39c", - "file-lock": "\f39d", - "file-lock2-fill": "\f39e", - "file-lock2": "\f39f", - "file-medical-fill": "\f3a0", - "file-medical": "\f3a1", - "file-minus-fill": "\f3a2", - "file-minus": "\f3a3", - "file-music-fill": "\f3a4", - "file-music": "\f3a5", - "file-person-fill": "\f3a6", - "file-person": "\f3a7", - "file-play-fill": "\f3a8", - "file-play": "\f3a9", - "file-plus-fill": "\f3aa", - "file-plus": "\f3ab", - "file-post-fill": "\f3ac", - "file-post": "\f3ad", - "file-ppt-fill": "\f3ae", - "file-ppt": "\f3af", - "file-richtext-fill": "\f3b0", - "file-richtext": "\f3b1", - "file-ruled-fill": "\f3b2", - "file-ruled": "\f3b3", - "file-slides-fill": "\f3b4", - "file-slides": "\f3b5", - "file-spreadsheet-fill": "\f3b6", - "file-spreadsheet": "\f3b7", - "file-text-fill": "\f3b8", - "file-text": "\f3b9", - "file-word-fill": "\f3ba", - "file-word": "\f3bb", - "file-x-fill": "\f3bc", - "file-x": "\f3bd", - "file-zip-fill": "\f3be", - "file-zip": "\f3bf", - "file": "\f3c0", - "files-alt": "\f3c1", - "files": "\f3c2", - "film": "\f3c3", - "filter-circle-fill": "\f3c4", - "filter-circle": "\f3c5", - "filter-left": "\f3c6", - "filter-right": "\f3c7", - "filter-square-fill": "\f3c8", - "filter-square": "\f3c9", - "filter": "\f3ca", - "flag-fill": "\f3cb", - "flag": "\f3cc", - "flower1": "\f3cd", - "flower2": "\f3ce", - "flower3": "\f3cf", - "folder-check": "\f3d0", - "folder-fill": "\f3d1", - "folder-minus": "\f3d2", - "folder-plus": "\f3d3", - "folder-symlink-fill": "\f3d4", - "folder-symlink": "\f3d5", - "folder-x": "\f3d6", - "folder": "\f3d7", - "folder2-open": "\f3d8", - "folder2": "\f3d9", - "fonts": "\f3da", - "forward-fill": "\f3db", - "forward": "\f3dc", - "front": "\f3dd", - "fullscreen-exit": "\f3de", - "fullscreen": "\f3df", - "funnel-fill": "\f3e0", - "funnel": "\f3e1", - "gear-fill": "\f3e2", - "gear-wide-connected": "\f3e3", - "gear-wide": "\f3e4", - "gear": "\f3e5", - "gem": "\f3e6", - "geo-alt-fill": "\f3e7", - "geo-alt": "\f3e8", - "geo-fill": "\f3e9", - "geo": "\f3ea", - "gift-fill": "\f3eb", - "gift": "\f3ec", - "github": "\f3ed", - "globe": "\f3ee", - "globe2": "\f3ef", - "google": "\f3f0", - "graph-down": "\f3f1", - "graph-up": "\f3f2", - "grid-1x2-fill": "\f3f3", - "grid-1x2": "\f3f4", - "grid-3x2-gap-fill": "\f3f5", - "grid-3x2-gap": "\f3f6", - "grid-3x2": "\f3f7", - "grid-3x3-gap-fill": "\f3f8", - "grid-3x3-gap": "\f3f9", - "grid-3x3": "\f3fa", - "grid-fill": "\f3fb", - "grid": "\f3fc", - "grip-horizontal": "\f3fd", - "grip-vertical": "\f3fe", - "hammer": "\f3ff", - "hand-index-fill": "\f400", - "hand-index-thumb-fill": "\f401", - "hand-index-thumb": "\f402", - "hand-index": "\f403", - "hand-thumbs-down-fill": "\f404", - "hand-thumbs-down": "\f405", - "hand-thumbs-up-fill": "\f406", - "hand-thumbs-up": "\f407", - "handbag-fill": "\f408", - "handbag": "\f409", - "hash": "\f40a", - "hdd-fill": "\f40b", - "hdd-network-fill": "\f40c", - "hdd-network": "\f40d", - "hdd-rack-fill": "\f40e", - "hdd-rack": "\f40f", - "hdd-stack-fill": "\f410", - "hdd-stack": "\f411", - "hdd": "\f412", - "headphones": "\f413", - "headset": "\f414", - "heart-fill": "\f415", - "heart-half": "\f416", - "heart": "\f417", - "heptagon-fill": "\f418", - "heptagon-half": "\f419", - "heptagon": "\f41a", - "hexagon-fill": "\f41b", - "hexagon-half": "\f41c", - "hexagon": "\f41d", - "hourglass-bottom": "\f41e", - "hourglass-split": "\f41f", - "hourglass-top": "\f420", - "hourglass": "\f421", - "house-door-fill": "\f422", - "house-door": "\f423", - "house-fill": "\f424", - "house": "\f425", - "hr": "\f426", - "hurricane": "\f427", - "image-alt": "\f428", - "image-fill": "\f429", - "image": "\f42a", - "images": "\f42b", - "inbox-fill": "\f42c", - "inbox": "\f42d", - "inboxes-fill": "\f42e", - "inboxes": "\f42f", - "info-circle-fill": "\f430", - "info-circle": "\f431", - "info-square-fill": "\f432", - "info-square": "\f433", - "info": "\f434", - "input-cursor-text": "\f435", - "input-cursor": "\f436", - "instagram": "\f437", - "intersect": "\f438", - "journal-album": "\f439", - "journal-arrow-down": "\f43a", - "journal-arrow-up": "\f43b", - "journal-bookmark-fill": "\f43c", - "journal-bookmark": "\f43d", - "journal-check": "\f43e", - "journal-code": "\f43f", - "journal-medical": "\f440", - "journal-minus": "\f441", - "journal-plus": "\f442", - "journal-richtext": "\f443", - "journal-text": "\f444", - "journal-x": "\f445", - "journal": "\f446", - "journals": "\f447", - "joystick": "\f448", - "justify-left": "\f449", - "justify-right": "\f44a", - "justify": "\f44b", - "kanban-fill": "\f44c", - "kanban": "\f44d", - "key-fill": "\f44e", - "key": "\f44f", - "keyboard-fill": "\f450", - "keyboard": "\f451", - "ladder": "\f452", - "lamp-fill": "\f453", - "lamp": "\f454", - "laptop-fill": "\f455", - "laptop": "\f456", - "layer-backward": "\f457", - "layer-forward": "\f458", - "layers-fill": "\f459", - "layers-half": "\f45a", - "layers": "\f45b", - "layout-sidebar-inset-reverse": "\f45c", - "layout-sidebar-inset": "\f45d", - "layout-sidebar-reverse": "\f45e", - "layout-sidebar": "\f45f", - "layout-split": "\f460", - "layout-text-sidebar-reverse": "\f461", - "layout-text-sidebar": "\f462", - "layout-text-window-reverse": "\f463", - "layout-text-window": "\f464", - "layout-three-columns": "\f465", - "layout-wtf": "\f466", - "life-preserver": "\f467", - "lightbulb-fill": "\f468", - "lightbulb-off-fill": "\f469", - "lightbulb-off": "\f46a", - "lightbulb": "\f46b", - "lightning-charge-fill": "\f46c", - "lightning-charge": "\f46d", - "lightning-fill": "\f46e", - "lightning": "\f46f", - "link-45deg": "\f470", - "link": "\f471", - "linkedin": "\f472", - "list-check": "\f473", - "list-nested": "\f474", - "list-ol": "\f475", - "list-stars": "\f476", - "list-task": "\f477", - "list-ul": "\f478", - "list": "\f479", - "lock-fill": "\f47a", - "lock": "\f47b", - "mailbox": "\f47c", - "mailbox2": "\f47d", - "map-fill": "\f47e", - "map": "\f47f", - "markdown-fill": "\f480", - "markdown": "\f481", - "mask": "\f482", - "megaphone-fill": "\f483", - "megaphone": "\f484", - "menu-app-fill": "\f485", - "menu-app": "\f486", - "menu-button-fill": "\f487", - "menu-button-wide-fill": "\f488", - "menu-button-wide": "\f489", - "menu-button": "\f48a", - "menu-down": "\f48b", - "menu-up": "\f48c", - "mic-fill": "\f48d", - "mic-mute-fill": "\f48e", - "mic-mute": "\f48f", - "mic": "\f490", - "minecart-loaded": "\f491", - "minecart": "\f492", - "moisture": "\f493", - "moon-fill": "\f494", - "moon-stars-fill": "\f495", - "moon-stars": "\f496", - "moon": "\f497", - "mouse-fill": "\f498", - "mouse": "\f499", - "mouse2-fill": "\f49a", - "mouse2": "\f49b", - "mouse3-fill": "\f49c", - "mouse3": "\f49d", - "music-note-beamed": "\f49e", - "music-note-list": "\f49f", - "music-note": "\f4a0", - "music-player-fill": "\f4a1", - "music-player": "\f4a2", - "newspaper": "\f4a3", - "node-minus-fill": "\f4a4", - "node-minus": "\f4a5", - "node-plus-fill": "\f4a6", - "node-plus": "\f4a7", - "nut-fill": "\f4a8", - "nut": "\f4a9", - "octagon-fill": "\f4aa", - "octagon-half": "\f4ab", - "octagon": "\f4ac", - "option": "\f4ad", - "outlet": "\f4ae", - "paint-bucket": "\f4af", - "palette-fill": "\f4b0", - "palette": "\f4b1", - "palette2": "\f4b2", - "paperclip": "\f4b3", - "paragraph": "\f4b4", - "patch-check-fill": "\f4b5", - "patch-check": "\f4b6", - "patch-exclamation-fill": "\f4b7", - "patch-exclamation": "\f4b8", - "patch-minus-fill": "\f4b9", - "patch-minus": "\f4ba", - "patch-plus-fill": "\f4bb", - "patch-plus": "\f4bc", - "patch-question-fill": "\f4bd", - "patch-question": "\f4be", - "pause-btn-fill": "\f4bf", - "pause-btn": "\f4c0", - "pause-circle-fill": "\f4c1", - "pause-circle": "\f4c2", - "pause-fill": "\f4c3", - "pause": "\f4c4", - "peace-fill": "\f4c5", - "peace": "\f4c6", - "pen-fill": "\f4c7", - "pen": "\f4c8", - "pencil-fill": "\f4c9", - "pencil-square": "\f4ca", - "pencil": "\f4cb", - "pentagon-fill": "\f4cc", - "pentagon-half": "\f4cd", - "pentagon": "\f4ce", - "people-fill": "\f4cf", - "people": "\f4d0", - "percent": "\f4d1", - "person-badge-fill": "\f4d2", - "person-badge": "\f4d3", - "person-bounding-box": "\f4d4", - "person-check-fill": "\f4d5", - "person-check": "\f4d6", - "person-circle": "\f4d7", - "person-dash-fill": "\f4d8", - "person-dash": "\f4d9", - "person-fill": "\f4da", - "person-lines-fill": "\f4db", - "person-plus-fill": "\f4dc", - "person-plus": "\f4dd", - "person-square": "\f4de", - "person-x-fill": "\f4df", - "person-x": "\f4e0", - "person": "\f4e1", - "phone-fill": "\f4e2", - "phone-landscape-fill": "\f4e3", - "phone-landscape": "\f4e4", - "phone-vibrate-fill": "\f4e5", - "phone-vibrate": "\f4e6", - "phone": "\f4e7", - "pie-chart-fill": "\f4e8", - "pie-chart": "\f4e9", - "pin-angle-fill": "\f4ea", - "pin-angle": "\f4eb", - "pin-fill": "\f4ec", - "pin": "\f4ed", - "pip-fill": "\f4ee", - "pip": "\f4ef", - "play-btn-fill": "\f4f0", - "play-btn": "\f4f1", - "play-circle-fill": "\f4f2", - "play-circle": "\f4f3", - "play-fill": "\f4f4", - "play": "\f4f5", - "plug-fill": "\f4f6", - "plug": "\f4f7", - "plus-circle-dotted": "\f4f8", - "plus-circle-fill": "\f4f9", - "plus-circle": "\f4fa", - "plus-square-dotted": "\f4fb", - "plus-square-fill": "\f4fc", - "plus-square": "\f4fd", - "plus": "\f4fe", - "power": "\f4ff", - "printer-fill": "\f500", - "printer": "\f501", - "puzzle-fill": "\f502", - "puzzle": "\f503", - "question-circle-fill": "\f504", - "question-circle": "\f505", - "question-diamond-fill": "\f506", - "question-diamond": "\f507", - "question-octagon-fill": "\f508", - "question-octagon": "\f509", - "question-square-fill": "\f50a", - "question-square": "\f50b", - "question": "\f50c", - "rainbow": "\f50d", - "receipt-cutoff": "\f50e", - "receipt": "\f50f", - "reception-0": "\f510", - "reception-1": "\f511", - "reception-2": "\f512", - "reception-3": "\f513", - "reception-4": "\f514", - "record-btn-fill": "\f515", - "record-btn": "\f516", - "record-circle-fill": "\f517", - "record-circle": "\f518", - "record-fill": "\f519", - "record": "\f51a", - "record2-fill": "\f51b", - "record2": "\f51c", - "reply-all-fill": "\f51d", - "reply-all": "\f51e", - "reply-fill": "\f51f", - "reply": "\f520", - "rss-fill": "\f521", - "rss": "\f522", - "rulers": "\f523", - "save-fill": "\f524", - "save": "\f525", - "save2-fill": "\f526", - "save2": "\f527", - "scissors": "\f528", - "screwdriver": "\f529", - "search": "\f52a", - "segmented-nav": "\f52b", - "server": "\f52c", - "share-fill": "\f52d", - "share": "\f52e", - "shield-check": "\f52f", - "shield-exclamation": "\f530", - "shield-fill-check": "\f531", - "shield-fill-exclamation": "\f532", - "shield-fill-minus": "\f533", - "shield-fill-plus": "\f534", - "shield-fill-x": "\f535", - "shield-fill": "\f536", - "shield-lock-fill": "\f537", - "shield-lock": "\f538", - "shield-minus": "\f539", - "shield-plus": "\f53a", - "shield-shaded": "\f53b", - "shield-slash-fill": "\f53c", - "shield-slash": "\f53d", - "shield-x": "\f53e", - "shield": "\f53f", - "shift-fill": "\f540", - "shift": "\f541", - "shop-window": "\f542", - "shop": "\f543", - "shuffle": "\f544", - "signpost-2-fill": "\f545", - "signpost-2": "\f546", - "signpost-fill": "\f547", - "signpost-split-fill": "\f548", - "signpost-split": "\f549", - "signpost": "\f54a", - "sim-fill": "\f54b", - "sim": "\f54c", - "skip-backward-btn-fill": "\f54d", - "skip-backward-btn": "\f54e", - "skip-backward-circle-fill": "\f54f", - "skip-backward-circle": "\f550", - "skip-backward-fill": "\f551", - "skip-backward": "\f552", - "skip-end-btn-fill": "\f553", - "skip-end-btn": "\f554", - "skip-end-circle-fill": "\f555", - "skip-end-circle": "\f556", - "skip-end-fill": "\f557", - "skip-end": "\f558", - "skip-forward-btn-fill": "\f559", - "skip-forward-btn": "\f55a", - "skip-forward-circle-fill": "\f55b", - "skip-forward-circle": "\f55c", - "skip-forward-fill": "\f55d", - "skip-forward": "\f55e", - "skip-start-btn-fill": "\f55f", - "skip-start-btn": "\f560", - "skip-start-circle-fill": "\f561", - "skip-start-circle": "\f562", - "skip-start-fill": "\f563", - "skip-start": "\f564", - "slack": "\f565", - "slash-circle-fill": "\f566", - "slash-circle": "\f567", - "slash-square-fill": "\f568", - "slash-square": "\f569", - "slash": "\f56a", - "sliders": "\f56b", - "smartwatch": "\f56c", - "snow": "\f56d", - "snow2": "\f56e", - "snow3": "\f56f", - "sort-alpha-down-alt": "\f570", - "sort-alpha-down": "\f571", - "sort-alpha-up-alt": "\f572", - "sort-alpha-up": "\f573", - "sort-down-alt": "\f574", - "sort-down": "\f575", - "sort-numeric-down-alt": "\f576", - "sort-numeric-down": "\f577", - "sort-numeric-up-alt": "\f578", - "sort-numeric-up": "\f579", - "sort-up-alt": "\f57a", - "sort-up": "\f57b", - "soundwave": "\f57c", - "speaker-fill": "\f57d", - "speaker": "\f57e", - "speedometer": "\f57f", - "speedometer2": "\f580", - "spellcheck": "\f581", - "square-fill": "\f582", - "square-half": "\f583", - "square": "\f584", - "stack": "\f585", - "star-fill": "\f586", - "star-half": "\f587", - "star": "\f588", - "stars": "\f589", - "stickies-fill": "\f58a", - "stickies": "\f58b", - "sticky-fill": "\f58c", - "sticky": "\f58d", - "stop-btn-fill": "\f58e", - "stop-btn": "\f58f", - "stop-circle-fill": "\f590", - "stop-circle": "\f591", - "stop-fill": "\f592", - "stop": "\f593", - "stoplights-fill": "\f594", - "stoplights": "\f595", - "stopwatch-fill": "\f596", - "stopwatch": "\f597", - "subtract": "\f598", - "suit-club-fill": "\f599", - "suit-club": "\f59a", - "suit-diamond-fill": "\f59b", - "suit-diamond": "\f59c", - "suit-heart-fill": "\f59d", - "suit-heart": "\f59e", - "suit-spade-fill": "\f59f", - "suit-spade": "\f5a0", - "sun-fill": "\f5a1", - "sun": "\f5a2", - "sunglasses": "\f5a3", - "sunrise-fill": "\f5a4", - "sunrise": "\f5a5", - "sunset-fill": "\f5a6", - "sunset": "\f5a7", - "symmetry-horizontal": "\f5a8", - "symmetry-vertical": "\f5a9", - "table": "\f5aa", - "tablet-fill": "\f5ab", - "tablet-landscape-fill": "\f5ac", - "tablet-landscape": "\f5ad", - "tablet": "\f5ae", - "tag-fill": "\f5af", - "tag": "\f5b0", - "tags-fill": "\f5b1", - "tags": "\f5b2", - "telegram": "\f5b3", - "telephone-fill": "\f5b4", - "telephone-forward-fill": "\f5b5", - "telephone-forward": "\f5b6", - "telephone-inbound-fill": "\f5b7", - "telephone-inbound": "\f5b8", - "telephone-minus-fill": "\f5b9", - "telephone-minus": "\f5ba", - "telephone-outbound-fill": "\f5bb", - "telephone-outbound": "\f5bc", - "telephone-plus-fill": "\f5bd", - "telephone-plus": "\f5be", - "telephone-x-fill": "\f5bf", - "telephone-x": "\f5c0", - "telephone": "\f5c1", - "terminal-fill": "\f5c2", - "terminal": "\f5c3", - "text-center": "\f5c4", - "text-indent-left": "\f5c5", - "text-indent-right": "\f5c6", - "text-left": "\f5c7", - "text-paragraph": "\f5c8", - "text-right": "\f5c9", - "textarea-resize": "\f5ca", - "textarea-t": "\f5cb", - "textarea": "\f5cc", - "thermometer-half": "\f5cd", - "thermometer-high": "\f5ce", - "thermometer-low": "\f5cf", - "thermometer-snow": "\f5d0", - "thermometer-sun": "\f5d1", - "thermometer": "\f5d2", - "three-dots-vertical": "\f5d3", - "three-dots": "\f5d4", - "toggle-off": "\f5d5", - "toggle-on": "\f5d6", - "toggle2-off": "\f5d7", - "toggle2-on": "\f5d8", - "toggles": "\f5d9", - "toggles2": "\f5da", - "tools": "\f5db", - "tornado": "\f5dc", - "trash-fill": "\f5dd", - "trash": "\f5de", - "trash2-fill": "\f5df", - "trash2": "\f5e0", - "tree-fill": "\f5e1", - "tree": "\f5e2", - "triangle-fill": "\f5e3", - "triangle-half": "\f5e4", - "triangle": "\f5e5", - "trophy-fill": "\f5e6", - "trophy": "\f5e7", - "tropical-storm": "\f5e8", - "truck-flatbed": "\f5e9", - "truck": "\f5ea", - "tsunami": "\f5eb", - "tv-fill": "\f5ec", - "tv": "\f5ed", - "twitch": "\f5ee", - "twitter": "\f5ef", - "type-bold": "\f5f0", - "type-h1": "\f5f1", - "type-h2": "\f5f2", - "type-h3": "\f5f3", - "type-italic": "\f5f4", - "type-strikethrough": "\f5f5", - "type-underline": "\f5f6", - "type": "\f5f7", - "ui-checks-grid": "\f5f8", - "ui-checks": "\f5f9", - "ui-radios-grid": "\f5fa", - "ui-radios": "\f5fb", - "umbrella-fill": "\f5fc", - "umbrella": "\f5fd", - "union": "\f5fe", - "unlock-fill": "\f5ff", - "unlock": "\f600", - "upc-scan": "\f601", - "upc": "\f602", - "upload": "\f603", - "vector-pen": "\f604", - "view-list": "\f605", - "view-stacked": "\f606", - "vinyl-fill": "\f607", - "vinyl": "\f608", - "voicemail": "\f609", - "volume-down-fill": "\f60a", - "volume-down": "\f60b", - "volume-mute-fill": "\f60c", - "volume-mute": "\f60d", - "volume-off-fill": "\f60e", - "volume-off": "\f60f", - "volume-up-fill": "\f610", - "volume-up": "\f611", - "vr": "\f612", - "wallet-fill": "\f613", - "wallet": "\f614", - "wallet2": "\f615", - "watch": "\f616", - "water": "\f617", - "whatsapp": "\f618", - "wifi-1": "\f619", - "wifi-2": "\f61a", - "wifi-off": "\f61b", - "wifi": "\f61c", - "wind": "\f61d", - "window-dock": "\f61e", - "window-sidebar": "\f61f", - "window": "\f620", - "wrench": "\f621", - "x-circle-fill": "\f622", - "x-circle": "\f623", - "x-diamond-fill": "\f624", - "x-diamond": "\f625", - "x-octagon-fill": "\f626", - "x-octagon": "\f627", - "x-square-fill": "\f628", - "x-square": "\f629", - "x": "\f62a", - "youtube": "\f62b", - "zoom-in": "\f62c", - "zoom-out": "\f62d", - "bank": "\f62e", - "bank2": "\f62f", - "bell-slash-fill": "\f630", - "bell-slash": "\f631", - "cash-coin": "\f632", - "check-lg": "\f633", - "coin": "\f634", - "currency-bitcoin": "\f635", - "currency-dollar": "\f636", - "currency-euro": "\f637", - "currency-exchange": "\f638", - "currency-pound": "\f639", - "currency-yen": "\f63a", - "dash-lg": "\f63b", - "exclamation-lg": "\f63c", - "file-earmark-pdf-fill": "\f63d", - "file-earmark-pdf": "\f63e", - "file-pdf-fill": "\f63f", - "file-pdf": "\f640", - "gender-ambiguous": "\f641", - "gender-female": "\f642", - "gender-male": "\f643", - "gender-trans": "\f644", - "headset-vr": "\f645", - "info-lg": "\f646", - "mastodon": "\f647", - "messenger": "\f648", - "piggy-bank-fill": "\f649", - "piggy-bank": "\f64a", - "pin-map-fill": "\f64b", - "pin-map": "\f64c", - "plus-lg": "\f64d", - "question-lg": "\f64e", - "recycle": "\f64f", - "reddit": "\f650", - "safe-fill": "\f651", - "safe2-fill": "\f652", - "safe2": "\f653", - "sd-card-fill": "\f654", - "sd-card": "\f655", - "skype": "\f656", - "slash-lg": "\f657", - "translate": "\f658", - "x-lg": "\f659", - "safe": "\f65a", - "apple": "\f65b", - "microsoft": "\f65d", - "windows": "\f65e", - "behance": "\f65c", - "dribbble": "\f65f", - "line": "\f660", - "medium": "\f661", - "paypal": "\f662", - "pinterest": "\f663", - "signal": "\f664", - "snapchat": "\f665", - "spotify": "\f666", - "stack-overflow": "\f667", - "strava": "\f668", - "wordpress": "\f669", - "vimeo": "\f66a", - "activity": "\f66b", - "easel2-fill": "\f66c", - "easel2": "\f66d", - "easel3-fill": "\f66e", - "easel3": "\f66f", - "fan": "\f670", - "fingerprint": "\f671", - "graph-down-arrow": "\f672", - "graph-up-arrow": "\f673", - "hypnotize": "\f674", - "magic": "\f675", - "person-rolodex": "\f676", - "person-video": "\f677", - "person-video2": "\f678", - "person-video3": "\f679", - "person-workspace": "\f67a", - "radioactive": "\f67b", - "webcam-fill": "\f67c", - "webcam": "\f67d", - "yin-yang": "\f67e", - "bandaid-fill": "\f680", - "bandaid": "\f681", - "bluetooth": "\f682", - "body-text": "\f683", - "boombox": "\f684", - "boxes": "\f685", - "dpad-fill": "\f686", - "dpad": "\f687", - "ear-fill": "\f688", - "ear": "\f689", - "envelope-check-fill": "\f68b", - "envelope-check": "\f68c", - "envelope-dash-fill": "\f68e", - "envelope-dash": "\f68f", - "envelope-exclamation-fill": "\f691", - "envelope-exclamation": "\f692", - "envelope-plus-fill": "\f693", - "envelope-plus": "\f694", - "envelope-slash-fill": "\f696", - "envelope-slash": "\f697", - "envelope-x-fill": "\f699", - "envelope-x": "\f69a", - "explicit-fill": "\f69b", - "explicit": "\f69c", - "git": "\f69d", - "infinity": "\f69e", - "list-columns-reverse": "\f69f", - "list-columns": "\f6a0", - "meta": "\f6a1", - "nintendo-switch": "\f6a4", - "pc-display-horizontal": "\f6a5", - "pc-display": "\f6a6", - "pc-horizontal": "\f6a7", - "pc": "\f6a8", - "playstation": "\f6a9", - "plus-slash-minus": "\f6aa", - "projector-fill": "\f6ab", - "projector": "\f6ac", - "qr-code-scan": "\f6ad", - "qr-code": "\f6ae", - "quora": "\f6af", - "quote": "\f6b0", - "robot": "\f6b1", - "send-check-fill": "\f6b2", - "send-check": "\f6b3", - "send-dash-fill": "\f6b4", - "send-dash": "\f6b5", - "send-exclamation-fill": "\f6b7", - "send-exclamation": "\f6b8", - "send-fill": "\f6b9", - "send-plus-fill": "\f6ba", - "send-plus": "\f6bb", - "send-slash-fill": "\f6bc", - "send-slash": "\f6bd", - "send-x-fill": "\f6be", - "send-x": "\f6bf", - "send": "\f6c0", - "steam": "\f6c1", - "terminal-dash": "\f6c3", - "terminal-plus": "\f6c4", - "terminal-split": "\f6c5", - "ticket-detailed-fill": "\f6c6", - "ticket-detailed": "\f6c7", - "ticket-fill": "\f6c8", - "ticket-perforated-fill": "\f6c9", - "ticket-perforated": "\f6ca", - "ticket": "\f6cb", - "tiktok": "\f6cc", - "window-dash": "\f6cd", - "window-desktop": "\f6ce", - "window-fullscreen": "\f6cf", - "window-plus": "\f6d0", - "window-split": "\f6d1", - "window-stack": "\f6d2", - "window-x": "\f6d3", - "xbox": "\f6d4", - "ethernet": "\f6d5", - "hdmi-fill": "\f6d6", - "hdmi": "\f6d7", - "usb-c-fill": "\f6d8", - "usb-c": "\f6d9", - "usb-fill": "\f6da", - "usb-plug-fill": "\f6db", - "usb-plug": "\f6dc", - "usb-symbol": "\f6dd", - "usb": "\f6de", - "boombox-fill": "\f6df", - "displayport": "\f6e1", - "gpu-card": "\f6e2", - "memory": "\f6e3", - "modem-fill": "\f6e4", - "modem": "\f6e5", - "motherboard-fill": "\f6e6", - "motherboard": "\f6e7", - "optical-audio-fill": "\f6e8", - "optical-audio": "\f6e9", - "pci-card": "\f6ea", - "router-fill": "\f6eb", - "router": "\f6ec", - "thunderbolt-fill": "\f6ef", - "thunderbolt": "\f6f0", - "usb-drive-fill": "\f6f1", - "usb-drive": "\f6f2", - "usb-micro-fill": "\f6f3", - "usb-micro": "\f6f4", - "usb-mini-fill": "\f6f5", - "usb-mini": "\f6f6", - "cloud-haze2": "\f6f7", - "device-hdd-fill": "\f6f8", - "device-hdd": "\f6f9", - "device-ssd-fill": "\f6fa", - "device-ssd": "\f6fb", - "displayport-fill": "\f6fc", - "mortarboard-fill": "\f6fd", - "mortarboard": "\f6fe", - "terminal-x": "\f6ff", - "arrow-through-heart-fill": "\f700", - "arrow-through-heart": "\f701", - "badge-sd-fill": "\f702", - "badge-sd": "\f703", - "bag-heart-fill": "\f704", - "bag-heart": "\f705", - "balloon-fill": "\f706", - "balloon-heart-fill": "\f707", - "balloon-heart": "\f708", - "balloon": "\f709", - "box2-fill": "\f70a", - "box2-heart-fill": "\f70b", - "box2-heart": "\f70c", - "box2": "\f70d", - "braces-asterisk": "\f70e", - "calendar-heart-fill": "\f70f", - "calendar-heart": "\f710", - "calendar2-heart-fill": "\f711", - "calendar2-heart": "\f712", - "chat-heart-fill": "\f713", - "chat-heart": "\f714", - "chat-left-heart-fill": "\f715", - "chat-left-heart": "\f716", - "chat-right-heart-fill": "\f717", - "chat-right-heart": "\f718", - "chat-square-heart-fill": "\f719", - "chat-square-heart": "\f71a", - "clipboard-check-fill": "\f71b", - "clipboard-data-fill": "\f71c", - "clipboard-fill": "\f71d", - "clipboard-heart-fill": "\f71e", - "clipboard-heart": "\f71f", - "clipboard-minus-fill": "\f720", - "clipboard-plus-fill": "\f721", - "clipboard-pulse": "\f722", - "clipboard-x-fill": "\f723", - "clipboard2-check-fill": "\f724", - "clipboard2-check": "\f725", - "clipboard2-data-fill": "\f726", - "clipboard2-data": "\f727", - "clipboard2-fill": "\f728", - "clipboard2-heart-fill": "\f729", - "clipboard2-heart": "\f72a", - "clipboard2-minus-fill": "\f72b", - "clipboard2-minus": "\f72c", - "clipboard2-plus-fill": "\f72d", - "clipboard2-plus": "\f72e", - "clipboard2-pulse-fill": "\f72f", - "clipboard2-pulse": "\f730", - "clipboard2-x-fill": "\f731", - "clipboard2-x": "\f732", - "clipboard2": "\f733", - "emoji-kiss-fill": "\f734", - "emoji-kiss": "\f735", - "envelope-heart-fill": "\f736", - "envelope-heart": "\f737", - "envelope-open-heart-fill": "\f738", - "envelope-open-heart": "\f739", - "envelope-paper-fill": "\f73a", - "envelope-paper-heart-fill": "\f73b", - "envelope-paper-heart": "\f73c", - "envelope-paper": "\f73d", - "filetype-aac": "\f73e", - "filetype-ai": "\f73f", - "filetype-bmp": "\f740", - "filetype-cs": "\f741", - "filetype-css": "\f742", - "filetype-csv": "\f743", - "filetype-doc": "\f744", - "filetype-docx": "\f745", - "filetype-exe": "\f746", - "filetype-gif": "\f747", - "filetype-heic": "\f748", - "filetype-html": "\f749", - "filetype-java": "\f74a", - "filetype-jpg": "\f74b", - "filetype-js": "\f74c", - "filetype-jsx": "\f74d", - "filetype-key": "\f74e", - "filetype-m4p": "\f74f", - "filetype-md": "\f750", - "filetype-mdx": "\f751", - "filetype-mov": "\f752", - "filetype-mp3": "\f753", - "filetype-mp4": "\f754", - "filetype-otf": "\f755", - "filetype-pdf": "\f756", - "filetype-php": "\f757", - "filetype-png": "\f758", - "filetype-ppt": "\f75a", - "filetype-psd": "\f75b", - "filetype-py": "\f75c", - "filetype-raw": "\f75d", - "filetype-rb": "\f75e", - "filetype-sass": "\f75f", - "filetype-scss": "\f760", - "filetype-sh": "\f761", - "filetype-svg": "\f762", - "filetype-tiff": "\f763", - "filetype-tsx": "\f764", - "filetype-ttf": "\f765", - "filetype-txt": "\f766", - "filetype-wav": "\f767", - "filetype-woff": "\f768", - "filetype-xls": "\f76a", - "filetype-xml": "\f76b", - "filetype-yml": "\f76c", - "heart-arrow": "\f76d", - "heart-pulse-fill": "\f76e", - "heart-pulse": "\f76f", - "heartbreak-fill": "\f770", - "heartbreak": "\f771", - "hearts": "\f772", - "hospital-fill": "\f773", - "hospital": "\f774", - "house-heart-fill": "\f775", - "house-heart": "\f776", - "incognito": "\f777", - "magnet-fill": "\f778", - "magnet": "\f779", - "person-heart": "\f77a", - "person-hearts": "\f77b", - "phone-flip": "\f77c", - "plugin": "\f77d", - "postage-fill": "\f77e", - "postage-heart-fill": "\f77f", - "postage-heart": "\f780", - "postage": "\f781", - "postcard-fill": "\f782", - "postcard-heart-fill": "\f783", - "postcard-heart": "\f784", - "postcard": "\f785", - "search-heart-fill": "\f786", - "search-heart": "\f787", - "sliders2-vertical": "\f788", - "sliders2": "\f789", - "trash3-fill": "\f78a", - "trash3": "\f78b", - "valentine": "\f78c", - "valentine2": "\f78d", - "wrench-adjustable-circle-fill": "\f78e", - "wrench-adjustable-circle": "\f78f", - "wrench-adjustable": "\f790", - "filetype-json": "\f791", - "filetype-pptx": "\f792", - "filetype-xlsx": "\f793", - "1-circle-fill": "\f796", - "1-circle": "\f797", - "1-square-fill": "\f798", - "1-square": "\f799", - "2-circle-fill": "\f79c", - "2-circle": "\f79d", - "2-square-fill": "\f79e", - "2-square": "\f79f", - "3-circle-fill": "\f7a2", - "3-circle": "\f7a3", - "3-square-fill": "\f7a4", - "3-square": "\f7a5", - "4-circle-fill": "\f7a8", - "4-circle": "\f7a9", - "4-square-fill": "\f7aa", - "4-square": "\f7ab", - "5-circle-fill": "\f7ae", - "5-circle": "\f7af", - "5-square-fill": "\f7b0", - "5-square": "\f7b1", - "6-circle-fill": "\f7b4", - "6-circle": "\f7b5", - "6-square-fill": "\f7b6", - "6-square": "\f7b7", - "7-circle-fill": "\f7ba", - "7-circle": "\f7bb", - "7-square-fill": "\f7bc", - "7-square": "\f7bd", - "8-circle-fill": "\f7c0", - "8-circle": "\f7c1", - "8-square-fill": "\f7c2", - "8-square": "\f7c3", - "9-circle-fill": "\f7c6", - "9-circle": "\f7c7", - "9-square-fill": "\f7c8", - "9-square": "\f7c9", - "airplane-engines-fill": "\f7ca", - "airplane-engines": "\f7cb", - "airplane-fill": "\f7cc", - "airplane": "\f7cd", - "alexa": "\f7ce", - "alipay": "\f7cf", - "android": "\f7d0", - "android2": "\f7d1", - "box-fill": "\f7d2", - "box-seam-fill": "\f7d3", - "browser-chrome": "\f7d4", - "browser-edge": "\f7d5", - "browser-firefox": "\f7d6", - "browser-safari": "\f7d7", - "c-circle-fill": "\f7da", - "c-circle": "\f7db", - "c-square-fill": "\f7dc", - "c-square": "\f7dd", - "capsule-pill": "\f7de", - "capsule": "\f7df", - "car-front-fill": "\f7e0", - "car-front": "\f7e1", - "cassette-fill": "\f7e2", - "cassette": "\f7e3", - "cc-circle-fill": "\f7e6", - "cc-circle": "\f7e7", - "cc-square-fill": "\f7e8", - "cc-square": "\f7e9", - "cup-hot-fill": "\f7ea", - "cup-hot": "\f7eb", - "currency-rupee": "\f7ec", - "dropbox": "\f7ed", - "escape": "\f7ee", - "fast-forward-btn-fill": "\f7ef", - "fast-forward-btn": "\f7f0", - "fast-forward-circle-fill": "\f7f1", - "fast-forward-circle": "\f7f2", - "fast-forward-fill": "\f7f3", - "fast-forward": "\f7f4", - "filetype-sql": "\f7f5", - "fire": "\f7f6", - "google-play": "\f7f7", - "h-circle-fill": "\f7fa", - "h-circle": "\f7fb", - "h-square-fill": "\f7fc", - "h-square": "\f7fd", - "indent": "\f7fe", - "lungs-fill": "\f7ff", - "lungs": "\f800", - "microsoft-teams": "\f801", - "p-circle-fill": "\f804", - "p-circle": "\f805", - "p-square-fill": "\f806", - "p-square": "\f807", - "pass-fill": "\f808", - "pass": "\f809", - "prescription": "\f80a", - "prescription2": "\f80b", - "r-circle-fill": "\f80e", - "r-circle": "\f80f", - "r-square-fill": "\f810", - "r-square": "\f811", - "repeat-1": "\f812", - "repeat": "\f813", - "rewind-btn-fill": "\f814", - "rewind-btn": "\f815", - "rewind-circle-fill": "\f816", - "rewind-circle": "\f817", - "rewind-fill": "\f818", - "rewind": "\f819", - "train-freight-front-fill": "\f81a", - "train-freight-front": "\f81b", - "train-front-fill": "\f81c", - "train-front": "\f81d", - "train-lightrail-front-fill": "\f81e", - "train-lightrail-front": "\f81f", - "truck-front-fill": "\f820", - "truck-front": "\f821", - "ubuntu": "\f822", - "unindent": "\f823", - "unity": "\f824", - "universal-access-circle": "\f825", - "universal-access": "\f826", - "virus": "\f827", - "virus2": "\f828", - "wechat": "\f829", - "yelp": "\f82a", - "sign-stop-fill": "\f82b", - "sign-stop-lights-fill": "\f82c", - "sign-stop-lights": "\f82d", - "sign-stop": "\f82e", - "sign-turn-left-fill": "\f82f", - "sign-turn-left": "\f830", - "sign-turn-right-fill": "\f831", - "sign-turn-right": "\f832", - "sign-turn-slight-left-fill": "\f833", - "sign-turn-slight-left": "\f834", - "sign-turn-slight-right-fill": "\f835", - "sign-turn-slight-right": "\f836", - "sign-yield-fill": "\f837", - "sign-yield": "\f838", - "ev-station-fill": "\f839", - "ev-station": "\f83a", - "fuel-pump-diesel-fill": "\f83b", - "fuel-pump-diesel": "\f83c", - "fuel-pump-fill": "\f83d", - "fuel-pump": "\f83e", - "0-circle-fill": "\f83f", - "0-circle": "\f840", - "0-square-fill": "\f841", - "0-square": "\f842", - "rocket-fill": "\f843", - "rocket-takeoff-fill": "\f844", - "rocket-takeoff": "\f845", - "rocket": "\f846", - "stripe": "\f847", - "subscript": "\f848", - "superscript": "\f849", - "trello": "\f84a", - "envelope-at-fill": "\f84b", - "envelope-at": "\f84c", - "regex": "\f84d", - "text-wrap": "\f84e", - "sign-dead-end-fill": "\f84f", - "sign-dead-end": "\f850", - "sign-do-not-enter-fill": "\f851", - "sign-do-not-enter": "\f852", - "sign-intersection-fill": "\f853", - "sign-intersection-side-fill": "\f854", - "sign-intersection-side": "\f855", - "sign-intersection-t-fill": "\f856", - "sign-intersection-t": "\f857", - "sign-intersection-y-fill": "\f858", - "sign-intersection-y": "\f859", - "sign-intersection": "\f85a", - "sign-merge-left-fill": "\f85b", - "sign-merge-left": "\f85c", - "sign-merge-right-fill": "\f85d", - "sign-merge-right": "\f85e", - "sign-no-left-turn-fill": "\f85f", - "sign-no-left-turn": "\f860", - "sign-no-parking-fill": "\f861", - "sign-no-parking": "\f862", - "sign-no-right-turn-fill": "\f863", - "sign-no-right-turn": "\f864", - "sign-railroad-fill": "\f865", - "sign-railroad": "\f866", - "building-add": "\f867", - "building-check": "\f868", - "building-dash": "\f869", - "building-down": "\f86a", - "building-exclamation": "\f86b", - "building-fill-add": "\f86c", - "building-fill-check": "\f86d", - "building-fill-dash": "\f86e", - "building-fill-down": "\f86f", - "building-fill-exclamation": "\f870", - "building-fill-gear": "\f871", - "building-fill-lock": "\f872", - "building-fill-slash": "\f873", - "building-fill-up": "\f874", - "building-fill-x": "\f875", - "building-fill": "\f876", - "building-gear": "\f877", - "building-lock": "\f878", - "building-slash": "\f879", - "building-up": "\f87a", - "building-x": "\f87b", - "buildings-fill": "\f87c", - "buildings": "\f87d", - "bus-front-fill": "\f87e", - "bus-front": "\f87f", - "ev-front-fill": "\f880", - "ev-front": "\f881", - "globe-americas": "\f882", - "globe-asia-australia": "\f883", - "globe-central-south-asia": "\f884", - "globe-europe-africa": "\f885", - "house-add-fill": "\f886", - "house-add": "\f887", - "house-check-fill": "\f888", - "house-check": "\f889", - "house-dash-fill": "\f88a", - "house-dash": "\f88b", - "house-down-fill": "\f88c", - "house-down": "\f88d", - "house-exclamation-fill": "\f88e", - "house-exclamation": "\f88f", - "house-gear-fill": "\f890", - "house-gear": "\f891", - "house-lock-fill": "\f892", - "house-lock": "\f893", - "house-slash-fill": "\f894", - "house-slash": "\f895", - "house-up-fill": "\f896", - "house-up": "\f897", - "house-x-fill": "\f898", - "house-x": "\f899", - "person-add": "\f89a", - "person-down": "\f89b", - "person-exclamation": "\f89c", - "person-fill-add": "\f89d", - "person-fill-check": "\f89e", - "person-fill-dash": "\f89f", - "person-fill-down": "\f8a0", - "person-fill-exclamation": "\f8a1", - "person-fill-gear": "\f8a2", - "person-fill-lock": "\f8a3", - "person-fill-slash": "\f8a4", - "person-fill-up": "\f8a5", - "person-fill-x": "\f8a6", - "person-gear": "\f8a7", - "person-lock": "\f8a8", - "person-slash": "\f8a9", - "person-up": "\f8aa", - "scooter": "\f8ab", - "taxi-front-fill": "\f8ac", - "taxi-front": "\f8ad", - "amd": "\f8ae", - "database-add": "\f8af", - "database-check": "\f8b0", - "database-dash": "\f8b1", - "database-down": "\f8b2", - "database-exclamation": "\f8b3", - "database-fill-add": "\f8b4", - "database-fill-check": "\f8b5", - "database-fill-dash": "\f8b6", - "database-fill-down": "\f8b7", - "database-fill-exclamation": "\f8b8", - "database-fill-gear": "\f8b9", - "database-fill-lock": "\f8ba", - "database-fill-slash": "\f8bb", - "database-fill-up": "\f8bc", - "database-fill-x": "\f8bd", - "database-fill": "\f8be", - "database-gear": "\f8bf", - "database-lock": "\f8c0", - "database-slash": "\f8c1", - "database-up": "\f8c2", - "database-x": "\f8c3", - "database": "\f8c4", - "houses-fill": "\f8c5", - "houses": "\f8c6", - "nvidia": "\f8c7", - "person-vcard-fill": "\f8c8", - "person-vcard": "\f8c9", - "sina-weibo": "\f8ca", - "tencent-qq": "\f8cb", - "wikipedia": "\f8cc", - "alphabet-uppercase": "\f2a5", - "alphabet": "\f68a", - "amazon": "\f68d", - "arrows-collapse-vertical": "\f690", - "arrows-expand-vertical": "\f695", - "arrows-vertical": "\f698", - "arrows": "\f6a2", - "ban-fill": "\f6a3", - "ban": "\f6b6", - "bing": "\f6c2", - "cake": "\f6e0", - "cake2": "\f6ed", - "cookie": "\f6ee", - "copy": "\f759", - "crosshair": "\f769", - "crosshair2": "\f794", - "emoji-astonished-fill": "\f795", - "emoji-astonished": "\f79a", - "emoji-grimace-fill": "\f79b", - "emoji-grimace": "\f7a0", - "emoji-grin-fill": "\f7a1", - "emoji-grin": "\f7a6", - "emoji-surprise-fill": "\f7a7", - "emoji-surprise": "\f7ac", - "emoji-tear-fill": "\f7ad", - "emoji-tear": "\f7b2", - "envelope-arrow-down-fill": "\f7b3", - "envelope-arrow-down": "\f7b8", - "envelope-arrow-up-fill": "\f7b9", - "envelope-arrow-up": "\f7be", - "feather": "\f7bf", - "feather2": "\f7c4", - "floppy-fill": "\f7c5", - "floppy": "\f7d8", - "floppy2-fill": "\f7d9", - "floppy2": "\f7e4", - "gitlab": "\f7e5", - "highlighter": "\f7f8", - "marker-tip": "\f802", - "nvme-fill": "\f803", - "nvme": "\f80c", - "opencollective": "\f80d", - "pci-card-network": "\f8cd", - "pci-card-sound": "\f8ce", - "radar": "\f8cf", - "send-arrow-down-fill": "\f8d0", - "send-arrow-down": "\f8d1", - "send-arrow-up-fill": "\f8d2", - "send-arrow-up": "\f8d3", - "sim-slash-fill": "\f8d4", - "sim-slash": "\f8d5", - "sourceforge": "\f8d6", - "substack": "\f8d7", - "threads-fill": "\f8d8", - "threads": "\f8d9", - "transparency": "\f8da", - "twitter-x": "\f8db", - "type-h4": "\f8dc", - "type-h5": "\f8dd", - "type-h6": "\f8de", - "backpack-fill": "\f8df", - "backpack": "\f8e0", - "backpack2-fill": "\f8e1", - "backpack2": "\f8e2", - "backpack3-fill": "\f8e3", - "backpack3": "\f8e4", - "backpack4-fill": "\f8e5", - "backpack4": "\f8e6", - "brilliance": "\f8e7", - "cake-fill": "\f8e8", - "cake2-fill": "\f8e9", - "duffle-fill": "\f8ea", - "duffle": "\f8eb", - "exposure": "\f8ec", - "gender-neuter": "\f8ed", - "highlights": "\f8ee", - "luggage-fill": "\f8ef", - "luggage": "\f8f0", - "mailbox-flag": "\f8f1", - "mailbox2-flag": "\f8f2", - "noise-reduction": "\f8f3", - "passport-fill": "\f8f4", - "passport": "\f8f5", - "person-arms-up": "\f8f6", - "person-raised-hand": "\f8f7", - "person-standing-dress": "\f8f8", - "person-standing": "\f8f9", - "person-walking": "\f8fa", - "person-wheelchair": "\f8fb", - "shadows": "\f8fc", - "suitcase-fill": "\f8fd", - "suitcase-lg-fill": "\f8fe", - "suitcase-lg": "\f8ff", - "suitcase": "\f900", - "suitcase2-fill": "\f901", - "suitcase2": "\f902", - "vignette": "\f903", -); - -@each $icon, $codepoint in $bootstrap-icons-map { - .bi-#{$icon}::before { content: $codepoint; } -} diff --git a/static/bootstrap/icons/fonts/bootstrap-icons.woff b/static/bootstrap/icons/fonts/bootstrap-icons.woff deleted file mode 100644 index ae24c6507f202a8bbe910b1ba7dcf3ff09a3d987..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176088 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

UyCmIv96cio>;J2&t+aOr4D&5Hr12%4+_? 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

RF~ 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 diff --git a/static/bootstrap/icons/fonts/bootstrap-icons.woff2 b/static/bootstrap/icons/fonts/bootstrap-icons.woff2 deleted file mode 100644 index fff9d0cfb88c9d82af94f48a70fd9add77d5f894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 130648 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

6_^ zD4!O`e z4{{}t2BP5Mvrd3iK^zr@ACj^-Vv)Y9hBOdNAjFAX>540kic)})NP*;8o~Y6n$+bLT zSqPVJaa3@L&^<0#=B%$!!6{%L8dB0W?aNIkMaGP22|~-*bXuq}h~tX$_uxS}c9#ei z_>2v7pQL-9nBtuudkeQ22|dp>vj8_?%a4ymywL>b!iB!AM>+?g)@2(IGNKomU8UIYrLDGEQN{Njj3`mP3~fhdwObx;SR;1fW@ zG@Zom7&Wk4rKsQ>*$O3m*I(79E|)fUH434kX!Zi`6olTw;H3Gv6fmleXB^T40-=}t znLR`LzkdVdmWWYsG~7(oV!Vat!G_Lbf=BxIGJMeB;0OGL8kX6zZi z_??&teEck}qLc>2)W{IxQb3=n+!&Y!c3X#T}!zekHU7J-@x(DcK_X3R6fkG{GUb#n%BYEmJ^$NkD zdb>#|Ow+-&+xwX)E!~8*MR)v@q%uI~SsCR(C|9Lu9d4QU2DtfRgjzh0=S2i=6j2!c ziECXeEm3qkMh5g|wiMV38#;GJ=4uLPm|f5C!BtUb8dS(aa|-TYh;9rv2zTtqYIkt79?(whZ+@Z=jEi(4PhJ8peC@3i&#yz|zV^DbLo$#uu% zVoz*kv+YSu=!B)rTSChS<3D#!I790Nax9-uLVw)|bQb!*DUu0$1^rUQyrWk_jh+g) zICKKnyY3b+n={sqofol1-pzeX>1<_-%&*?GgCi|GQ@*CJ?w=6W5r)ByjKRcRx7%3d z8&_fBYA@O4q~%$zn=2xqK%ltV;p88xE3k{jtuJktH^Q=~K>q{j!R@ez2!Fs*LeQCO z3~TzI*U%SiW^c%)&>!8E8>Q&Wy`jWWfm-K3-IUP{#_w>CVb2Jq_!I-IB!dSfCNmv# z3&*7pXPl(;>ysj_67#@8NG43I25f()!}0aXssbaAZ zjnD+tF{?RUeY-cmgd_AQ-of_u!hCpeslqD#9a?b-rWA5Ydtm`H`q@k9Ei8Ak0muZ8 z^zSVe9~%DK&(NO`Qii?v(4Le|GOoVzWU*1gQBHM|D1AIrk@L)w7Z6G@f9L4Bfqil{ zB?(z67rh%(kxA-q8WBE45^iWuwn`=+?qy_X8|gceqy`U4p(jYu$bFttBB?19&8Ju_ zeM5V)>E-pbMEhIXL}p15u`Et;<$4uW^Brd`{mX(zTUE&=;am6KHU}!~Ie6=v3r+q1 zv#D$d={UZdW9Mbgc01pR$>|-YoB@wGO*};wVd0w6V;2#R5ruRVJ{LH4wo z9z%Pwo#fj^3!yvgZX-><=-I!`=TGkIQ;ReZeCBaVX_XcB+<6>Or!=`YSL8Ud^A^oQ zNX@nfKMmYDtuu+JcfR#umOgTR{K*? zX^;zXQVX9HX`rFKS;-}7uz^`s@kbhPU`FADwn62Is`zpZEKgWTne4L$W>wAKkFZ+} zl`K|i&J<@ld7>&Am^*l@fl*bGbJxe@iIP90p|fUG?U%4r=)B#;3?7t~M9I~jfmv1a z_eZOEtD(|g=XkzNI5kD3H%^#X=H}JNN=>=*3VEWczOXX#gf;x7Dx{!RmLD2)DM90R zQOw@&oD3i7N@LDRh0XcEtg6)0g1UE`#GySY{FV<51mnv6rr3r0{GieluGsQKReX&X zEdcU_m7MW0T|2qbC|CBvaz zb2bk)KWj#V+9<|f(@7ACj5j8Dq}}*p0)s+3o)Y7rvFP~WQh=Ph@sc@fNz6QRM6}}} zbHuc9_#=EEXfB6)t3;>_8Qx6rkZ(GixfJ5jtqossR6tQ(wwbd)y5X5QLJD|)A6zJ` z9e#;%ud4!tT2?eT)wb!xfBqM}GiZR7mNJsLHERr<;)dSy^6J_V)E5n52Y_U^AZ4bv z1{-T=+~H|Dh()5^)ElPQq0Exq__pO|c}SUUnf==$$Vyxo?+xLA0TM1l=4K1I=!Ej;zTN8%nYhEO=_cqSx@E7?~6sYnWH< zfUMRzBS2|AwH_<^kmx4fwtkX@`M8uUgp( z*Avdg@V*5{do?Oj>GCjrOG2G{eUxJ?2%2ln+8exR#L>Wd37#%CU_%$LBj~Vu68@5m z730ccBj$Oct*DtCxR?Wt3g2%D99MmXXWJ#NV`ALHdw})omo05YNh>2)6F`3Hfi-?> zTHT>Iqd3K~{GZ%sMC zhuOT*P=(M0Z$35KkuhDSRU6%>$G!IKp)h68@ZLStgV6k}IKQ2gmRD75#2%Jns~L)8 zamN&_Osk2qzM5m|j;A_B-_!Mi~dNoWrGU3DAhVs(n zUM0<5va}NUu4=oU^=)uSl~L}jImD0oQYF1oVTw!1t1?UXL>u}(H_mjx9PDN( zxEfC*GL6g3L@55Z79c%m8)d~BTp-jw4%inn!fhn34qQs17Gdyd05Gu%(mPEE)t;dRKZIs*;6($F?7n9wPCdnc12=?bOepyNevcF znGd_(f_gzbwHC&aQ5y;>#X-0#SthX6C%NPk>L^}eOwf3u)hb+h(&7BN0axXomrP*X zadL*al#seCJQEm~p{@l~ii+ZupBReW7(0_82$v&R65RqoJne5ec`ih6O$45gIVSRd zf#)`^15P5}5o#V9e^SKMyCsF1hVBQ~+_&Hf@~PXjL{F)ix`Rk;>Nnqf>w8>(OSQ|? z53Lx{5~FBHrp#A({KR$hM!Gq>>HJgp)C)CID(g8CU;#_&P8&uOH28H}XXHw~gi)UF zaU7Oy48_slR%))t+@Xma30VAk6`Twx6XwCzhT$OA3o)|1^pb3y^kuG|MLce-xj z-NA(HKc7gLTbX>?q5I7u# zJ?f^@1PPW`76R7}M$H%g1|0?q-)kt3Dev!IW&X(XmEYGk&#is+rv93_*%Hs`Qv;F1L{^cIGe zZSE2Hu2LW_fYkySR!V8S%BM?N{9DxRgl=fvH>Q$qq>W}R{I6m@N(5_=G|4z{j4X*F z2fYFrejlvJ7upcG?Ohlq=A0Y6f$&vv{78o?dAM*Xsfb@dcW^`%VqdkP=0P%aS^xoZ z?OR{0mk-OVo^%y~b~G!v!Bfe~FfjoYQ{d;-K^8)%d<*l+SIH&=4%H$-bV=(!Pxd}k zxso$o!1Y{LqQyYKe|ld)3*BbPr^ss26$#8)n|koh8(t49L~P}Ax;jH9LfJHm?C4uS zbi)fhVQ!J0Z_`k&uZ~n;e;o5QkWrgn3 zCJR`C6d;wgXX+)+E@bi`NZgIVrDPN8J_Npi(;4xs9x4jS!PhpSz+!>9pwiJF4Rc2S zC7)2rVCXp^*T=Sbs^c#d2aaV9l4{R?(q-??w;()xTqgel4ItRN@yV~BMer#gq;U|7 z;?H%oxKTlO4mZC8{yxC^{=cD&6P{NKcSx=-BC+|N z?e5d1VM!+wTR$IOWi&yhL6eWTuyGPcLzdDSTH+UJ6meu^)AV9grQ5BAtaRw47wWy(`mptJ>r>tN zeaFj_JrfhSpE=#_R>{3Y<~M^Nb_{DQ5NNmSZ3D!A);Ul0-UYr`FM_lB@Y=ZRjfL>m z&<9lJFp7x|yrDkoAbk0_yB7B|uTU!Y5+T*M7pz6sL{ii*O1~!)!vhMkLa)XKstjqn z#A74IOj3s3&b-S;DgYL)xIySE?}dib6KbyF-tv6?bAzXX|Jxfn`BD;=R;QE*Q0j#6 za_FCcozC4o`Zheuq%>$he%N$MZ0P^8QZ6e*0;emU2W51wWi<_-v881Mv8e?Z!J+4* z9l3+yIH_iY#nAw<%`agHDV8`0Tc)25BREKkjnp9gg;j9J_ylaV8JAu~P`n#M%~y2V zJcQlv=aBAEKglFZ)qHq|HJ5qPHzU!z-Y9A9xc{>8T*(8M%Mz0YO~kBw^?n8+S53Fep)5R6FNz{iW>HQktZF* za;2X3IvDuLl2$idh?9BXlj5ztTDV%w?`!?R>uWeDw<*L0y8TN-#E+P?s~1ND9LlI_ zCD*mWc$x}bIw%tcKB~y1Axa+@w&qqfFq=T$C-4DV>a~i59wn_ZWk(-sRp_x$L*^1B zqx)Pe-o>TL4v?H4Y0$7AIOzJxs)mnx`KN)b_(Gh_u)VzAdQ4#76w&O_5ppV|k28Vg zcbU6j@SZtP?FW$9{~PKgYRX_=?^*h9fWP0!n^dk0viQ9jp* zC&pgHTe=#gmmzy++D*21LzVXQs&zR3xyQ@LDkKe_@5UA2ikt?OPk2j@xvdHT*(Eb4 z;W#;CtrgJQS@L9P_X@0C8p0q$F!!xcrJQAp?q!}Jtw%u%w}cCH8eksz5R5uW|2??0 z0s(fO8bf;mLU@BKzL1)nib59(Q||*L_ONF4ln0;#Ca~`db4}R2MW{;Njpk|W zW}kB#)wOWvnb-Sx551NrjlNx%vM@}nY-3p{VF1*1fJC65(=ab~Ca72FdU(tu8q;#% zBuY%Ae$38$XJC4xn>rIM!&Lop>=4$sK;=0dOMMLp<)6)f$?zZcdR$i^tnSQ{YHz^h zwc#2-{@_arMWvKQ91XFNW|`ptyPer_#HwfQZ#x*ie5WBM@SQMYfCbIk=cKBKpCEl2 z%9D=9+B)?L%ql^~4utj^Qq!;xe3@3Xs)5W+lyesfREt2qmQdff0Jn@ypg+As=m6o5W(3dxYbeI0*8?-~+<_@=YF zrRxW{PlI5zu=u|qu)dtY4;rljuFov6yD24=TQiW$lU`FdX{RK=s}<#n&KiR0k)dya z-#hGo$zIn?s4DmKZqWf=Q=s!fq?vI57U8J3Y+Tsr!1Jr76iV2^7>!Gx_K}TILR!(?UqgFs8dV#E z%kTI@n1`*hc!)E6)OQ?~#}W)d$Ig-sLbPwuwEejn9^_9vQxG82+WJy^c~b@$vXuvn zBO!#OTHNUnY7(JIleENkf3FFaY;P-gYl7C1a7{JuW*<7bp)0r%#hn5s;%YHlYugsh z>RUU^41KdhV|9@%w>=0@kLwA~-M@Vbt|dzTHmdnv^P}cx&94o=-;SJy3Es|O4;|#4U>gZnt2kMT4e7zeZCPs*29*ElAXyn{ik#jeYZFtzKG>>otYlo$(m~BKZhn;yS-ISN1N! zjC?kDX|h5cLFtEk3y#gUL?D8CwiS|?ExyB{AP&f9;#QjHetvV7x3C%?##v!o?clPd zL{DMt2eKs<21=LfWeF_woT}8aaCnVxbIJuFqyq3a-~N-&ucnotA&|t)tL^WaZv-$j z_HKwR`dr22+$?tU`am`u-|)8gTa{Pfi#>b>=Z)JPopjmR;Zg4W_bx0CN?8y8X`_hV zE}Dwan~Wl~MG*}lFabOh0wdOOHRjuYpr>5;B6Jy{l;2B2w08~j|F)7XDYBjy>T`xX zX=9_TQ)Ai0(E5I)95eS%s>UZ;Vv17w%&97xUwCbs|kqU142LJ#*d`YAL diff --git a/static/bootstrap/js/bootstrap.min.js b/static/bootstrap/js/bootstrap.min.js deleted file mode 100644 index c35e1da1..00000000 --- a/static/bootstrap/js/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.3.2 (https://getbootstrap.com/) - * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use strict";function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s=new Map,n={set(t,e,i){s.has(t)||s.set(t,new Map);const n=s.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>s.has(t)&&s.get(t).get(e)||null,remove(t,e){if(!s.has(t))return;const i=s.get(t);i.delete(e),0===i.size&&s.delete(t)}},o="transitionend",r=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),a=t=>{t.dispatchEvent(new Event(o))},l=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),c=t=>l(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(r(t)):null,h=t=>{if(!l(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},d=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),u=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?u(t.parentNode):null},_=()=>{},g=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,m=[],p=()=>"rtl"===document.documentElement.dir,b=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of m)t()})),m.push(e)):e()},v=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,y=(t,e,i=!0)=>{if(!i)return void v(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let n=!1;const r=({target:i})=>{i===e&&(n=!0,e.removeEventListener(o,r),v(t))};e.addEventListener(o,r),setTimeout((()=>{n||a(e)}),s)},w=(t,e,i,s)=>{const n=t.length;let o=t.indexOf(e);return-1===o?!i&&s?t[n-1]:t[0]:(o+=i?1:-1,s&&(o=(o+n)%n),t[Math.max(0,Math.min(o,n-1))])},A=/[^.]*(?=\..*)\.|.*/,E=/\..*/,C=/::\d+$/,T={};let k=1;const $={mouseenter:"mouseover",mouseleave:"mouseout"},S=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${k++}`||t.uidEvent||k++}function O(t){const e=L(t);return t.uidEvent=e,T[e]=T[e]||{},T[e]}function I(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function D(t,e,i){const s="string"==typeof e,n=s?i:e||i;let o=M(t);return S.has(o)||(o=t),[s,n,o]}function N(t,e,i,s,n){if("string"!=typeof e||!t)return;let[o,r,a]=D(e,i,s);if(e in $){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=O(t),c=l[a]||(l[a]={}),h=I(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=L(r,e.replace(A,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return F(n,{delegateTarget:r}),s.oneOff&&j.off(t,n.type,e,i),i.apply(r,[n])}}(t,i,r):function(t,e){return function i(s){return F(s,{delegateTarget:t}),i.oneOff&&j.off(t,s.type,e),e.apply(t,[s])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function P(t,e,i,s,n){const o=I(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function x(t,e,i,s){const n=e[i]||{};for(const[o,r]of Object.entries(n))o.includes(s)&&P(t,e,i,r.callable,r.delegationSelector)}function M(t){return t=t.replace(E,""),$[t]||t}const j={on(t,e,i,s){N(t,e,i,s,!1)},one(t,e,i,s){N(t,e,i,s,!0)},off(t,e,i,s){if("string"!=typeof e||!t)return;const[n,o,r]=D(e,i,s),a=r!==e,l=O(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))x(t,l,i,e.slice(1));for(const[i,s]of Object.entries(c)){const n=i.replace(C,"");a&&!e.includes(n)||P(t,l,r,s.callable,s.delegationSelector)}}else{if(!Object.keys(c).length)return;P(t,l,r,o,n?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const s=f();let n=null,o=!0,r=!0,a=!1;e!==M(e)&&s&&(n=s.Event(e,i),s(t).trigger(n),o=!n.isPropagationStopped(),r=!n.isImmediatePropagationStopped(),a=n.isDefaultPrevented());const l=F(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&n&&n.preventDefault(),l}};function F(t,e={}){for(const[i,s]of Object.entries(e))try{t[i]=s}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>s})}return t}function z(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function H(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const B={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${H(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${H(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const s of i){let i=s.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=z(t.dataset[s])}return e},getDataAttribute:(t,e)=>z(t.getAttribute(`data-bs-${H(e)}`))};class q{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=l(e)?B.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...l(e)?B.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[s,n]of Object.entries(e)){const e=t[s],o=l(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(n).test(o))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${s}" provided type "${o}" but expected type "${n}".`)}var i}}class W extends q{constructor(t,e){super(),(t=c(t))&&(this._element=t,this._config=this._getConfig(e),n.set(this._element,this.constructor.DATA_KEY,this))}dispose(){n.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){y(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return n.get(c(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.2"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const R=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?r(i.trim()):null}return e},K={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let s=t.parentNode.closest(e);for(;s;)i.push(s),s=s.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!d(t)&&h(t)))},getSelectorFromElement(t){const e=R(t);return e&&K.findOne(e)?e:null},getElementFromSelector(t){const e=R(t);return e?K.findOne(e):null},getMultipleElementsFromSelector(t){const e=R(t);return e?K.find(e):[]}},V=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),d(this))return;const n=K.getElementFromSelector(this)||this.closest(`.${s}`);t.getOrCreateInstance(n)[e]()}))},Q=".bs.alert",X=`close${Q}`,Y=`closed${Q}`;class U extends W{static get NAME(){return"alert"}close(){if(j.trigger(this._element,X).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,Y),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=U.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}V(U,"close"),b(U);const G='[data-bs-toggle="button"]';class J extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=J.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}j.on(document,"click.bs.button.data-api",G,(t=>{t.preventDefault();const e=t.target.closest(G);J.getOrCreateInstance(e).toggle()})),b(J);const Z=".bs.swipe",tt=`touchstart${Z}`,et=`touchmove${Z}`,it=`touchend${Z}`,st=`pointerdown${Z}`,nt=`pointerup${Z}`,ot={endCallback:null,leftCallback:null,rightCallback:null},rt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class at extends q{constructor(t,e){super(),this._element=t,t&&at.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return ot}static get DefaultType(){return rt}static get NAME(){return"swipe"}dispose(){j.off(this._element,Z)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),v(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&v(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(j.on(this._element,st,(t=>this._start(t))),j.on(this._element,nt,(t=>this._end(t))),this._element.classList.add("pointer-event")):(j.on(this._element,tt,(t=>this._start(t))),j.on(this._element,et,(t=>this._move(t))),j.on(this._element,it,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const lt=".bs.carousel",ct=".data-api",ht="next",dt="prev",ut="left",_t="right",gt=`slide${lt}`,ft=`slid${lt}`,mt=`keydown${lt}`,pt=`mouseenter${lt}`,bt=`mouseleave${lt}`,vt=`dragstart${lt}`,yt=`load${lt}${ct}`,wt=`click${lt}${ct}`,At="carousel",Et="active",Ct=".active",Tt=".carousel-item",kt=Ct+Tt,$t={ArrowLeft:_t,ArrowRight:ut},St={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Lt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Ot extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=K.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===At&&this.cycle()}static get Default(){return St}static get DefaultType(){return Lt}static get NAME(){return"carousel"}next(){this._slide(ht)}nextWhenVisible(){!document.hidden&&h(this._element)&&this.next()}prev(){this._slide(dt)}pause(){this._isSliding&&a(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?j.one(this._element,ft,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,ft,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const s=t>i?ht:dt;this._slide(s,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&j.on(this._element,mt,(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,pt,(()=>this.pause())),j.on(this._element,bt,(()=>this._maybeEnableCycle()))),this._config.touch&&at.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of K.find(".carousel-item img",this._element))j.on(t,vt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ut)),rightCallback:()=>this._slide(this._directionToOrder(_t)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new at(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=$t[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=K.findOne(Ct,this._indicatorsElement);e.classList.remove(Et),e.removeAttribute("aria-current");const i=K.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(Et),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),s=t===ht,n=e||w(this._getItems(),i,s,this._config.wrap);if(n===i)return;const o=this._getItemIndex(n),r=e=>j.trigger(this._element,e,{relatedTarget:n,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(gt).defaultPrevented)return;if(!i||!n)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=n;const l=s?"carousel-item-start":"carousel-item-end",c=s?"carousel-item-next":"carousel-item-prev";n.classList.add(c),g(n),i.classList.add(l),n.classList.add(l),this._queueCallback((()=>{n.classList.remove(l,c),n.classList.add(Et),i.classList.remove(Et,c,l),this._isSliding=!1,r(ft)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return K.findOne(kt,this._element)}_getItems(){return K.find(Tt,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ut?dt:ht:t===ut?ht:dt}_orderToDirection(t){return p()?t===dt?ut:_t:t===dt?_t:ut}static jQueryInterface(t){return this.each((function(){const e=Ot.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}j.on(document,wt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=K.getElementFromSelector(this);if(!e||!e.classList.contains(At))return;t.preventDefault();const i=Ot.getOrCreateInstance(e),s=this.getAttribute("data-bs-slide-to");return s?(i.to(s),void i._maybeEnableCycle()):"next"===B.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),j.on(window,yt,(()=>{const t=K.find('[data-bs-ride="carousel"]');for(const e of t)Ot.getOrCreateInstance(e)})),b(Ot);const It=".bs.collapse",Dt=`show${It}`,Nt=`shown${It}`,Pt=`hide${It}`,xt=`hidden${It}`,Mt=`click${It}.data-api`,jt="show",Ft="collapse",zt="collapsing",Ht=`:scope .${Ft} .${Ft}`,Bt='[data-bs-toggle="collapse"]',qt={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Rt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=K.find(Bt);for(const t of i){const e=K.getSelectorFromElement(t),i=K.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return qt}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Rt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(j.trigger(this._element,Dt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Ft),this._element.classList.add(zt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(zt),this._element.classList.add(Ft,jt),this._element.style[e]="",j.trigger(this._element,Nt)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,Pt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,g(this._element),this._element.classList.add(zt),this._element.classList.remove(Ft,jt);for(const t of this._triggerArray){const e=K.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(zt),this._element.classList.add(Ft),j.trigger(this._element,xt)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(jt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=c(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Bt);for(const e of t){const t=K.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=K.find(Ht,this._config.parent);return K.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Rt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,Mt,Bt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of K.getMultipleElementsFromSelector(this))Rt.getOrCreateInstance(t,{toggle:!1}).toggle()})),b(Rt);const Kt="dropdown",Vt=".bs.dropdown",Qt=".data-api",Xt="ArrowUp",Yt="ArrowDown",Ut=`hide${Vt}`,Gt=`hidden${Vt}`,Jt=`show${Vt}`,Zt=`shown${Vt}`,te=`click${Vt}${Qt}`,ee=`keydown${Vt}${Qt}`,ie=`keyup${Vt}${Qt}`,se="show",ne='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',oe=`${ne}.${se}`,re=".dropdown-menu",ae=p()?"top-end":"top-start",le=p()?"top-start":"top-end",ce=p()?"bottom-end":"bottom-start",he=p()?"bottom-start":"bottom-end",de=p()?"left-start":"right-start",ue=p()?"right-start":"left-start",_e={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},ge={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class fe extends W{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=K.next(this._element,re)[0]||K.prev(this._element,re)[0]||K.findOne(re,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return _e}static get DefaultType(){return ge}static get NAME(){return Kt}toggle(){return this._isShown()?this.hide():this.show()}show(){if(d(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!j.trigger(this._element,Jt,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))j.on(t,"mouseover",_);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(se),this._element.classList.add(se),j.trigger(this._element,Zt,t)}}hide(){if(d(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!j.trigger(this._element,Ut,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.off(t,"mouseover",_);this._popper&&this._popper.destroy(),this._menu.classList.remove(se),this._element.classList.remove(se),this._element.setAttribute("aria-expanded","false"),B.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,Gt,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!l(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Kt.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let t=this._element;"parent"===this._config.reference?t=this._parent:l(this._config.reference)?t=c(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=i.createPopper(t,this._menu,e)}_isShown(){return this._menu.classList.contains(se)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return de;if(t.classList.contains("dropstart"))return ue;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?le:ae:e?he:ce}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(B.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...v(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=K.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>h(t)));i.length&&w(i,e,t===Yt,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=fe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=K.find(oe);for(const i of e){const e=fe.getInstance(i);if(!e||!1===e._config.autoClose)continue;const s=t.composedPath(),n=s.includes(e._menu);if(s.includes(e._element)||"inside"===e._config.autoClose&&!n||"outside"===e._config.autoClose&&n)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,s=[Xt,Yt].includes(t.key);if(!s&&!i)return;if(e&&!i)return;t.preventDefault();const n=this.matches(ne)?this:K.prev(this,ne)[0]||K.next(this,ne)[0]||K.findOne(ne,t.delegateTarget.parentNode),o=fe.getOrCreateInstance(n);if(s)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),n.focus())}}j.on(document,ee,ne,fe.dataApiKeydownHandler),j.on(document,ee,re,fe.dataApiKeydownHandler),j.on(document,te,fe.clearMenus),j.on(document,ie,fe.clearMenus),j.on(document,te,ne,(function(t){t.preventDefault(),fe.getOrCreateInstance(this).toggle()})),b(fe);const me="backdrop",pe="show",be=`mousedown.bs.${me}`,ve={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},ye={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class we extends q{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return ve}static get DefaultType(){return ye}static get NAME(){return me}show(t){if(!this._config.isVisible)return void v(t);this._append();const e=this._getElement();this._config.isAnimated&&g(e),e.classList.add(pe),this._emulateAnimation((()=>{v(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(pe),this._emulateAnimation((()=>{this.dispose(),v(t)}))):v(t)}dispose(){this._isAppended&&(j.off(this._element,be),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=c(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),j.on(t,be,(()=>{v(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){y(t,this._getElement(),this._config.isAnimated)}}const Ae=".bs.focustrap",Ee=`focusin${Ae}`,Ce=`keydown.tab${Ae}`,Te="backward",ke={autofocus:!0,trapElement:null},$e={autofocus:"boolean",trapElement:"element"};class Se extends q{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return ke}static get DefaultType(){return $e}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),j.off(document,Ae),j.on(document,Ee,(t=>this._handleFocusin(t))),j.on(document,Ce,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,Ae))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=K.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===Te?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Te:"forward")}}const Le=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Oe=".sticky-top",Ie="padding-right",De="margin-right";class Ne{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Ie,(e=>e+t)),this._setElementAttributes(Le,Ie,(e=>e+t)),this._setElementAttributes(Oe,De,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Ie),this._resetElementAttributes(Le,Ie),this._resetElementAttributes(Oe,De)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const s=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+s)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(n))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&B.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=B.getDataAttribute(t,e);null!==i?(B.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(l(t))e(t);else for(const i of K.find(t,this._element))e(i)}}const Pe=".bs.modal",xe=`hide${Pe}`,Me=`hidePrevented${Pe}`,je=`hidden${Pe}`,Fe=`show${Pe}`,ze=`shown${Pe}`,He=`resize${Pe}`,Be=`click.dismiss${Pe}`,qe=`mousedown.dismiss${Pe}`,We=`keydown.dismiss${Pe}`,Re=`click${Pe}.data-api`,Ke="modal-open",Ve="show",Qe="modal-static",Xe={backdrop:!0,focus:!0,keyboard:!0},Ye={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ue extends W{constructor(t,e){super(t,e),this._dialog=K.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new Ne,this._addEventListeners()}static get Default(){return Xe}static get DefaultType(){return Ye}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,Fe,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Ke),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(j.trigger(this._element,xe).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Ve),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){j.off(window,Pe),j.off(this._dialog,Pe),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new we({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Se({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=K.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),g(this._element),this._element.classList.add(Ve),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,ze,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){j.on(this._element,We,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),j.on(window,He,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),j.on(this._element,qe,(t=>{j.one(this._element,Be,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Ke),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,je)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,Me).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Qe)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Qe),this._queueCallback((()=>{this._element.classList.remove(Qe),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Ue.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,Re,'[data-bs-toggle="modal"]',(function(t){const e=K.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,Fe,(t=>{t.defaultPrevented||j.one(e,je,(()=>{h(this)&&this.focus()}))}));const i=K.findOne(".modal.show");i&&Ue.getInstance(i).hide(),Ue.getOrCreateInstance(e).toggle(this)})),V(Ue),b(Ue);const Ge=".bs.offcanvas",Je=".data-api",Ze=`load${Ge}${Je}`,ti="show",ei="showing",ii="hiding",si=".offcanvas.show",ni=`show${Ge}`,oi=`shown${Ge}`,ri=`hide${Ge}`,ai=`hidePrevented${Ge}`,li=`hidden${Ge}`,ci=`resize${Ge}`,hi=`click${Ge}${Je}`,di=`keydown.dismiss${Ge}`,ui={backdrop:!0,keyboard:!0,scroll:!1},_i={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class gi extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return ui}static get DefaultType(){return _i}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,ni,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new Ne).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(ei),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(ti),this._element.classList.remove(ei),j.trigger(this._element,oi,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,ri).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(ii),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(ti,ii),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new Ne).reset(),j.trigger(this._element,li)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new we({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():j.trigger(this._element,ai)}:null})}_initializeFocusTrap(){return new Se({trapElement:this._element})}_addEventListeners(){j.on(this._element,di,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():j.trigger(this._element,ai))}))}static jQueryInterface(t){return this.each((function(){const e=gi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,hi,'[data-bs-toggle="offcanvas"]',(function(t){const e=K.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),d(this))return;j.one(e,li,(()=>{h(this)&&this.focus()}));const i=K.findOne(si);i&&i!==e&&gi.getInstance(i).hide(),gi.getOrCreateInstance(e).toggle(this)})),j.on(window,Ze,(()=>{for(const t of K.find(si))gi.getOrCreateInstance(t).show()})),j.on(window,ci,(()=>{for(const t of K.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&gi.getOrCreateInstance(t).hide()})),V(gi),b(gi);const fi={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},mi=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),pi=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,bi=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!mi.has(i)||Boolean(pi.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},vi={allowList:fi,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"

"},yi={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},wi={entry:"(string|element|function|null)",selector:"(string|element)"};class Ai extends q{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return vi}static get DefaultType(){return yi}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},wi)}_setContent(t,e,i){const s=K.findOne(i,t);s&&((e=this._resolvePossibleFunction(e))?l(e)?this._putElementInTemplate(c(e),s):this._config.html?s.innerHTML=this._maybeSanitize(e):s.textContent=e:s.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const s=(new window.DOMParser).parseFromString(t,"text/html"),n=[].concat(...s.body.querySelectorAll("*"));for(const t of n){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const s=[].concat(...t.attributes),n=[].concat(e["*"]||[],e[i]||[]);for(const e of s)bi(e,n)||t.removeAttribute(e.nodeName)}return s.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return v(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Ei=new Set(["sanitize","allowList","sanitizeFn"]),Ci="fade",Ti="show",ki=".modal",$i="hide.bs.modal",Si="hover",Li="focus",Oi={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},Ii={allowList:fi,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},Di={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class Ni extends W{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return Ii}static get DefaultType(){return Di}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ki),$i,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.eventName("show")),e=(u(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:s}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(s.append(i),j.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(Ti),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.on(t,"mouseover",_);this._queueCallback((()=>{j.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!j.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(Ti),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.off(t,"mouseover",_);this._activeTrigger.click=!1,this._activeTrigger[Li]=!1,this._activeTrigger[Si]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(Ci,Ti),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(Ci),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Ai({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(Ci)}_isShown(){return this.tip&&this.tip.classList.contains(Ti)}_createPopper(t){const e=v(this._config.placement,[this,t,this._element]),s=Oi[e.toUpperCase()];return i.createPopper(this._element,t,this._getPopperConfig(s))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return v(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...v(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)j.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===Si?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===Si?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");j.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?Li:Si]=!0,e._enter()})),j.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?Li:Si]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ki),$i,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=B.getDataAttributes(this._element);for(const t of Object.keys(e))Ei.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:c(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=Ni.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}b(Ni);const Pi={...Ni.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},xi={...Ni.DefaultType,content:"(null|string|element|function)"};class Mi extends Ni{static get Default(){return Pi}static get DefaultType(){return xi}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=Mi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}b(Mi);const ji=".bs.scrollspy",Fi=`activate${ji}`,zi=`click${ji}`,Hi=`load${ji}.data-api`,Bi="active",qi="[href]",Wi=".nav-link",Ri=`${Wi}, .nav-item > ${Wi}, .list-group-item`,Ki={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Vi={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Qi extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return Ki}static get DefaultType(){return Vi}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=c(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(j.off(this._config.target,zi),j.on(this._config.target,zi,qi,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,s=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:s,behavior:"smooth"});i.scrollTop=s}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},s=(this._rootElement||document.documentElement).scrollTop,n=s>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=s;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(n&&t){if(i(o),!s)return}else n||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=K.find(qi,this._config.target);for(const e of t){if(!e.hash||d(e))continue;const t=K.findOne(decodeURI(e.hash),this._element);h(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Bi),this._activateParents(t),j.trigger(this._element,Fi,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))K.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Bi);else for(const e of K.parents(t,".nav, .list-group"))for(const t of K.prev(e,Ri))t.classList.add(Bi)}_clearActiveClass(t){t.classList.remove(Bi);const e=K.find(`${qi}.${Bi}`,t);for(const t of e)t.classList.remove(Bi)}static jQueryInterface(t){return this.each((function(){const e=Qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,Hi,(()=>{for(const t of K.find('[data-bs-spy="scroll"]'))Qi.getOrCreateInstance(t)})),b(Qi);const Xi=".bs.tab",Yi=`hide${Xi}`,Ui=`hidden${Xi}`,Gi=`show${Xi}`,Ji=`shown${Xi}`,Zi=`click${Xi}`,ts=`keydown${Xi}`,es=`load${Xi}`,is="ArrowLeft",ss="ArrowRight",ns="ArrowUp",os="ArrowDown",rs="Home",as="End",ls="active",cs="fade",hs="show",ds=".dropdown-toggle",us=`:not(${ds})`,_s='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',gs=`.nav-link${us}, .list-group-item${us}, [role="tab"]${us}, ${_s}`,fs=`.${ls}[data-bs-toggle="tab"], .${ls}[data-bs-toggle="pill"], .${ls}[data-bs-toggle="list"]`;class ms extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),j.on(this._element,ts,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?j.trigger(e,Yi,{relatedTarget:t}):null;j.trigger(t,Gi,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(ls),this._activate(K.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),j.trigger(t,Ji,{relatedTarget:e})):t.classList.add(hs)}),t,t.classList.contains(cs)))}_deactivate(t,e){t&&(t.classList.remove(ls),t.blur(),this._deactivate(K.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),j.trigger(t,Ui,{relatedTarget:e})):t.classList.remove(hs)}),t,t.classList.contains(cs)))}_keydown(t){if(![is,ss,ns,os,rs,as].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!d(t)));let i;if([rs,as].includes(t.key))i=e[t.key===rs?0:e.length-1];else{const s=[ss,os].includes(t.key);i=w(e,t.target,s,!0)}i&&(i.focus({preventScroll:!0}),ms.getOrCreateInstance(i).show())}_getChildren(){return K.find(gs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=K.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const s=(t,s)=>{const n=K.findOne(t,i);n&&n.classList.toggle(s,e)};s(ds,ls),s(".dropdown-menu",hs),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(ls)}_getInnerElement(t){return t.matches(gs)?t:K.findOne(gs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=ms.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,Zi,_s,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),d(this)||ms.getOrCreateInstance(this).show()})),j.on(window,es,(()=>{for(const t of K.find(fs))ms.getOrCreateInstance(t)})),b(ms);const ps=".bs.toast",bs=`mouseover${ps}`,vs=`mouseout${ps}`,ys=`focusin${ps}`,ws=`focusout${ps}`,As=`hide${ps}`,Es=`hidden${ps}`,Cs=`show${ps}`,Ts=`shown${ps}`,ks="hide",$s="show",Ss="showing",Ls={animation:"boolean",autohide:"boolean",delay:"number"},Os={animation:!0,autohide:!0,delay:5e3};class Is extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return Os}static get DefaultType(){return Ls}static get NAME(){return"toast"}show(){j.trigger(this._element,Cs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(ks),g(this._element),this._element.classList.add($s,Ss),this._queueCallback((()=>{this._element.classList.remove(Ss),j.trigger(this._element,Ts),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(j.trigger(this._element,As).defaultPrevented||(this._element.classList.add(Ss),this._queueCallback((()=>{this._element.classList.add(ks),this._element.classList.remove(Ss,$s),j.trigger(this._element,Es)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove($s),super.dispose()}isShown(){return this._element.classList.contains($s)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,bs,(t=>this._onInteraction(t,!0))),j.on(this._element,vs,(t=>this._onInteraction(t,!1))),j.on(this._element,ys,(t=>this._onInteraction(t,!0))),j.on(this._element,ws,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Is.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return V(Is),b(Is),{Alert:U,Button:J,Carousel:Ot,Collapse:Rt,Dropdown:fe,Modal:Ue,Offcanvas:gi,Popover:Mi,ScrollSpy:Qi,Tab:ms,Toast:Is,Tooltip:Ni}})); -//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file

0EZ=fBWqCNa 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 syUQ;nHRMz5c&#)Foh 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