├── crates ├── capgen │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── templates │ │ └── base.jinja │ │ └── lib.rs ├── filetype │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── tiny-tile-proxy │ ├── assets │ │ ├── wmts │ │ │ ├── favicon.ico │ │ │ └── xyz.xml │ │ └── templates │ │ │ └── geocloud.xml │ ├── docs │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── logo_dark.webp │ │ │ └── logo_light.webp │ │ ├── setting.md │ │ ├── GetAddress.vue │ │ ├── index.md │ │ ├── .vitepress │ │ │ └── config.mjs │ │ ├── proxys.md │ │ └── SetToken.vue │ ├── src │ │ ├── routers │ │ │ ├── mod.rs │ │ │ ├── index.rs │ │ │ ├── docs.rs │ │ │ ├── config.rs │ │ │ ├── jilin1.rs │ │ │ ├── geocloud.rs │ │ │ └── wmts.rs │ │ ├── libs │ │ │ ├── mod.rs │ │ │ ├── utils.rs │ │ │ ├── config.rs │ │ │ ├── jilin1.rs │ │ │ └── geocloud.rs │ │ └── main.rs │ └── Cargo.toml ├── jilin1 │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── webp_to_png │ ├── Cargo.toml │ └── src │ └── lib.rs ├── .dockerignore ├── README.md ├── docs ├── public │ ├── favicon.ico │ ├── logo_dark.webp │ └── logo_light.webp ├── setting.md ├── GetAddress.vue ├── index.md ├── .vitepress │ └── config.mjs ├── proxys.md └── SetToken.vue ├── .gitignore ├── package.json ├── dist-workspace.toml ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── .github └── workflows │ ├── docker.yml │ ├── Release_docker.yml │ ├── Commit.yml │ └── Release.yml └── pnpm-lock.yaml /crates/capgen/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | Cache 3 | target -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyTileProxy 2 | A Simple Tile Porxy Server 3 | -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuxspro/TinyTileProxy/main/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/logo_dark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuxspro/TinyTileProxy/main/docs/public/logo_dark.webp -------------------------------------------------------------------------------- /docs/public/logo_light.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuxspro/TinyTileProxy/main/docs/public/logo_light.webp -------------------------------------------------------------------------------- /docs/setting.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # 设置 Tokens 7 | -------------------------------------------------------------------------------- /crates/filetype/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "filetype" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/assets/wmts/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuxspro/TinyTileProxy/main/crates/tiny-tile-proxy/assets/wmts/favicon.ico -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuxspro/TinyTileProxy/main/crates/tiny-tile-proxy/docs/public/favicon.ico -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/setting.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # 设置 Tokens 7 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/public/logo_dark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuxspro/TinyTileProxy/main/crates/tiny-tile-proxy/docs/public/logo_dark.webp -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/public/logo_light.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuxspro/TinyTileProxy/main/crates/tiny-tile-proxy/docs/public/logo_light.webp -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/routers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod docs; 3 | pub mod geocloud; 4 | pub mod index; 5 | pub mod jilin1; 6 | pub mod wmts; 7 | -------------------------------------------------------------------------------- /crates/capgen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "capgen" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | minijinja = "2.8.0" 8 | serde = { workspace = true } 9 | -------------------------------------------------------------------------------- /crates/jilin1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jilin1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | anyhow = { workspace = true } 8 | reqwest = { workspace = true } -------------------------------------------------------------------------------- /crates/webp_to_png/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "webp_to_png" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | image = { version = "0.25.5", default-features = false, features = [ 8 | "webp", 9 | "png", 10 | ] } 11 | anyhow = { workspace = true } 12 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/routers/index.rs: -------------------------------------------------------------------------------- 1 | use rocket::response::Redirect; 2 | 3 | #[get("/")] 4 | pub fn index() -> Redirect { 5 | Redirect::to(uri!("/docs/index.html")) 6 | } 7 | 8 | #[get("/favicon.ico")] 9 | pub fn favicon() -> Redirect { 10 | Redirect::to(uri!("/docs/favicon.ico")) 11 | } 12 | -------------------------------------------------------------------------------- /docs/GetAddress.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/GetAddress.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | config.toml 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | pnpm-debug.log* 11 | lerna-debug.log* 12 | 13 | node_modules 14 | dist 15 | dist-ssr 16 | *.local 17 | 18 | # Editor directories and files 19 | .vscode/* 20 | !.vscode/extensions.json 21 | .idea 22 | .DS_Store 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | docs/.vitepress/cache 29 | Cache -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.1.10", 4 | "description": "docs for tiny tile proxy", 5 | "main": "index.js", 6 | "scripts": { 7 | "docs:dev": "vitepress dev docs", 8 | "docs:build": "vitepress build docs", 9 | "docs:preview": "vitepress preview docs", 10 | "build": "vitepress build docs && cargo build --release" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "vitepress": "^1.6.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /crates/webp_to_png/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result as AnyhowResult; 2 | use image::ImageFormat; 3 | use std::io::Cursor; 4 | 5 | pub fn webp_to_png(webp_data: Vec) -> AnyhowResult> { 6 | // 使用 Cursor 将 Vec 转换为可读的流 7 | let reader = Cursor::new(webp_data); 8 | // 解码 WebP 图片 9 | let img = image::load(reader, ImageFormat::WebP)?; 10 | // 创建一个 Vec 来存储 PNG 数据 11 | let mut png_data = Vec::new(); 12 | // 将图片保存为 PNG 格式 13 | img.write_to(&mut Cursor::new(&mut png_data), ImageFormat::Png)?; 14 | 15 | Ok(png_data) 16 | } 17 | -------------------------------------------------------------------------------- /dist-workspace.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["cargo:."] 3 | 4 | # Config for 'dist' 5 | [dist] 6 | # The preferred dist version to use in CI (Cargo.toml SemVer syntax) 7 | cargo-dist-version = "0.28.0" 8 | # CI backends to support 9 | ci = "github" 10 | # The installers to generate for each app 11 | installers = [] 12 | allow-dirty = ["ci", "msi"] 13 | 14 | # Target platforms to build apps for (Rust target-triple syntax) 15 | targets = [ 16 | "aarch64-apple-darwin", 17 | "x86_64-apple-darwin", 18 | "x86_64-unknown-linux-gnu", 19 | "x86_64-pc-windows-msvc", 20 | ] 21 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "Tiny Tile Proxy" 7 | tagline: A Simple Tile Porxy Server 8 | image: 9 | light: /logo_light.webp 10 | dark: /logo_dark.webp 11 | alt: Logo 12 | actions: 13 | - theme: brand 14 | text: 开始使用 15 | link: /proxys 16 | - theme: alt 17 | text: 配置Tokens 18 | link: /setting 19 | 20 | features: 21 | - title: 📄 WMTS Proxy 服务 22 | details: 代理一些常用但是 QGIS 不能正常加载的 WMTS 服务 23 | - title: 📦 XYZ/TMS to WMTS 24 | details: 也许对 Arcmap 有用?🤔 25 | # - title: 💯开源 26 | # details: Code with ♥️ 27 | --- 28 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "Tiny Tile Proxy" 7 | tagline: A Simple Tile Porxy Server 8 | image: 9 | light: /logo_light.webp 10 | dark: /logo_dark.webp 11 | alt: Logo 12 | actions: 13 | - theme: brand 14 | text: 开始使用 15 | link: /proxys 16 | - theme: alt 17 | text: 配置Tokens 18 | link: /setting 19 | 20 | features: 21 | - title: 📄 WMTS Proxy 服务 22 | details: 代理一些常用但是 QGIS 不能正常加载的 WMTS 服务 23 | - title: 📦 XYZ/TMS to WMTS 24 | details: 也许对 Arcmap 有用?🤔 25 | # - title: 💯开源 26 | # details: Code with ♥️ 27 | --- 28 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["crates/*"] 4 | 5 | [workspace.dependencies] 6 | anyhow = "1.0.93" 7 | reqwest = { version = "0.12", features = [ 8 | "gzip", 9 | "rustls-tls", 10 | ], default-features = false } 11 | serde = { version = "1.0", features = ["derive"] } 12 | 13 | # https://doc.rust-lang.org/cargo/reference/profiles.html 14 | [profile.release] 15 | codegen-units = 1 # 控制代码生成的单元数量 16 | lto = true # 启用链接时优化, 减少生成的二进制文件的大小并提高性能 17 | opt-level = "s" # 设置优化级别 18 | panic = "unwind" # 控制 panic 时的行为 unwind: 在 panic 时展开堆栈 19 | strip = true # 控制是否剥离生成的二进制文件中的符号信息 20 | 21 | # The profile that 'dist' will build with 22 | [profile.dist] 23 | inherits = "release" 24 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest AS builder 2 | 3 | WORKDIR /app 4 | 5 | # 安装 musl 工具链 6 | RUN rustup target add x86_64-unknown-linux-musl 7 | 8 | # 安装 musl 9 | RUN apt-get update && apt-get install -y musl-tools 10 | 11 | # 复制当前目录的所有内容到工作目录 12 | COPY ./ . 13 | 14 | RUN cargo build --target x86_64-unknown-linux-musl --release 15 | 16 | # 使用一个轻量级的镜像来运行应用程序 17 | FROM alpine:latest 18 | 19 | WORKDIR /app 20 | # 复制构建好的二进制文件 21 | COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/TinyTileProxy /usr/local/bin/TinyTileProxy 22 | 23 | # 设置环境变量 24 | ENV ROCKET_ADDRESS=0.0.0.0 25 | ENV ROCKET_PORT=8000 26 | ENV ROCKET_USE_HTTPS=false 27 | 28 | # 暴露端口 29 | EXPOSE 8000 30 | 31 | # 创建挂载点 32 | VOLUME /app 33 | 34 | # 运行应用程序 35 | CMD ["TinyTileProxy"] -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tiny-tile-proxy" 3 | authors = ["liuxspro "] 4 | version = "0.1.10" 5 | repository = "https://github.com/liuxspro/TinyTileProxy" 6 | edition = "2021" 7 | 8 | [[bin]] 9 | name = "TinyTileProxy" 10 | path = "src/main.rs" 11 | 12 | [dependencies] 13 | anyhow = { workspace = true } 14 | reqwest = { workspace = true } 15 | figment = { version = "0.10", features = ["toml"] } 16 | minijinja = "2.3.1" 17 | rocket = { version = "0.5.1", features = ["json"] } 18 | rust-embed = "8.5.0" 19 | serde = { workspace = true } 20 | tokio = { version = "1", features = ["full"] } 21 | toml = "0.8.19" 22 | # My Crates 23 | webp_to_png = { path = "../webp_to_png" } 24 | jilin1 = { path = "../jilin1" } 25 | filetype = { path = "../filetype" } 26 | capgen = { path = "../capgen" } 27 | -------------------------------------------------------------------------------- /docs/.vitepress/config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitepress"; 2 | 3 | // https://vitepress.dev/reference/site-config 4 | export default defineConfig({ 5 | base: "/docs/", 6 | title: "Tiny Tile Proxy", 7 | description: "A Simple Tile Porxy Server", 8 | themeConfig: { 9 | // https://vitepress.dev/reference/default-theme-config 10 | nav: [{ text: "Home", link: "/" }], 11 | 12 | sidebar: [ 13 | { 14 | text: "Ueage", 15 | items: [ 16 | { text: "Proxys", link: "/proxys" }, 17 | { text: "Setting", link: "/setting" }, 18 | ], 19 | }, 20 | ], 21 | 22 | socialLinks: [ 23 | { icon: "github", link: "https://github.com/liuxspro/TinyTileProxy" }, 24 | ], 25 | }, 26 | ignoreDeadLinks: true, 27 | head: [["link", { rel: "icon", href: "/docs/favicon.ico" }]], 28 | }); 29 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/.vitepress/config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitepress"; 2 | 3 | // https://vitepress.dev/reference/site-config 4 | export default defineConfig({ 5 | base: "/docs/", 6 | title: "Tiny Tile Proxy", 7 | description: "A Simple Tile Porxy Server", 8 | themeConfig: { 9 | // https://vitepress.dev/reference/default-theme-config 10 | nav: [{ text: "Home", link: "/" }], 11 | 12 | sidebar: [ 13 | { 14 | text: "Ueage", 15 | items: [ 16 | { text: "Proxys", link: "/proxys" }, 17 | { text: "Setting", link: "/setting" }, 18 | ], 19 | }, 20 | ], 21 | 22 | socialLinks: [ 23 | { icon: "github", link: "https://github.com/liuxspro/TinyTileProxy" }, 24 | ], 25 | }, 26 | ignoreDeadLinks: true, 27 | head: [["link", { rel: "icon", href: "/docs/favicon.ico" }]], 28 | }); 29 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/routers/docs.rs: -------------------------------------------------------------------------------- 1 | use rocket::http::ContentType; 2 | use rocket::response::content::RawHtml; 3 | use rust_embed::Embed; 4 | use std::borrow::Cow; 5 | use std::ffi::OsStr; 6 | use std::path::PathBuf; 7 | 8 | #[derive(Embed)] 9 | #[folder = "../../docs/.vitepress/dist"] 10 | struct Asset; 11 | 12 | #[get("/docs")] 13 | pub fn docs() -> Option>> { 14 | let asset = Asset::get("index.html")?; 15 | Some(RawHtml(asset.data)) 16 | } 17 | 18 | #[get("/docs/")] 19 | pub fn static_file(file: PathBuf) -> Option<(ContentType, Cow<'static, [u8]>)> { 20 | let filename = file.display().to_string(); 21 | let asset = Asset::get(&filename)?; 22 | let content_type = file 23 | .extension() 24 | .and_then(OsStr::to_str) 25 | .and_then(ContentType::from_extension) 26 | .unwrap_or(ContentType::Bytes); 27 | Some((content_type, asset.data)) 28 | } 29 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/libs/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod geocloud; 3 | pub mod jilin1; 4 | pub mod utils; 5 | 6 | #[cfg(test)] 7 | mod tests { 8 | use utils::ZXY; 9 | 10 | use super::*; 11 | 12 | #[tokio::test] 13 | async fn get_geocloud_tile() { 14 | let tk = config::get_tk_from_local_config().unwrap(); 15 | let zxy = ZXY { 16 | z: "4".to_string(), 17 | x: 24, 18 | y: 5, 19 | }; 20 | let result = geocloud::get_geocloud_tile( 21 | zxy, 22 | "qg250w_20210416_ZAZSeOGX".to_string(), 23 | tk.geocloud, 24 | None, 25 | ) 26 | .await; 27 | 28 | assert!(result.is_ok(), "get_geocloud_tile should return Ok"); 29 | // 如果结果为 Ok,进一步验证返回的 body 是否符合预期 30 | if let Ok(body) = result { 31 | assert!(body.len() == 15301, "Body length should be 15301"); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /crates/jilin1/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result as AnyhowResult; 2 | /// 请求吉林1号瓦片 3 | /// 4 | /// ## 参数 5 | /// 6 | /// - `z` - z 值 7 | /// - `x` - x 值 8 | /// - `y` - y 值 9 | /// - `mk` - 地图 mk 10 | /// - `tk` - Token 11 | /// ## Returns 12 | /// 返回瓦片二进制数据 Result, reqwest::Error> 13 | pub async fn get_tile(z: u32, x: u32, y: u32, mk: String, tk: String) -> AnyhowResult> { 14 | const AGENT:&str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"; 15 | // 通过添加sch=wmts可返回正常XYZ顺序, 否则使用 `reversed_y: u32 = (1u32 << z) - 1 - y` 计算 -y 值 16 | let url = format!( 17 | "https://api.jl1mall.com/getMap/{}/{}/{}?mk={}&tk={}&sch=wmts", 18 | z, x, y, mk, tk 19 | ); 20 | // 获取瓦片内容 21 | // 创建一个客户端并启用 Gzip 解压缩 22 | let client = reqwest::Client::builder() 23 | .user_agent(AGENT) 24 | .gzip(true) 25 | .build()?; 26 | // 发送 GET 请求 27 | let response = client.get(url).send().await?; 28 | let body = response.bytes().await?; 29 | // TODO tk不正确的时候也返回瓦片(参数有误),应返回错误 30 | Ok(body.to_vec()) 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 liuxspro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/libs/utils.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result as AnyhowResult}; 2 | 3 | use std::{io::Write, path::PathBuf}; 4 | 5 | use std::fs::File; 6 | use std::path::Path; 7 | 8 | use filetype::is_png; 9 | // use geocloud::get_map_names; 10 | 11 | // use super::geocloud::get_map_names as get_geocloud_map_names; 12 | 13 | pub struct ZXY { 14 | pub z: String, 15 | pub x: u32, 16 | pub y: u32, 17 | } 18 | 19 | pub fn create_cache_dir() { 20 | // 获取当前工作目录 21 | let cache_dir = get_cache_dir(); 22 | if !cache_dir.exists() { 23 | // 创建 Cache 文件夹 24 | println!("Create Cache dir"); 25 | std::fs::create_dir(&cache_dir).expect("无法创建 Cache 文件夹"); 26 | } 27 | } 28 | 29 | pub fn get_cache_dir() -> PathBuf { 30 | // 获取当前工作目录 31 | let current_dir = std::env::current_dir().expect("无法获取当前目录"); 32 | current_dir.join("Cache") 33 | } 34 | 35 | pub fn read_file(file_path: &Path) -> Result, std::io::Error> { 36 | std::fs::read(file_path) 37 | } 38 | 39 | pub fn save_png(tile_path: PathBuf, buffer: &[u8]) -> AnyhowResult { 40 | if is_png(buffer) { 41 | let mut tile_file = File::create(&tile_path)?; 42 | tile_file.write_all(buffer)?; 43 | Ok(true) 44 | } else { 45 | Err(anyhow!("Filed to save: Not A PNG File")) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: 📦 Build Docker Image 2 | 3 | on: 4 | # push: 5 | # branches: [dev] 6 | # Allows you to run this workflow manually from the Actions tab 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build_docker_images: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | 16 | - name: Install pnpm 17 | uses: pnpm/action-setup@v4 18 | with: 19 | version: 9 20 | run_install: false 21 | 22 | - name: Install Node.js 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: 20 26 | cache: "pnpm" 27 | 28 | - name: Install dependencies 29 | run: pnpm install 30 | 31 | - name: Build docs 32 | run: pnpm docs:build 33 | 34 | - name: Set Up QEMU 35 | uses: docker/setup-qemu-action@v3 36 | 37 | - name: Set up Docker BuildX 38 | uses: docker/setup-buildx-action@v3 39 | with: 40 | install: true 41 | 42 | - name: Login to DockerHub 43 | uses: docker/login-action@v3 44 | with: 45 | username: ${{ secrets.DOCKERHUB_USERNAME }} 46 | password: ${{ secrets.DOCKERHUB_TOKEN }} 47 | 48 | - name: Build Images and push 49 | run: docker build . --platform linux/amd64 -t liuxspro/tiny-tile-proxy:dev --push 50 | -------------------------------------------------------------------------------- /.github/workflows/Release_docker.yml: -------------------------------------------------------------------------------- 1 | name: 🎉 Release Docker Image 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | dokcer: 13 | name: Build Docker Image 14 | permissions: write-all 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Install pnpm 21 | uses: pnpm/action-setup@v4 22 | with: 23 | version: 9 24 | run_install: false 25 | - name: Install Node.js 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: 20 29 | cache: "pnpm" 30 | 31 | - name: Install dependencies 32 | run: pnpm install 33 | 34 | - name: Build docs 35 | run: pnpm docs:build 36 | 37 | - name: Set Up QEMU 38 | uses: docker/setup-qemu-action@v3 39 | 40 | - name: Set up Docker BuildX 41 | uses: docker/setup-buildx-action@v3 42 | with: 43 | install: true 44 | 45 | - name: Login to DockerHub 46 | uses: docker/login-action@v3 47 | with: 48 | username: ${{ secrets.DOCKERHUB_USERNAME }} 49 | password: ${{ secrets.DOCKERHUB_TOKEN }} 50 | 51 | - name: Build Images and push 52 | run: docker build . --platform linux/amd64 -t liuxspro/tiny-tile-proxy:latest -t liuxspro/tiny-tile-proxy:${{ github.ref_name }} --push 53 | -------------------------------------------------------------------------------- /crates/filetype/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn is_png(data: &[u8]) -> bool { 2 | const PNG_MAGIC_NUMBER: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; 3 | data.len() >= 8 && data.starts_with(&PNG_MAGIC_NUMBER) 4 | } 5 | 6 | pub fn is_webp(data: &[u8]) -> bool { 7 | // 检查数据是否至少有 12 个字节 8 | if data.len() < 12 { 9 | return false; 10 | } 11 | 12 | // 使用 starts_with 避免显式索引 13 | if !data.starts_with(b"RIFF") { 14 | return false; 15 | } 16 | 17 | // 使用 get() 避免索引越界 18 | if let Some(file_type) = data.get(8..12) { 19 | if file_type == b"WEBP" { 20 | return true; 21 | } 22 | } 23 | 24 | false 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::*; 30 | 31 | #[test] 32 | fn test_is_png() { 33 | let png_header = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; 34 | let non_png_header = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x75]; 35 | 36 | assert!(is_png(&png_header)); 37 | assert!(!is_png(&non_png_header)); 38 | assert!(!is_png(&[])); // 空数据 39 | assert!(!is_png(&png_header[..4])); // 数据不足 8 字节 40 | } 41 | 42 | #[test] 43 | fn test_is_webp() { 44 | let valid_webp: &[u8] = b"RIFF\x00\x00\x00\x00WEBP"; 45 | let invalid_webp: &[u8] = b"RIFF\x00\x00\x00\x00JPEG"; 46 | 47 | assert!(is_webp(valid_webp), "应该识别为 WebP"); 48 | assert!(!is_webp(invalid_webp), "不应识别为 WebP"); 49 | assert!(!is_webp(b""), "空数据不应是 WebP"); 50 | assert!(!is_webp(b"RIFF"), "无效的 RIFF 数据"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/Commit.yml: -------------------------------------------------------------------------------- 1 | name: 🤖 Commit 2 | 3 | on: 4 | push: 5 | branches: ["dev"] 6 | pull_request: 7 | branches: ["dev"] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | commit: 14 | name: Commit Build 15 | permissions: write-all 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Install pnpm 21 | uses: pnpm/action-setup@v4 22 | with: 23 | version: 9 24 | run_install: false 25 | 26 | - name: Install Node.js 27 | uses: actions/setup-node@v4 28 | with: 29 | node-version: 20 30 | cache: "pnpm" 31 | 32 | - name: Install dependencies 33 | run: pnpm install 34 | 35 | - uses: actions/cache@v4 36 | with: 37 | path: | 38 | ~/.cargo/bin/ 39 | ~/.cargo/registry/index/ 40 | ~/.cargo/registry/cache/ 41 | ~/.cargo/git/db/ 42 | target/ 43 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 44 | 45 | - name: Build 46 | run: pnpm build 47 | 48 | # - name: Orgnize file (Windows) 49 | # if: runner.os == 'Windows' 50 | # run: Compress-Archive -Path "./target/release/*.exe" -DestinationPath "TinyTileProxy-${{ github.ref_name }}-x86_64-pc-windows-msvc.zip" 51 | 52 | # - name: Upload a Build Artifact 53 | # uses: actions/upload-artifact@v4 54 | # with: 55 | # name: TinyTileProxy-${{ github.ref_name }} 56 | # path: TinyTileProxy-${{ github.ref_name }}-x86_64-pc-windows-msvc.zip 57 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/routers/config.rs: -------------------------------------------------------------------------------- 1 | use crate::libs::config::{get_config, save_tokens, Config, StateConfig, Tokens}; 2 | use rocket::serde::json::Json; 3 | use rocket::State; 4 | 5 | #[derive(FromForm)] 6 | pub(crate) struct PASS { 7 | pwd: String, 8 | } 9 | 10 | pub fn get_pwd() -> Result { 11 | let config: Config = get_config().extract()?; 12 | let pwd = config.default.password; 13 | Ok(pwd) 14 | } 15 | 16 | #[get("/config/auth?")] 17 | pub fn auth(q: PASS) -> String { 18 | let local_pwd = get_pwd().unwrap(); 19 | if q.pwd == local_pwd { 20 | "Ok".to_string() 21 | } else { 22 | "Error".to_string() 23 | } 24 | } 25 | 26 | #[get("/config/tokens?")] 27 | pub fn show_tokens(config: &State, query: PASS) -> Json { 28 | let local_pwd = get_pwd().unwrap(); 29 | if query.pwd == local_pwd { 30 | Json(config.tokens.read().unwrap().clone()) 31 | } else { 32 | Json(Tokens { 33 | geocloud: "".to_string(), 34 | jl1: "".to_string(), 35 | jl1earth: "".to_string(), 36 | }) 37 | } 38 | } 39 | 40 | #[post("/config/set_tokens?", data = "")] 41 | pub fn set_tokens(tokens: Json, config: &State, query: PASS) -> String { 42 | let local_pwd = get_pwd().unwrap(); 43 | if query.pwd == local_pwd { 44 | let token = tokens.into_inner(); 45 | // 修改 State 46 | *config.tokens.write().unwrap() = token.clone(); 47 | // 保存 Token 48 | save_tokens(&token).unwrap(); 49 | "ok".to_string() 50 | } else { 51 | "Error".to_string() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/proxys.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Proxys 3 | --- 4 | 5 | 9 | 10 | # Proxys 11 | 12 | ## 吉林一号 13 | 14 | ::: danger ⚠️ 注意 15 | ‼️ 请先在`config.toml`中填写自己的 token 16 | 访问 [吉林 1 号官网](https://www.jl1mall.com/rskit/MyRSservice) 获取 TK 17 | ::: 18 | 19 | Arcmap / Arcgis Pro 可通过 WMTS 服务加载 20 | 21 | WMTS服务地址: 22 | 23 | 24 | XYZ 服务地址: 25 | 26 | 27 | > 2023 年度全国高质量一张图 mk: `73ad26c4aa6957eef051ecc5a15308b4` 28 | 29 | > 视频教程: 30 | 31 | 32 | ## 地质云 33 | 34 | 可通过 WMTS 服务加载 35 | 36 | WMTS服务地址: 37 | 38 | 39 | 目前代理的地图有 40 | 41 | - 基础地质图: 全国 1/250 万地质图 42 | - 基础地质图: 全国 1/150 万地质图 43 | - 基础地质图: 全国 1/100 万地质图 44 | - 基础地质图: 全国 1/50 万地质图 45 | - 基础地质图: 全国 1/20 万地质图 46 | - 水文地质: 中国地下水资源图 47 | - 水文地质: 中国水文地质图 48 | 49 | ::: danger ⚠️ 注意 50 | 地质云需要 token,请自行从官网获取 51 | 公共 token 有时效性, 每几天需要更换新 token 52 | 请在`config.toml`中填写 token 53 | ::: 54 | 55 | > 视频演示: 56 | 57 | 58 | ## 常用 XYZ 服务转 WMTS 59 | 60 | > 直连无代理 61 | 62 | 支持以下地图: 63 | 64 | - Open Street Map 65 | - Google Map 66 | 67 | 可通过 WMTS 链接加载 68 | 69 | 70 | ::: info 71 | 🤔 适合在 Arcmap 中使用 72 | ::: 73 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/routers/jilin1.rs: -------------------------------------------------------------------------------- 1 | use rocket::http::ContentType; 2 | use rocket::State; 3 | use rocket::{http::Status, response::status}; 4 | 5 | use crate::libs::config::StateConfig; 6 | use crate::libs::jilin1::{get_earthtile_from_cache, get_tile_from_cache}; 7 | 8 | #[derive(FromForm)] 9 | pub(crate) struct JiLin1Query { 10 | mk: String, 11 | } 12 | 13 | #[get("/getTile/jl1///?")] 14 | pub async fn get_jl1( 15 | z: u32, 16 | x: u32, 17 | y: u32, 18 | query: JiLin1Query, 19 | config: &State, 20 | ) -> Result<(ContentType, Vec), status::Custom> { 21 | let tokens = config.tokens.read().unwrap().clone(); 22 | let tk = tokens.jl1; 23 | if tk.is_empty() { 24 | return Err(status::Custom( 25 | Status::InternalServerError, 26 | "Error: jilin1 tk not set".to_string(), 27 | )); 28 | } 29 | match get_tile_from_cache(z, x, y, query.mk, tk.to_string()).await { 30 | Ok(body) => Ok((ContentType::PNG, body)), 31 | Err(e) => Err(status::Custom( 32 | Status::InternalServerError, 33 | format!("Error is: {}", e), 34 | )), 35 | } 36 | } 37 | 38 | #[get("/getTile/jl1earth///")] 39 | pub async fn get_jl1earth( 40 | z: u32, 41 | x: u32, 42 | y: u32, 43 | config: &State, 44 | ) -> Result<(ContentType, Vec), status::Custom> { 45 | let tokens = config.tokens.read().unwrap().clone(); 46 | let tk = tokens.jl1earth; 47 | match get_earthtile_from_cache(z, x, y, tk.to_string()).await { 48 | Ok(body) => Ok((ContentType::PNG, body)), 49 | Err(e) => Err(status::Custom( 50 | Status::InternalServerError, 51 | format!("Error: {}", e), 52 | )), 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docs/proxys.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Proxys 3 | --- 4 | 5 | 9 | 10 | # Proxys 11 | 12 | ## 吉林一号 13 | 14 | ::: danger ⚠️ 注意 15 | ‼️ 请先在请在 `Setting` 页面或`config.toml`中填写自己的 token 16 | 访问 [吉林 1 号官网](https://www.jl1mall.com/rskit/MyRSservice) 获取 TK 17 | ::: 18 | 19 | Arcmap / Arcgis Pro 可通过 WMTS 服务加载 20 | 21 | WMTS服务地址: 22 | 23 | 24 | XYZ 服务地址: 25 | 26 | 27 | > 2023 年度全国高质量一张图 mk: `73ad26c4aa6957eef051ecc5a15308b4` 28 | 29 | > 视频教程: 30 | 31 | 32 | ## 地质云 33 | 34 | 可通过 WMTS 服务加载 35 | 36 | WMTS服务地址: 37 | 38 | 39 | 目前代理的地图有 40 | 41 | - 基础地质图: 全国 1/250 万地质图 42 | - 基础地质图: 全国 1/150 万地质图 43 | - 基础地质图: 全国 1/100 万地质图 44 | - 基础地质图: 全国 1/50 万地质图 45 | - 基础地质图: 全国 1/20 万地质图 46 | 47 | ::: danger ⚠️ 注意 48 | 地质云需要 token,请自行从[官网](https://igss.cgs.gov.cn/admin/token/index.jsp)获取 49 | 公共 token 有时效性, 每几天需要更换新 token 50 | 请在 `Setting` 页面或者`config.toml`中填写 token 51 | ::: 52 | 53 | > 视频演示: 54 | 55 | 56 | ## 常用 XYZ 服务转 WMTS 57 | 58 | > 直连无代理 59 | 60 | 支持以下地图: 61 | 62 | - Open Street Map 63 | - Google Map 64 | 65 | 可通过 WMTS 链接加载 66 | 67 | 68 | ::: info 69 | 🤔 适合在 Arcmap 中使用 70 | ::: 71 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate rocket; 3 | use figment::{ 4 | providers::{Env, Format, Toml}, 5 | Figment, 6 | }; 7 | use std::sync::{Arc, RwLock}; 8 | 9 | mod libs; 10 | mod routers; 11 | 12 | use libs::config::{ 13 | create_default_config_file, get_jl1_mk_from_local_config, get_tk_from_local_config, 14 | ServerConfig, StateConfig, 15 | }; 16 | use libs::utils::create_cache_dir; 17 | use routers::config::{auth, set_tokens, show_tokens}; 18 | use routers::docs::{docs, static_file}; 19 | use routers::geocloud::get_geocloud; 20 | use routers::index::{favicon, index}; 21 | use routers::jilin1::{get_jl1, get_jl1earth}; 22 | use routers::wmts; 23 | 24 | #[launch] 25 | fn rocket() -> _ { 26 | println!("Tiny Tile Proxy\t v{}\n", env!("CARGO_PKG_VERSION")); 27 | create_default_config_file(); 28 | create_cache_dir(); 29 | 30 | let figment = Figment::from(rocket::Config::default()) 31 | .merge(Toml::file("config.toml").nested()) 32 | .merge(Env::prefixed("ROCKET_").global()); 33 | 34 | // 获取 tk 值 35 | let tk = get_tk_from_local_config().unwrap(); 36 | let jl1_mk = get_jl1_mk_from_local_config().unwrap(); 37 | 38 | let config: ServerConfig = figment.clone().extract().expect("Failed to extract config"); 39 | 40 | let mut routers = routes![ 41 | index, 42 | get_geocloud, 43 | get_jl1, 44 | get_jl1earth, 45 | docs, 46 | static_file, 47 | favicon, 48 | show_tokens, 49 | set_tokens, 50 | auth 51 | ]; 52 | routers.extend(wmts::routers()); 53 | 54 | rocket::custom(figment) 55 | .manage(StateConfig { 56 | tokens: Arc::new(RwLock::new(tk)), 57 | use_https: Arc::new(RwLock::new(config.use_https)), 58 | jl1_mk: Arc::new(RwLock::new(jl1_mk)), 59 | }) 60 | .mount("/", routers) 61 | } 62 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/routers/geocloud.rs: -------------------------------------------------------------------------------- 1 | use rocket::http::ContentType; 2 | use rocket::State; 3 | use rocket::{http::Status, response::status}; 4 | use std::collections::HashMap; 5 | 6 | use crate::libs::config::StateConfig; 7 | use crate::libs::geocloud::get_geocloud_tile_cache; 8 | use crate::libs::utils::ZXY; 9 | 10 | use filetype::is_png; 11 | 12 | #[derive(FromForm)] 13 | pub(crate) struct GeoCloudQuery { 14 | layer: String, 15 | tilematrixset: Option, 16 | } 17 | 18 | #[get("/getTile/geocloud///?")] 19 | pub async fn get_geocloud( 20 | z: &str, 21 | x: u32, 22 | y: u32, 23 | query: GeoCloudQuery, 24 | config: &State, 25 | ) -> Result<(ContentType, Vec), status::Custom> { 26 | let zxy = ZXY { 27 | z: z.to_string(), 28 | x, 29 | y, 30 | }; 31 | let tokens = config.tokens.read().unwrap().clone(); 32 | match get_geocloud_tile_cache(zxy, query.layer, tokens.geocloud, query.tilematrixset).await { 33 | Ok(body) => { 34 | if is_png(&body) { 35 | Ok((ContentType::PNG, body)) 36 | } else { 37 | Err(status::Custom( 38 | Status::NotFound, 39 | format!("{}", String::from_utf8_lossy(&body)), 40 | )) 41 | } 42 | } 43 | Err(e) => Err(status::Custom( 44 | Status::InternalServerError, 45 | format!("Error is: {}", e), 46 | )), 47 | } 48 | } 49 | 50 | #[get("/geocloud/wms?")] 51 | pub async fn _geocloud_wms( 52 | params: HashMap, 53 | ) -> Result<(ContentType, Vec), status::Custom> { 54 | let base_url = 55 | "https://igss.cgs.gov.cn:6160/igs/rest/ogc/doc/H50E022002_20201014_QusseidO/WMSServer"; 56 | let client = reqwest::Client::builder().build().unwrap(); 57 | // 发送 GET 请求 58 | let response = client.get(base_url).query(¶ms).send().await.unwrap(); 59 | // println!("{} ", response.url().as_str()); 60 | let body = response.bytes().await.unwrap(); 61 | // println!("{:?}", body); 62 | Ok((ContentType::PNG, body.to_vec())) 63 | // format!("{:?}", params) 64 | } 65 | -------------------------------------------------------------------------------- /docs/SetToken.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 69 | 70 | 108 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/docs/SetToken.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 69 | 70 | 108 | -------------------------------------------------------------------------------- /crates/capgen/src/templates/base.jinja: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | {{ service.title | default("Untitled WMTS Service") }} 11 | {{ service.abstract_ }} 12 | OGC WMTS 13 | 1.0.0 14 | 15 | {% for keyword in service.keywords %} 16 | {{ keyword }} 17 | {% endfor %} 18 | 19 | none 20 | none 21 | 22 | 23 | {% for layer in layers %} 24 | 25 | {{ layer.title }} 26 | {{ layer.abstract_ }} 27 | 28 | -180.0 -85.051129 29 | 180.0 85.051129 30 | 31 | {{ layer.id }} 32 | 35 | image/png 36 | 37 | {{ layer.tile_matrix_set }} 38 | 39 | 40 | 41 | {% endfor %} 42 | 43 | {{ tile_matrix_set.title }} 44 | {{ tile_matrix_set.identifier }} 45 | {{ tile_matrix_set.supported_crs }} 46 | {{ tile_matrix_set.well_known_scale_set }} 47 | {% for tile_matrix in tile_matrix_set.tile_matrixs %} 48 | 49 | {{ tile_matrix.identifier }} 50 | {{ tile_matrix.scale_denominator }} 51 | -20037508.3427892 20037508.3427892 52 | {{ tile_matrix.tile_width }} 53 | {{ tile_matrix.tile_height }} 54 | {{ tile_matrix.matrix_width }} 55 | {{ tile_matrix.matrix_height }} 56 | 57 | {% endfor %} 58 | 59 | 60 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/libs/config.rs: -------------------------------------------------------------------------------- 1 | use figment::{ 2 | providers::{Format, Toml}, 3 | Figment, 4 | }; 5 | 6 | use serde::{Deserialize, Serialize}; 7 | use std::{ 8 | collections::HashMap, 9 | sync::{Arc, RwLock}, 10 | }; 11 | use std::{fs, path::Path}; 12 | use toml::to_string; 13 | 14 | #[derive(Deserialize, Serialize, Debug)] 15 | pub struct ServerConfig { 16 | pub address: String, 17 | pub port: u32, 18 | pub use_https: bool, 19 | pub password: String, 20 | } 21 | 22 | impl Default for ServerConfig { 23 | fn default() -> Self { 24 | ServerConfig { 25 | address: String::from("127.0.0.1"), 26 | port: 8000, 27 | use_https: false, 28 | password: String::from("ttp123456"), 29 | } 30 | } 31 | } 32 | 33 | #[derive(Deserialize, Serialize, Debug, Clone, Default)] 34 | pub struct Tokens { 35 | pub geocloud: String, 36 | pub jl1: String, 37 | pub jl1earth: String, 38 | } 39 | 40 | #[derive(Deserialize, Serialize, Debug)] 41 | pub struct Config { 42 | pub default: ServerConfig, 43 | pub tokens: Tokens, 44 | pub jl1_mk: HashMap, 45 | } 46 | 47 | impl Default for Config { 48 | fn default() -> Self { 49 | let mut mks = HashMap::new(); 50 | mks.insert( 51 | "73ad26c4aa6957eef051ecc5a15308b4".to_string(), 52 | "2023年度全国高质量一张图".to_string(), 53 | ); 54 | Config { 55 | default: ServerConfig::default(), 56 | tokens: Tokens::default(), 57 | jl1_mk: mks, 58 | } 59 | } 60 | } 61 | 62 | #[derive(Clone)] 63 | pub struct StateConfig { 64 | pub tokens: Arc>, 65 | pub use_https: Arc>, 66 | pub jl1_mk: Arc>>, 67 | } 68 | 69 | pub fn get_config() -> Figment { 70 | Figment::new().merge(Toml::file("config.toml")) 71 | } 72 | 73 | /// 创建默认配置文件 74 | pub fn create_default_config_file() { 75 | let config_path = "config.toml"; 76 | // 检查文件是否存在 77 | if !Path::new(config_path).exists() { 78 | println!("create default config file [config.toml]"); 79 | let config = Config::default(); 80 | let toml_str = to_string(&config).expect("Failed to serialize config"); 81 | fs::write(config_path, toml_str).expect("Failed to write config file"); 82 | } 83 | } 84 | 85 | /// 从配置文件中获取 Tokens 86 | pub fn get_tk_from_local_config() -> Result { 87 | let config: Config = get_config().extract()?; 88 | let tk = config.tokens; 89 | 90 | Ok(tk) 91 | } 92 | 93 | pub fn get_jl1_mk_from_local_config() -> Result, figment::Error> { 94 | let config: Config = get_config().extract()?; 95 | let jl1_mk = config.jl1_mk; 96 | 97 | Ok(jl1_mk) 98 | } 99 | 100 | /// 保存 Tokens 至配置文件 101 | pub fn save_tokens(tk: &Tokens) -> Result { 102 | let mut config: Config = get_config().extract()?; 103 | config.tokens = tk.clone(); 104 | let config_path = "config.toml"; 105 | let toml_str = to_string(&config).expect("Failed to serialize config"); 106 | fs::write(config_path, toml_str).expect("Failed to write config file"); 107 | Ok(tk.clone()) 108 | } 109 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/routers/wmts.rs: -------------------------------------------------------------------------------- 1 | use minijinja::{context, Environment}; 2 | use rocket::http::Status; 3 | use rocket::request::{self, FromRequest, Outcome, Request}; 4 | use rocket::response::content::RawXml; 5 | use rocket::State; 6 | 7 | use rust_embed::Embed; 8 | 9 | use crate::libs::config::StateConfig; 10 | use capgen::{generate_capabilities, get_web_mercator_quad_matrixs, Layer, ServiceMetadata}; 11 | 12 | #[derive(Embed)] 13 | #[folder = "assets"] 14 | struct Asset; 15 | 16 | #[derive(Debug)] 17 | pub struct HostFromHeader(String, String); 18 | 19 | #[rocket::async_trait] 20 | impl<'r> FromRequest<'r> for HostFromHeader { 21 | type Error = (); 22 | 23 | async fn from_request(request: &'r Request<'_>) -> request::Outcome { 24 | if let Some(host) = request.headers().get_one("Host") { 25 | // 尝试获取协议 26 | // 使用 Caddy 反向代理, 并启用 https, 默认会添加 X-Forwarded-Proto 27 | let protocol = request 28 | .headers() 29 | .get_one("X-Forwarded-Proto") 30 | .unwrap_or("http"); 31 | Outcome::Success(HostFromHeader(protocol.to_string(), host.to_string())) 32 | } else { 33 | Outcome::Error((Status::BadRequest, ())) 34 | } 35 | } 36 | } 37 | 38 | #[get("/WMTS/geocloud")] 39 | pub fn get_geocloud_wmts(host: HostFromHeader, config: &State) -> RawXml { 40 | let use_https = *config.use_https.read().unwrap(); 41 | let proto = if use_https { "https" } else { &host.0 }; 42 | let address = format!("{}://{}", proto, host.1); 43 | 44 | let wmts_xml = Asset::get("templates/geocloud.xml").unwrap(); 45 | let file_content = String::from_utf8(wmts_xml.data.to_vec()).expect("filed to read"); 46 | let mut env = Environment::new(); 47 | env.add_template("geocloud.xml", &file_content).unwrap(); 48 | let template = env.get_template("geocloud.xml").unwrap(); 49 | let rendered = template.render(context! {base_url=> &address}).unwrap(); 50 | RawXml(rendered) 51 | } 52 | 53 | #[get("/WMTS/jl1")] 54 | pub fn get_jl1_wmts(host: HostFromHeader, config: &State) -> RawXml { 55 | let use_https = *config.use_https.read().unwrap(); 56 | let mks = config.jl1_mk.read().unwrap(); 57 | let proto = if use_https { "https" } else { &host.0 }; 58 | let address = format!("{}://{}", proto, host.1); 59 | 60 | let service = ServiceMetadata { 61 | title: "Tiny Tile Proxy".to_string(), 62 | abstract_: "吉林一号卫星影像2".to_string(), 63 | keywords: vec!["吉林一号".to_string()], 64 | }; 65 | 66 | let layers = mks 67 | .iter() 68 | .map(|(k, v)| Layer { 69 | title: v.to_string(), 70 | abstract_: v.to_string(), 71 | id: k.to_string(), 72 | tile_matrix_set: "WebMercatorQuad".to_string(), 73 | url: format!( 74 | "{}/getTile/jl1/{{TileMatrix}}/{{TileCol}}/{{TileRow}}?mk={}", 75 | address, k 76 | ), 77 | }) 78 | .collect(); 79 | 80 | let tile_matrix_set = get_web_mercator_quad_matrixs(0, 18); 81 | 82 | let cap = generate_capabilities(&service, &layers, &tile_matrix_set).unwrap(); 83 | 84 | RawXml(cap) 85 | } 86 | 87 | #[get("/WMTS/XYZ")] 88 | pub fn get_xyz_wmts() -> RawXml { 89 | let wmts_xml = Asset::get("wmts/xyz.xml").unwrap(); 90 | let file_content = String::from_utf8(wmts_xml.data.to_vec()).expect("filed to read"); 91 | RawXml(file_content) 92 | } 93 | 94 | pub fn routers() -> Vec { 95 | routes![get_geocloud_wmts, get_jl1_wmts, get_xyz_wmts,] 96 | } 97 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/libs/jilin1.rs: -------------------------------------------------------------------------------- 1 | use super::config::get_jl1_mk_from_local_config; 2 | use super::utils::{get_cache_dir, read_file, save_png}; 3 | use std::collections::HashMap; 4 | use std::sync::OnceLock; 5 | 6 | use anyhow::{anyhow, Result as AnyhowResult}; 7 | use std::fs::create_dir_all; 8 | use webp_to_png::webp_to_png; 9 | 10 | use filetype::is_webp; 11 | use jilin1::get_tile; 12 | 13 | static JL1_MKS: OnceLock> = OnceLock::new(); 14 | 15 | pub async fn get_tile_from_cache( 16 | z: u32, 17 | x: u32, 18 | y: u32, 19 | mk: String, 20 | tk: String, 21 | ) -> AnyhowResult> { 22 | let map_names = JL1_MKS.get_or_init(|| get_jl1_mk_from_local_config().unwrap()); 23 | let cache_dir = get_cache_dir(); 24 | let map_dir = cache_dir.join(format!("吉林1号/{}", map_names.get(&mk).unwrap_or(&mk))); 25 | let tile_dir = map_dir.join(format!("{}/{}/", z, x)); 26 | let tile_path = tile_dir.join(format!("{}.png", y)); 27 | if tile_path.exists() { 28 | let png_data = read_file(&tile_path)?; 29 | Ok(png_data) 30 | } else { 31 | create_dir_all(&tile_dir).expect("Filed to create Tile Dir"); 32 | match get_tile(z, x, y, mk, tk).await { 33 | Ok(body) => { 34 | // 缓存瓦片,将 webp 转为 png 保存 35 | // 存在一些瓦片实际上是 png 格式的(透明),这里做一下检查 36 | if is_webp(&body) { 37 | let png_data = webp_to_png(body).unwrap(); 38 | save_png(tile_path, &png_data)?; 39 | Ok(png_data) 40 | } else { 41 | save_png(tile_path, &body)?; 42 | Ok(body) 43 | } 44 | } 45 | Err(e) => Err(e), 46 | } 47 | } 48 | } 49 | 50 | pub async fn get_jlearth_tile(z: u32, x: u32, y: u32, tk: String) -> AnyhowResult> { 51 | const AGENT:&str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"; 52 | let url = format!( 53 | "https://tile.charmingglobe.com/tile/china2023_5_shield/wmts/{}/{}/{}?v=v1&token={}", 54 | z, x, y, tk 55 | ); 56 | // 获取瓦片内容 57 | let client = reqwest::Client::builder() 58 | .user_agent(AGENT) 59 | .gzip(true) 60 | .build()?; 61 | // 发送 GET 请求 62 | let response = client.get(url).send().await?; 63 | let content_type = response 64 | .headers() 65 | .get("Content-Type") 66 | .ok_or(anyhow!("Missing Content-Type header"))?; 67 | 68 | if content_type == "image/webp" { 69 | let body = response.bytes().await?; 70 | Ok(body.to_vec()) 71 | } else { 72 | Err(anyhow!( 73 | "Expected Content-Type 'image/webp', but got {:?}", 74 | content_type 75 | )) 76 | } 77 | } 78 | 79 | pub async fn get_earthtile_from_cache(z: u32, x: u32, y: u32, tk: String) -> AnyhowResult> { 80 | let cache_dir = get_cache_dir(); 81 | let map_dir = cache_dir.join("吉林1号/2023年度全国高质量一张图 - 共生地球"); 82 | let tile_dir = map_dir.join(format!("{}/{}/", z, x)); 83 | let tile_path = tile_dir.join(format!("{}.png", y)); 84 | if tile_path.exists() { 85 | let png_data = read_file(&tile_path)?; 86 | Ok(png_data) 87 | } else { 88 | create_dir_all(&tile_dir).expect("Filed to create Tile Dir"); 89 | match get_jlearth_tile(z, x, y, tk).await { 90 | Ok(body) => { 91 | // 缓存瓦片,将 webp 转为 png 保存 92 | // 存在一些瓦片实际上是 png 格式的(透明),这里做一下检查 93 | if is_webp(&body) { 94 | let png_data = webp_to_png(body).unwrap(); 95 | save_png(tile_path, &png_data)?; 96 | Ok(png_data) 97 | } else { 98 | save_png(tile_path, &body)?; 99 | Ok(body) 100 | } 101 | } 102 | Err(e) => Err(e), 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/src/libs/geocloud.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result as AnyhowResult; 2 | use reqwest::Error; 3 | use std::collections::HashMap; 4 | use std::fs::create_dir_all; 5 | 6 | use super::utils::{get_cache_dir, read_file, save_png, ZXY}; 7 | 8 | fn get_z_value(zxy: &ZXY) -> String { 9 | let z = &zxy.z; 10 | if z.as_str().len() <= 2 { 11 | z.to_string() 12 | } else { 13 | let z_slice: &str = z; 14 | let parts: Vec<&str> = z_slice.split(':').collect(); 15 | parts.last().unwrap().to_string() 16 | } 17 | } 18 | 19 | fn create_parms( 20 | zxy: ZXY, 21 | layer: String, 22 | tk: String, 23 | tilematrixset: Option, 24 | ) -> HashMap<&'static str, String> { 25 | let mut params = HashMap::new(); 26 | params.insert("tk", tk); 27 | params.insert("Width", "256".to_string()); 28 | params.insert("Height", "256".to_string()); 29 | params.insert("layer", layer); 30 | // params.insert("style", "default".to_string()); 31 | // tilematrixset EPSG%:4326_{layer}_028mm_GB / EPSG:4326 32 | if let Some(tms) = tilematrixset { 33 | params.insert("tilematrixset", tms); 34 | } 35 | 36 | params.insert("Service", "WMTS".to_string()); 37 | params.insert("Request", "GetTile".to_string()); 38 | params.insert("Version", "1.0.0".to_string()); 39 | params.insert("Format", "image%2Fpng".to_string()); 40 | params.insert("TileMatrix", zxy.z); 41 | params.insert("TileCol", zxy.x.to_string()); 42 | params.insert("TileRow", zxy.y.to_string()); 43 | 44 | params 45 | } 46 | 47 | pub async fn get_geocloud_tile( 48 | zxy: ZXY, 49 | layer: String, 50 | tk: String, 51 | tilematrixset: Option, 52 | ) -> Result, Error> { 53 | let url = format!( 54 | "https://igss.cgs.gov.cn:6160/igs/rest/ogc/{}/WMTSServer", 55 | layer 56 | ); 57 | 58 | let params = create_parms(zxy, layer, tk, tilematrixset); 59 | 60 | let client = reqwest::Client::builder().build()?; 61 | // 发送 GET 请求 62 | let response = client.get(url).query(¶ms).send().await?; 63 | // println!("{} ", response.url().as_str()); 64 | let body = response.bytes().await?; 65 | // println!("{:?}", body); 66 | Ok(body.to_vec()) 67 | } 68 | 69 | pub async fn get_geocloud_tile_cache( 70 | zxy: ZXY, 71 | layer: String, 72 | tk: String, 73 | tilematrixset: Option, 74 | ) -> AnyhowResult> { 75 | let map_names = get_map_names(); 76 | let cache_dir = get_cache_dir(); 77 | let map_dir = cache_dir.join(format!( 78 | "Geocloud/{}", 79 | map_names.get(layer.as_str()).unwrap_or(&layer.as_str()) 80 | )); 81 | let tile_dir = map_dir.join(format!("{}/{}/", get_z_value(&zxy), zxy.x)); 82 | let tile_path = tile_dir.join(format!("{}.png", zxy.y)); 83 | if tile_path.exists() { 84 | let png_data = read_file(&tile_path)?; 85 | Ok(png_data) 86 | } else { 87 | create_dir_all(&tile_dir).expect("Filed to create Tile Dir"); 88 | match get_geocloud_tile(zxy, layer, tk, tilematrixset).await { 89 | Ok(body) => { 90 | save_png(tile_path, &body)?; 91 | Ok(body) 92 | } 93 | Err(e) => Err(e.into()), 94 | } 95 | } 96 | } 97 | 98 | pub fn get_map_names() -> HashMap<&'static str, &'static str> { 99 | // 地质云 服务接口 https://igss.cgs.gov.cn/admin/token/index.jsp 100 | // 授权范围内一共 10 个服务 101 | // 其中有 2 个为重复(使用 web 墨卡托投影) 102 | let mut map_names = HashMap::new(); 103 | map_names.insert("qg20_20210401_FCnDDRJd", "全国1比20万地质图空间数据库"); 104 | map_names.insert("qg50w_20210416_F7qGy9A7", "全国1比50万地质图数据"); 105 | map_names.insert( 106 | "全国100万地质图_20210330_rpam5kdJ", 107 | "全国1比100万地质图空间数据", 108 | ); 109 | map_names.insert("qg150w_20210416_BIwqE0wU", "全国1比150万地质图数据"); 110 | map_names.insert("qg250w_20210416_ZAZSeOGX", "全国1比250万地质图数据"); 111 | map_names.insert( 112 | "gisdatamanageCZL:zgdzhjfqt2015556_20220902_jFEtRvYd", 113 | "中国地质环境分区图", 114 | ); 115 | map_names.insert( 116 | "gisdatamanageCZL:hhhpytrxhjt24172036_20220905_bAcMBmmq", 117 | "黄淮海平原土壤硒环境图", 118 | ); 119 | map_names.insert( 120 | "gisdatamanageCZL:0715zgdzhjaqcdt17155125_20220905_ejCKPwC4", 121 | "中国地质环境安全程度图", 122 | ); 123 | // 这两个不是授权范围内的 124 | // map_names.insert( 125 | // "gisdatamanageCZL:500wdxszyt2616300_20220905_BhR4tgbF", 126 | // "中国地下水资源图", 127 | // ); 128 | // map_names.insert( 129 | // "gisdatamanageCZL:zgswdzt16175436_20220905_BbcQipWD", 130 | // "中国水文地质图", 131 | // ); 132 | 133 | map_names 134 | } 135 | -------------------------------------------------------------------------------- /crates/capgen/src/lib.rs: -------------------------------------------------------------------------------- 1 | use minijinja::{context, Environment}; 2 | use serde::Serialize; 3 | 4 | #[derive(Serialize)] 5 | pub struct ServiceMetadata { 6 | pub title: String, 7 | pub abstract_: String, 8 | pub keywords: Vec, 9 | } 10 | 11 | #[derive(Serialize)] 12 | pub struct Layer { 13 | pub title: String, 14 | pub abstract_: String, 15 | pub id: String, 16 | pub tile_matrix_set: String, 17 | pub url: String, 18 | } 19 | 20 | pub type Layers = Vec; 21 | 22 | #[derive(Debug, Clone, Serialize)] 23 | pub struct TileMatrix { 24 | pub identifier: String, 25 | pub scale_denominator: f64, 26 | pub top_left_corner: (f64, f64), 27 | pub tile_width: u32, 28 | pub tile_height: u32, 29 | pub matrix_width: u32, 30 | pub matrix_height: u32, 31 | } 32 | 33 | #[derive(Debug, Serialize)] 34 | pub struct TileMatrixSet { 35 | pub title: String, 36 | pub identifier: String, 37 | pub supported_crs: String, 38 | pub well_known_scale_set: String, 39 | pub tile_matrixs: Vec, 40 | } 41 | 42 | /// 生成瓦片矩阵集 43 | /// ## 参数 44 | /// - `min_zoom` - 起始级别 45 | /// - `max_zoom` - 最大级别 46 | /// ## Returns 47 | /// 返回 TileMatrix 集合 48 | pub fn generate_tile_matrix_set(min_zoom: u32, max_zoom: u32) -> Vec { 49 | (min_zoom..=max_zoom) 50 | .map(|zoom| { 51 | let base_scale = 559_082_264.02871774; 52 | let scale = base_scale / 2f64.powi(zoom as i32); 53 | let matrix_size = 2u32.pow(zoom); 54 | 55 | TileMatrix { 56 | identifier: zoom.to_string(), 57 | scale_denominator: scale, 58 | top_left_corner: (-20037508.3427892, 20037508.3427892), 59 | tile_width: 256, 60 | tile_height: 256, 61 | matrix_width: matrix_size, 62 | matrix_height: matrix_size, 63 | } 64 | }) 65 | .collect() 66 | } 67 | 68 | /// 生成 WebMercatorQuad 瓦片矩阵集 69 | /// ## 参数 70 | /// - `min_zoom` - 起始级别 71 | /// - `max_zoom` - 最大级别 72 | /// ### 参考 73 | /// https://docs.ogc.org/is/17-083r4/17-083r4.html#toc49 74 | /// https://docs.ogc.org/is/17-083r2/17-083r2.html#72 75 | pub fn get_web_mercator_quad_matrixs(min_zoom: u32, max_zoom: u32) -> TileMatrixSet { 76 | TileMatrixSet { 77 | title: "Google Maps Compatible for the World".to_string(), 78 | identifier: "WebMercatorQuad".to_string(), 79 | supported_crs: "urn:ogc:def:crs:EPSG:6.18.3:3857".to_string(), 80 | well_known_scale_set: "urn:ogc:def:wkss:OGC:1.0:GoogleMapsCompatible".to_string(), 81 | tile_matrixs: generate_tile_matrix_set(min_zoom, max_zoom), 82 | } 83 | } 84 | 85 | /// 生成能力文档 86 | /// ## 参数 87 | /// - `service` - 服务元数据 88 | /// - `layers` - 图层集合 89 | /// - `tile_matrix_set` - 瓦片矩阵集 90 | /// ## Returns 91 | /// 返回能力文档字符串 92 | pub fn generate_capabilities( 93 | service: &ServiceMetadata, 94 | layers: &Layers, 95 | tile_matrix_set: &TileMatrixSet, 96 | ) -> Result { 97 | let mut env = Environment::new(); 98 | env.set_trim_blocks(true); // 自动删除块后的换行符 99 | env.set_lstrip_blocks(true); // 自动删除块前的空格 100 | 101 | env.add_template("base", include_str!("templates/base.jinja"))?; 102 | let template = env.get_template("base")?; 103 | let rendered = template.render(context! { 104 | service => service, 105 | layers => layers, 106 | tile_matrix_set => tile_matrix_set, 107 | })?; 108 | Ok(rendered) 109 | } 110 | 111 | #[cfg(test)] 112 | mod tests { 113 | use super::*; 114 | 115 | #[test] 116 | fn test_service_metadata_rendering() { 117 | // 创建测试用的 ServiceMetadata 118 | let service = ServiceMetadata { 119 | title: "Test Service".to_string(), 120 | abstract_: "This is a test WMTS service".to_string(), 121 | keywords: vec!["test".to_string(), "wmts".to_string()], 122 | }; 123 | 124 | let layer = Layer { 125 | title: "吉林一号".to_string(), 126 | abstract_: "This is a test WMTS layer".to_string(), 127 | id: "test".to_string(), 128 | tile_matrix_set: "WebMercatorQuad".to_string(), 129 | url: "http://localhost:8000".to_string(), 130 | }; 131 | 132 | let layers = vec![layer]; 133 | 134 | let tile_matrix_set = get_web_mercator_quad_matrixs(0, 18); 135 | 136 | // 生成 XML 能力文档 137 | let rendered = generate_capabilities(&service, &layers, &tile_matrix_set).unwrap(); 138 | println!("{}", rendered); 139 | // 验证关键字段是否正确渲染 140 | assert!(rendered.contains("Test Service")); 141 | assert!(rendered.contains("This is a test WMTS service")); 142 | assert!(rendered.contains("test")); 143 | assert!(rendered.contains("wmts")); 144 | } 145 | 146 | #[test] 147 | fn test_matrix() { 148 | let matrix = get_web_mercator_quad_matrixs(0, 18); 149 | println!("{:?}", matrix); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/assets/wmts/xyz.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | XYZ to WMTS 9 | 常用XYZ瓦片服务➡️WMTS 10 | OGC WMTS 11 | 1.0.0 12 | none 13 | none 14 | 15 | 16 | 17 | Open Street Map 18 | Open Street Map 19 | 20 | -180.0 -90 21 | 180.0 90 22 | 23 | osm 24 | 27 | image/png 28 | 29 | GLOBAL_WEBMERCATOR 30 | 31 | 32 | 33 | 34 | Google Map - Satellite 35 | Google Map - Satellite 36 | 37 | -180.0 -90 38 | 180.0 90 39 | 40 | Google Map - Satellite 41 | 44 | image/png 45 | 46 | GLOBAL_WEBMERCATOR 47 | 48 | 49 | 50 | 51 | Google Maps Compatible for the World 52 | GLOBAL_WEBMERCATOR 53 | urn:ogc:def:crs:EPSG:6.18.3:3857 54 | urn:ogc:def:wkss:OGC:1.0:GoogleMapsCompatible 55 | 56 | 0 57 | 559082264.0287178 58 | -20037508.3427892 20037508.3427892 59 | 256 60 | 256 61 | 1 62 | 1 63 | 64 | 65 | 1 66 | 279541132.0143589 67 | -20037508.3427892 20037508.3427892 68 | 256 69 | 256 70 | 2 71 | 2 72 | 73 | 74 | 2 75 | 139770566.0071794 76 | -20037508.3427892 20037508.3427892 77 | 256 78 | 256 79 | 4 80 | 4 81 | 82 | 83 | 3 84 | 69885283.00358972 85 | -20037508.3427892 20037508.3427892 86 | 256 87 | 256 88 | 8 89 | 8 90 | 91 | 92 | 4 93 | 34942641.50179486 94 | -20037508.3427892 20037508.3427892 95 | 256 96 | 256 97 | 16 98 | 16 99 | 100 | 101 | 5 102 | 17471320.75089743 103 | -20037508.3427892 20037508.3427892 104 | 256 105 | 256 106 | 32 107 | 32 108 | 109 | 110 | 6 111 | 8735660.375448715 112 | -20037508.3427892 20037508.3427892 113 | 256 114 | 256 115 | 64 116 | 64 117 | 118 | 119 | 7 120 | 4367830.187724357 121 | -20037508.3427892 20037508.3427892 122 | 256 123 | 256 124 | 128 125 | 128 126 | 127 | 128 | 8 129 | 2183915.093862179 130 | -20037508.3427892 20037508.3427892 131 | 256 132 | 256 133 | 256 134 | 256 135 | 136 | 137 | 9 138 | 1091957.546931089 139 | -20037508.3427892 20037508.3427892 140 | 256 141 | 256 142 | 512 143 | 512 144 | 145 | 146 | 10 147 | 545978.7734655447 148 | -20037508.3427892 20037508.3427892 149 | 256 150 | 256 151 | 1024 152 | 1024 153 | 154 | 155 | 11 156 | 272989.3867327723 157 | -20037508.3427892 20037508.3427892 158 | 256 159 | 256 160 | 2048 161 | 2048 162 | 163 | 164 | 12 165 | 136494.6933663862 166 | -20037508.3427892 20037508.3427892 167 | 256 168 | 256 169 | 4096 170 | 4096 171 | 172 | 173 | 13 174 | 68247.34668319309 175 | -20037508.3427892 20037508.3427892 176 | 256 177 | 256 178 | 8192 179 | 8192 180 | 181 | 182 | 14 183 | 34123.67334159654 184 | -20037508.3427892 20037508.3427892 185 | 256 186 | 256 187 | 16384 188 | 16384 189 | 190 | 191 | 15 192 | 17061.83667079827 193 | -20037508.3427892 20037508.3427892 194 | 256 195 | 256 196 | 32768 197 | 32768 198 | 199 | 200 | 16 201 | 8530.918335399136 202 | -20037508.3427892 20037508.3427892 203 | 256 204 | 256 205 | 65536 206 | 65536 207 | 208 | 209 | 17 210 | 4265.459167699568 211 | -20037508.3427892 20037508.3427892 212 | 256 213 | 256 214 | 131072 215 | 131072 216 | 217 | 218 | 18 219 | 2132.729583849784 220 | -20037508.3427892 20037508.3427892 221 | 256 222 | 256 223 | 262114 224 | 262114 225 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /.github/workflows/Release.yml: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by dist: https://opensource.axo.dev/cargo-dist/ 2 | # 3 | # Copyright 2022-2024, axodotdev 4 | # SPDX-License-Identifier: MIT or Apache-2.0 5 | # 6 | # CI that: 7 | # 8 | # * checks for a Git Tag that looks like a release 9 | # * builds artifacts with dist (archives, installers, hashes) 10 | # * uploads those artifacts to temporary workflow zip 11 | # * on success, uploads the artifacts to a GitHub Release 12 | # 13 | # Note that the GitHub Release will be created with a generated 14 | # title/body based on your changelogs. 15 | 16 | name: Release 17 | permissions: 18 | "contents": "write" 19 | 20 | # This task will run whenever you push a git tag that looks like a version 21 | # like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. 22 | # Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where 23 | # PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION 24 | # must be a Cargo-style SemVer Version (must have at least major.minor.patch). 25 | # 26 | # If PACKAGE_NAME is specified, then the announcement will be for that 27 | # package (erroring out if it doesn't have the given version or isn't dist-able). 28 | # 29 | # If PACKAGE_NAME isn't specified, then the announcement will be for all 30 | # (dist-able) packages in the workspace with that version (this mode is 31 | # intended for workspaces with only one dist-able package, or with all dist-able 32 | # packages versioned/released in lockstep). 33 | # 34 | # If you push multiple tags at once, separate instances of this workflow will 35 | # spin up, creating an independent announcement for each one. However, GitHub 36 | # will hard limit this to 3 tags per commit, as it will assume more tags is a 37 | # mistake. 38 | # 39 | # If there's a prerelease-style suffix to the version, then the release(s) 40 | # will be marked as a prerelease. 41 | on: 42 | pull_request: 43 | push: 44 | tags: 45 | - "**[0-9]+.[0-9]+.[0-9]+*" 46 | 47 | jobs: 48 | # Run 'dist plan' (or host) to determine what tasks we need to do 49 | plan: 50 | runs-on: "ubuntu-20.04" 51 | outputs: 52 | val: ${{ steps.plan.outputs.manifest }} 53 | tag: ${{ !github.event.pull_request && github.ref_name || '' }} 54 | tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} 55 | publishing: ${{ !github.event.pull_request }} 56 | env: 57 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | steps: 59 | - uses: actions/checkout@v4 60 | with: 61 | submodules: recursive 62 | - name: Install dist 63 | # we specify bash to get pipefail; it guards against the `curl` command 64 | # failing. otherwise `sh` won't catch that `curl` returned non-0 65 | shell: bash 66 | run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.28.0/cargo-dist-installer.sh | sh" 67 | - name: Cache dist 68 | uses: actions/upload-artifact@v4 69 | with: 70 | name: cargo-dist-cache 71 | path: ~/.cargo/bin/dist 72 | # sure would be cool if github gave us proper conditionals... 73 | # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible 74 | # functionality based on whether this is a pull_request, and whether it's from a fork. 75 | # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* 76 | # but also really annoying to build CI around when it needs secrets to work right.) 77 | - id: plan 78 | run: | 79 | dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json 80 | echo "dist ran successfully" 81 | cat plan-dist-manifest.json 82 | echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" 83 | - name: "Upload dist-manifest.json" 84 | uses: actions/upload-artifact@v4 85 | with: 86 | name: artifacts-plan-dist-manifest 87 | path: plan-dist-manifest.json 88 | 89 | # Build and packages all the platform-specific things 90 | build-local-artifacts: 91 | name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) 92 | # Let the initial task tell us to not run (currently very blunt) 93 | needs: 94 | - plan 95 | if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} 96 | strategy: 97 | fail-fast: false 98 | # Target platforms/runners are computed by dist in create-release. 99 | # Each member of the matrix has the following arguments: 100 | # 101 | # - runner: the github runner 102 | # - dist-args: cli flags to pass to dist 103 | # - install-dist: expression to run to install dist on the runner 104 | # 105 | # Typically there will be: 106 | # - 1 "global" task that builds universal installers 107 | # - N "local" tasks that build each platform's binaries and platform-specific installers 108 | matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} 109 | runs-on: ${{ matrix.runner }} 110 | container: ${{ matrix.container && matrix.container.image || null }} 111 | env: 112 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 113 | BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json 114 | steps: 115 | - name: enable windows longpaths 116 | run: | 117 | git config --global core.longpaths true 118 | - uses: actions/checkout@v4 119 | with: 120 | submodules: recursive 121 | - name: Install Rust non-interactively if not already installed 122 | if: ${{ matrix.container }} 123 | run: | 124 | if ! command -v cargo > /dev/null 2>&1; then 125 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 126 | echo "$HOME/.cargo/bin" >> $GITHUB_PATH 127 | fi 128 | - name: Install dist 129 | run: ${{ matrix.install_dist.run }} 130 | # Get the dist-manifest 131 | - name: Fetch local artifacts 132 | uses: actions/download-artifact@v4 133 | with: 134 | pattern: artifacts-* 135 | path: target/distrib/ 136 | merge-multiple: true 137 | - name: Install dependencies 138 | run: | 139 | ${{ matrix.packages_install }} 140 | # To Build Doc 141 | - name: Install pnpm 142 | uses: pnpm/action-setup@v4 143 | with: 144 | version: 9 145 | run_install: false 146 | - name: Install Node.js 147 | uses: actions/setup-node@v4 148 | with: 149 | node-version: 20 150 | cache: "pnpm" 151 | - name: Install dependencies 152 | run: pnpm install 153 | - name: Build 154 | run: pnpm docs:build 155 | 156 | - name: Build artifacts 157 | run: | 158 | # Actually do builds and make zips and whatnot 159 | dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json 160 | echo "dist ran successfully" 161 | - id: cargo-dist 162 | name: Post-build 163 | # We force bash here just because github makes it really hard to get values up 164 | # to "real" actions without writing to env-vars, and writing to env-vars has 165 | # inconsistent syntax between shell and powershell. 166 | shell: bash 167 | run: | 168 | # Parse out what we just built and upload it to scratch storage 169 | echo "paths<> "$GITHUB_OUTPUT" 170 | dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" 171 | echo "EOF" >> "$GITHUB_OUTPUT" 172 | 173 | cp dist-manifest.json "$BUILD_MANIFEST_NAME" 174 | - name: "Upload artifacts" 175 | uses: actions/upload-artifact@v4 176 | with: 177 | name: artifacts-build-local-${{ join(matrix.targets, '_') }} 178 | path: | 179 | ${{ steps.cargo-dist.outputs.paths }} 180 | ${{ env.BUILD_MANIFEST_NAME }} 181 | 182 | # Build and package all the platform-agnostic(ish) things 183 | build-global-artifacts: 184 | needs: 185 | - plan 186 | - build-local-artifacts 187 | runs-on: "ubuntu-20.04" 188 | env: 189 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 190 | BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json 191 | steps: 192 | - uses: actions/checkout@v4 193 | with: 194 | submodules: recursive 195 | - name: Install cached dist 196 | uses: actions/download-artifact@v4 197 | with: 198 | name: cargo-dist-cache 199 | path: ~/.cargo/bin/ 200 | - run: chmod +x ~/.cargo/bin/dist 201 | # Get all the local artifacts for the global tasks to use (for e.g. checksums) 202 | - name: Fetch local artifacts 203 | uses: actions/download-artifact@v4 204 | with: 205 | pattern: artifacts-* 206 | path: target/distrib/ 207 | merge-multiple: true 208 | - id: cargo-dist 209 | shell: bash 210 | run: | 211 | dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json 212 | echo "dist ran successfully" 213 | 214 | # Parse out what we just built and upload it to scratch storage 215 | echo "paths<> "$GITHUB_OUTPUT" 216 | jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" 217 | echo "EOF" >> "$GITHUB_OUTPUT" 218 | 219 | cp dist-manifest.json "$BUILD_MANIFEST_NAME" 220 | - name: "Upload artifacts" 221 | uses: actions/upload-artifact@v4 222 | with: 223 | name: artifacts-build-global 224 | path: | 225 | ${{ steps.cargo-dist.outputs.paths }} 226 | ${{ env.BUILD_MANIFEST_NAME }} 227 | # Determines if we should publish/announce 228 | host: 229 | needs: 230 | - plan 231 | - build-local-artifacts 232 | - build-global-artifacts 233 | # Only run if we're "publishing", and only if local and global didn't fail (skipped is fine) 234 | if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} 235 | env: 236 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 237 | runs-on: "ubuntu-20.04" 238 | outputs: 239 | val: ${{ steps.host.outputs.manifest }} 240 | steps: 241 | - uses: actions/checkout@v4 242 | with: 243 | submodules: recursive 244 | - name: Install cached dist 245 | uses: actions/download-artifact@v4 246 | with: 247 | name: cargo-dist-cache 248 | path: ~/.cargo/bin/ 249 | - run: chmod +x ~/.cargo/bin/dist 250 | # Fetch artifacts from scratch-storage 251 | - name: Fetch artifacts 252 | uses: actions/download-artifact@v4 253 | with: 254 | pattern: artifacts-* 255 | path: target/distrib/ 256 | merge-multiple: true 257 | - id: host 258 | shell: bash 259 | run: | 260 | dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json 261 | echo "artifacts uploaded and released successfully" 262 | cat dist-manifest.json 263 | echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" 264 | - name: "Upload dist-manifest.json" 265 | uses: actions/upload-artifact@v4 266 | with: 267 | # Overwrite the previous copy 268 | name: artifacts-dist-manifest 269 | path: dist-manifest.json 270 | # Create a GitHub Release while uploading all files to it 271 | - name: "Download GitHub Artifacts" 272 | uses: actions/download-artifact@v4 273 | with: 274 | pattern: artifacts-* 275 | path: artifacts 276 | merge-multiple: true 277 | - name: Cleanup 278 | run: | 279 | # Remove the granular manifests 280 | rm -f artifacts/*-dist-manifest.json 281 | - name: Create GitHub Release 282 | env: 283 | PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" 284 | ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" 285 | ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" 286 | RELEASE_COMMIT: "${{ github.sha }}" 287 | run: | 288 | # Write and read notes from a file to avoid quoting breaking things 289 | echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt 290 | 291 | gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* 292 | 293 | announce: 294 | needs: 295 | - plan 296 | - host 297 | # use "always() && ..." to allow us to wait for all publish jobs while 298 | # still allowing individual publish jobs to skip themselves (for prereleases). 299 | # "host" however must run to completion, no skipping allowed! 300 | if: ${{ always() && needs.host.result == 'success' }} 301 | runs-on: "ubuntu-20.04" 302 | env: 303 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 304 | steps: 305 | - uses: actions/checkout@v4 306 | with: 307 | submodules: recursive 308 | -------------------------------------------------------------------------------- /crates/tiny-tile-proxy/assets/templates/geocloud.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | Tiny Map Proxy 11 | Tiny Map Proxy: 地质云 12 | OGC WMTS 13 | 1.0.0 14 | none 15 | none 16 | 17 | 18 | 19 | 1 全国1/250万地质图 20 | 地质云 - 基础地质/全国1/250万地质图 21 | 22 | 73.49895477 3.83254099 23 | 135.08738708 53.55849838 24 | 25 | qg250w_20210416_ZAZSeOGX 26 | 29 | image/png 30 | 31 | default028mm 32 | 33 | 35 | 36 | 37 | 2 全国1/150万地质图 38 | 地质云 - 基础地质/全国1/150万地质图 39 | 40 | 73.49895477 3.83254099 41 | 135.08738708 53.55849838 42 | 43 | qg150w_20210416_BIwqE0wU 44 | 47 | image/png 48 | 49 | default028mm 50 | 51 | 53 | 54 | 55 | 3 全国1/100万地质图 56 | 地质云 - 基础地质/全国1/100万地质图 57 | 58 | 73.49895477 3.83254099 59 | 135.08738708 53.55849838 60 | 61 | 全国100万地质图_20210330_rpam5kdJ 62 | 65 | image/png 66 | 67 | default028mm 68 | 69 | 71 | 72 | 73 | 4 全国1/50万地质图 74 | 地质云 - 基础地质/全国1/50万地质图 75 | 76 | 73.49895477 3.83254099 77 | 135.08738708 53.55849838 78 | 79 | qg50w_20210416_F7qGy9A7 80 | 83 | image/png 84 | 85 | default028mm 86 | 87 | 89 | 90 | 91 | 5 全国1/20万地质图 92 | 地质云 - 基础地质/全国1/20万地质图 93 | 94 | 73.49895477 3.83254099 95 | 135.08738708 53.55849838 96 | 97 | qg20_20210401_FCnDDRJd 98 | 101 | image/png 102 | 103 | default028mm 104 | 105 | 107 | 108 | 109 | 110 | 111 | default028mm 112 | urn:ogc:def:crs:EPSG::4490 113 | 114 | 0 115 | 2.7922764150666654E8 116 | 90 -180 117 | 256 118 | 256 119 | 2 120 | 1 121 | 122 | 123 | 1 124 | 1.3961382075333327E8 125 | 90 -180 126 | 256 127 | 256 128 | 4 129 | 2 130 | 131 | 132 | 2 133 | 6.988528430719091E7 134 | 90 -180 135 | 256 136 | 256 137 | 8 138 | 4 139 | 140 | 141 | 3 142 | 3.49426421535955E7 143 | 90 -180 144 | 256 145 | 256 146 | 16 147 | 8 148 | 149 | 150 | 4 151 | 1.747132107679775E7 152 | 90 -180 153 | 256 154 | 256 155 | 32 156 | 16 157 | 158 | 159 | 5 160 | 8735660.538398864 161 | 90 -180 162 | 256 163 | 256 164 | 64 165 | 32 166 | 167 | 168 | 6 169 | 4367830.269199428 170 | 90 -180 171 | 256 172 | 256 173 | 128 174 | 64 175 | 176 | 177 | 7 178 | 2183915.1345997187 179 | 90 -180 180 | 256 181 | 256 182 | 256 183 | 128 184 | 185 | 186 | 8 187 | 1091957.5672998547 188 | 90 -180 189 | 256 190 | 256 191 | 512 192 | 256 193 | 194 | 195 | 9 196 | 545978.7836499291 197 | 90 -180 198 | 256 199 | 256 200 | 1024 201 | 512 202 | 203 | 204 | 10 205 | 272989.39182496455 206 | 90 -180 207 | 256 208 | 256 209 | 2048 210 | 1024 211 | 212 | 213 | 11 214 | 136494.69591248184 215 | 90 -180 216 | 256 217 | 256 218 | 4096 219 | 2048 220 | 221 | 222 | 12 223 | 68247.34795624111 224 | 90 -180 225 | 256 226 | 256 227 | 8192 228 | 4096 229 | 230 | 231 | 13 232 | 34123.673978120605 233 | 90 -180 234 | 256 235 | 256 236 | 16384 237 | 4096 238 | 239 | 240 | 14 241 | 17061.836989060303 242 | 90 -180 243 | 256 244 | 256 245 | 32768 246 | 16384 247 | 248 | 249 | 15 250 | 8530.91849453014 251 | 90 -180 252 | 256 253 | 256 254 | 65536 255 | 32768 256 | 257 | 258 | 16 259 | 4265.45924726507 260 | 90 -180 261 | 256 262 | 256 263 | 131072 264 | 65536 265 | 266 | 267 | 17 268 | 2132.729623632535 269 | 90 -180 270 | 256 271 | 256 272 | 262144 273 | 131072 274 | 275 | 276 | 18 277 | 1066.364811816268 278 | 90 -180 279 | 256 280 | 256 281 | 524288 282 | 262144 283 | 284 | 285 | 19 286 | 533.1824059081338 287 | 90 -180 288 | 256 289 | 256 290 | 1048576 291 | 524288 292 | 293 | 294 | 295 | default028mmWithEPSG 296 | urn:ogc:def:crs:EPSG::4326 297 | 298 | EPSG:4326:0 299 | 2.7922764150666654E8 300 | 90 -180 301 | 256 302 | 256 303 | 2 304 | 1 305 | 306 | 307 | EPSG:4326:1 308 | 1.3961382075333327E8 309 | 90 -180 310 | 256 311 | 256 312 | 4 313 | 2 314 | 315 | 316 | EPSG:4326:2 317 | 6.988528430719091E7 318 | 90 -180 319 | 256 320 | 256 321 | 8 322 | 4 323 | 324 | 325 | EPSG:4326:3 326 | 3.49426421535955E7 327 | 90 -180 328 | 256 329 | 256 330 | 16 331 | 8 332 | 333 | 334 | EPSG:4326:4 335 | 1.747132107679775E7 336 | 90 -180 337 | 256 338 | 256 339 | 32 340 | 16 341 | 342 | 343 | EPSG:4326:5 344 | 8735660.538398864 345 | 90 -180 346 | 256 347 | 256 348 | 64 349 | 32 350 | 351 | 352 | EPSG:4326:6 353 | 4367830.269199428 354 | 90 -180 355 | 256 356 | 256 357 | 128 358 | 64 359 | 360 | 361 | EPSG:4326:7 362 | 2183915.1345997187 363 | 90 -180 364 | 256 365 | 256 366 | 256 367 | 128 368 | 369 | 370 | EPSG:4326:8 371 | 1091957.5672998547 372 | 90 -180 373 | 256 374 | 256 375 | 512 376 | 256 377 | 378 | 379 | EPSG:4326:9 380 | 545978.7836499291 381 | 90 -180 382 | 256 383 | 256 384 | 1024 385 | 512 386 | 387 | 388 | EPSG:4326:10 389 | 272989.39182496455 390 | 90 -180 391 | 256 392 | 256 393 | 2048 394 | 1024 395 | 396 | 397 | EPSG:4326:11 398 | 136494.69591248184 399 | 90 -180 400 | 256 401 | 256 402 | 4096 403 | 2048 404 | 405 | 406 | EPSG:4326:12 407 | 68247.34795624111 408 | 90 -180 409 | 256 410 | 256 411 | 8192 412 | 4096 413 | 414 | 415 | EPSG:4326:13 416 | 34123.673978120605 417 | 90 -180 418 | 256 419 | 256 420 | 16384 421 | 4096 422 | 423 | 424 | EPSG:4326:14 425 | 17061.836989060303 426 | 90 -180 427 | 256 428 | 256 429 | 32768 430 | 16384 431 | 432 | 433 | EPSG:4326:15 434 | 8530.91849453014 435 | 90 -180 436 | 256 437 | 256 438 | 65536 439 | 32768 440 | 441 | 442 | EPSG:4326:16 443 | 4265.45924726507 444 | 90 -180 445 | 256 446 | 256 447 | 131072 448 | 65536 449 | 450 | 451 | EPSG:4326:17 452 | 2132.729623632535 453 | 90 -180 454 | 256 455 | 256 456 | 262144 457 | 131072 458 | 459 | 460 | EPSG:4326:18 461 | 1066.364811816268 462 | 90 -180 463 | 256 464 | 256 465 | 524288 466 | 262144 467 | 468 | 469 | 470 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | vitepress: 12 | specifier: ^1.6.3 13 | version: 1.6.3(@algolia/client-search@5.20.1)(postcss@8.5.1)(search-insights@2.17.2) 14 | 15 | packages: 16 | 17 | '@algolia/autocomplete-core@1.17.7': 18 | resolution: {integrity: sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==} 19 | 20 | '@algolia/autocomplete-plugin-algolia-insights@1.17.7': 21 | resolution: {integrity: sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==} 22 | peerDependencies: 23 | search-insights: '>= 1 < 3' 24 | 25 | '@algolia/autocomplete-preset-algolia@1.17.7': 26 | resolution: {integrity: sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==} 27 | peerDependencies: 28 | '@algolia/client-search': '>= 4.9.1 < 6' 29 | algoliasearch: '>= 4.9.1 < 6' 30 | 31 | '@algolia/autocomplete-shared@1.17.7': 32 | resolution: {integrity: sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==} 33 | peerDependencies: 34 | '@algolia/client-search': '>= 4.9.1 < 6' 35 | algoliasearch: '>= 4.9.1 < 6' 36 | 37 | '@algolia/client-abtesting@5.20.1': 38 | resolution: {integrity: sha512-73pnrUixMVnfjgldxhRi5eYLraMt95/MhQHevoFtqwy+t2hfayxYBZXJ2k6JJDld8UmjcWwq3wXnvZJCOm7vZA==} 39 | engines: {node: '>= 14.0.0'} 40 | 41 | '@algolia/client-analytics@5.20.1': 42 | resolution: {integrity: sha512-BRiyL+AwPfGTlo3HbrFDMeTK2z5SaJmB8PBd1JI66d6MeP85+38Mux2FFw+nvDOfBwlGaN/uw2AQTOZ9r4JYtA==} 43 | engines: {node: '>= 14.0.0'} 44 | 45 | '@algolia/client-common@5.20.1': 46 | resolution: {integrity: sha512-Dk4RhklaAbqLzOeJO/MoIFUjcKYGECiAJYYqDzmE/sbXICk5Uo6dGlv8w4z09lmvsASpNUoMvGYHGBK+WkEGpA==} 47 | engines: {node: '>= 14.0.0'} 48 | 49 | '@algolia/client-insights@5.20.1': 50 | resolution: {integrity: sha512-eu5vhmyYgzZjFIPmkoLo/TU4s+IdsjQ+bEfLj2jcMvyfBD4DcqySKp03TrXjdrHPGO2I3fF7dPZOoCgEi1j2/g==} 51 | engines: {node: '>= 14.0.0'} 52 | 53 | '@algolia/client-personalization@5.20.1': 54 | resolution: {integrity: sha512-TrUCJ0nVqE0PnOGoRG/RCirxWZ6pF+skZgaaESN2IBnJtk/In14xVmoj8Yzck81bGUY/UI+5dUUOOS7YTSVEhQ==} 55 | engines: {node: '>= 14.0.0'} 56 | 57 | '@algolia/client-query-suggestions@5.20.1': 58 | resolution: {integrity: sha512-rHHX/30R3Kkx2aZeR7/8+jU0s6h1cNPMAKOvcMUGVmoiuh46F1sxzmiswHLg6CuLrQ0ikhpdhn3ehFSJwHgp2Q==} 59 | engines: {node: '>= 14.0.0'} 60 | 61 | '@algolia/client-search@5.20.1': 62 | resolution: {integrity: sha512-YzHD0Nqp7AjvzbFrMIjhCUl6apHkWfZxKDSlMqf80mXkuG52wY289zFlvTfHjHK1nEiDslH3uHYAR/poOOa21Q==} 63 | engines: {node: '>= 14.0.0'} 64 | 65 | '@algolia/ingestion@1.20.1': 66 | resolution: {integrity: sha512-sHNZ8b5tK7TvXMiiKK+89UsXnFthnAZc0vpwvDKygdTqvsfmfJPhthx36eHTAVYfh7NnA1+eqZsT/hMUGeZFkQ==} 67 | engines: {node: '>= 14.0.0'} 68 | 69 | '@algolia/monitoring@1.20.1': 70 | resolution: {integrity: sha512-+fHd1U3gSeszCH03UtyUZmprpmcJH6aJKyUTOfY73lKKRR7hVofmV812ahScR0T4xUkBlGjTLeGnsKY0IG6K6Q==} 71 | engines: {node: '>= 14.0.0'} 72 | 73 | '@algolia/recommend@5.20.1': 74 | resolution: {integrity: sha512-+IuiUv3OSOFFKoXFMlZHfFzXGqEQbKhncpAcRSAtJmN4pupY4aNblvJ9Wv0SMm7/MSFRy2JLIoYWRSBpSV2yEg==} 75 | engines: {node: '>= 14.0.0'} 76 | 77 | '@algolia/requester-browser-xhr@5.20.1': 78 | resolution: {integrity: sha512-+RaJa5MpJqPHaSbBw0nrHeyIAd5C4YC9C1LfDbZJqrn5ZwOvHMUTod852XmzX/1S8oi1jTynB4FjicmauZIKwA==} 79 | engines: {node: '>= 14.0.0'} 80 | 81 | '@algolia/requester-fetch@5.20.1': 82 | resolution: {integrity: sha512-4l1cba8t02rNkLeX/B7bmgDg3CwuRunmuCSgN2zORDtepjg9YAU1qcyRTyc/rAuNJ54AduRfoBplmKXjowYzbQ==} 83 | engines: {node: '>= 14.0.0'} 84 | 85 | '@algolia/requester-node-http@5.20.1': 86 | resolution: {integrity: sha512-4npKo1qpLG5xusFoFUj4xIIR/6y3YoCuS/uhagv2blGFotDj+D6OLTML3Pp6JCVcES4zDbkoY7pmNBA8ARtidQ==} 87 | engines: {node: '>= 14.0.0'} 88 | 89 | '@babel/helper-string-parser@7.25.9': 90 | resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} 91 | engines: {node: '>=6.9.0'} 92 | 93 | '@babel/helper-validator-identifier@7.25.9': 94 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 95 | engines: {node: '>=6.9.0'} 96 | 97 | '@babel/parser@7.26.7': 98 | resolution: {integrity: sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==} 99 | engines: {node: '>=6.0.0'} 100 | hasBin: true 101 | 102 | '@babel/types@7.26.7': 103 | resolution: {integrity: sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==} 104 | engines: {node: '>=6.9.0'} 105 | 106 | '@docsearch/css@3.8.2': 107 | resolution: {integrity: sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==} 108 | 109 | '@docsearch/js@3.8.2': 110 | resolution: {integrity: sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==} 111 | 112 | '@docsearch/react@3.8.2': 113 | resolution: {integrity: sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==} 114 | peerDependencies: 115 | '@types/react': '>= 16.8.0 < 19.0.0' 116 | react: '>= 16.8.0 < 19.0.0' 117 | react-dom: '>= 16.8.0 < 19.0.0' 118 | search-insights: '>= 1 < 3' 119 | peerDependenciesMeta: 120 | '@types/react': 121 | optional: true 122 | react: 123 | optional: true 124 | react-dom: 125 | optional: true 126 | search-insights: 127 | optional: true 128 | 129 | '@esbuild/aix-ppc64@0.21.5': 130 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 131 | engines: {node: '>=12'} 132 | cpu: [ppc64] 133 | os: [aix] 134 | 135 | '@esbuild/android-arm64@0.21.5': 136 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 137 | engines: {node: '>=12'} 138 | cpu: [arm64] 139 | os: [android] 140 | 141 | '@esbuild/android-arm@0.21.5': 142 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 143 | engines: {node: '>=12'} 144 | cpu: [arm] 145 | os: [android] 146 | 147 | '@esbuild/android-x64@0.21.5': 148 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 149 | engines: {node: '>=12'} 150 | cpu: [x64] 151 | os: [android] 152 | 153 | '@esbuild/darwin-arm64@0.21.5': 154 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 155 | engines: {node: '>=12'} 156 | cpu: [arm64] 157 | os: [darwin] 158 | 159 | '@esbuild/darwin-x64@0.21.5': 160 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 161 | engines: {node: '>=12'} 162 | cpu: [x64] 163 | os: [darwin] 164 | 165 | '@esbuild/freebsd-arm64@0.21.5': 166 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 167 | engines: {node: '>=12'} 168 | cpu: [arm64] 169 | os: [freebsd] 170 | 171 | '@esbuild/freebsd-x64@0.21.5': 172 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 173 | engines: {node: '>=12'} 174 | cpu: [x64] 175 | os: [freebsd] 176 | 177 | '@esbuild/linux-arm64@0.21.5': 178 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 179 | engines: {node: '>=12'} 180 | cpu: [arm64] 181 | os: [linux] 182 | 183 | '@esbuild/linux-arm@0.21.5': 184 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 185 | engines: {node: '>=12'} 186 | cpu: [arm] 187 | os: [linux] 188 | 189 | '@esbuild/linux-ia32@0.21.5': 190 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 191 | engines: {node: '>=12'} 192 | cpu: [ia32] 193 | os: [linux] 194 | 195 | '@esbuild/linux-loong64@0.21.5': 196 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 197 | engines: {node: '>=12'} 198 | cpu: [loong64] 199 | os: [linux] 200 | 201 | '@esbuild/linux-mips64el@0.21.5': 202 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 203 | engines: {node: '>=12'} 204 | cpu: [mips64el] 205 | os: [linux] 206 | 207 | '@esbuild/linux-ppc64@0.21.5': 208 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 209 | engines: {node: '>=12'} 210 | cpu: [ppc64] 211 | os: [linux] 212 | 213 | '@esbuild/linux-riscv64@0.21.5': 214 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 215 | engines: {node: '>=12'} 216 | cpu: [riscv64] 217 | os: [linux] 218 | 219 | '@esbuild/linux-s390x@0.21.5': 220 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 221 | engines: {node: '>=12'} 222 | cpu: [s390x] 223 | os: [linux] 224 | 225 | '@esbuild/linux-x64@0.21.5': 226 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 227 | engines: {node: '>=12'} 228 | cpu: [x64] 229 | os: [linux] 230 | 231 | '@esbuild/netbsd-x64@0.21.5': 232 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 233 | engines: {node: '>=12'} 234 | cpu: [x64] 235 | os: [netbsd] 236 | 237 | '@esbuild/openbsd-x64@0.21.5': 238 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 239 | engines: {node: '>=12'} 240 | cpu: [x64] 241 | os: [openbsd] 242 | 243 | '@esbuild/sunos-x64@0.21.5': 244 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 245 | engines: {node: '>=12'} 246 | cpu: [x64] 247 | os: [sunos] 248 | 249 | '@esbuild/win32-arm64@0.21.5': 250 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 251 | engines: {node: '>=12'} 252 | cpu: [arm64] 253 | os: [win32] 254 | 255 | '@esbuild/win32-ia32@0.21.5': 256 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 257 | engines: {node: '>=12'} 258 | cpu: [ia32] 259 | os: [win32] 260 | 261 | '@esbuild/win32-x64@0.21.5': 262 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 263 | engines: {node: '>=12'} 264 | cpu: [x64] 265 | os: [win32] 266 | 267 | '@iconify-json/simple-icons@1.2.23': 268 | resolution: {integrity: sha512-ySyZ0ZXdNveWnR71t7XGV7jhknxSlTtpM2TyIR1cUHTUzZLP36hYHTNqb2pYYsCzH5ed85KTTKz7vYT33FyNIQ==} 269 | 270 | '@iconify/types@2.0.0': 271 | resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} 272 | 273 | '@jridgewell/sourcemap-codec@1.5.0': 274 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 275 | 276 | '@rollup/rollup-android-arm-eabi@4.34.5': 277 | resolution: {integrity: sha512-JXmmQcKQtpf3Z6lvA8akkrHDZ5AEfgc2hLMix1/X5BhQbezBQ0AP5GYLdU8jsQRme8qr2sscCe3wizp7UT0L9g==} 278 | cpu: [arm] 279 | os: [android] 280 | 281 | '@rollup/rollup-android-arm64@4.34.5': 282 | resolution: {integrity: sha512-9/A8/ZBOprUjkrJoP9BBEq2vdSud6BPd3LChw09bJQiEZH5oN4kWIkHu90cA0Cj0cSF5cIaD76+0lA+d5KHmpQ==} 283 | cpu: [arm64] 284 | os: [android] 285 | 286 | '@rollup/rollup-darwin-arm64@4.34.5': 287 | resolution: {integrity: sha512-b9oCfgHKfc1AJEQ5sEpE8Kf6s7aeygj5bZAsl1hTpZc1V9cfZASFSXzzNj7o/BQNPbjmVkVxpCCLRhBfLXhJ5g==} 288 | cpu: [arm64] 289 | os: [darwin] 290 | 291 | '@rollup/rollup-darwin-x64@4.34.5': 292 | resolution: {integrity: sha512-Gz42gKBQPoFdMYdsVqkcpttYOO/0aP7f+1CgMaeZEz0gss7dop1TsO3hT77Iroz/TV7PdPUG/RYlj9EA39L4dw==} 293 | cpu: [x64] 294 | os: [darwin] 295 | 296 | '@rollup/rollup-freebsd-arm64@4.34.5': 297 | resolution: {integrity: sha512-JPkafjkOFaupd8VQYsXfGFKC2pfMr7hwSYGkVGNwhbW0k0lHHyIdhCSNBendJ4O7YlT4yRyKXoms1TL7saO7SQ==} 298 | cpu: [arm64] 299 | os: [freebsd] 300 | 301 | '@rollup/rollup-freebsd-x64@4.34.5': 302 | resolution: {integrity: sha512-j6Q8VFqyI8hZM33h1JC6DZK2w8ejkXqEMozTrtIEGfRVMpVZL3GrLOOYEUkAgUSpJ9sb2w+FEpjGj7IHRcQfdw==} 303 | cpu: [x64] 304 | os: [freebsd] 305 | 306 | '@rollup/rollup-linux-arm-gnueabihf@4.34.5': 307 | resolution: {integrity: sha512-6jyiXKF9Xq6x9yQjct5xrRT0VghJk5VzAfed3o0hgncwacZkzOdR0TXLRNjexsEXWN8tG7jWWwsVk7WeFi//gw==} 308 | cpu: [arm] 309 | os: [linux] 310 | 311 | '@rollup/rollup-linux-arm-musleabihf@4.34.5': 312 | resolution: {integrity: sha512-cOTYe5tLcGAvGztRLIqx87LE7j/qjaAqFrrHsPFlnuhhhFO5LSr2AzvdQYuxomJMzMBrXkMRNl9bQEpDZ5bjLQ==} 313 | cpu: [arm] 314 | os: [linux] 315 | 316 | '@rollup/rollup-linux-arm64-gnu@4.34.5': 317 | resolution: {integrity: sha512-KHlrd+YqmS7rriW+LBb1kQNYmd5w1sAIG3z7HEpnQOrg/skeYYv9DAcclGL9gpFdpnzmiAEkzsTT74kZWUtChQ==} 318 | cpu: [arm64] 319 | os: [linux] 320 | 321 | '@rollup/rollup-linux-arm64-musl@4.34.5': 322 | resolution: {integrity: sha512-uOb6hzDqym4Sw+qw3+svS3SmwQGVUhyTdPKyHDdlYg1Z0aHjdNmjwRY7zw/90/UfBe/yD7Mv2mYKhQpOfy4RYA==} 323 | cpu: [arm64] 324 | os: [linux] 325 | 326 | '@rollup/rollup-linux-loongarch64-gnu@4.34.5': 327 | resolution: {integrity: sha512-pARu8ZKANZH4wINLdHLKG69EPwJswM6A+Ox1a9LpiclRQoyjacFFTtXN3akKQ2ufJXDasO/pWvxKN9ZfCgEoFA==} 328 | cpu: [loong64] 329 | os: [linux] 330 | 331 | '@rollup/rollup-linux-powerpc64le-gnu@4.34.5': 332 | resolution: {integrity: sha512-crUWn12NRmCdao2YwS1GvlPCVypMBMJlexTaantaP2+dAMd2eZBErFcKG8hZYEHjSbbk2UoH1aTlyeA4iKLqSA==} 333 | cpu: [ppc64] 334 | os: [linux] 335 | 336 | '@rollup/rollup-linux-riscv64-gnu@4.34.5': 337 | resolution: {integrity: sha512-XtD/oMhCdixi3x8rCNyDRMUsLo1Z+1UQcK+oR7AsjglGov9ETiT3TNFhUPzaGC1jH+uaMtPhxrVRUub+pnAKTg==} 338 | cpu: [riscv64] 339 | os: [linux] 340 | 341 | '@rollup/rollup-linux-s390x-gnu@4.34.5': 342 | resolution: {integrity: sha512-V3+BvgyHb21aF7lw0sc78Tv0+xLp4lm2OM7CKFVrBuppsMvtl/9O5y2OX4tdDT0EhIsDP/ObJPqDuEg1ZoTwSQ==} 343 | cpu: [s390x] 344 | os: [linux] 345 | 346 | '@rollup/rollup-linux-x64-gnu@4.34.5': 347 | resolution: {integrity: sha512-SkCIXLGk42yldTcH8UXh++m0snVxp9DLf4meb1mWm0lC8jzxjFBwSLGtUSeLgQDsC05iBaIhyjNX46DlByrApQ==} 348 | cpu: [x64] 349 | os: [linux] 350 | 351 | '@rollup/rollup-linux-x64-musl@4.34.5': 352 | resolution: {integrity: sha512-iUcH3FBtBN2/Ce0rI84suRhD0+bB5BVEffqOwsGaX5py5TuYLOQa7S7oVBP0NKtB5rub3i9IvZtMXiD96l5v0A==} 353 | cpu: [x64] 354 | os: [linux] 355 | 356 | '@rollup/rollup-win32-arm64-msvc@4.34.5': 357 | resolution: {integrity: sha512-PUbWd+h/h6rUowalDYIdc9S9LJXbQDMcJe0BjABl3oT3efYRgZ8aUe8ZZDSie7y+fz6Z+rueNfdorIbkWv5Eqg==} 358 | cpu: [arm64] 359 | os: [win32] 360 | 361 | '@rollup/rollup-win32-ia32-msvc@4.34.5': 362 | resolution: {integrity: sha512-3vncGhOJiAUR85fnAXJyvSp2GaDWYByIQmW68ZAr+e8kIxgvJ1VaZbfHD5BO5X6hwRQdY6Um/XfA3l5c2lV+OQ==} 363 | cpu: [ia32] 364 | os: [win32] 365 | 366 | '@rollup/rollup-win32-x64-msvc@4.34.5': 367 | resolution: {integrity: sha512-Mi8yVUlQOoeBpY72n75VLATptPGvj2lHa47rQdK9kZ4MoG5Ve86aVIU+PO3tBklTCBtILtdRfXS0EvIbXgmCAg==} 368 | cpu: [x64] 369 | os: [win32] 370 | 371 | '@shikijs/core@2.3.2': 372 | resolution: {integrity: sha512-s7vyL3LzUKm3Qwf36zRWlavX9BQMZTIq9B1almM63M5xBuSldnsTHCmsXzoF/Kyw4k7Xgas7yAyJz9VR/vcP1A==} 373 | 374 | '@shikijs/engine-javascript@2.3.2': 375 | resolution: {integrity: sha512-w3IEMu5HfL/OaJTsMbIfZ1HRPnWVYRANeDtmsdIIEgUOcLjzFJFQwlnkckGjKHekEzNqlMLbgB/twnfZ/EEAGg==} 376 | 377 | '@shikijs/engine-oniguruma@2.3.2': 378 | resolution: {integrity: sha512-vikMY1TroyZXUHIXbMnvY/mjtOxMn+tavcfAeQPgWS9FHcgFSUoEtywF5B5sOLb9NXb8P2vb7odkh3nj15/00A==} 379 | 380 | '@shikijs/langs@2.3.2': 381 | resolution: {integrity: sha512-UqI6bSxFzhexIJficZLKeB1L2Sc3xoNiAV0yHpfbg5meck93du+EKQtsGbBv66Ki53XZPhnR/kYkOr85elIuFw==} 382 | 383 | '@shikijs/themes@2.3.2': 384 | resolution: {integrity: sha512-QAh7D/hhfYKHibkG2tti8vxNt3ekAH5EqkXJeJbTh7FGvTCWEI7BHqNCtMdjFvZ0vav5nvUgdvA7/HI7pfsB4w==} 385 | 386 | '@shikijs/transformers@2.3.2': 387 | resolution: {integrity: sha512-2HDnJumw8A/9GecRpTgvfqSbPjEbJ4DPWq5J++OVP1gNMLvbV0MqFsP4canqRNM1LqB7VmWY45Stipb0ZIJ+0A==} 388 | 389 | '@shikijs/types@2.3.2': 390 | resolution: {integrity: sha512-CBaMY+a3pepyC4SETi7+bSzO0f6hxEQJUUuS4uD7zppzjmrN4ZRtBqxaT+wOan26CR9eeJ5iBhc4qvWEwn7Eeg==} 391 | 392 | '@shikijs/vscode-textmate@10.0.1': 393 | resolution: {integrity: sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg==} 394 | 395 | '@types/estree@1.0.6': 396 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 397 | 398 | '@types/hast@3.0.4': 399 | resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} 400 | 401 | '@types/linkify-it@5.0.0': 402 | resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} 403 | 404 | '@types/markdown-it@14.1.2': 405 | resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} 406 | 407 | '@types/mdast@4.0.4': 408 | resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} 409 | 410 | '@types/mdurl@2.0.0': 411 | resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} 412 | 413 | '@types/unist@3.0.3': 414 | resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} 415 | 416 | '@types/web-bluetooth@0.0.20': 417 | resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} 418 | 419 | '@ungap/structured-clone@1.3.0': 420 | resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} 421 | 422 | '@vitejs/plugin-vue@5.2.1': 423 | resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==} 424 | engines: {node: ^18.0.0 || >=20.0.0} 425 | peerDependencies: 426 | vite: ^5.0.0 || ^6.0.0 427 | vue: ^3.2.25 428 | 429 | '@vue/compiler-core@3.5.13': 430 | resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} 431 | 432 | '@vue/compiler-dom@3.5.13': 433 | resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} 434 | 435 | '@vue/compiler-sfc@3.5.13': 436 | resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} 437 | 438 | '@vue/compiler-ssr@3.5.13': 439 | resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} 440 | 441 | '@vue/devtools-api@7.7.1': 442 | resolution: {integrity: sha512-Cexc8GimowoDkJ6eNelOPdYIzsu2mgNyp0scOQ3tiaYSb9iok6LOESSsJvHaI+ib3joRfqRJNLkHFjhNuWA5dg==} 443 | 444 | '@vue/devtools-kit@7.7.1': 445 | resolution: {integrity: sha512-yhZ4NPnK/tmxGtLNQxmll90jIIXdb2jAhPF76anvn5M/UkZCiLJy28bYgPIACKZ7FCosyKoaope89/RsFJll1w==} 446 | 447 | '@vue/devtools-shared@7.7.1': 448 | resolution: {integrity: sha512-BtgF7kHq4BHG23Lezc/3W2UhK2ga7a8ohAIAGJMBr4BkxUFzhqntQtCiuL1ijo2ztWnmusymkirgqUrXoQKumA==} 449 | 450 | '@vue/reactivity@3.5.13': 451 | resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} 452 | 453 | '@vue/runtime-core@3.5.13': 454 | resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} 455 | 456 | '@vue/runtime-dom@3.5.13': 457 | resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} 458 | 459 | '@vue/server-renderer@3.5.13': 460 | resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} 461 | peerDependencies: 462 | vue: 3.5.13 463 | 464 | '@vue/shared@3.5.13': 465 | resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} 466 | 467 | '@vueuse/core@12.5.0': 468 | resolution: {integrity: sha512-GVyH1iYqNANwcahAx8JBm6awaNgvR/SwZ1fjr10b8l1HIgDp82ngNbfzJUgOgWEoxjL+URAggnlilAEXwCOZtg==} 469 | 470 | '@vueuse/integrations@12.5.0': 471 | resolution: {integrity: sha512-HYLt8M6mjUfcoUOzyBcX2RjpfapIwHPBmQJtTmXOQW845Y/Osu9VuTJ5kPvnmWJ6IUa05WpblfOwZ+P0G4iZsQ==} 472 | peerDependencies: 473 | async-validator: ^4 474 | axios: ^1 475 | change-case: ^5 476 | drauu: ^0.4 477 | focus-trap: ^7 478 | fuse.js: ^7 479 | idb-keyval: ^6 480 | jwt-decode: ^4 481 | nprogress: ^0.2 482 | qrcode: ^1.5 483 | sortablejs: ^1 484 | universal-cookie: ^7 485 | peerDependenciesMeta: 486 | async-validator: 487 | optional: true 488 | axios: 489 | optional: true 490 | change-case: 491 | optional: true 492 | drauu: 493 | optional: true 494 | focus-trap: 495 | optional: true 496 | fuse.js: 497 | optional: true 498 | idb-keyval: 499 | optional: true 500 | jwt-decode: 501 | optional: true 502 | nprogress: 503 | optional: true 504 | qrcode: 505 | optional: true 506 | sortablejs: 507 | optional: true 508 | universal-cookie: 509 | optional: true 510 | 511 | '@vueuse/metadata@12.5.0': 512 | resolution: {integrity: sha512-Ui7Lo2a7AxrMAXRF+fAp9QsXuwTeeZ8fIB9wsLHqzq9MQk+2gMYE2IGJW48VMJ8ecvCB3z3GsGLKLbSasQ5Qlg==} 513 | 514 | '@vueuse/shared@12.5.0': 515 | resolution: {integrity: sha512-vMpcL1lStUU6O+kdj6YdHDixh0odjPAUM15uJ9f7MY781jcYkIwFA4iv2EfoIPO6vBmvutI1HxxAwmf0cx5ISQ==} 516 | 517 | algoliasearch@5.20.1: 518 | resolution: {integrity: sha512-SiCOCVBCQUg/aWkfMnjT+8TQxNNFlPZTI7v8y4+aZXzJg6zDIzKy9KcYVS4sc+xk5cwW5hyJ+9z836f4+wvgzA==} 519 | engines: {node: '>= 14.0.0'} 520 | 521 | birpc@0.2.19: 522 | resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==} 523 | 524 | ccount@2.0.1: 525 | resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} 526 | 527 | character-entities-html4@2.1.0: 528 | resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} 529 | 530 | character-entities-legacy@3.0.0: 531 | resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} 532 | 533 | comma-separated-tokens@2.0.3: 534 | resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} 535 | 536 | copy-anything@3.0.5: 537 | resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} 538 | engines: {node: '>=12.13'} 539 | 540 | csstype@3.1.3: 541 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 542 | 543 | dequal@2.0.3: 544 | resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 545 | engines: {node: '>=6'} 546 | 547 | devlop@1.1.0: 548 | resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} 549 | 550 | emoji-regex-xs@1.0.0: 551 | resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} 552 | 553 | entities@4.5.0: 554 | resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} 555 | engines: {node: '>=0.12'} 556 | 557 | esbuild@0.21.5: 558 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 559 | engines: {node: '>=12'} 560 | hasBin: true 561 | 562 | estree-walker@2.0.2: 563 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 564 | 565 | focus-trap@7.6.4: 566 | resolution: {integrity: sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==} 567 | 568 | fsevents@2.3.3: 569 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 570 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 571 | os: [darwin] 572 | 573 | hast-util-to-html@9.0.4: 574 | resolution: {integrity: sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==} 575 | 576 | hast-util-whitespace@3.0.0: 577 | resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} 578 | 579 | hookable@5.5.3: 580 | resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} 581 | 582 | html-void-elements@3.0.0: 583 | resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} 584 | 585 | is-what@4.1.16: 586 | resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} 587 | engines: {node: '>=12.13'} 588 | 589 | magic-string@0.30.17: 590 | resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} 591 | 592 | mark.js@8.11.1: 593 | resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} 594 | 595 | mdast-util-to-hast@13.2.0: 596 | resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} 597 | 598 | micromark-util-character@2.1.1: 599 | resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} 600 | 601 | micromark-util-encode@2.0.1: 602 | resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} 603 | 604 | micromark-util-sanitize-uri@2.0.1: 605 | resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} 606 | 607 | micromark-util-symbol@2.0.1: 608 | resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} 609 | 610 | micromark-util-types@2.0.1: 611 | resolution: {integrity: sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==} 612 | 613 | minisearch@7.1.1: 614 | resolution: {integrity: sha512-b3YZEYCEH4EdCAtYP7OlDyx7FdPwNzuNwLQ34SfJpM9dlbBZzeXndGavTrC+VCiRWomL21SWfMc6SCKO/U2ZNw==} 615 | 616 | mitt@3.0.1: 617 | resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} 618 | 619 | nanoid@3.3.8: 620 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 621 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 622 | hasBin: true 623 | 624 | oniguruma-to-es@3.1.0: 625 | resolution: {integrity: sha512-BJ3Jy22YlgejHSO7Fvmz1kKazlaPmRSUH+4adTDUS/dKQ4wLxI+gALZ8updbaux7/m7fIlpgOZ5fp/Inq5jUAw==} 626 | 627 | perfect-debounce@1.0.0: 628 | resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} 629 | 630 | picocolors@1.1.1: 631 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 632 | 633 | postcss@8.5.1: 634 | resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} 635 | engines: {node: ^10 || ^12 || >=14} 636 | 637 | preact@10.25.4: 638 | resolution: {integrity: sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==} 639 | 640 | property-information@6.5.0: 641 | resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} 642 | 643 | regex-recursion@6.0.2: 644 | resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} 645 | 646 | regex-utilities@2.3.0: 647 | resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} 648 | 649 | regex@6.0.1: 650 | resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} 651 | 652 | rfdc@1.4.1: 653 | resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} 654 | 655 | rollup@4.34.5: 656 | resolution: {integrity: sha512-GyVCmpo9z/HYqFD8QWoBUnz1Q9xC22t8tPAZm/AvAcUg2U2/+DkboEvSioMwv042zE4I9N3FEhx7fiCT2YHzKQ==} 657 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 658 | hasBin: true 659 | 660 | search-insights@2.17.2: 661 | resolution: {integrity: sha512-zFNpOpUO+tY2D85KrxJ+aqwnIfdEGi06UH2+xEb+Bp9Mwznmauqc9djbnBibJO5mpfUPPa8st6Sx65+vbeO45g==} 662 | 663 | shiki@2.3.2: 664 | resolution: {integrity: sha512-UZhz/gsUz7DHFbQBOJP7eXqvKyYvMGramxQiSDc83M/7OkWm6OdVHAReEc3vMLh6L6TRhgL9dvhXz9XDkCDaaw==} 665 | 666 | source-map-js@1.2.1: 667 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 668 | engines: {node: '>=0.10.0'} 669 | 670 | space-separated-tokens@2.0.2: 671 | resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} 672 | 673 | speakingurl@14.0.1: 674 | resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} 675 | engines: {node: '>=0.10.0'} 676 | 677 | stringify-entities@4.0.4: 678 | resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} 679 | 680 | superjson@2.2.2: 681 | resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} 682 | engines: {node: '>=16'} 683 | 684 | tabbable@6.2.0: 685 | resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} 686 | 687 | trim-lines@3.0.1: 688 | resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} 689 | 690 | unist-util-is@6.0.0: 691 | resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} 692 | 693 | unist-util-position@5.0.0: 694 | resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} 695 | 696 | unist-util-stringify-position@4.0.0: 697 | resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} 698 | 699 | unist-util-visit-parents@6.0.1: 700 | resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} 701 | 702 | unist-util-visit@5.0.0: 703 | resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} 704 | 705 | vfile-message@4.0.2: 706 | resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} 707 | 708 | vfile@6.0.3: 709 | resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} 710 | 711 | vite@5.4.14: 712 | resolution: {integrity: sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==} 713 | engines: {node: ^18.0.0 || >=20.0.0} 714 | hasBin: true 715 | peerDependencies: 716 | '@types/node': ^18.0.0 || >=20.0.0 717 | less: '*' 718 | lightningcss: ^1.21.0 719 | sass: '*' 720 | sass-embedded: '*' 721 | stylus: '*' 722 | sugarss: '*' 723 | terser: ^5.4.0 724 | peerDependenciesMeta: 725 | '@types/node': 726 | optional: true 727 | less: 728 | optional: true 729 | lightningcss: 730 | optional: true 731 | sass: 732 | optional: true 733 | sass-embedded: 734 | optional: true 735 | stylus: 736 | optional: true 737 | sugarss: 738 | optional: true 739 | terser: 740 | optional: true 741 | 742 | vitepress@1.6.3: 743 | resolution: {integrity: sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw==} 744 | hasBin: true 745 | peerDependencies: 746 | markdown-it-mathjax3: ^4 747 | postcss: ^8 748 | peerDependenciesMeta: 749 | markdown-it-mathjax3: 750 | optional: true 751 | postcss: 752 | optional: true 753 | 754 | vue@3.5.13: 755 | resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} 756 | peerDependencies: 757 | typescript: '*' 758 | peerDependenciesMeta: 759 | typescript: 760 | optional: true 761 | 762 | zwitch@2.0.4: 763 | resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} 764 | 765 | snapshots: 766 | 767 | '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1)(search-insights@2.17.2)': 768 | dependencies: 769 | '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1)(search-insights@2.17.2) 770 | '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1) 771 | transitivePeerDependencies: 772 | - '@algolia/client-search' 773 | - algoliasearch 774 | - search-insights 775 | 776 | '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1)(search-insights@2.17.2)': 777 | dependencies: 778 | '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1) 779 | search-insights: 2.17.2 780 | transitivePeerDependencies: 781 | - '@algolia/client-search' 782 | - algoliasearch 783 | 784 | '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1)': 785 | dependencies: 786 | '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1) 787 | '@algolia/client-search': 5.20.1 788 | algoliasearch: 5.20.1 789 | 790 | '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1)': 791 | dependencies: 792 | '@algolia/client-search': 5.20.1 793 | algoliasearch: 5.20.1 794 | 795 | '@algolia/client-abtesting@5.20.1': 796 | dependencies: 797 | '@algolia/client-common': 5.20.1 798 | '@algolia/requester-browser-xhr': 5.20.1 799 | '@algolia/requester-fetch': 5.20.1 800 | '@algolia/requester-node-http': 5.20.1 801 | 802 | '@algolia/client-analytics@5.20.1': 803 | dependencies: 804 | '@algolia/client-common': 5.20.1 805 | '@algolia/requester-browser-xhr': 5.20.1 806 | '@algolia/requester-fetch': 5.20.1 807 | '@algolia/requester-node-http': 5.20.1 808 | 809 | '@algolia/client-common@5.20.1': {} 810 | 811 | '@algolia/client-insights@5.20.1': 812 | dependencies: 813 | '@algolia/client-common': 5.20.1 814 | '@algolia/requester-browser-xhr': 5.20.1 815 | '@algolia/requester-fetch': 5.20.1 816 | '@algolia/requester-node-http': 5.20.1 817 | 818 | '@algolia/client-personalization@5.20.1': 819 | dependencies: 820 | '@algolia/client-common': 5.20.1 821 | '@algolia/requester-browser-xhr': 5.20.1 822 | '@algolia/requester-fetch': 5.20.1 823 | '@algolia/requester-node-http': 5.20.1 824 | 825 | '@algolia/client-query-suggestions@5.20.1': 826 | dependencies: 827 | '@algolia/client-common': 5.20.1 828 | '@algolia/requester-browser-xhr': 5.20.1 829 | '@algolia/requester-fetch': 5.20.1 830 | '@algolia/requester-node-http': 5.20.1 831 | 832 | '@algolia/client-search@5.20.1': 833 | dependencies: 834 | '@algolia/client-common': 5.20.1 835 | '@algolia/requester-browser-xhr': 5.20.1 836 | '@algolia/requester-fetch': 5.20.1 837 | '@algolia/requester-node-http': 5.20.1 838 | 839 | '@algolia/ingestion@1.20.1': 840 | dependencies: 841 | '@algolia/client-common': 5.20.1 842 | '@algolia/requester-browser-xhr': 5.20.1 843 | '@algolia/requester-fetch': 5.20.1 844 | '@algolia/requester-node-http': 5.20.1 845 | 846 | '@algolia/monitoring@1.20.1': 847 | dependencies: 848 | '@algolia/client-common': 5.20.1 849 | '@algolia/requester-browser-xhr': 5.20.1 850 | '@algolia/requester-fetch': 5.20.1 851 | '@algolia/requester-node-http': 5.20.1 852 | 853 | '@algolia/recommend@5.20.1': 854 | dependencies: 855 | '@algolia/client-common': 5.20.1 856 | '@algolia/requester-browser-xhr': 5.20.1 857 | '@algolia/requester-fetch': 5.20.1 858 | '@algolia/requester-node-http': 5.20.1 859 | 860 | '@algolia/requester-browser-xhr@5.20.1': 861 | dependencies: 862 | '@algolia/client-common': 5.20.1 863 | 864 | '@algolia/requester-fetch@5.20.1': 865 | dependencies: 866 | '@algolia/client-common': 5.20.1 867 | 868 | '@algolia/requester-node-http@5.20.1': 869 | dependencies: 870 | '@algolia/client-common': 5.20.1 871 | 872 | '@babel/helper-string-parser@7.25.9': {} 873 | 874 | '@babel/helper-validator-identifier@7.25.9': {} 875 | 876 | '@babel/parser@7.26.7': 877 | dependencies: 878 | '@babel/types': 7.26.7 879 | 880 | '@babel/types@7.26.7': 881 | dependencies: 882 | '@babel/helper-string-parser': 7.25.9 883 | '@babel/helper-validator-identifier': 7.25.9 884 | 885 | '@docsearch/css@3.8.2': {} 886 | 887 | '@docsearch/js@3.8.2(@algolia/client-search@5.20.1)(search-insights@2.17.2)': 888 | dependencies: 889 | '@docsearch/react': 3.8.2(@algolia/client-search@5.20.1)(search-insights@2.17.2) 890 | preact: 10.25.4 891 | transitivePeerDependencies: 892 | - '@algolia/client-search' 893 | - '@types/react' 894 | - react 895 | - react-dom 896 | - search-insights 897 | 898 | '@docsearch/react@3.8.2(@algolia/client-search@5.20.1)(search-insights@2.17.2)': 899 | dependencies: 900 | '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1)(search-insights@2.17.2) 901 | '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.20.1)(algoliasearch@5.20.1) 902 | '@docsearch/css': 3.8.2 903 | algoliasearch: 5.20.1 904 | optionalDependencies: 905 | search-insights: 2.17.2 906 | transitivePeerDependencies: 907 | - '@algolia/client-search' 908 | 909 | '@esbuild/aix-ppc64@0.21.5': 910 | optional: true 911 | 912 | '@esbuild/android-arm64@0.21.5': 913 | optional: true 914 | 915 | '@esbuild/android-arm@0.21.5': 916 | optional: true 917 | 918 | '@esbuild/android-x64@0.21.5': 919 | optional: true 920 | 921 | '@esbuild/darwin-arm64@0.21.5': 922 | optional: true 923 | 924 | '@esbuild/darwin-x64@0.21.5': 925 | optional: true 926 | 927 | '@esbuild/freebsd-arm64@0.21.5': 928 | optional: true 929 | 930 | '@esbuild/freebsd-x64@0.21.5': 931 | optional: true 932 | 933 | '@esbuild/linux-arm64@0.21.5': 934 | optional: true 935 | 936 | '@esbuild/linux-arm@0.21.5': 937 | optional: true 938 | 939 | '@esbuild/linux-ia32@0.21.5': 940 | optional: true 941 | 942 | '@esbuild/linux-loong64@0.21.5': 943 | optional: true 944 | 945 | '@esbuild/linux-mips64el@0.21.5': 946 | optional: true 947 | 948 | '@esbuild/linux-ppc64@0.21.5': 949 | optional: true 950 | 951 | '@esbuild/linux-riscv64@0.21.5': 952 | optional: true 953 | 954 | '@esbuild/linux-s390x@0.21.5': 955 | optional: true 956 | 957 | '@esbuild/linux-x64@0.21.5': 958 | optional: true 959 | 960 | '@esbuild/netbsd-x64@0.21.5': 961 | optional: true 962 | 963 | '@esbuild/openbsd-x64@0.21.5': 964 | optional: true 965 | 966 | '@esbuild/sunos-x64@0.21.5': 967 | optional: true 968 | 969 | '@esbuild/win32-arm64@0.21.5': 970 | optional: true 971 | 972 | '@esbuild/win32-ia32@0.21.5': 973 | optional: true 974 | 975 | '@esbuild/win32-x64@0.21.5': 976 | optional: true 977 | 978 | '@iconify-json/simple-icons@1.2.23': 979 | dependencies: 980 | '@iconify/types': 2.0.0 981 | 982 | '@iconify/types@2.0.0': {} 983 | 984 | '@jridgewell/sourcemap-codec@1.5.0': {} 985 | 986 | '@rollup/rollup-android-arm-eabi@4.34.5': 987 | optional: true 988 | 989 | '@rollup/rollup-android-arm64@4.34.5': 990 | optional: true 991 | 992 | '@rollup/rollup-darwin-arm64@4.34.5': 993 | optional: true 994 | 995 | '@rollup/rollup-darwin-x64@4.34.5': 996 | optional: true 997 | 998 | '@rollup/rollup-freebsd-arm64@4.34.5': 999 | optional: true 1000 | 1001 | '@rollup/rollup-freebsd-x64@4.34.5': 1002 | optional: true 1003 | 1004 | '@rollup/rollup-linux-arm-gnueabihf@4.34.5': 1005 | optional: true 1006 | 1007 | '@rollup/rollup-linux-arm-musleabihf@4.34.5': 1008 | optional: true 1009 | 1010 | '@rollup/rollup-linux-arm64-gnu@4.34.5': 1011 | optional: true 1012 | 1013 | '@rollup/rollup-linux-arm64-musl@4.34.5': 1014 | optional: true 1015 | 1016 | '@rollup/rollup-linux-loongarch64-gnu@4.34.5': 1017 | optional: true 1018 | 1019 | '@rollup/rollup-linux-powerpc64le-gnu@4.34.5': 1020 | optional: true 1021 | 1022 | '@rollup/rollup-linux-riscv64-gnu@4.34.5': 1023 | optional: true 1024 | 1025 | '@rollup/rollup-linux-s390x-gnu@4.34.5': 1026 | optional: true 1027 | 1028 | '@rollup/rollup-linux-x64-gnu@4.34.5': 1029 | optional: true 1030 | 1031 | '@rollup/rollup-linux-x64-musl@4.34.5': 1032 | optional: true 1033 | 1034 | '@rollup/rollup-win32-arm64-msvc@4.34.5': 1035 | optional: true 1036 | 1037 | '@rollup/rollup-win32-ia32-msvc@4.34.5': 1038 | optional: true 1039 | 1040 | '@rollup/rollup-win32-x64-msvc@4.34.5': 1041 | optional: true 1042 | 1043 | '@shikijs/core@2.3.2': 1044 | dependencies: 1045 | '@shikijs/engine-javascript': 2.3.2 1046 | '@shikijs/engine-oniguruma': 2.3.2 1047 | '@shikijs/types': 2.3.2 1048 | '@shikijs/vscode-textmate': 10.0.1 1049 | '@types/hast': 3.0.4 1050 | hast-util-to-html: 9.0.4 1051 | 1052 | '@shikijs/engine-javascript@2.3.2': 1053 | dependencies: 1054 | '@shikijs/types': 2.3.2 1055 | '@shikijs/vscode-textmate': 10.0.1 1056 | oniguruma-to-es: 3.1.0 1057 | 1058 | '@shikijs/engine-oniguruma@2.3.2': 1059 | dependencies: 1060 | '@shikijs/types': 2.3.2 1061 | '@shikijs/vscode-textmate': 10.0.1 1062 | 1063 | '@shikijs/langs@2.3.2': 1064 | dependencies: 1065 | '@shikijs/types': 2.3.2 1066 | 1067 | '@shikijs/themes@2.3.2': 1068 | dependencies: 1069 | '@shikijs/types': 2.3.2 1070 | 1071 | '@shikijs/transformers@2.3.2': 1072 | dependencies: 1073 | '@shikijs/core': 2.3.2 1074 | '@shikijs/types': 2.3.2 1075 | 1076 | '@shikijs/types@2.3.2': 1077 | dependencies: 1078 | '@shikijs/vscode-textmate': 10.0.1 1079 | '@types/hast': 3.0.4 1080 | 1081 | '@shikijs/vscode-textmate@10.0.1': {} 1082 | 1083 | '@types/estree@1.0.6': {} 1084 | 1085 | '@types/hast@3.0.4': 1086 | dependencies: 1087 | '@types/unist': 3.0.3 1088 | 1089 | '@types/linkify-it@5.0.0': {} 1090 | 1091 | '@types/markdown-it@14.1.2': 1092 | dependencies: 1093 | '@types/linkify-it': 5.0.0 1094 | '@types/mdurl': 2.0.0 1095 | 1096 | '@types/mdast@4.0.4': 1097 | dependencies: 1098 | '@types/unist': 3.0.3 1099 | 1100 | '@types/mdurl@2.0.0': {} 1101 | 1102 | '@types/unist@3.0.3': {} 1103 | 1104 | '@types/web-bluetooth@0.0.20': {} 1105 | 1106 | '@ungap/structured-clone@1.3.0': {} 1107 | 1108 | '@vitejs/plugin-vue@5.2.1(vite@5.4.14)(vue@3.5.13)': 1109 | dependencies: 1110 | vite: 5.4.14 1111 | vue: 3.5.13 1112 | 1113 | '@vue/compiler-core@3.5.13': 1114 | dependencies: 1115 | '@babel/parser': 7.26.7 1116 | '@vue/shared': 3.5.13 1117 | entities: 4.5.0 1118 | estree-walker: 2.0.2 1119 | source-map-js: 1.2.1 1120 | 1121 | '@vue/compiler-dom@3.5.13': 1122 | dependencies: 1123 | '@vue/compiler-core': 3.5.13 1124 | '@vue/shared': 3.5.13 1125 | 1126 | '@vue/compiler-sfc@3.5.13': 1127 | dependencies: 1128 | '@babel/parser': 7.26.7 1129 | '@vue/compiler-core': 3.5.13 1130 | '@vue/compiler-dom': 3.5.13 1131 | '@vue/compiler-ssr': 3.5.13 1132 | '@vue/shared': 3.5.13 1133 | estree-walker: 2.0.2 1134 | magic-string: 0.30.17 1135 | postcss: 8.5.1 1136 | source-map-js: 1.2.1 1137 | 1138 | '@vue/compiler-ssr@3.5.13': 1139 | dependencies: 1140 | '@vue/compiler-dom': 3.5.13 1141 | '@vue/shared': 3.5.13 1142 | 1143 | '@vue/devtools-api@7.7.1': 1144 | dependencies: 1145 | '@vue/devtools-kit': 7.7.1 1146 | 1147 | '@vue/devtools-kit@7.7.1': 1148 | dependencies: 1149 | '@vue/devtools-shared': 7.7.1 1150 | birpc: 0.2.19 1151 | hookable: 5.5.3 1152 | mitt: 3.0.1 1153 | perfect-debounce: 1.0.0 1154 | speakingurl: 14.0.1 1155 | superjson: 2.2.2 1156 | 1157 | '@vue/devtools-shared@7.7.1': 1158 | dependencies: 1159 | rfdc: 1.4.1 1160 | 1161 | '@vue/reactivity@3.5.13': 1162 | dependencies: 1163 | '@vue/shared': 3.5.13 1164 | 1165 | '@vue/runtime-core@3.5.13': 1166 | dependencies: 1167 | '@vue/reactivity': 3.5.13 1168 | '@vue/shared': 3.5.13 1169 | 1170 | '@vue/runtime-dom@3.5.13': 1171 | dependencies: 1172 | '@vue/reactivity': 3.5.13 1173 | '@vue/runtime-core': 3.5.13 1174 | '@vue/shared': 3.5.13 1175 | csstype: 3.1.3 1176 | 1177 | '@vue/server-renderer@3.5.13(vue@3.5.13)': 1178 | dependencies: 1179 | '@vue/compiler-ssr': 3.5.13 1180 | '@vue/shared': 3.5.13 1181 | vue: 3.5.13 1182 | 1183 | '@vue/shared@3.5.13': {} 1184 | 1185 | '@vueuse/core@12.5.0': 1186 | dependencies: 1187 | '@types/web-bluetooth': 0.0.20 1188 | '@vueuse/metadata': 12.5.0 1189 | '@vueuse/shared': 12.5.0 1190 | vue: 3.5.13 1191 | transitivePeerDependencies: 1192 | - typescript 1193 | 1194 | '@vueuse/integrations@12.5.0(focus-trap@7.6.4)': 1195 | dependencies: 1196 | '@vueuse/core': 12.5.0 1197 | '@vueuse/shared': 12.5.0 1198 | vue: 3.5.13 1199 | optionalDependencies: 1200 | focus-trap: 7.6.4 1201 | transitivePeerDependencies: 1202 | - typescript 1203 | 1204 | '@vueuse/metadata@12.5.0': {} 1205 | 1206 | '@vueuse/shared@12.5.0': 1207 | dependencies: 1208 | vue: 3.5.13 1209 | transitivePeerDependencies: 1210 | - typescript 1211 | 1212 | algoliasearch@5.20.1: 1213 | dependencies: 1214 | '@algolia/client-abtesting': 5.20.1 1215 | '@algolia/client-analytics': 5.20.1 1216 | '@algolia/client-common': 5.20.1 1217 | '@algolia/client-insights': 5.20.1 1218 | '@algolia/client-personalization': 5.20.1 1219 | '@algolia/client-query-suggestions': 5.20.1 1220 | '@algolia/client-search': 5.20.1 1221 | '@algolia/ingestion': 1.20.1 1222 | '@algolia/monitoring': 1.20.1 1223 | '@algolia/recommend': 5.20.1 1224 | '@algolia/requester-browser-xhr': 5.20.1 1225 | '@algolia/requester-fetch': 5.20.1 1226 | '@algolia/requester-node-http': 5.20.1 1227 | 1228 | birpc@0.2.19: {} 1229 | 1230 | ccount@2.0.1: {} 1231 | 1232 | character-entities-html4@2.1.0: {} 1233 | 1234 | character-entities-legacy@3.0.0: {} 1235 | 1236 | comma-separated-tokens@2.0.3: {} 1237 | 1238 | copy-anything@3.0.5: 1239 | dependencies: 1240 | is-what: 4.1.16 1241 | 1242 | csstype@3.1.3: {} 1243 | 1244 | dequal@2.0.3: {} 1245 | 1246 | devlop@1.1.0: 1247 | dependencies: 1248 | dequal: 2.0.3 1249 | 1250 | emoji-regex-xs@1.0.0: {} 1251 | 1252 | entities@4.5.0: {} 1253 | 1254 | esbuild@0.21.5: 1255 | optionalDependencies: 1256 | '@esbuild/aix-ppc64': 0.21.5 1257 | '@esbuild/android-arm': 0.21.5 1258 | '@esbuild/android-arm64': 0.21.5 1259 | '@esbuild/android-x64': 0.21.5 1260 | '@esbuild/darwin-arm64': 0.21.5 1261 | '@esbuild/darwin-x64': 0.21.5 1262 | '@esbuild/freebsd-arm64': 0.21.5 1263 | '@esbuild/freebsd-x64': 0.21.5 1264 | '@esbuild/linux-arm': 0.21.5 1265 | '@esbuild/linux-arm64': 0.21.5 1266 | '@esbuild/linux-ia32': 0.21.5 1267 | '@esbuild/linux-loong64': 0.21.5 1268 | '@esbuild/linux-mips64el': 0.21.5 1269 | '@esbuild/linux-ppc64': 0.21.5 1270 | '@esbuild/linux-riscv64': 0.21.5 1271 | '@esbuild/linux-s390x': 0.21.5 1272 | '@esbuild/linux-x64': 0.21.5 1273 | '@esbuild/netbsd-x64': 0.21.5 1274 | '@esbuild/openbsd-x64': 0.21.5 1275 | '@esbuild/sunos-x64': 0.21.5 1276 | '@esbuild/win32-arm64': 0.21.5 1277 | '@esbuild/win32-ia32': 0.21.5 1278 | '@esbuild/win32-x64': 0.21.5 1279 | 1280 | estree-walker@2.0.2: {} 1281 | 1282 | focus-trap@7.6.4: 1283 | dependencies: 1284 | tabbable: 6.2.0 1285 | 1286 | fsevents@2.3.3: 1287 | optional: true 1288 | 1289 | hast-util-to-html@9.0.4: 1290 | dependencies: 1291 | '@types/hast': 3.0.4 1292 | '@types/unist': 3.0.3 1293 | ccount: 2.0.1 1294 | comma-separated-tokens: 2.0.3 1295 | hast-util-whitespace: 3.0.0 1296 | html-void-elements: 3.0.0 1297 | mdast-util-to-hast: 13.2.0 1298 | property-information: 6.5.0 1299 | space-separated-tokens: 2.0.2 1300 | stringify-entities: 4.0.4 1301 | zwitch: 2.0.4 1302 | 1303 | hast-util-whitespace@3.0.0: 1304 | dependencies: 1305 | '@types/hast': 3.0.4 1306 | 1307 | hookable@5.5.3: {} 1308 | 1309 | html-void-elements@3.0.0: {} 1310 | 1311 | is-what@4.1.16: {} 1312 | 1313 | magic-string@0.30.17: 1314 | dependencies: 1315 | '@jridgewell/sourcemap-codec': 1.5.0 1316 | 1317 | mark.js@8.11.1: {} 1318 | 1319 | mdast-util-to-hast@13.2.0: 1320 | dependencies: 1321 | '@types/hast': 3.0.4 1322 | '@types/mdast': 4.0.4 1323 | '@ungap/structured-clone': 1.3.0 1324 | devlop: 1.1.0 1325 | micromark-util-sanitize-uri: 2.0.1 1326 | trim-lines: 3.0.1 1327 | unist-util-position: 5.0.0 1328 | unist-util-visit: 5.0.0 1329 | vfile: 6.0.3 1330 | 1331 | micromark-util-character@2.1.1: 1332 | dependencies: 1333 | micromark-util-symbol: 2.0.1 1334 | micromark-util-types: 2.0.1 1335 | 1336 | micromark-util-encode@2.0.1: {} 1337 | 1338 | micromark-util-sanitize-uri@2.0.1: 1339 | dependencies: 1340 | micromark-util-character: 2.1.1 1341 | micromark-util-encode: 2.0.1 1342 | micromark-util-symbol: 2.0.1 1343 | 1344 | micromark-util-symbol@2.0.1: {} 1345 | 1346 | micromark-util-types@2.0.1: {} 1347 | 1348 | minisearch@7.1.1: {} 1349 | 1350 | mitt@3.0.1: {} 1351 | 1352 | nanoid@3.3.8: {} 1353 | 1354 | oniguruma-to-es@3.1.0: 1355 | dependencies: 1356 | emoji-regex-xs: 1.0.0 1357 | regex: 6.0.1 1358 | regex-recursion: 6.0.2 1359 | 1360 | perfect-debounce@1.0.0: {} 1361 | 1362 | picocolors@1.1.1: {} 1363 | 1364 | postcss@8.5.1: 1365 | dependencies: 1366 | nanoid: 3.3.8 1367 | picocolors: 1.1.1 1368 | source-map-js: 1.2.1 1369 | 1370 | preact@10.25.4: {} 1371 | 1372 | property-information@6.5.0: {} 1373 | 1374 | regex-recursion@6.0.2: 1375 | dependencies: 1376 | regex-utilities: 2.3.0 1377 | 1378 | regex-utilities@2.3.0: {} 1379 | 1380 | regex@6.0.1: 1381 | dependencies: 1382 | regex-utilities: 2.3.0 1383 | 1384 | rfdc@1.4.1: {} 1385 | 1386 | rollup@4.34.5: 1387 | dependencies: 1388 | '@types/estree': 1.0.6 1389 | optionalDependencies: 1390 | '@rollup/rollup-android-arm-eabi': 4.34.5 1391 | '@rollup/rollup-android-arm64': 4.34.5 1392 | '@rollup/rollup-darwin-arm64': 4.34.5 1393 | '@rollup/rollup-darwin-x64': 4.34.5 1394 | '@rollup/rollup-freebsd-arm64': 4.34.5 1395 | '@rollup/rollup-freebsd-x64': 4.34.5 1396 | '@rollup/rollup-linux-arm-gnueabihf': 4.34.5 1397 | '@rollup/rollup-linux-arm-musleabihf': 4.34.5 1398 | '@rollup/rollup-linux-arm64-gnu': 4.34.5 1399 | '@rollup/rollup-linux-arm64-musl': 4.34.5 1400 | '@rollup/rollup-linux-loongarch64-gnu': 4.34.5 1401 | '@rollup/rollup-linux-powerpc64le-gnu': 4.34.5 1402 | '@rollup/rollup-linux-riscv64-gnu': 4.34.5 1403 | '@rollup/rollup-linux-s390x-gnu': 4.34.5 1404 | '@rollup/rollup-linux-x64-gnu': 4.34.5 1405 | '@rollup/rollup-linux-x64-musl': 4.34.5 1406 | '@rollup/rollup-win32-arm64-msvc': 4.34.5 1407 | '@rollup/rollup-win32-ia32-msvc': 4.34.5 1408 | '@rollup/rollup-win32-x64-msvc': 4.34.5 1409 | fsevents: 2.3.3 1410 | 1411 | search-insights@2.17.2: {} 1412 | 1413 | shiki@2.3.2: 1414 | dependencies: 1415 | '@shikijs/core': 2.3.2 1416 | '@shikijs/engine-javascript': 2.3.2 1417 | '@shikijs/engine-oniguruma': 2.3.2 1418 | '@shikijs/langs': 2.3.2 1419 | '@shikijs/themes': 2.3.2 1420 | '@shikijs/types': 2.3.2 1421 | '@shikijs/vscode-textmate': 10.0.1 1422 | '@types/hast': 3.0.4 1423 | 1424 | source-map-js@1.2.1: {} 1425 | 1426 | space-separated-tokens@2.0.2: {} 1427 | 1428 | speakingurl@14.0.1: {} 1429 | 1430 | stringify-entities@4.0.4: 1431 | dependencies: 1432 | character-entities-html4: 2.1.0 1433 | character-entities-legacy: 3.0.0 1434 | 1435 | superjson@2.2.2: 1436 | dependencies: 1437 | copy-anything: 3.0.5 1438 | 1439 | tabbable@6.2.0: {} 1440 | 1441 | trim-lines@3.0.1: {} 1442 | 1443 | unist-util-is@6.0.0: 1444 | dependencies: 1445 | '@types/unist': 3.0.3 1446 | 1447 | unist-util-position@5.0.0: 1448 | dependencies: 1449 | '@types/unist': 3.0.3 1450 | 1451 | unist-util-stringify-position@4.0.0: 1452 | dependencies: 1453 | '@types/unist': 3.0.3 1454 | 1455 | unist-util-visit-parents@6.0.1: 1456 | dependencies: 1457 | '@types/unist': 3.0.3 1458 | unist-util-is: 6.0.0 1459 | 1460 | unist-util-visit@5.0.0: 1461 | dependencies: 1462 | '@types/unist': 3.0.3 1463 | unist-util-is: 6.0.0 1464 | unist-util-visit-parents: 6.0.1 1465 | 1466 | vfile-message@4.0.2: 1467 | dependencies: 1468 | '@types/unist': 3.0.3 1469 | unist-util-stringify-position: 4.0.0 1470 | 1471 | vfile@6.0.3: 1472 | dependencies: 1473 | '@types/unist': 3.0.3 1474 | vfile-message: 4.0.2 1475 | 1476 | vite@5.4.14: 1477 | dependencies: 1478 | esbuild: 0.21.5 1479 | postcss: 8.5.1 1480 | rollup: 4.34.5 1481 | optionalDependencies: 1482 | fsevents: 2.3.3 1483 | 1484 | vitepress@1.6.3(@algolia/client-search@5.20.1)(postcss@8.5.1)(search-insights@2.17.2): 1485 | dependencies: 1486 | '@docsearch/css': 3.8.2 1487 | '@docsearch/js': 3.8.2(@algolia/client-search@5.20.1)(search-insights@2.17.2) 1488 | '@iconify-json/simple-icons': 1.2.23 1489 | '@shikijs/core': 2.3.2 1490 | '@shikijs/transformers': 2.3.2 1491 | '@shikijs/types': 2.3.2 1492 | '@types/markdown-it': 14.1.2 1493 | '@vitejs/plugin-vue': 5.2.1(vite@5.4.14)(vue@3.5.13) 1494 | '@vue/devtools-api': 7.7.1 1495 | '@vue/shared': 3.5.13 1496 | '@vueuse/core': 12.5.0 1497 | '@vueuse/integrations': 12.5.0(focus-trap@7.6.4) 1498 | focus-trap: 7.6.4 1499 | mark.js: 8.11.1 1500 | minisearch: 7.1.1 1501 | shiki: 2.3.2 1502 | vite: 5.4.14 1503 | vue: 3.5.13 1504 | optionalDependencies: 1505 | postcss: 8.5.1 1506 | transitivePeerDependencies: 1507 | - '@algolia/client-search' 1508 | - '@types/node' 1509 | - '@types/react' 1510 | - async-validator 1511 | - axios 1512 | - change-case 1513 | - drauu 1514 | - fuse.js 1515 | - idb-keyval 1516 | - jwt-decode 1517 | - less 1518 | - lightningcss 1519 | - nprogress 1520 | - qrcode 1521 | - react 1522 | - react-dom 1523 | - sass 1524 | - sass-embedded 1525 | - search-insights 1526 | - sortablejs 1527 | - stylus 1528 | - sugarss 1529 | - terser 1530 | - typescript 1531 | - universal-cookie 1532 | 1533 | vue@3.5.13: 1534 | dependencies: 1535 | '@vue/compiler-dom': 3.5.13 1536 | '@vue/compiler-sfc': 3.5.13 1537 | '@vue/runtime-dom': 3.5.13 1538 | '@vue/server-renderer': 3.5.13(vue@3.5.13) 1539 | '@vue/shared': 3.5.13 1540 | 1541 | zwitch@2.0.4: {} 1542 | --------------------------------------------------------------------------------