├── page
├── src
│ ├── vite-env.d.ts
│ ├── App.css
│ ├── index.tsx
│ ├── index.css
│ ├── assets
│ │ └── solid.svg
│ └── App.tsx
├── uno.config.ts
├── vite.config.ts
├── tsconfig.node.json
├── .gitignore
├── index.html
├── package.json
├── tsconfig.json
├── README.md
├── public
│ └── vite.svg
└── pnpm-lock.yaml
├── tasks.sh
├── package.json
├── .gitignore
├── pnpm-lock.yaml
├── .github
└── workflows
│ └── page.yml
├── README.md
├── LICENSE
├── Cargo.toml
├── tasks.mjs
└── src
├── lib.rs
└── worker
├── db.rs
└── main.rs
/page/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/tasks.sh:
--------------------------------------------------------------------------------
1 | cargo build -r
2 | rm -rf .data
3 | rm -rf *.jsonl
4 |
5 | node tasks.mjs
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "chalk": "5.3.0",
4 | "tiny-async-pool": "2.1.0"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/page/uno.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "unocss";
2 |
3 | export default defineConfig({
4 | // ...UnoCSS options
5 | });
6 |
--------------------------------------------------------------------------------
/page/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | padding: 1rem;
3 | }
4 |
5 | .apexcharts-menu.apexcharts-menu-open {
6 | background: #101010 !important;
7 | }
--------------------------------------------------------------------------------
/page/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import solid from "vite-plugin-solid";
3 | import UnoCSS from "unocss/vite";
4 |
5 | export default defineConfig({
6 | plugins: [solid(), UnoCSS()],
7 | base: "/rust-storage-bench/"
8 | });
9 |
--------------------------------------------------------------------------------
/page/src/index.tsx:
--------------------------------------------------------------------------------
1 | /* @refresh reload */
2 |
3 | import "./index.css";
4 | import "virtual:uno.css";
5 |
6 | import { render } from "solid-js/web";
7 | import App from "./App";
8 |
9 | const root = document.getElementById("root")
10 |
11 | render(() => , root!)
12 |
--------------------------------------------------------------------------------
/page/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/page/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 |
8 | font-synthesis: none;
9 | text-rendering: optimizeLegibility;
10 | -webkit-font-smoothing: antialiased;
11 | -moz-osx-font-smoothing: grayscale;
12 | }
13 |
--------------------------------------------------------------------------------
/page/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 | .vite
26 |
--------------------------------------------------------------------------------
/page/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Rust Storage Engine Benchmark
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/page/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "page",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "solid-apexcharts": "0.3.2",
13 | "solid-js": "1.8.5"
14 | },
15 | "devDependencies": {
16 | "typescript": "5.2.2",
17 | "unocss": "0.58.0",
18 | "vite": "4",
19 | "vite-plugin-solid": "2.7.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Generated by Cargo
2 | # will have compiled files and executables
3 | debug/
4 | target/
5 |
6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
8 | Cargo.lock
9 |
10 | # These are backup files generated by rustfmt
11 | **/*.rs.bk
12 |
13 | # MSVC Windows builds of rustc generate these, which store debugging information
14 | *.pdb
15 |
16 | .data
17 | *.jsonl
18 | node_modules
19 | .results
20 |
--------------------------------------------------------------------------------
/page/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "module": "ESNext",
6 | "lib": ["es2022", "DOM", "DOM.Iterable"],
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "preserve",
16 | "jsxImportSource": "solid-js",
17 |
18 | /* Linting */
19 | "strict": true,
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | "noFallthroughCasesInSwitch": true
23 | },
24 | "include": ["src"],
25 | "references": [{ "path": "./tsconfig.node.json" }]
26 | }
27 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | dependencies:
11 | chalk:
12 | specifier: 5.3.0
13 | version: 5.3.0
14 | tiny-async-pool:
15 | specifier: 2.1.0
16 | version: 2.1.0
17 |
18 | packages:
19 |
20 | chalk@5.3.0:
21 | resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
22 | engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
23 |
24 | tiny-async-pool@2.1.0:
25 | resolution: {integrity: sha512-ltAHPh/9k0STRQqaoUX52NH4ZQYAJz24ZAEwf1Zm+HYg3l9OXTWeqWKyYsHu40wF/F0rxd2N2bk5sLvX2qlSvg==}
26 |
27 | snapshots:
28 |
29 | chalk@5.3.0: {}
30 |
31 | tiny-async-pool@2.1.0: {}
32 |
--------------------------------------------------------------------------------
/.github/workflows/page.yml:
--------------------------------------------------------------------------------
1 | name: Deploy page
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v4
13 | - uses: pnpm/action-setup@v2
14 | with:
15 | version: 9
16 | - name: Use Node.js 22
17 | uses: actions/setup-node@v4
18 | with:
19 | node-version: 22
20 | cache: pnpm
21 | cache-dependency-path: page/pnpm-lock.yaml
22 | - name: Install dependencies
23 | run: pnpm i
24 | working-directory: page
25 | - name: Generate page
26 | run: pnpm build
27 | working-directory: page
28 | - name: Deploy page
29 | uses: JamesIves/github-pages-deploy-action@v4
30 | with:
31 | folder: page/dist
32 |
--------------------------------------------------------------------------------
/page/README.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | ```bash
4 | $ npm install # or pnpm install or yarn install
5 | ```
6 |
7 | ### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
8 |
9 | ## Available Scripts
10 |
11 | In the project directory, you can run:
12 |
13 | ### `npm run dev`
14 |
15 | Runs the app in the development mode.
16 | Open [http://localhost:5173](http://localhost:5173) to view it in the browser.
17 |
18 | ### `npm run build`
19 |
20 | Builds the app for production to the `dist` folder.
21 | It correctly bundles Solid in production mode and optimizes the build for the best performance.
22 |
23 | The build is minified and the filenames include the hashes.
24 | Your app is ready to be deployed!
25 |
26 | ## Deployment
27 |
28 | Learn more about deploying your application with the [documentations](https://vitejs.dev/guide/static-deploy.html)
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rust-storage-bench
2 |
3 | Benchmarking Rust storage engines:
4 |
5 | - fjall Δ ★ (https://github.com/fjall-rs/fjall)
6 | - jammdb Ω (https://github.com/pjtatlow/jammdb)
7 | - nebari Ω (https://github.com/khonsulabs/nebari)
8 | - persy Ω ★ (https://persy.rs)
9 | - redb Ω ★ (https://www.redb.org)
10 | - sled Ψ (https://sled.rs)
11 |
12 | Non-Rust (bindings):
13 |
14 | - rocksdb Δ (https://rocksdb.org/)
15 | - heed Ω (https://github.com/meilisearch/heed)
16 |
17 | ---
18 |
19 | - Δ LSM based
20 | - Ω B-tree based
21 | - Ψ Hybrid (Bw-Tree, ...)
22 | - ★ has reached 1.0
23 |
24 | ## Example usage
25 |
26 | ```
27 | cargo build -r
28 | alias bencher='cargo run --bin daemon -r --'
29 |
30 | bencher --out task_e_fjall_lcs.jsonl --workload task-e --backend fjall --minutes 5 --key-size 8 --value-size 256 --items 1000 --cache-size 1000000
31 | ```
32 |
33 | ## Run many benchmarks
34 |
35 | ```
36 | node tasks.mjs <...filter>
37 | ```
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 marvin-j97
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 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rust-storage-bench"
3 | version = "0.0.1"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [[bin]]
9 | name = "worker"
10 | path = "src/worker/main.rs"
11 |
12 | [features]
13 | default = ["heed", "rocksdb"]
14 | rocksdb = ["dep:rocksdb"]
15 | heed = ["dep:heed"]
16 |
17 | # [target.'cfg(not(target_env = "msvc"))'.dependencies]
18 | # jemallocator = "0.3.2"
19 |
20 | [dependencies]
21 | clap = { version = "4.4.10", features = ["derive"] }
22 | # bloodstone = { package = "sled", version = "1.0.0-alpha.121" }
23 | sled = { version = "0.34.7", features = ["compression"] }
24 | fjall = { version = "1.4.0" }
25 | nanoid = "0.4.0"
26 | rand = "0.8.5"
27 | sysinfo = { version = "0.30.1", features = ["serde"] }
28 | serde = { version = "1.0.193", features = ["derive", "rc"] }
29 | serde_json = "1.0.108"
30 | fs_extra = "1.3.0"
31 | env_logger = "0.10.1"
32 | log = { version = "0.4.20", features = ["release_max_level_trace"] }
33 | persy = { version = "1.5.0", features = ["background_ops"] }
34 | jammdb = "0.11.0"
35 | zipf = "7.0.1"
36 | redb = "2.1.1"
37 | nebari = "0.5.5"
38 | heed = { version = "0.20.0", optional = true }
39 | rocksdb = { version = "0.22.0", optional = true, default-features = false, features = [
40 | "lz4",
41 | ] }
42 |
--------------------------------------------------------------------------------
/page/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/page/src/assets/solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tasks.mjs:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | import { spawn } from "node:child_process";
4 | import { existsSync, mkdirSync, rmSync } from "node:fs";
5 | import { resolve } from "node:path";
6 |
7 | import chalk from "chalk";
8 | import asyncPool from "tiny-async-pool";
9 |
10 | if (existsSync(".data")) {
11 | rmSync(".data", {
12 | recursive: true,
13 | });
14 | }
15 |
16 | /* const CLEAN_DATA_FOLDER_AFTER_EACH_TASK = true; */
17 | const PARALLELISM = 1;
18 |
19 | const steps = [
20 | {
21 | tasks: ["d", "e", "f", "g", "h"],
22 | backends: ["fjall_lcs", "fjall_stcs", "persy", "redb", "sled"],
23 | minutes: 5,
24 | outFolder: ".results/nosync/5m/low_cache",
25 | fsync: false,
26 | valueSize: 128,
27 | cacheSize: 128_000,
28 | },
29 | {
30 | tasks: ["d", "e", "f", "g", "h"],
31 | backends: ["fjall_lcs", "fjall_stcs", "persy", "redb", "sled"],
32 | minutes: 5,
33 | outFolder: ".results/nosync/5m/high_cache",
34 | fsync: false,
35 | valueSize: 128,
36 | cacheSize: 32_000_000,
37 | },
38 | ]
39 |
40 | for (const config of steps) {
41 | let tasks = [];
42 |
43 | for (const task of config.tasks) {
44 | for (const backend of config.backends) {
45 | const args = [
46 | ...(config.fsync ? ["--fsync"] : []),
47 | ...["--threads", "1"],
48 | ...["--minutes", config.minutes],
49 | ...["--key-size", 8],
50 | ...["--value-size", config.valueSize],
51 | ...["--items", 100],
52 | ...["--cache-size", config.cacheSize],
53 | ...["--lsm-block-size", config.blockSize ?? 4_096],
54 | ];
55 |
56 | const folder = resolve(config.outFolder, `task_${task}`);
57 | const out = resolve(folder, `${backend}.jsonl`);
58 | mkdirSync(folder, { recursive: true });
59 |
60 | if (backend === "fjall_stcs") {
61 | args.push("--lsm-compaction", "tiered");
62 | }
63 |
64 | const be = backend.startsWith("fjall_") ? "fjall" : backend;
65 |
66 | args.push(
67 | ...["--out", out],
68 | ...["--workload", `task-${task}`],
69 | ...["--backend", be]
70 | );
71 |
72 | tasks.push(
73 | args
74 | );
75 | }
76 | }
77 |
78 | console.log("Running tasks", tasks.map(x => x.join(" ")));
79 |
80 | async function processTask(task) {
81 | await new Promise((resolve, reject) => {
82 | const args = ["run", "-r", "--", ...task];
83 |
84 | console.error(
85 | chalk.blueBright(`Spawning: cargo ${args.join(" ")}`)
86 | );
87 |
88 | const childProcess = spawn("cargo", args, {
89 | shell: true,
90 | stdio: "pipe"
91 | });
92 | childProcess.stdout.on("data", (buf) => console.log(
93 | chalk.grey(`${String(buf)}`)
94 | ));
95 | childProcess.stderr.on("data", (buf) => console.error(
96 | chalk.yellow(`${String(buf)}`)
97 | ));
98 |
99 | // @ts-ignore
100 | childProcess.on('exit', () => resolve());
101 | childProcess.on('error', reject);
102 | });
103 |
104 | // TODO: need to only delete subfolder of specific task
105 | // TODO: also each invocation needs its own .data subfolder...
106 | /* if (CLEAN_DATA_FOLDER_AFTER_EACH_TASK) {
107 | if (existsSync(".data")) {
108 | rmSync(".data", {
109 | recursive: true,
110 | });
111 | }
112 | } */
113 |
114 | return task;
115 | }
116 |
117 | // Filter out sled, if fsync, because it doesn't actually call fsync??? UNLESS it's Workload C (read-only)
118 | if (config.fsync) {
119 | tasks = tasks.filter(args => ["sled", "bloodstone"].every(term => (args.join(" ")).includes("task_c") || !(args.join(" ")).includes(term)));
120 | }
121 | else {
122 | // Filter out jammdb & nebari, if !fsync, because they always fsync??? UNLESS it's Workload C (read-only)
123 | tasks = tasks.filter(args => ["jamm", "nebari"].every(term => (args.join(" ")).includes("task_c") || !(args.join(" ")).includes(term)));
124 | }
125 |
126 | for await (const name of asyncPool(PARALLELISM, tasks, processTask)) {
127 | console.log(
128 | chalk.greenBright(`${name.join(" ")} done`)
129 | );
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | use clap::{Parser, ValueEnum};
2 | use serde::Serialize;
3 |
4 | #[derive(Copy, Eq, PartialEq, Debug, Clone, ValueEnum, Serialize)]
5 | #[clap(rename_all = "kebab_case")]
6 | pub enum Backend {
7 | Sled,
8 | // Bloodstone,
9 | Fjall,
10 | Persy,
11 | JammDb,
12 | Redb,
13 | Nebari,
14 |
15 | #[cfg(feature = "heed")]
16 | Heed,
17 |
18 | #[cfg(feature = "rocksdb")]
19 | RocksDb,
20 | }
21 |
22 | impl std::fmt::Display for Backend {
23 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 | write!(
25 | f,
26 | "{}",
27 | match self {
28 | Self::Sled => "sled 0.34.7",
29 | // Self::Bloodstone => "sled 1.0.0-alpha.118",
30 | Self::Fjall => "fjall 1.4.0",
31 | Self::Persy => "persy 1.5.0",
32 | Self::JammDb => "jammdb 0.11.0",
33 | Self::Redb => "redb 2.1.1",
34 | Self::Nebari => "nebari 0.5.5",
35 |
36 | #[cfg(feature = "heed")]
37 | Self::Heed => "heed 0.20.0",
38 |
39 | #[cfg(feature = "rocksdb")]
40 | Self::RocksDb => "rocksdb 0.22.0",
41 | }
42 | )
43 | }
44 | }
45 |
46 | #[derive(Copy, Debug, Clone, ValueEnum, Serialize, PartialEq, Eq)]
47 | #[clap(rename_all = "kebab_case")]
48 | pub enum Workload {
49 | /// Workload A: Update heavy workload
50 | ///
51 | /// Application example: Session store recording recent actions
52 | TaskA,
53 |
54 | /// Workload B: Read mostly workload
55 | ///
56 | /// Application example: photo tagging; add a tag is an update, but most operations are to read tags
57 | TaskB,
58 |
59 | /// Workload C: Read only
60 | ///
61 | /// Application example: user profile cache, where profiles are constructed elsewhere (e.g., Hadoop)
62 | TaskC,
63 |
64 | /// Workload D: Read latest workload with light inserts
65 | ///
66 | /// Application example: user status updates; people want to read the latest
67 | TaskD,
68 |
69 | /// Workload E: Read latest workload with heavy inserts
70 | ///
71 | /// Application example: Event logging, getting the latest events
72 | TaskE,
73 |
74 | /// Workload F: Read zipfian workload with light inserts
75 | TaskF,
76 |
77 | /// Workload G: Read zipfian workload with heavy inserts
78 | TaskG,
79 | }
80 |
81 | #[derive(Clone, Debug, Eq, PartialEq, clap::ValueEnum)]
82 | pub enum LsmCompaction {
83 | Leveled,
84 | Tiered,
85 | }
86 |
87 | impl std::fmt::Display for LsmCompaction {
88 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 | write!(
90 | f,
91 | "{}",
92 | match self {
93 | Self::Leveled => "LCS",
94 | Self::Tiered => "STCS",
95 | }
96 | )
97 | }
98 | }
99 |
100 | /// CLI argument parse
101 | #[derive(Clone, Parser, Debug)]
102 | #[command(author = "marvin-j97", version = env!("CARGO_PKG_VERSION"), about = "Rust KV-store profiler")]
103 | #[command(propagate_version = true)]
104 | pub struct Args {
105 | #[arg(long, value_enum)]
106 | pub backend: Backend,
107 |
108 | #[arg(long, value_enum)]
109 | pub workload: Workload,
110 |
111 | #[arg(long, default_value_t = 1)]
112 | pub threads: u8,
113 |
114 | #[arg(long)]
115 | pub items: u32,
116 |
117 | #[arg(long)]
118 | pub key_size: u8,
119 |
120 | #[arg(long)]
121 | pub value_size: u32,
122 |
123 | /// Block size for LSM-trees
124 | #[arg(long, default_value_t = 4_096)]
125 | pub lsm_block_size: u16,
126 |
127 | /// Compaction for LSM-trees
128 | #[arg(long, value_enum, default_value_t = LsmCompaction::Leveled)]
129 | pub lsm_compaction: LsmCompaction,
130 |
131 | /// Intermittenly flush sled to keep memory usage sane
132 | /// This is hopefully a temporary workaround
133 | #[arg(long, default_value_t = false)]
134 | pub sled_flush: bool,
135 |
136 | #[arg(long, default_value_t = 16_000_000)]
137 | pub cache_size: u32,
138 |
139 | #[arg(long, default_value = "log.jsonl")]
140 | pub out: String,
141 |
142 | #[arg(long, default_value_t = false)]
143 | pub snapshot_heap: bool,
144 |
145 | #[arg(long, default_value_t = false)]
146 | pub fsync: bool,
147 |
148 | #[arg(long, default_value_t = 1)]
149 | pub minutes: u16,
150 | }
151 |
--------------------------------------------------------------------------------
/src/worker/db.rs:
--------------------------------------------------------------------------------
1 | use crate::Args;
2 | use nebari::{io::fs::StdFile, tree::Unversioned};
3 | use redb::TableDefinition;
4 | use std::{
5 | sync::{atomic::AtomicU64, Arc},
6 | time::Instant,
7 | };
8 |
9 | #[derive(Clone)]
10 | pub struct DatabaseWrapper {
11 | pub inner: GenericDatabase,
12 | pub write_ops: Arc,
13 | pub read_ops: Arc,
14 | pub delete_ops: Arc,
15 | pub scan_ops: Arc,
16 |
17 | pub write_latency: Arc,
18 | pub read_latency: Arc,
19 | }
20 |
21 | impl std::ops::Deref for DatabaseWrapper {
22 | type Target = GenericDatabase;
23 |
24 | fn deref(&self) -> &Self::Target {
25 | &self.inner
26 | }
27 | }
28 |
29 | #[derive(Clone)]
30 | pub enum GenericDatabase {
31 | Fjall {
32 | keyspace: fjall::Keyspace,
33 | db: fjall::PartitionHandle,
34 | },
35 | Sled(sled::Db),
36 | // Bloodstone(bloodstone::Db),
37 | Jamm(jammdb::DB),
38 | Persy(persy::Persy),
39 | Redb(Arc),
40 | Nebari {
41 | roots: nebari::Roots,
42 | tree: nebari::Tree,
43 | },
44 |
45 | #[cfg(feature = "heed")]
46 | Heed {
47 | db: heed::Database,
48 | env: heed::Env,
49 | },
50 |
51 | #[cfg(feature = "rocksdb")]
52 | RocksDb(Arc),
53 | }
54 |
55 | const TABLE: TableDefinition<&[u8], Vec> = TableDefinition::new("data");
56 |
57 | impl DatabaseWrapper {
58 | pub fn insert(&self, key: &[u8], value: &[u8], durable: bool, args: Arc) {
59 | match &self.inner {
60 | #[cfg(feature = "rocksdb")]
61 | GenericDatabase::RocksDb(db) => {
62 | let start = Instant::now();
63 |
64 | db.put(key, value).unwrap();
65 |
66 | if durable {
67 | db.flush_wal(true).unwrap();
68 | }
69 |
70 | self.write_latency.fetch_add(
71 | start.elapsed().as_micros() as u64,
72 | std::sync::atomic::Ordering::Relaxed,
73 | );
74 | }
75 |
76 | #[cfg(feature = "heed")]
77 | GenericDatabase::Heed { env, db } => {
78 | let start = Instant::now();
79 |
80 | let mut wtxn = env.write_txn().unwrap();
81 | db.put(&mut wtxn, key, value).unwrap();
82 |
83 | wtxn.commit().unwrap();
84 |
85 | self.write_latency.fetch_add(
86 | start.elapsed().as_micros() as u64,
87 | std::sync::atomic::Ordering::Relaxed,
88 | );
89 | }
90 | GenericDatabase::Nebari { roots: _, tree } => {
91 | if !durable {
92 | log::warn!("WARNING: Nebari does not support eventual durability");
93 | }
94 |
95 | let key = key.to_vec();
96 | let value = key.to_vec();
97 |
98 | let start = Instant::now();
99 |
100 | tree.set(key, value).unwrap();
101 |
102 | self.write_latency.fetch_add(
103 | start.elapsed().as_micros() as u64,
104 | std::sync::atomic::Ordering::Relaxed,
105 | );
106 | }
107 | GenericDatabase::Fjall { keyspace, db } => {
108 | let start = Instant::now();
109 |
110 | db.insert(key, value).unwrap();
111 |
112 | if durable {
113 | keyspace.persist(fjall::FlushMode::SyncAll).unwrap();
114 | }
115 |
116 | self.write_latency.fetch_add(
117 | start.elapsed().as_micros() as u64,
118 | std::sync::atomic::Ordering::Relaxed,
119 | );
120 | }
121 | GenericDatabase::Sled(db) => {
122 | let start = Instant::now();
123 |
124 | db.insert(key, value).unwrap();
125 |
126 | if durable {
127 | db.flush().unwrap();
128 | }
129 |
130 | self.write_latency.fetch_add(
131 | start.elapsed().as_micros() as u64,
132 | std::sync::atomic::Ordering::Relaxed,
133 | );
134 | }
135 | // GenericDatabase::Bloodstone(db) => {
136 | // let start = Instant::now();
137 |
138 | // db.insert(key, value).unwrap();
139 |
140 | // if durable {
141 | // db.flush().unwrap();
142 | // } else if args.sled_flush {
143 | // // NOTE: TODO: OOM Workaround
144 | // // Intermittenly flush sled to keep memory usage sane
145 | // // This is hopefully a temporary workaround
146 | // if self.write_ops.load(std::sync::atomic::Ordering::Relaxed) % 5_000_000 == 0 {
147 | // db.flush().unwrap();
148 | // }
149 | // }
150 |
151 | // self.write_latency.fetch_add(
152 | // start.elapsed().as_micros() as u64,
153 | // std::sync::atomic::Ordering::Relaxed,
154 | // );
155 | // }
156 | GenericDatabase::Jamm(db) => {
157 | if !durable {
158 | log::warn!("WARNING: JammDB does not support eventual durability",);
159 | }
160 |
161 | let start = Instant::now();
162 |
163 | let tx = db.tx(true).unwrap();
164 | let bucket = tx.get_bucket("data").unwrap();
165 | bucket.put(key, value).unwrap();
166 | tx.commit().unwrap();
167 |
168 | self.write_latency.fetch_add(
169 | start.elapsed().as_micros() as u64,
170 | std::sync::atomic::Ordering::Relaxed,
171 | );
172 | }
173 | GenericDatabase::Persy(db) => {
174 | use persy::{PersyId, TransactionConfig};
175 |
176 | let key = String::from_utf8_lossy(key);
177 | let key = key.to_string();
178 |
179 | let start = Instant::now();
180 |
181 | let mut tx = db
182 | .begin_with(TransactionConfig::new().set_background_sync(!durable))
183 | .unwrap();
184 | let id = tx.insert("data", value).unwrap();
185 |
186 | tx.put::("primary", key, id).unwrap();
187 | let prepared = tx.prepare().unwrap();
188 |
189 | prepared.commit().unwrap();
190 |
191 | self.write_latency.fetch_add(
192 | start.elapsed().as_micros() as u64,
193 | std::sync::atomic::Ordering::Relaxed,
194 | );
195 | }
196 | GenericDatabase::Redb(db) => {
197 | use redb::Durability::{Eventual, Immediate};
198 |
199 | let start = Instant::now();
200 |
201 | let mut write_txn = db.begin_write().unwrap();
202 |
203 | write_txn.set_durability(if durable { Immediate } else { Eventual });
204 |
205 | {
206 | let mut table = write_txn.open_table(TABLE).unwrap();
207 | table.insert(key, value.to_vec()).unwrap();
208 | }
209 | write_txn.commit().unwrap();
210 |
211 | self.write_latency.fetch_add(
212 | start.elapsed().as_micros() as u64,
213 | std::sync::atomic::Ordering::Relaxed,
214 | );
215 | }
216 | }
217 |
218 | self.write_ops
219 | .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
220 | }
221 |
222 | pub fn get(&self, key: &[u8]) -> Option> {
223 | let start = Instant::now();
224 |
225 | let item = match &self.inner {
226 | #[cfg(feature = "rocksdb")]
227 | GenericDatabase::RocksDb(db) => db.get(key).unwrap().map(|x| x.to_vec()),
228 |
229 | #[cfg(feature = "heed")]
230 | GenericDatabase::Heed { db, env } => {
231 | let rtxn = env.read_txn().unwrap();
232 | let ret = db.get(&rtxn, key).unwrap();
233 | ret.map(|x| x.to_vec())
234 | }
235 |
236 | GenericDatabase::Nebari { roots: _, tree } => {
237 | let item = tree.get(key).unwrap();
238 | item.map(|x| x.to_vec())
239 | }
240 | GenericDatabase::Fjall { keyspace: _, db } => db.get(key).unwrap().map(|x| x.to_vec()),
241 | GenericDatabase::Sled(db) => db.get(key).unwrap().map(|x| x.to_vec()),
242 | // GenericDatabase::Bloodstone(db) => db.get(key).unwrap().map(|x| x.to_vec()),
243 | GenericDatabase::Jamm(db) => {
244 | let tx = db.tx(false).unwrap();
245 | let bucket = tx.get_bucket("data").unwrap();
246 | bucket.get(key).map(|item| item.kv().value().into())
247 | }
248 | GenericDatabase::Persy(db) => {
249 | let key = String::from_utf8_lossy(key);
250 |
251 | let mut read_id = db
252 | .get::("primary", &key.to_string())
253 | .unwrap();
254 | if let Some(id) = read_id.next() {
255 | db.read("data", &id).unwrap()
256 | } else {
257 | None
258 | }
259 | }
260 | GenericDatabase::Redb(db) => {
261 | let read_txn = db.begin_read().unwrap();
262 | let table = read_txn.open_table(TABLE).unwrap();
263 | table.get(key).unwrap().map(|x| x.value())
264 | }
265 | };
266 |
267 | self.read_latency.fetch_add(
268 | start.elapsed().as_micros() as u64,
269 | std::sync::atomic::Ordering::Relaxed,
270 | );
271 |
272 | self.read_ops
273 | .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
274 |
275 | item
276 | }
277 | }
278 |
--------------------------------------------------------------------------------
/page/src/App.tsx:
--------------------------------------------------------------------------------
1 | import "./App.css";
2 |
3 | import { ApexChartProps, SolidApexCharts } from 'solid-apexcharts';
4 | import { For, Show, createSignal, onMount } from 'solid-js'
5 |
6 | const thousandsFormatter = Intl.NumberFormat(undefined, {
7 | maximumFractionDigits: 0,
8 | });
9 | const formatThousands = (n: number) => thousandsFormatter.format(n);
10 |
11 | export function readFile(file: File): Promise {
12 | const fileReader = new FileReader();
13 |
14 | const promise = new Promise((resolve, reject) => {
15 | fileReader.onloadend = (ev) => {
16 | resolve(ev.target!.result!.toString());
17 | };
18 | fileReader.onerror = (error) => {
19 | reject(error);
20 | };
21 | });
22 |
23 | fileReader.readAsText(file);
24 |
25 | return promise;
26 | }
27 |
28 | export function parseJsonl(text: string): T[] {
29 | return text
30 | .split("\n")
31 | .filter(Boolean)
32 | .map((line) => JSON.parse(line));
33 | }
34 |
35 | type HistoryEntry = MetricEntry;
36 |
37 | type MetricEntry = {
38 | cpu: number;
39 | mem_mib: number;
40 | time_micro: number;
41 | du_mib: number;
42 | disk_mib_w: number;
43 | disk_mib_r: number;
44 | space_amp: number;
45 | write_amp?: number;
46 | dataset_size?: number;
47 | write_ops: number
48 | read_ops: number
49 | delete_ops: number
50 | scan_ops: number;
51 |
52 | avg_write_latency: number;
53 | avg_read_latency: number;
54 | };
55 |
56 | const chartOptions: ApexChartProps["options"]["chart"] = {
57 | background: "#030712",
58 | animations: {
59 | enabled: false,
60 | },
61 | /* toolbar: {
62 | show: true,
63 | tools: {
64 | download: true,
65 | reset: true,
66 | pan: true,
67 | selection: true,
68 | zoomout: true,
69 | zoom: true,
70 | }
71 | },
72 | zoom: {
73 | enabled: true
74 | }, */
75 | }
76 |
77 | const xaxisOptions: ApexChartProps["options"]["xaxis"] = {
78 | axisBorder: {
79 | show: true,
80 | },
81 | type: "numeric",
82 | labels: {
83 | style: {
84 | colors: "white"
85 | },
86 | formatter: (value) => `${Math.floor(+value)}s`
87 | }
88 | }
89 |
90 | const colors = [
91 | "#a78bfa", "#38bdf8", "#4ade80", "#fbbf24",
92 | "#f87171", "#f472b6", "#777777", "#fafafa",
93 | ];
94 |
95 | const baseOptions: ApexChartProps["options"] = {
96 | grid: {
97 | show: false,
98 | },
99 | tooltip: {
100 | enabled: false,
101 | },
102 | dataLabels: {
103 | enabled: false
104 | },
105 | legend: {
106 | position: "top",
107 | horizontalAlign: 'right',
108 | labels: {
109 | colors: "white"
110 | }
111 | }
112 | }
113 |
114 | function LineChart(props: { xaxis?: ApexChartProps["options"]["xaxis"]; yaxis?: ApexChartProps["options"]["yaxis"], title: string, yFormatter: (val: number) => string, series: { name: string, data: { x: number, y: number }[] }[] }) {
115 | const options = () => ({
116 | ...baseOptions,
117 | title: {
118 | text: props.title,
119 | style: {
120 | color: "white"
121 | }
122 | },
123 | stroke: {
124 | colors: ["#aaffff"],
125 | width: 2
126 | },
127 | chart: {
128 | id: 'mem',
129 | ...chartOptions,
130 | },
131 | xaxis: {
132 | ...xaxisOptions,
133 | ...props.xaxis,
134 | },
135 | yaxis: {
136 | axisBorder: {
137 | show: true,
138 | },
139 | labels: {
140 | style: {
141 | colors: "white"
142 | },
143 | formatter: props.yFormatter,
144 | },
145 | ...props.yaxis,
146 | },
147 | } satisfies ApexChartProps["options"]);
148 |
149 | const series = () => ({
150 | list: [
151 | ...props.series.map(({ name, data }, idx) => {
152 |
153 | return {
154 | name,
155 | data: data.map(({ x, y }) => ({
156 | x,
157 | y,
158 | })),
159 | color: colors[idx % colors.length]
160 | } satisfies ApexAxisChartSeries[0]
161 | }),
162 | ] satisfies ApexAxisChartSeries
163 | });
164 |
165 | return
171 | }
172 |
173 | function WriteLatencyHistory(props: { series: HistoryEntry[][] }) {
174 | const series = () => props.series.map((series, idx) => {
175 | const metrics = series.slice(2);
176 | const start = metrics[0].time_micro;
177 |
178 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
179 |
180 | return {
181 | name: setupInfo.backend,
182 | data: metrics.map(({ time_micro, avg_write_latency }) => ({
183 | x: (time_micro - start) / 1000 / 1000,
184 | y: avg_write_latency,
185 | })),
186 | color: colors[idx % colors.length]
187 | } satisfies ApexAxisChartSeries[0]
188 | });
189 |
190 | return `${n.toFixed(1)}µs`}
192 | title="Average write latency (lower is better)"
193 | series={series()}
194 | />;
195 | }
196 |
197 | function ReadLatencyHistory(props: { series: HistoryEntry[][] }) {
198 | const series = () => props.series.map((series, idx) => {
199 | const metrics = series.slice(2);
200 | const start = metrics[0].time_micro;
201 |
202 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
203 |
204 | return {
205 | name: setupInfo.backend,
206 | data: metrics.map(({ time_micro, avg_read_latency }) => ({
207 | x: (time_micro - start) / 1000 / 1000,
208 | y: avg_read_latency,
209 | })),
210 | color: colors[idx % colors.length]
211 | } satisfies ApexAxisChartSeries[0]
212 | });
213 |
214 | return `${n.toFixed(1)}µs`}
216 | title="Average read latency (lower is better)"
217 | series={series()}
218 | />;
219 | }
220 |
221 | function WriteAmpHistory(props: { series: HistoryEntry[][] }) {
222 | const series = () => props.series.map((series, idx) => {
223 | const metrics = series.slice(2);
224 | const start = metrics[0].time_micro;
225 |
226 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
227 |
228 | return {
229 | name: setupInfo.backend,
230 | data: metrics.map(({ time_micro, du_mib, disk_mib_w, write_amp }) => ({
231 | x: (time_micro - start) / 1000 / 1000,
232 | y: write_amp ??
233 | // TODO: remove
234 | (disk_mib_w / du_mib),
235 | })),
236 | color: colors[idx % colors.length]
237 | } satisfies ApexAxisChartSeries[0]
238 | });
239 |
240 | return `${(n).toFixed(1)}x`}
242 | title="Write amplification (lower is better)"
243 | series={series()}
244 | yaxis={{
245 | min: 0,
246 | max: (n) => Math.min(1_000, n),
247 | }}
248 | />;
249 | }
250 |
251 | function DatasetSizeHistory(props: { series: HistoryEntry[][] }) {
252 | const series = () => props.series.map((series, idx) => {
253 | const metrics = series.slice(2);
254 | const start = metrics[0].time_micro;
255 |
256 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
257 |
258 | return {
259 | name: setupInfo.backend,
260 | data: metrics.map(({ time_micro, dataset_size }) => ({
261 | x: (time_micro - start) / 1000 / 1000,
262 | y: (dataset_size ?? 0) / 1_024 / 1_024
263 | })),
264 | color: colors[idx % colors.length]
265 | } satisfies ApexAxisChartSeries[0]
266 | });
267 |
268 | return `${formatThousands(n)} MiB`}
270 | title="True data set size (higher is better)"
271 | series={series()}
272 | />;
273 | }
274 |
275 | function DiskWritesCumulative(props: { series: HistoryEntry[][] }) {
276 | const series = () => props.series.map((series, idx) => {
277 | const metrics = series.slice(2);
278 | const start = metrics[0].time_micro;
279 |
280 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
281 |
282 | return {
283 | name: setupInfo.backend,
284 | data: metrics.map(({ time_micro, disk_mib_w }) => ({
285 | x: (time_micro - start) / 1000 / 1000,
286 | y: disk_mib_w,
287 | })),
288 | color: colors[idx % colors.length]
289 | } satisfies ApexAxisChartSeries[0]
290 | });
291 |
292 | return `${formatThousands(n)} MiB`}
294 | title="Written bytes cumulative"
295 | series={series()}
296 | />;
297 | }
298 |
299 | function WriteHistory(props: { series: HistoryEntry[][] }) {
300 | const series = () => props.series.map((series, idx) => {
301 | const metrics = series.slice(2);
302 | const start = metrics[0].time_micro;
303 |
304 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
305 |
306 | return {
307 | name: setupInfo.backend,
308 | data: metrics.map(({ time_micro, write_ops }) => ({
309 | x: (time_micro - start) / 1000 / 1000,
310 | y: write_ops,
311 | })),
312 | color: colors[idx % colors.length]
313 | } satisfies ApexAxisChartSeries[0]
314 | });
315 |
316 | return `${n} ops`}
318 | title="Write ops cumulative (higher is better)"
319 | series={series()}
320 | />;
321 | }
322 |
323 | function ReadHistory(props: { series: HistoryEntry[][] }) {
324 | const series = () => props.series.map((series, idx) => {
325 | const metrics = series.slice(2);
326 | const start = metrics[0].time_micro;
327 |
328 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
329 |
330 | return {
331 | name: setupInfo.backend,
332 | data: metrics.map(({ time_micro, read_ops }) => ({
333 | x: (time_micro - start) / 1000 / 1000,
334 | y: read_ops,
335 | })),
336 | color: colors[idx % colors.length]
337 | } satisfies ApexAxisChartSeries[0]
338 | });
339 |
340 | return `${n} ops`}
342 | title="Read ops cumulative (higher is better)"
343 | series={series()}
344 | />;
345 | }
346 |
347 | function SpaceAmpHistory(props: { series: HistoryEntry[][] }) {
348 | const series = () => props.series.map((series, idx) => {
349 | const metrics = series.slice(2);
350 | const start = metrics[0].time_micro;
351 |
352 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
353 |
354 | return {
355 | name: setupInfo.backend,
356 | data: metrics.map(({ time_micro, space_amp }) => ({
357 | x: (time_micro - start) / 1000 / 1000,
358 | y: space_amp,
359 | })),
360 | color: colors[idx % colors.length]
361 | } satisfies ApexAxisChartSeries[0]
362 | });
363 |
364 | return `${(n).toFixed(1)}x`}
366 | title="Space amplification (lower is better)"
367 | series={series()}
368 | yaxis={{
369 | min: 1,
370 | max: (n) => Math.min(5, n),
371 | }}
372 | />;
373 | }
374 |
375 | function DiskSpaceUsageHistory(props: { series: HistoryEntry[][] }) {
376 | const series = () => props.series.map((series, idx) => {
377 | const metrics = series.slice(2);
378 | const start = metrics[0].time_micro;
379 |
380 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
381 |
382 | return {
383 | name: setupInfo.backend,
384 | data: metrics.map(({ time_micro, du_mib }) => ({
385 | x: (time_micro - start) / 1000 / 1000,
386 | y: du_mib,
387 | })),
388 | color: colors[idx % colors.length]
389 | } satisfies ApexAxisChartSeries[0]
390 | });
391 |
392 | return `${formatThousands(n)} MiB`}
394 | title="Disk space usage"
395 | series={series()}
396 | />;
397 | }
398 |
399 | function MemoryUsageHistory(props: { series: HistoryEntry[][] }) {
400 | const series = () => props.series.map((series, idx) => {
401 | const metrics = series.slice(2);
402 | const start = metrics[0].time_micro;
403 |
404 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
405 |
406 | return {
407 | name: setupInfo.backend,
408 | data: metrics.map(({ time_micro, mem_mib }) => ({
409 | x: (time_micro - start) / 1000 / 1000,
410 | y: mem_mib,
411 | })),
412 | color: colors[idx % colors.length]
413 | } satisfies ApexAxisChartSeries[0]
414 | });
415 |
416 | return `${formatThousands(n)} MiB`}
418 | title="Memory pressure (lower is better)"
419 | series={series()}
420 | />;
421 | }
422 |
423 | function CpuUsageHistory(props: { series: HistoryEntry[][] }) {
424 | const series = () => props.series.map((series, idx) => {
425 | const metrics = series.slice(2);
426 | const start = metrics[0].time_micro;
427 |
428 | const setupInfo = series[1] as unknown as { backend: string, workload: string };
429 |
430 | return {
431 | name: setupInfo.backend,
432 | data: metrics.map(({ time_micro, cpu }) => ({
433 | x: (time_micro - start) / 1000 / 1000,
434 | y: cpu,
435 | })),
436 | color: colors[idx % colors.length]
437 | } satisfies ApexAxisChartSeries[0]
438 | });
439 |
440 | return `${n} %`}
442 | title="CPU usage (lower is better)"
443 | series={series()}
444 | />;
445 | }
446 |
447 | function PerformanceChart(props: { title: string, values: { backend: string, value: number }[] }) {
448 | const series = () => ({
449 | list: [
450 | {
451 | name: "ops",
452 | data: [
453 | ...props.values.map(({ backend, value }, idx) => ({
454 | x: backend,
455 | y: value,
456 | fillColor: colors[idx % colors.length],
457 | }))
458 | ].sort((a, b) => b.y - a.y),
459 | }
460 | ] satisfies ApexAxisChartSeries,
461 | });
462 |
463 | const options = () => ({
464 | ...baseOptions,
465 | title: {
466 | text: `${props.title} (higher is better)`,
467 | style: {
468 | color: "white"
469 | }
470 | },
471 | stroke: {
472 | show: false,
473 | },
474 | chart: {
475 | id: 'mem',
476 | ...chartOptions,
477 | },
478 | xaxis: {
479 | categories: series().list[0].data.map(({ x }) => x),
480 | type: "category",
481 | labels: {
482 | style: {
483 | colors: "white",
484 | }
485 | }
486 | },
487 | yaxis: {
488 | axisBorder: {
489 | show: true,
490 | },
491 | labels: {
492 | style: {
493 | colors: "white"
494 | },
495 | formatter: (value) => `${formatThousands(value)} ops`
496 | },
497 | },
498 | } satisfies ApexChartProps["options"]);
499 |
500 |
501 |
502 | return
508 | }
509 |
510 | type OpsObject = { backend: string, write_ops: number; read_ops: number; scan_ops: number; delete_ops: number };
511 |
512 | function App() {
513 | const [items, setItems] = createSignal<(HistoryEntry)[][]>([]);
514 | const [ops, setOps] = createSignal([]);
515 |
516 | async function handleFileUpload(file: File) {
517 |
518 | await readFile(file)
519 | .then((text) => {
520 | const items = parseJsonl(text);
521 | setItems(x => [...x, items]);
522 |
523 | setOps(x => {
524 | const copy = structuredClone(x);
525 | let item = items.at(-1)!;
526 | return [...copy, item];
527 | });
528 | })
529 | .catch((error) => {
530 | console.error(error);
531 | });
532 | }
533 |
534 | onMount(() => {
535 | const handler = async (ev: DragEvent) => {
536 | ev.preventDefault();
537 |
538 | setItems([]);
539 |
540 | const fileList = [...(ev.dataTransfer?.files ?? [])];
541 | fileList.sort((a, b) => a.name.localeCompare(b.name));
542 |
543 | for (const file of fileList) {
544 | await handleFileUpload(file);
545 | }
546 | };
547 |
548 | document.addEventListener("drop", handler);
549 | document.addEventListener("dragover", (ev) => ev.preventDefault());
550 | });
551 |
552 | const sysInfo = () => items()[0][0] as unknown as {
553 | cpu: string;
554 | mem: number;
555 | os: string;
556 | kernel: string;
557 | };
558 |
559 | const runtimeSecs = () => {
560 | if (!items().length) {
561 | return 0;
562 | }
563 | return (items().at(0)!.at(-1)!.time_micro - items().at(0)!.at(0)!.time_micro) / 1000 / 1000
564 | };
565 |
566 | return (
567 | <>
568 | Rust Storage Engine Benchmark
569 | 0} fallback={"Drag a .jsonl file here!!"}>
570 |
571 |
572 |
573 | System: {sysInfo().os} - {sysInfo().cpu} - {(sysInfo().mem / 1024 / 1024 / 1024).toFixed(2)} GB
574 |
575 |
576 |
577 |
578 | {item => {
579 | const setupInfo = () => item[1] as unknown as { backend: string, workload: string };
580 |
581 | return
582 |
583 | Backend: {setupInfo().backend} - Workload: {setupInfo().workload} - Runtime: {(runtimeSecs() / 60).toFixed(2)} min
584 |
585 |
586 | }}
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 | 0}>
609 |
610 |
({
614 | backend,
615 | value
616 | }))
617 | }
618 | />
619 | ({
623 | backend,
624 | value
625 | }))
626 | }
627 | />
628 | ({
632 | backend,
633 | value
634 | }))
635 | }
636 | />
637 | ({
641 | backend,
642 | value
643 | }))
644 | }
645 | />
646 |
647 |
648 |
649 |
650 |
651 | | Backend |
652 | Writes |
653 | Reads |
654 | Scans |
655 | Deletes |
656 |
657 |
658 |
659 | {
660 | ops().slice().sort((a, b) => {
661 | if (b.read_ops > b.write_ops) {
662 | return b.read_ops - a.read_ops;
663 | }
664 | return b.write_ops - a.write_ops;
665 | }).map(({ backend, write_ops, read_ops, scan_ops, delete_ops }) =>
666 |
667 | | {backend} |
668 | {formatThousands(write_ops)} |
669 | {formatThousands(read_ops)} |
670 | {formatThousands(scan_ops)} |
671 | {formatThousands(delete_ops)} |
672 |
673 | )
674 | }
675 |
676 |
677 |
678 |
679 | >
680 | )
681 | }
682 |
683 | export default App
684 |
--------------------------------------------------------------------------------
/src/worker/main.rs:
--------------------------------------------------------------------------------
1 | mod db;
2 |
3 | use crate::db::DatabaseWrapper;
4 | use clap::Parser;
5 | use db::GenericDatabase;
6 | use rand::distributions::Distribution;
7 | use rand::Rng;
8 | use rust_storage_bench::{Args, Backend, Workload};
9 | use std::fs::{create_dir_all, remove_dir_all};
10 | use std::io::Write;
11 | use std::path::Path;
12 | use std::sync::Arc;
13 | use std::time::Duration;
14 | use sysinfo::Pid;
15 | use zipf::ZipfDistribution;
16 |
17 | /// Gets the unix timestamp as a duration
18 | pub fn unix_timestamp() -> std::time::Duration {
19 | let now = std::time::SystemTime::now();
20 |
21 | // NOTE: Unwrap is trivial
22 | #[allow(clippy::unwrap_used)]
23 | now.duration_since(std::time::SystemTime::UNIX_EPOCH)
24 | .unwrap()
25 | }
26 |
27 | fn start_killer(min: u64) {
28 | std::thread::spawn(move || {
29 | std::thread::sleep(Duration::from_secs(min * 60));
30 | std::process::exit(0);
31 | });
32 | }
33 |
34 | /*
35 | #[cfg(not(target_env = "msvc"))]
36 | use jemallocator::Jemalloc;
37 |
38 | #[cfg(not(target_env = "msvc"))]
39 | #[global_allocator]
40 | static GLOBAL: Jemalloc = Jemalloc;
41 | */
42 |
43 | fn main() {
44 | env_logger::Builder::from_default_env().init();
45 |
46 | let args = Arc::new(Args::parse());
47 |
48 | eprintln!("Workload: {:?}", args.workload);
49 | eprintln!("Backend : {:?}", args.backend);
50 | eprintln!("Threads : {}", args.threads);
51 | eprintln!("# items : {}", args.items);
52 |
53 | if args.workload != Workload::TaskC {
54 | if args.fsync && (args.backend == Backend::Sled/*|| args.backend == Backend::Bloodstone*/) {
55 | panic!("Sled doesn't fsync...");
56 | }
57 | }
58 |
59 | let data_dir = Path::new(".data").join(match args.backend {
60 | Backend::Fjall => match args.lsm_compaction {
61 | rust_storage_bench::LsmCompaction::Leveled => "fjall_lcs".to_owned(),
62 | rust_storage_bench::LsmCompaction::Tiered => "fjall_stcs".to_owned(),
63 | },
64 | be => be.to_string(),
65 | });
66 |
67 | if data_dir.exists() {
68 | remove_dir_all(&data_dir).unwrap();
69 | }
70 |
71 | let db = match args.backend {
72 | #[cfg(feature = "rocksdb")]
73 | Backend::RocksDb => {
74 | create_dir_all(&data_dir).unwrap();
75 |
76 | let mut opts = rocksdb::Options::default();
77 | opts.set_manual_wal_flush(true);
78 | opts.create_if_missing(true);
79 |
80 | let db = rocksdb::DB::open(&opts, &data_dir).unwrap();
81 | GenericDatabase::RocksDb(Arc::new(db))
82 | }
83 |
84 | #[cfg(feature = "heed")]
85 | Backend::Heed => {
86 | create_dir_all(&data_dir).unwrap();
87 |
88 | let env = unsafe {
89 | heed::EnvOpenOptions::new()
90 | .map_size(8_000_000_000)
91 | .open(&data_dir)
92 | .unwrap()
93 | };
94 |
95 | let mut wtxn = env.write_txn().unwrap();
96 | let db = env.create_database(&mut wtxn, None).unwrap();
97 | wtxn.commit().unwrap();
98 |
99 | GenericDatabase::Heed { db, env }
100 | }
101 | Backend::Fjall => {
102 | use fjall::{
103 | compaction::{Levelled, SizeTiered, Strategy},
104 | BlockCache, PartitionCreateOptions,
105 | };
106 |
107 | let compaction_strategy: Arc = match args.lsm_compaction {
108 | rust_storage_bench::LsmCompaction::Leveled => Arc::new(Levelled::default()),
109 | rust_storage_bench::LsmCompaction::Tiered => Arc::new(SizeTiered::default()),
110 | };
111 |
112 | let config = fjall::Config::new(&data_dir)
113 | .fsync_ms(if args.fsync { None } else { Some(1_000) })
114 | .block_cache(BlockCache::with_capacity_bytes(args.cache_size.into()).into());
115 |
116 | let create_opts =
117 | PartitionCreateOptions::default().block_size(args.lsm_block_size.into());
118 |
119 | let keyspace = config.open().unwrap();
120 | let db = keyspace.open_partition("data", create_opts).unwrap();
121 | db.set_compaction_strategy(compaction_strategy);
122 |
123 | GenericDatabase::Fjall { keyspace, db }
124 | }
125 | Backend::Sled => GenericDatabase::Sled(
126 | sled::Config::new()
127 | .path(&data_dir)
128 | .flush_every_ms(if args.fsync { None } else { Some(1_000) })
129 | .cache_capacity(args.cache_size as u64)
130 | .open()
131 | .unwrap(),
132 | ),
133 | // Backend::Bloodstone => GenericDatabase::Bloodstone(
134 | // bloodstone::Config::new()
135 | // .cache_capacity_bytes(args.cache_size as usize)
136 | // .path(&data_dir)
137 | // .open()
138 | // .unwrap(),
139 | // ),
140 | Backend::JammDb => {
141 | create_dir_all(&data_dir).unwrap();
142 |
143 | let db = jammdb::DB::open(data_dir.join("data.db")).unwrap();
144 | let tx = db.tx(true).unwrap();
145 | let _ = tx.create_bucket("data").unwrap();
146 | tx.commit().unwrap();
147 |
148 | GenericDatabase::Jamm(db)
149 | }
150 |
151 | Backend::Persy => {
152 | use persy::{Config, Persy, PersyId, ValueMode};
153 |
154 | create_dir_all(&data_dir).unwrap();
155 |
156 | Persy::create(data_dir.join("data.persy")).unwrap();
157 |
158 | let mut cfg = Config::default();
159 | cfg.change_cache_size(args.cache_size.into());
160 | let db = Persy::open(data_dir.join("data.persy"), cfg).unwrap();
161 |
162 | let mut tx = db.begin().unwrap();
163 | tx.create_segment("data").unwrap();
164 | tx.create_index::("primary", ValueMode::Replace)
165 | .unwrap();
166 | let prepared = tx.prepare().unwrap();
167 | prepared.commit().unwrap();
168 |
169 | GenericDatabase::Persy(db)
170 | }
171 | Backend::Redb => {
172 | create_dir_all(&data_dir).unwrap();
173 |
174 | GenericDatabase::Redb(Arc::new(
175 | redb::Builder::new()
176 | .set_cache_size(args.cache_size as usize)
177 | .create(data_dir.join("my_db.redb"))
178 | .unwrap(),
179 | ))
180 | }
181 | Backend::Nebari => {
182 | use nebari::{
183 | tree::{Root, Unversioned},
184 | Config,
185 | };
186 |
187 | create_dir_all(&data_dir).unwrap();
188 |
189 | let roots = Config::default_for(data_dir.join("db.nebari"))
190 | .open()
191 | .unwrap();
192 | let tree = roots.tree(Unversioned::tree("data")).unwrap();
193 |
194 | GenericDatabase::Nebari { roots, tree }
195 | }
196 | };
197 |
198 | let db = DatabaseWrapper {
199 | inner: db,
200 | write_ops: Default::default(),
201 | read_ops: Default::default(),
202 | delete_ops: Default::default(),
203 | scan_ops: Default::default(),
204 | read_latency: Default::default(),
205 | write_latency: Default::default(),
206 | };
207 |
208 | {
209 | let db = db.clone();
210 | let args = args.clone();
211 |
212 | std::thread::spawn(move || {
213 | use std::sync::atomic::Ordering::Relaxed;
214 |
215 | let backend = match args.backend {
216 | Backend::Fjall => format!("{} {}", args.backend, args.lsm_compaction),
217 | _ => args.backend.to_string(),
218 | };
219 |
220 | let mut sys = sysinfo::System::new_all();
221 | sys.refresh_all();
222 |
223 | let pid = std::process::id();
224 | let pid = Pid::from(pid as usize);
225 |
226 | let mut file_writer = std::fs::File::create(&args.out).unwrap();
227 |
228 | {
229 | let json = serde_json::json!({
230 | "time_micro": unix_timestamp().as_micros(),
231 | "type": "system",
232 | "os": sysinfo::System::long_os_version(),
233 | "kernel": sysinfo::System::kernel_version(),
234 | "cpu": sys.global_cpu_info().brand(),
235 | "mem": sys.total_memory(),
236 | });
237 |
238 | writeln!(
239 | &mut file_writer,
240 | "{}",
241 | serde_json::to_string(&json).unwrap()
242 | )
243 | .unwrap();
244 | }
245 |
246 | {
247 | let json = serde_json::json!({
248 | "time_micro": unix_timestamp().as_micros(),
249 | "type": "setup",
250 | "backend": backend.to_string(),
251 | "workload": args.workload,
252 | "threads": args.threads,
253 | "items": args.items,
254 | "value_size": args.value_size,
255 | "cache_size_in_bytes": args.cache_size
256 | });
257 |
258 | writeln!(
259 | &mut file_writer,
260 | "{}",
261 | serde_json::to_string(&json).unwrap()
262 | )
263 | .unwrap();
264 | }
265 |
266 | let mut prev_write_ops = 0;
267 | let mut prev_read_ops = 0;
268 |
269 | loop {
270 | if let Ok(du_bytes) = fs_extra::dir::get_size(&data_dir) {
271 | sys.refresh_all();
272 |
273 | let cpu = sys.global_cpu_info().cpu_usage();
274 |
275 | let proc = sys.processes();
276 | let child = proc.get(&pid).unwrap();
277 |
278 | let mem = child.memory() as f32;
279 | let disk = child.disk_usage();
280 |
281 | let write_ops = db.write_ops.load(Relaxed);
282 | let read_ops = db.read_ops.load(Relaxed);
283 |
284 | let dataset_size_bytes =
285 | write_ops as f64 * (args.key_size as f64 + args.value_size as f64);
286 |
287 | let space_amp = du_bytes as f64 / dataset_size_bytes;
288 |
289 | let write_amp = disk.total_written_bytes as f64 / dataset_size_bytes;
290 |
291 | let accumulated_write_latency = db
292 | .write_latency
293 | .fetch_min(0, std::sync::atomic::Ordering::Release);
294 |
295 | let accumulated_read_latency = db
296 | .read_latency
297 | .fetch_min(0, std::sync::atomic::Ordering::Release);
298 |
299 | let write_ops_since = write_ops - prev_write_ops;
300 | let read_ops_since = read_ops - prev_read_ops;
301 |
302 | let avg_write_latency = accumulated_write_latency / write_ops_since.max(1);
303 | let avg_read_latency = accumulated_read_latency / read_ops_since.max(1);
304 |
305 | let json = serde_json::json!({
306 | "backend": backend,
307 | "type": "metrics",
308 | "time_micro": unix_timestamp().as_micros(),
309 | "write_ops": write_ops,
310 | "read_ops": read_ops,
311 | "delete_ops": db.delete_ops,
312 | "scan_ops": db.scan_ops,
313 | "cpu": cpu,
314 | "mem_bytes": mem,
315 | "mem_mib": mem / 1024.0 / 1024.0,
316 | "disk_bytes_w": disk.total_written_bytes,
317 | "disk_bytes_r": disk.total_read_bytes,
318 | "disk_mib_w": (disk.total_written_bytes as f32) / 1024.0 / 1024.0,
319 | "disk_mib_r": (disk.total_read_bytes as f32) / 1024.0 / 1024.0,
320 | "du_bytes": du_bytes,
321 | "du_mib": (du_bytes as f32) / 1024.0 / 1024.0,
322 | "space_amp": space_amp,
323 | "write_amp": write_amp,
324 | "dataset_size": dataset_size_bytes,
325 | "avg_write_latency": avg_write_latency,
326 | "avg_read_latency": avg_read_latency,
327 | });
328 |
329 | prev_write_ops = write_ops;
330 | prev_read_ops = read_ops;
331 |
332 | writeln!(
333 | &mut file_writer,
334 | "{}",
335 | serde_json::to_string(&json).unwrap()
336 | )
337 | .unwrap();
338 | }
339 |
340 | // As minutes increase, decrease granularity
341 | // to keep log files low(ish)
342 | let sec = args.minutes as f32 / 2.0;
343 | let duration = Duration::from_secs_f32(sec);
344 | std::thread::sleep(duration);
345 | }
346 | });
347 | }
348 |
349 | match args.workload {
350 | Workload::TaskA => {
351 | let users = args.threads;
352 |
353 | {
354 | let mut rng = rand::thread_rng();
355 |
356 | for idx in 0..users {
357 | let user_id = format!("user{idx:0>2}");
358 |
359 | for x in 0..args.items {
360 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
361 | for _ in 0..args.value_size {
362 | val.push(rng.gen::());
363 | }
364 |
365 | let key = format!("{user_id}:{x:0>10}");
366 | let key = key.as_bytes();
367 |
368 | db.insert(key, &val, false, args.clone());
369 | }
370 | }
371 | }
372 |
373 | let threads = (0..users)
374 | .map(|idx| {
375 | let args = args.clone();
376 | let db = db.clone();
377 | let user_id = format!("user{idx:0>2}");
378 |
379 | std::thread::spawn(move || {
380 | let mut rng = rand::thread_rng();
381 |
382 | let zipf = ZipfDistribution::new((args.items - 1) as usize, 0.99).unwrap();
383 |
384 | loop {
385 | let x = zipf.sample(&mut rng);
386 | let key = format!("{user_id}:{x:0>10}");
387 | let key = key.as_bytes();
388 |
389 | let choice: f32 = rng.gen_range(0.0..1.0);
390 |
391 | if choice > 0.5 {
392 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
393 | for _ in 0..args.value_size {
394 | val.push(rng.gen::());
395 | }
396 |
397 | db.insert(key, &val, args.fsync, args.clone());
398 | } else {
399 | db.get(key).unwrap();
400 | }
401 | }
402 | })
403 | })
404 | .collect::>();
405 |
406 | start_killer(args.minutes.into());
407 |
408 | for t in threads {
409 | t.join().unwrap();
410 | }
411 | }
412 |
413 | Workload::TaskB => {
414 | let users = args.threads;
415 |
416 | {
417 | let mut rng = rand::thread_rng();
418 |
419 | for idx in 0..users {
420 | let user_id = format!("user{idx:0>2}");
421 |
422 | for x in 0..args.items {
423 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
424 | for _ in 0..args.value_size {
425 | val.push(rng.gen::());
426 | }
427 |
428 | let key = format!("{user_id}:{x:0>10}");
429 | let key = key.as_bytes();
430 |
431 | db.insert(key, &val, false, args.clone());
432 | }
433 | }
434 | }
435 |
436 | let threads = (0..users)
437 | .map(|idx| {
438 | let args = args.clone();
439 | let db = db.clone();
440 | let user_id = format!("user{idx:0>2}");
441 |
442 | std::thread::spawn(move || {
443 | let mut rng = rand::thread_rng();
444 |
445 | let zipf = ZipfDistribution::new((args.items - 1) as usize, 0.99).unwrap();
446 |
447 | loop {
448 | let x = zipf.sample(&mut rng);
449 | let key = format!("{user_id}:{x:0>10}");
450 | let key = key.as_bytes();
451 |
452 | let choice: f32 = rng.gen_range(0.0..1.0);
453 |
454 | if choice > 0.95 {
455 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
456 | for _ in 0..args.value_size {
457 | val.push(rng.gen::());
458 | }
459 |
460 | db.insert(key, &val, args.fsync, args.clone());
461 | } else {
462 | db.get(key).unwrap();
463 | }
464 | }
465 | })
466 | })
467 | .collect::>();
468 |
469 | start_killer(args.minutes.into());
470 |
471 | for t in threads {
472 | t.join().unwrap();
473 | }
474 | }
475 |
476 | Workload::TaskC => {
477 | let mut rng = rand::thread_rng();
478 |
479 | for x in 0..args.items {
480 | let key = (x as u64).to_be_bytes();
481 |
482 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
483 | for _ in 0..args.value_size {
484 | val.push(rng.gen::());
485 | }
486 |
487 | db.insert(&key, &val, false, args.clone());
488 | }
489 |
490 | start_killer(args.minutes.into());
491 |
492 | let zipf = ZipfDistribution::new((args.items - 1) as usize, 0.99).unwrap();
493 |
494 | loop {
495 | let x = zipf.sample(&mut rng);
496 | let key = (x as u64).to_be_bytes();
497 |
498 | db.get(&key).unwrap();
499 | }
500 | }
501 |
502 | Workload::TaskD => {
503 | let users = args.threads;
504 |
505 | {
506 | let mut rng = rand::thread_rng();
507 |
508 | for idx in 0..users {
509 | let user_id = format!("user{idx:0>2}");
510 |
511 | for x in 0..args.items {
512 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
513 | for _ in 0..args.value_size {
514 | val.push(rng.gen::());
515 | }
516 |
517 | let key = format!("{user_id}:{x:0>10}");
518 | let key = key.as_bytes();
519 |
520 | db.insert(key, &val, false, args.clone());
521 | }
522 | }
523 | }
524 |
525 | let threads = (0..users)
526 | .map(|idx| {
527 | let args = args.clone();
528 | let db = db.clone();
529 | let user_id = format!("user{idx:0>2}");
530 |
531 | std::thread::spawn(move || {
532 | let mut rng = rand::thread_rng();
533 | let mut records = args.items;
534 |
535 | loop {
536 | let choice: f32 = rng.gen_range(0.0..1.0);
537 |
538 | if choice > 0.95 {
539 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
540 | for _ in 0..args.value_size {
541 | val.push(rng.gen::());
542 | }
543 |
544 | let key = format!("{user_id}:{records:0>10}");
545 | let key = key.as_bytes();
546 |
547 | db.insert(key, &val, args.fsync, args.clone());
548 | records += 1;
549 | } else {
550 | let key = format!("{user_id}:{:0>10}", records - 1);
551 | let key = key.as_bytes();
552 |
553 | db.get(key).unwrap();
554 | }
555 | }
556 | })
557 | })
558 | .collect::>();
559 |
560 | start_killer(args.minutes.into());
561 |
562 | for t in threads {
563 | t.join().unwrap();
564 | }
565 | }
566 |
567 | Workload::TaskE => {
568 | let users = args.threads;
569 |
570 | {
571 | let mut rng = rand::thread_rng();
572 |
573 | for idx in 0..users {
574 | let user_id = format!("user{idx:0>2}");
575 |
576 | for x in 0..args.items {
577 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
578 | for _ in 0..args.value_size {
579 | val.push(rng.gen::());
580 | }
581 |
582 | let key = format!("{user_id}:{x:0>10}");
583 | let key = key.as_bytes();
584 |
585 | db.insert(key, &val, false, args.clone());
586 | }
587 | }
588 | }
589 |
590 | let threads = (0..users)
591 | .map(|idx| {
592 | let args = args.clone();
593 | let db = db.clone();
594 | let user_id = format!("user{idx:0>2}");
595 |
596 | std::thread::spawn(move || {
597 | let mut rng = rand::thread_rng();
598 | let mut records = args.items;
599 |
600 | loop {
601 | let choice: f32 = rng.gen_range(0.0..1.0);
602 |
603 | if choice < 0.95 {
604 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
605 | for _ in 0..args.value_size {
606 | val.push(rng.gen::());
607 | }
608 |
609 | let key = format!("{user_id}:{records:0>10}");
610 | let key = key.as_bytes();
611 |
612 | db.insert(key, &val, args.fsync, args.clone());
613 | records += 1;
614 | } else {
615 | let key = format!("{user_id}:{:0>10}", records - 1);
616 | let key = key.as_bytes();
617 |
618 | db.get(key).unwrap();
619 | }
620 | }
621 | })
622 | })
623 | .collect::>();
624 |
625 | start_killer(args.minutes.into());
626 |
627 | for t in threads {
628 | t.join().unwrap();
629 | }
630 | }
631 |
632 | Workload::TaskF => {
633 | let users = args.threads;
634 |
635 | {
636 | let mut rng = rand::thread_rng();
637 |
638 | for idx in 0..users {
639 | let user_id = format!("user{idx:0>2}");
640 |
641 | for x in 0..args.items {
642 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
643 | for _ in 0..args.value_size {
644 | val.push(rng.gen::());
645 | }
646 |
647 | let key = format!("{user_id:0>2}:{x:0>10}");
648 | let key = key.as_bytes();
649 |
650 | db.insert(key, &val, false, args.clone());
651 | }
652 | }
653 | }
654 |
655 | let threads = (0..users)
656 | .map(|idx| {
657 | let args = args.clone();
658 | let db = db.clone();
659 | let user_id = format!("user{idx:0>2}");
660 |
661 | std::thread::spawn(move || {
662 | let mut rng = rand::thread_rng();
663 | let mut records = args.items;
664 |
665 | loop {
666 | let choice: f32 = rng.gen_range(0.0..1.0);
667 |
668 | if choice > 0.95 {
669 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
670 | for _ in 0..args.value_size {
671 | val.push(rng.gen::());
672 | }
673 |
674 | let key = format!("{user_id}:{records:0>10}");
675 | let key = key.as_bytes();
676 |
677 | db.insert(key, &val, args.fsync, args.clone());
678 | records += 1;
679 | } else {
680 | let zipf =
681 | ZipfDistribution::new((records - 1) as usize, 0.99).unwrap();
682 | let x = zipf.sample(&mut rng);
683 |
684 | let key = format!("{user_id}:{x:0>10}");
685 | let key = key.as_bytes();
686 |
687 | db.get(key).unwrap();
688 | }
689 | }
690 | })
691 | })
692 | .collect::>();
693 |
694 | start_killer(args.minutes.into());
695 |
696 | for t in threads {
697 | t.join().unwrap();
698 | }
699 | }
700 |
701 | Workload::TaskG => {
702 | let users = args.threads;
703 |
704 | {
705 | let mut rng = rand::thread_rng();
706 |
707 | for idx in 0..users {
708 | let user_id = format!("user{idx:0>2}");
709 |
710 | for x in 0..args.items {
711 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
712 | for _ in 0..args.value_size {
713 | val.push(rng.gen::());
714 | }
715 |
716 | let key = format!("{user_id}:{x:0>10}");
717 | let key = key.as_bytes();
718 |
719 | db.insert(key, &val, false, args.clone());
720 | }
721 | }
722 | }
723 |
724 | let threads = (0..users)
725 | .map(|idx| {
726 | let args = args.clone();
727 | let db = db.clone();
728 | let user_id = format!("user{idx:0>2}");
729 |
730 | std::thread::spawn(move || {
731 | let mut rng = rand::thread_rng();
732 | let mut records = args.items;
733 |
734 | loop {
735 | let choice: f32 = rng.gen_range(0.0..1.0);
736 |
737 | if choice < 0.95 {
738 | let mut val: Vec = Vec::with_capacity(args.value_size as usize);
739 | for _ in 0..args.value_size {
740 | val.push(rng.gen::());
741 | }
742 |
743 | let key = format!("{user_id}:{records:0>10}");
744 | let key = key.as_bytes();
745 |
746 | db.insert(key, &val, args.fsync, args.clone());
747 | records += 1;
748 | } else {
749 | let zipf =
750 | ZipfDistribution::new((records - 1) as usize, 0.99).unwrap();
751 | let x = zipf.sample(&mut rng);
752 |
753 | let key = format!("{user_id}:{x:0>10}");
754 | let key = key.as_bytes();
755 |
756 | db.get(key).unwrap();
757 | }
758 | }
759 | })
760 | })
761 | .collect::>();
762 |
763 | start_killer(args.minutes.into());
764 |
765 | for t in threads {
766 | t.join().unwrap();
767 | }
768 | }
769 | }
770 | }
771 |
--------------------------------------------------------------------------------
/page/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '6.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | dependencies:
8 | solid-apexcharts:
9 | specifier: 0.3.2
10 | version: 0.3.2(apexcharts@3.44.0)(solid-js@1.8.5)
11 | solid-js:
12 | specifier: 1.8.5
13 | version: 1.8.5
14 |
15 | devDependencies:
16 | typescript:
17 | specifier: 5.2.2
18 | version: 5.2.2
19 | unocss:
20 | specifier: 0.58.0
21 | version: 0.58.0(postcss@8.4.31)(vite@4.5.0)
22 | vite:
23 | specifier: '4'
24 | version: 4.5.0
25 | vite-plugin-solid:
26 | specifier: 2.7.2
27 | version: 2.7.2(solid-js@1.8.5)(vite@4.5.0)
28 |
29 | packages:
30 |
31 | /@ampproject/remapping@2.2.1:
32 | resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
33 | engines: {node: '>=6.0.0'}
34 | dependencies:
35 | '@jridgewell/gen-mapping': 0.3.3
36 | '@jridgewell/trace-mapping': 0.3.20
37 | dev: true
38 |
39 | /@antfu/install-pkg@0.1.1:
40 | resolution: {integrity: sha512-LyB/8+bSfa0DFGC06zpCEfs89/XoWZwws5ygEa5D+Xsm3OfI+aXQ86VgVG7Acyef+rSZ5HE7J8rrxzrQeM3PjQ==}
41 | dependencies:
42 | execa: 5.1.1
43 | find-up: 5.0.0
44 | dev: true
45 |
46 | /@antfu/utils@0.7.6:
47 | resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==}
48 | dev: true
49 |
50 | /@babel/code-frame@7.23.5:
51 | resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
52 | engines: {node: '>=6.9.0'}
53 | dependencies:
54 | '@babel/highlight': 7.23.4
55 | chalk: 2.4.2
56 | dev: true
57 |
58 | /@babel/compat-data@7.23.5:
59 | resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
60 | engines: {node: '>=6.9.0'}
61 | dev: true
62 |
63 | /@babel/core@7.23.5:
64 | resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==}
65 | engines: {node: '>=6.9.0'}
66 | dependencies:
67 | '@ampproject/remapping': 2.2.1
68 | '@babel/code-frame': 7.23.5
69 | '@babel/generator': 7.23.5
70 | '@babel/helper-compilation-targets': 7.22.15
71 | '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5)
72 | '@babel/helpers': 7.23.5
73 | '@babel/parser': 7.23.5
74 | '@babel/template': 7.22.15
75 | '@babel/traverse': 7.23.5
76 | '@babel/types': 7.23.5
77 | convert-source-map: 2.0.0
78 | debug: 4.3.4
79 | gensync: 1.0.0-beta.2
80 | json5: 2.2.3
81 | semver: 6.3.1
82 | transitivePeerDependencies:
83 | - supports-color
84 | dev: true
85 |
86 | /@babel/generator@7.23.5:
87 | resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==}
88 | engines: {node: '>=6.9.0'}
89 | dependencies:
90 | '@babel/types': 7.23.5
91 | '@jridgewell/gen-mapping': 0.3.3
92 | '@jridgewell/trace-mapping': 0.3.20
93 | jsesc: 2.5.2
94 | dev: true
95 |
96 | /@babel/helper-annotate-as-pure@7.22.5:
97 | resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
98 | engines: {node: '>=6.9.0'}
99 | dependencies:
100 | '@babel/types': 7.23.5
101 | dev: true
102 |
103 | /@babel/helper-compilation-targets@7.22.15:
104 | resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==}
105 | engines: {node: '>=6.9.0'}
106 | dependencies:
107 | '@babel/compat-data': 7.23.5
108 | '@babel/helper-validator-option': 7.23.5
109 | browserslist: 4.22.1
110 | lru-cache: 5.1.1
111 | semver: 6.3.1
112 | dev: true
113 |
114 | /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.23.5):
115 | resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==}
116 | engines: {node: '>=6.9.0'}
117 | peerDependencies:
118 | '@babel/core': ^7.0.0
119 | dependencies:
120 | '@babel/core': 7.23.5
121 | '@babel/helper-annotate-as-pure': 7.22.5
122 | '@babel/helper-environment-visitor': 7.22.20
123 | '@babel/helper-function-name': 7.23.0
124 | '@babel/helper-member-expression-to-functions': 7.23.0
125 | '@babel/helper-optimise-call-expression': 7.22.5
126 | '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5)
127 | '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
128 | '@babel/helper-split-export-declaration': 7.22.6
129 | semver: 6.3.1
130 | dev: true
131 |
132 | /@babel/helper-environment-visitor@7.22.20:
133 | resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
134 | engines: {node: '>=6.9.0'}
135 | dev: true
136 |
137 | /@babel/helper-function-name@7.23.0:
138 | resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
139 | engines: {node: '>=6.9.0'}
140 | dependencies:
141 | '@babel/template': 7.22.15
142 | '@babel/types': 7.23.5
143 | dev: true
144 |
145 | /@babel/helper-hoist-variables@7.22.5:
146 | resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
147 | engines: {node: '>=6.9.0'}
148 | dependencies:
149 | '@babel/types': 7.23.5
150 | dev: true
151 |
152 | /@babel/helper-member-expression-to-functions@7.23.0:
153 | resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
154 | engines: {node: '>=6.9.0'}
155 | dependencies:
156 | '@babel/types': 7.23.5
157 | dev: true
158 |
159 | /@babel/helper-module-imports@7.18.6:
160 | resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
161 | engines: {node: '>=6.9.0'}
162 | dependencies:
163 | '@babel/types': 7.23.5
164 | dev: true
165 |
166 | /@babel/helper-module-imports@7.22.15:
167 | resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
168 | engines: {node: '>=6.9.0'}
169 | dependencies:
170 | '@babel/types': 7.23.5
171 | dev: true
172 |
173 | /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5):
174 | resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
175 | engines: {node: '>=6.9.0'}
176 | peerDependencies:
177 | '@babel/core': ^7.0.0
178 | dependencies:
179 | '@babel/core': 7.23.5
180 | '@babel/helper-environment-visitor': 7.22.20
181 | '@babel/helper-module-imports': 7.22.15
182 | '@babel/helper-simple-access': 7.22.5
183 | '@babel/helper-split-export-declaration': 7.22.6
184 | '@babel/helper-validator-identifier': 7.22.20
185 | dev: true
186 |
187 | /@babel/helper-optimise-call-expression@7.22.5:
188 | resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
189 | engines: {node: '>=6.9.0'}
190 | dependencies:
191 | '@babel/types': 7.23.5
192 | dev: true
193 |
194 | /@babel/helper-plugin-utils@7.22.5:
195 | resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==}
196 | engines: {node: '>=6.9.0'}
197 | dev: true
198 |
199 | /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.5):
200 | resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==}
201 | engines: {node: '>=6.9.0'}
202 | peerDependencies:
203 | '@babel/core': ^7.0.0
204 | dependencies:
205 | '@babel/core': 7.23.5
206 | '@babel/helper-environment-visitor': 7.22.20
207 | '@babel/helper-member-expression-to-functions': 7.23.0
208 | '@babel/helper-optimise-call-expression': 7.22.5
209 | dev: true
210 |
211 | /@babel/helper-simple-access@7.22.5:
212 | resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
213 | engines: {node: '>=6.9.0'}
214 | dependencies:
215 | '@babel/types': 7.23.5
216 | dev: true
217 |
218 | /@babel/helper-skip-transparent-expression-wrappers@7.22.5:
219 | resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
220 | engines: {node: '>=6.9.0'}
221 | dependencies:
222 | '@babel/types': 7.23.5
223 | dev: true
224 |
225 | /@babel/helper-split-export-declaration@7.22.6:
226 | resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
227 | engines: {node: '>=6.9.0'}
228 | dependencies:
229 | '@babel/types': 7.23.5
230 | dev: true
231 |
232 | /@babel/helper-string-parser@7.23.4:
233 | resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==}
234 | engines: {node: '>=6.9.0'}
235 | dev: true
236 |
237 | /@babel/helper-validator-identifier@7.22.20:
238 | resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
239 | engines: {node: '>=6.9.0'}
240 | dev: true
241 |
242 | /@babel/helper-validator-option@7.23.5:
243 | resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
244 | engines: {node: '>=6.9.0'}
245 | dev: true
246 |
247 | /@babel/helpers@7.23.5:
248 | resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==}
249 | engines: {node: '>=6.9.0'}
250 | dependencies:
251 | '@babel/template': 7.22.15
252 | '@babel/traverse': 7.23.5
253 | '@babel/types': 7.23.5
254 | transitivePeerDependencies:
255 | - supports-color
256 | dev: true
257 |
258 | /@babel/highlight@7.23.4:
259 | resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==}
260 | engines: {node: '>=6.9.0'}
261 | dependencies:
262 | '@babel/helper-validator-identifier': 7.22.20
263 | chalk: 2.4.2
264 | js-tokens: 4.0.0
265 | dev: true
266 |
267 | /@babel/parser@7.23.5:
268 | resolution: {integrity: sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==}
269 | engines: {node: '>=6.0.0'}
270 | hasBin: true
271 | dependencies:
272 | '@babel/types': 7.23.5
273 | dev: true
274 |
275 | /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5):
276 | resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
277 | engines: {node: '>=6.9.0'}
278 | peerDependencies:
279 | '@babel/core': ^7.0.0-0
280 | dependencies:
281 | '@babel/core': 7.23.5
282 | '@babel/helper-plugin-utils': 7.22.5
283 | dev: true
284 |
285 | /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5):
286 | resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
287 | engines: {node: '>=6.9.0'}
288 | peerDependencies:
289 | '@babel/core': ^7.0.0-0
290 | dependencies:
291 | '@babel/core': 7.23.5
292 | '@babel/helper-plugin-utils': 7.22.5
293 | dev: true
294 |
295 | /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.5):
296 | resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==}
297 | engines: {node: '>=6.9.0'}
298 | peerDependencies:
299 | '@babel/core': ^7.0.0-0
300 | dependencies:
301 | '@babel/core': 7.23.5
302 | '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.5)
303 | '@babel/helper-plugin-utils': 7.22.5
304 | '@babel/helper-simple-access': 7.22.5
305 | dev: true
306 |
307 | /@babel/plugin-transform-typescript@7.23.5(@babel/core@7.23.5):
308 | resolution: {integrity: sha512-2fMkXEJkrmwgu2Bsv1Saxgj30IXZdJ+84lQcKKI7sm719oXs0BBw2ZENKdJdR1PjWndgLCEBNXJOri0fk7RYQA==}
309 | engines: {node: '>=6.9.0'}
310 | peerDependencies:
311 | '@babel/core': ^7.0.0-0
312 | dependencies:
313 | '@babel/core': 7.23.5
314 | '@babel/helper-annotate-as-pure': 7.22.5
315 | '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5)
316 | '@babel/helper-plugin-utils': 7.22.5
317 | '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.5)
318 | dev: true
319 |
320 | /@babel/preset-typescript@7.23.3(@babel/core@7.23.5):
321 | resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==}
322 | engines: {node: '>=6.9.0'}
323 | peerDependencies:
324 | '@babel/core': ^7.0.0-0
325 | dependencies:
326 | '@babel/core': 7.23.5
327 | '@babel/helper-plugin-utils': 7.22.5
328 | '@babel/helper-validator-option': 7.23.5
329 | '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5)
330 | '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.5)
331 | '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.23.5)
332 | dev: true
333 |
334 | /@babel/template@7.22.15:
335 | resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
336 | engines: {node: '>=6.9.0'}
337 | dependencies:
338 | '@babel/code-frame': 7.23.5
339 | '@babel/parser': 7.23.5
340 | '@babel/types': 7.23.5
341 | dev: true
342 |
343 | /@babel/traverse@7.23.5:
344 | resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==}
345 | engines: {node: '>=6.9.0'}
346 | dependencies:
347 | '@babel/code-frame': 7.23.5
348 | '@babel/generator': 7.23.5
349 | '@babel/helper-environment-visitor': 7.22.20
350 | '@babel/helper-function-name': 7.23.0
351 | '@babel/helper-hoist-variables': 7.22.5
352 | '@babel/helper-split-export-declaration': 7.22.6
353 | '@babel/parser': 7.23.5
354 | '@babel/types': 7.23.5
355 | debug: 4.3.4
356 | globals: 11.12.0
357 | transitivePeerDependencies:
358 | - supports-color
359 | dev: true
360 |
361 | /@babel/types@7.23.5:
362 | resolution: {integrity: sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==}
363 | engines: {node: '>=6.9.0'}
364 | dependencies:
365 | '@babel/helper-string-parser': 7.23.4
366 | '@babel/helper-validator-identifier': 7.22.20
367 | to-fast-properties: 2.0.0
368 | dev: true
369 |
370 | /@esbuild/android-arm64@0.18.20:
371 | resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
372 | engines: {node: '>=12'}
373 | cpu: [arm64]
374 | os: [android]
375 | requiresBuild: true
376 | dev: true
377 | optional: true
378 |
379 | /@esbuild/android-arm@0.18.20:
380 | resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
381 | engines: {node: '>=12'}
382 | cpu: [arm]
383 | os: [android]
384 | requiresBuild: true
385 | dev: true
386 | optional: true
387 |
388 | /@esbuild/android-x64@0.18.20:
389 | resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
390 | engines: {node: '>=12'}
391 | cpu: [x64]
392 | os: [android]
393 | requiresBuild: true
394 | dev: true
395 | optional: true
396 |
397 | /@esbuild/darwin-arm64@0.18.20:
398 | resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
399 | engines: {node: '>=12'}
400 | cpu: [arm64]
401 | os: [darwin]
402 | requiresBuild: true
403 | dev: true
404 | optional: true
405 |
406 | /@esbuild/darwin-x64@0.18.20:
407 | resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
408 | engines: {node: '>=12'}
409 | cpu: [x64]
410 | os: [darwin]
411 | requiresBuild: true
412 | dev: true
413 | optional: true
414 |
415 | /@esbuild/freebsd-arm64@0.18.20:
416 | resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
417 | engines: {node: '>=12'}
418 | cpu: [arm64]
419 | os: [freebsd]
420 | requiresBuild: true
421 | dev: true
422 | optional: true
423 |
424 | /@esbuild/freebsd-x64@0.18.20:
425 | resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
426 | engines: {node: '>=12'}
427 | cpu: [x64]
428 | os: [freebsd]
429 | requiresBuild: true
430 | dev: true
431 | optional: true
432 |
433 | /@esbuild/linux-arm64@0.18.20:
434 | resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
435 | engines: {node: '>=12'}
436 | cpu: [arm64]
437 | os: [linux]
438 | requiresBuild: true
439 | dev: true
440 | optional: true
441 |
442 | /@esbuild/linux-arm@0.18.20:
443 | resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
444 | engines: {node: '>=12'}
445 | cpu: [arm]
446 | os: [linux]
447 | requiresBuild: true
448 | dev: true
449 | optional: true
450 |
451 | /@esbuild/linux-ia32@0.18.20:
452 | resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
453 | engines: {node: '>=12'}
454 | cpu: [ia32]
455 | os: [linux]
456 | requiresBuild: true
457 | dev: true
458 | optional: true
459 |
460 | /@esbuild/linux-loong64@0.18.20:
461 | resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
462 | engines: {node: '>=12'}
463 | cpu: [loong64]
464 | os: [linux]
465 | requiresBuild: true
466 | dev: true
467 | optional: true
468 |
469 | /@esbuild/linux-mips64el@0.18.20:
470 | resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
471 | engines: {node: '>=12'}
472 | cpu: [mips64el]
473 | os: [linux]
474 | requiresBuild: true
475 | dev: true
476 | optional: true
477 |
478 | /@esbuild/linux-ppc64@0.18.20:
479 | resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
480 | engines: {node: '>=12'}
481 | cpu: [ppc64]
482 | os: [linux]
483 | requiresBuild: true
484 | dev: true
485 | optional: true
486 |
487 | /@esbuild/linux-riscv64@0.18.20:
488 | resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
489 | engines: {node: '>=12'}
490 | cpu: [riscv64]
491 | os: [linux]
492 | requiresBuild: true
493 | dev: true
494 | optional: true
495 |
496 | /@esbuild/linux-s390x@0.18.20:
497 | resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
498 | engines: {node: '>=12'}
499 | cpu: [s390x]
500 | os: [linux]
501 | requiresBuild: true
502 | dev: true
503 | optional: true
504 |
505 | /@esbuild/linux-x64@0.18.20:
506 | resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
507 | engines: {node: '>=12'}
508 | cpu: [x64]
509 | os: [linux]
510 | requiresBuild: true
511 | dev: true
512 | optional: true
513 |
514 | /@esbuild/netbsd-x64@0.18.20:
515 | resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
516 | engines: {node: '>=12'}
517 | cpu: [x64]
518 | os: [netbsd]
519 | requiresBuild: true
520 | dev: true
521 | optional: true
522 |
523 | /@esbuild/openbsd-x64@0.18.20:
524 | resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
525 | engines: {node: '>=12'}
526 | cpu: [x64]
527 | os: [openbsd]
528 | requiresBuild: true
529 | dev: true
530 | optional: true
531 |
532 | /@esbuild/sunos-x64@0.18.20:
533 | resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
534 | engines: {node: '>=12'}
535 | cpu: [x64]
536 | os: [sunos]
537 | requiresBuild: true
538 | dev: true
539 | optional: true
540 |
541 | /@esbuild/win32-arm64@0.18.20:
542 | resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
543 | engines: {node: '>=12'}
544 | cpu: [arm64]
545 | os: [win32]
546 | requiresBuild: true
547 | dev: true
548 | optional: true
549 |
550 | /@esbuild/win32-ia32@0.18.20:
551 | resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
552 | engines: {node: '>=12'}
553 | cpu: [ia32]
554 | os: [win32]
555 | requiresBuild: true
556 | dev: true
557 | optional: true
558 |
559 | /@esbuild/win32-x64@0.18.20:
560 | resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
561 | engines: {node: '>=12'}
562 | cpu: [x64]
563 | os: [win32]
564 | requiresBuild: true
565 | dev: true
566 | optional: true
567 |
568 | /@iconify/types@2.0.0:
569 | resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
570 | dev: true
571 |
572 | /@iconify/utils@2.1.12:
573 | resolution: {integrity: sha512-7vf3Uk6H7TKX4QMs2gbg5KR1X9J0NJzKSRNWhMZ+PWN92l0t6Q3tj2ZxLDG07rC3ppWBtTtA4FPmkQphuEmdsg==}
574 | dependencies:
575 | '@antfu/install-pkg': 0.1.1
576 | '@antfu/utils': 0.7.6
577 | '@iconify/types': 2.0.0
578 | debug: 4.3.4
579 | kolorist: 1.8.0
580 | local-pkg: 0.4.3
581 | transitivePeerDependencies:
582 | - supports-color
583 | dev: true
584 |
585 | /@jridgewell/gen-mapping@0.3.3:
586 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
587 | engines: {node: '>=6.0.0'}
588 | dependencies:
589 | '@jridgewell/set-array': 1.1.2
590 | '@jridgewell/sourcemap-codec': 1.4.15
591 | '@jridgewell/trace-mapping': 0.3.20
592 | dev: true
593 |
594 | /@jridgewell/resolve-uri@3.1.1:
595 | resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
596 | engines: {node: '>=6.0.0'}
597 | dev: true
598 |
599 | /@jridgewell/set-array@1.1.2:
600 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
601 | engines: {node: '>=6.0.0'}
602 | dev: true
603 |
604 | /@jridgewell/sourcemap-codec@1.4.15:
605 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
606 | dev: true
607 |
608 | /@jridgewell/trace-mapping@0.3.20:
609 | resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==}
610 | dependencies:
611 | '@jridgewell/resolve-uri': 3.1.1
612 | '@jridgewell/sourcemap-codec': 1.4.15
613 | dev: true
614 |
615 | /@nodelib/fs.scandir@2.1.5:
616 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
617 | engines: {node: '>= 8'}
618 | dependencies:
619 | '@nodelib/fs.stat': 2.0.5
620 | run-parallel: 1.2.0
621 | dev: true
622 |
623 | /@nodelib/fs.stat@2.0.5:
624 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
625 | engines: {node: '>= 8'}
626 | dev: true
627 |
628 | /@nodelib/fs.walk@1.2.8:
629 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
630 | engines: {node: '>= 8'}
631 | dependencies:
632 | '@nodelib/fs.scandir': 2.1.5
633 | fastq: 1.15.0
634 | dev: true
635 |
636 | /@polka/url@1.0.0-next.24:
637 | resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
638 | dev: true
639 |
640 | /@rollup/pluginutils@5.1.0:
641 | resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
642 | engines: {node: '>=14.0.0'}
643 | peerDependencies:
644 | rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
645 | peerDependenciesMeta:
646 | rollup:
647 | optional: true
648 | dependencies:
649 | '@types/estree': 1.0.5
650 | estree-walker: 2.0.2
651 | picomatch: 2.3.1
652 | dev: true
653 |
654 | /@types/babel__core@7.20.5:
655 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
656 | dependencies:
657 | '@babel/parser': 7.23.5
658 | '@babel/types': 7.23.5
659 | '@types/babel__generator': 7.6.7
660 | '@types/babel__template': 7.4.4
661 | '@types/babel__traverse': 7.20.4
662 | dev: true
663 |
664 | /@types/babel__generator@7.6.7:
665 | resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==}
666 | dependencies:
667 | '@babel/types': 7.23.5
668 | dev: true
669 |
670 | /@types/babel__template@7.4.4:
671 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
672 | dependencies:
673 | '@babel/parser': 7.23.5
674 | '@babel/types': 7.23.5
675 | dev: true
676 |
677 | /@types/babel__traverse@7.20.4:
678 | resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==}
679 | dependencies:
680 | '@babel/types': 7.23.5
681 | dev: true
682 |
683 | /@types/estree@1.0.5:
684 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
685 | dev: true
686 |
687 | /@unocss/astro@0.58.0(vite@4.5.0):
688 | resolution: {integrity: sha512-df+tEFO5eKXjQOwSWQhS9IdjD0sfLHLtn8U09sEKR2Nmh5CvpwyBxmvLQgOCilPou7ehmyKfsyGRLZg7IMp+Ew==}
689 | peerDependencies:
690 | vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
691 | peerDependenciesMeta:
692 | vite:
693 | optional: true
694 | dependencies:
695 | '@unocss/core': 0.58.0
696 | '@unocss/reset': 0.58.0
697 | '@unocss/vite': 0.58.0(vite@4.5.0)
698 | vite: 4.5.0
699 | transitivePeerDependencies:
700 | - rollup
701 | dev: true
702 |
703 | /@unocss/cli@0.58.0:
704 | resolution: {integrity: sha512-rhsrDBxAVueygMcAbMkbuvsHbBL2rG6N96LllYwHn16FLgOE3Sf4JW1/LlNjQje3BtwMMtbSCCAeu2SryFhzbw==}
705 | engines: {node: '>=14'}
706 | hasBin: true
707 | dependencies:
708 | '@ampproject/remapping': 2.2.1
709 | '@rollup/pluginutils': 5.1.0
710 | '@unocss/config': 0.58.0
711 | '@unocss/core': 0.58.0
712 | '@unocss/preset-uno': 0.58.0
713 | cac: 6.7.14
714 | chokidar: 3.5.3
715 | colorette: 2.0.20
716 | consola: 3.2.3
717 | fast-glob: 3.3.2
718 | magic-string: 0.30.5
719 | pathe: 1.1.1
720 | perfect-debounce: 1.0.0
721 | transitivePeerDependencies:
722 | - rollup
723 | dev: true
724 |
725 | /@unocss/config@0.58.0:
726 | resolution: {integrity: sha512-WQD29gCZ7cajnMzezD1PRW0qQSxo/C6PX9ktygwhdinFx9nXuLZnKFOz65TiI8y48e53g1i7ivvgY3m4Sq5mIg==}
727 | engines: {node: '>=14'}
728 | dependencies:
729 | '@unocss/core': 0.58.0
730 | unconfig: 0.3.11
731 | dev: true
732 |
733 | /@unocss/core@0.58.0:
734 | resolution: {integrity: sha512-KhABQXGE2AgtO9vE28d+HnciuyGDcuygsnQdUwlzUuR4K05OSw2kRE9emRN4HaMycD+gA/zDbQrJxTXb6mQUiA==}
735 | dev: true
736 |
737 | /@unocss/extractor-arbitrary-variants@0.58.0:
738 | resolution: {integrity: sha512-s9wK2UugJM0WK1HpgPz2kTbpeyQc46zais+nauN/ykVX6NMq8PtGzSWszzf+0aIbtWAQGiqAfiYNTpf09tJHfg==}
739 | dependencies:
740 | '@unocss/core': 0.58.0
741 | dev: true
742 |
743 | /@unocss/inspector@0.58.0:
744 | resolution: {integrity: sha512-ZC4QauFGdh3/VkzW/FqkO2R03JEbzGNuX0DK03pwas8/jFIGh8pPldesj8GEKm1YWr1emx9cw7JUnhR8XSUBlA==}
745 | dependencies:
746 | '@unocss/core': 0.58.0
747 | '@unocss/rule-utils': 0.58.0
748 | gzip-size: 6.0.0
749 | sirv: 2.0.3
750 | dev: true
751 |
752 | /@unocss/postcss@0.58.0(postcss@8.4.31):
753 | resolution: {integrity: sha512-2hAwLbfUFqysi8FN1cn3xkHy5GhLMlYy6W4NrAZ2ws7F2MKpsCT2xCj7dT5cI2tW8ulD2YoVbKH15dBhNsMNUA==}
754 | engines: {node: '>=14'}
755 | peerDependencies:
756 | postcss: ^8.4.21
757 | dependencies:
758 | '@unocss/config': 0.58.0
759 | '@unocss/core': 0.58.0
760 | '@unocss/rule-utils': 0.58.0
761 | css-tree: 2.3.1
762 | fast-glob: 3.3.2
763 | magic-string: 0.30.5
764 | postcss: 8.4.31
765 | dev: true
766 |
767 | /@unocss/preset-attributify@0.58.0:
768 | resolution: {integrity: sha512-Ew78noYes12K9gk4dF36MkjpiIqTi1XVqcniiAzxCkzuctxN4B57vW3LVTwjInGmWNNKWN3UNR4q1o0VxH4xJg==}
769 | dependencies:
770 | '@unocss/core': 0.58.0
771 | dev: true
772 |
773 | /@unocss/preset-icons@0.58.0:
774 | resolution: {integrity: sha512-niT32avw+8l+L40LGhrmX6qDV9Z8/gOn4xjjRhLZZouKni3CJOpz9taILyF4xp1nak5nxGT4wa0tuC/htvOF5A==}
775 | dependencies:
776 | '@iconify/utils': 2.1.12
777 | '@unocss/core': 0.58.0
778 | ofetch: 1.3.3
779 | transitivePeerDependencies:
780 | - supports-color
781 | dev: true
782 |
783 | /@unocss/preset-mini@0.58.0:
784 | resolution: {integrity: sha512-oMliJZVTN3ecAvf52yN+MyJszaJOZoKwMMbUAFqVis62MaqRzZ8mSw12QFLFyX2pltulDFpMBTAKro+hP0wXEg==}
785 | dependencies:
786 | '@unocss/core': 0.58.0
787 | '@unocss/extractor-arbitrary-variants': 0.58.0
788 | '@unocss/rule-utils': 0.58.0
789 | dev: true
790 |
791 | /@unocss/preset-tagify@0.58.0:
792 | resolution: {integrity: sha512-I+dzfs/bofiGb2AUxkhcTDhB+r2+/3SO81PFwf3Ae7afnzhA2SLsKAkEqO8YN3M3mwZL7IfXn6vpsWeEAlk/yw==}
793 | dependencies:
794 | '@unocss/core': 0.58.0
795 | dev: true
796 |
797 | /@unocss/preset-typography@0.58.0:
798 | resolution: {integrity: sha512-8qo+Z1CJtXFMDbAvtizUTRLuLxCIzytgYU0GmuRkfc2iwASSDNDsvh8nAYQfWpyAEOV7QEHtS9c9xL4b0c89FA==}
799 | dependencies:
800 | '@unocss/core': 0.58.0
801 | '@unocss/preset-mini': 0.58.0
802 | dev: true
803 |
804 | /@unocss/preset-uno@0.58.0:
805 | resolution: {integrity: sha512-DpgfjtvSgsWeyZH+jQHc1k5IReiZNb7oGpHVnfF6SlHETTnMHSeNetxkPQWYrqJLPI6llNLPTdTa5j47NtmOiA==}
806 | dependencies:
807 | '@unocss/core': 0.58.0
808 | '@unocss/preset-mini': 0.58.0
809 | '@unocss/preset-wind': 0.58.0
810 | '@unocss/rule-utils': 0.58.0
811 | dev: true
812 |
813 | /@unocss/preset-web-fonts@0.58.0:
814 | resolution: {integrity: sha512-QarDDEUlexQ2IIn23pE1eHDskG2Tz+JjCe+FAN0DoNLLhvUUWSB4cQIMFWP6dSMJ047Blj9IpgAl9dERICW1qQ==}
815 | dependencies:
816 | '@unocss/core': 0.58.0
817 | ofetch: 1.3.3
818 | dev: true
819 |
820 | /@unocss/preset-wind@0.58.0:
821 | resolution: {integrity: sha512-2zgaIy9RAGie9CsUYCkYRDSERBi8kG6Q/mQLgNfP9HMz5IThlnDHFWF/hLAVD51xQUg9gH8qWBR9kN/1ioT5Tw==}
822 | dependencies:
823 | '@unocss/core': 0.58.0
824 | '@unocss/preset-mini': 0.58.0
825 | '@unocss/rule-utils': 0.58.0
826 | dev: true
827 |
828 | /@unocss/reset@0.58.0:
829 | resolution: {integrity: sha512-UVZ5kz37JGbwAA06k/gjKYcekcTwi6oIhev1EpTtCvHLL6XYcYqcwb/u4Wjzprd3L3lxDGYXvGdjREGm2u7vbQ==}
830 | dev: true
831 |
832 | /@unocss/rule-utils@0.58.0:
833 | resolution: {integrity: sha512-LBJ9dJ/j5UIMzJF7pmIig55MtJAYtG+tn/zQRveZuPRVahzP+KqwlyB7u3uCUnQhdgo/MJODMcqyr0jl6+kTuA==}
834 | engines: {node: '>=14'}
835 | dependencies:
836 | '@unocss/core': 0.58.0
837 | magic-string: 0.30.5
838 | dev: true
839 |
840 | /@unocss/scope@0.58.0:
841 | resolution: {integrity: sha512-XgUXZJvbxWSRC/DNOWI5DYdR6Nd6IZxsE5ls3AFA5msgtk5OH4YNQELLMabQw7xbRbU/fftlRJa3vncSfOyl6w==}
842 | dev: true
843 |
844 | /@unocss/transformer-attributify-jsx-babel@0.58.0:
845 | resolution: {integrity: sha512-ckDq/q476x2yikjS8usmSUGuakqMQrg2pm8sdBINTPdJxGc7kJRvI5UDnzRw4W9hE5IH+E4gg0XfCtFad0O3eg==}
846 | dependencies:
847 | '@babel/core': 7.23.5
848 | '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5)
849 | '@babel/preset-typescript': 7.23.3(@babel/core@7.23.5)
850 | '@unocss/core': 0.58.0
851 | transitivePeerDependencies:
852 | - supports-color
853 | dev: true
854 |
855 | /@unocss/transformer-attributify-jsx@0.58.0:
856 | resolution: {integrity: sha512-QDdBEFDE7ntfCH7+8zHRW72MIQ9NH3uYGUE7lYgr5Ap8qzBHCxMT1kUrY6gwuoo3U4dMu2wruglYRHD88hvGkw==}
857 | dependencies:
858 | '@unocss/core': 0.58.0
859 | dev: true
860 |
861 | /@unocss/transformer-compile-class@0.58.0:
862 | resolution: {integrity: sha512-/BysfTg2q9sGPfiRHqWw/bT60/gjpBGBRVkIFsG4WVT2pgf3BfQUPu5FumSvZSRd0rA/pR57Lp6ZREAdj6+q+A==}
863 | dependencies:
864 | '@unocss/core': 0.58.0
865 | dev: true
866 |
867 | /@unocss/transformer-directives@0.58.0:
868 | resolution: {integrity: sha512-sU2U/aIykRkGGbA4Qo9Z5XE/KqWf7KhBwC1m8pUoqjawsZex4aVnQgXzDPfcjtmy6pElwK0z2U5DnO+OK9vCgQ==}
869 | dependencies:
870 | '@unocss/core': 0.58.0
871 | '@unocss/rule-utils': 0.58.0
872 | css-tree: 2.3.1
873 | dev: true
874 |
875 | /@unocss/transformer-variant-group@0.58.0:
876 | resolution: {integrity: sha512-O2n8uVIpNic57rrkaaQ8jnC1WJ9N6FkoqxatRDXZ368aJ1CJNya0ZcVUL6lGGND0bOLXen4WmEN62ZxEWTqdkA==}
877 | dependencies:
878 | '@unocss/core': 0.58.0
879 | dev: true
880 |
881 | /@unocss/vite@0.58.0(vite@4.5.0):
882 | resolution: {integrity: sha512-OCUOLMSOBEtXOEyBbAvMI3/xdR175BWRzmvV9Wc34ANZclEvCdVH8+WU725ibjY4VT0gVIuX68b13fhXdHV41A==}
883 | peerDependencies:
884 | vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
885 | dependencies:
886 | '@ampproject/remapping': 2.2.1
887 | '@rollup/pluginutils': 5.1.0
888 | '@unocss/config': 0.58.0
889 | '@unocss/core': 0.58.0
890 | '@unocss/inspector': 0.58.0
891 | '@unocss/scope': 0.58.0
892 | '@unocss/transformer-directives': 0.58.0
893 | chokidar: 3.5.3
894 | fast-glob: 3.3.2
895 | magic-string: 0.30.5
896 | vite: 4.5.0
897 | transitivePeerDependencies:
898 | - rollup
899 | dev: true
900 |
901 | /@yr/monotone-cubic-spline@1.0.3:
902 | resolution: {integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==}
903 | dev: false
904 |
905 | /acorn@8.11.2:
906 | resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==}
907 | engines: {node: '>=0.4.0'}
908 | hasBin: true
909 | dev: true
910 |
911 | /ansi-styles@3.2.1:
912 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
913 | engines: {node: '>=4'}
914 | dependencies:
915 | color-convert: 1.9.3
916 | dev: true
917 |
918 | /anymatch@3.1.3:
919 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
920 | engines: {node: '>= 8'}
921 | dependencies:
922 | normalize-path: 3.0.0
923 | picomatch: 2.3.1
924 | dev: true
925 |
926 | /apexcharts@3.44.0:
927 | resolution: {integrity: sha512-u7Xzrbcxc2yWznN78Jh5NMCYVAsWDfBjRl5ea++rVzFAqjU2hLz4RgKIFwYOBDRQtW1e/Qz8azJTqIJ1+Vu9Qg==}
928 | dependencies:
929 | '@yr/monotone-cubic-spline': 1.0.3
930 | svg.draggable.js: 2.2.2
931 | svg.easing.js: 2.0.0
932 | svg.filter.js: 2.0.2
933 | svg.pathmorphing.js: 0.1.3
934 | svg.resize.js: 1.4.3
935 | svg.select.js: 3.0.1
936 | dev: false
937 |
938 | /babel-plugin-jsx-dom-expressions@0.37.9(@babel/core@7.23.5):
939 | resolution: {integrity: sha512-6w+zs2i14fVanj4e1hXCU5cp+x0U0LJ5jScknpMZZUteHhwFRGJflHMVJ+xAcW7ku41FYjr7DgtK9mnc2SXlJg==}
940 | peerDependencies:
941 | '@babel/core': ^7.20.12
942 | dependencies:
943 | '@babel/core': 7.23.5
944 | '@babel/helper-module-imports': 7.18.6
945 | '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5)
946 | '@babel/types': 7.23.5
947 | html-entities: 2.3.3
948 | validate-html-nesting: 1.2.2
949 | dev: true
950 |
951 | /babel-preset-solid@1.8.6(@babel/core@7.23.5):
952 | resolution: {integrity: sha512-Ened42CHjU4EFkvNeS042/3Pm21yvMWn8p4G4ddzQTlKaMwSGGD1VciA/e7EshBVHJCcBj9vHiUd/r3A4qLPZA==}
953 | peerDependencies:
954 | '@babel/core': ^7.0.0
955 | dependencies:
956 | '@babel/core': 7.23.5
957 | babel-plugin-jsx-dom-expressions: 0.37.9(@babel/core@7.23.5)
958 | dev: true
959 |
960 | /binary-extensions@2.2.0:
961 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
962 | engines: {node: '>=8'}
963 | dev: true
964 |
965 | /braces@3.0.2:
966 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
967 | engines: {node: '>=8'}
968 | dependencies:
969 | fill-range: 7.0.1
970 | dev: true
971 |
972 | /browserslist@4.22.1:
973 | resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==}
974 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
975 | hasBin: true
976 | dependencies:
977 | caniuse-lite: 1.0.30001565
978 | electron-to-chromium: 1.4.598
979 | node-releases: 2.0.13
980 | update-browserslist-db: 1.0.13(browserslist@4.22.1)
981 | dev: true
982 |
983 | /cac@6.7.14:
984 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
985 | engines: {node: '>=8'}
986 | dev: true
987 |
988 | /caniuse-lite@1.0.30001565:
989 | resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==}
990 | dev: true
991 |
992 | /chalk@2.4.2:
993 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
994 | engines: {node: '>=4'}
995 | dependencies:
996 | ansi-styles: 3.2.1
997 | escape-string-regexp: 1.0.5
998 | supports-color: 5.5.0
999 | dev: true
1000 |
1001 | /chokidar@3.5.3:
1002 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
1003 | engines: {node: '>= 8.10.0'}
1004 | dependencies:
1005 | anymatch: 3.1.3
1006 | braces: 3.0.2
1007 | glob-parent: 5.1.2
1008 | is-binary-path: 2.1.0
1009 | is-glob: 4.0.3
1010 | normalize-path: 3.0.0
1011 | readdirp: 3.6.0
1012 | optionalDependencies:
1013 | fsevents: 2.3.3
1014 | dev: true
1015 |
1016 | /color-convert@1.9.3:
1017 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
1018 | dependencies:
1019 | color-name: 1.1.3
1020 | dev: true
1021 |
1022 | /color-name@1.1.3:
1023 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
1024 | dev: true
1025 |
1026 | /colorette@2.0.20:
1027 | resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
1028 | dev: true
1029 |
1030 | /consola@3.2.3:
1031 | resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
1032 | engines: {node: ^14.18.0 || >=16.10.0}
1033 | dev: true
1034 |
1035 | /convert-source-map@2.0.0:
1036 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
1037 | dev: true
1038 |
1039 | /cross-spawn@7.0.3:
1040 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
1041 | engines: {node: '>= 8'}
1042 | dependencies:
1043 | path-key: 3.1.1
1044 | shebang-command: 2.0.0
1045 | which: 2.0.2
1046 | dev: true
1047 |
1048 | /css-tree@2.3.1:
1049 | resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
1050 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
1051 | dependencies:
1052 | mdn-data: 2.0.30
1053 | source-map-js: 1.0.2
1054 | dev: true
1055 |
1056 | /csstype@3.1.2:
1057 | resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
1058 |
1059 | /debug@4.3.4:
1060 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
1061 | engines: {node: '>=6.0'}
1062 | peerDependencies:
1063 | supports-color: '*'
1064 | peerDependenciesMeta:
1065 | supports-color:
1066 | optional: true
1067 | dependencies:
1068 | ms: 2.1.2
1069 | dev: true
1070 |
1071 | /defu@6.1.3:
1072 | resolution: {integrity: sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==}
1073 |
1074 | /destr@2.0.2:
1075 | resolution: {integrity: sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg==}
1076 | dev: true
1077 |
1078 | /duplexer@0.1.2:
1079 | resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
1080 | dev: true
1081 |
1082 | /electron-to-chromium@1.4.598:
1083 | resolution: {integrity: sha512-0JnipX0scPUlwsptQVCZggoCpREv+IrVD3h0ZG+sldmK9L27tSV3QjV8+QdaA4qQTzDf3PluNS45YYJky1oASw==}
1084 | dev: true
1085 |
1086 | /esbuild@0.18.20:
1087 | resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
1088 | engines: {node: '>=12'}
1089 | hasBin: true
1090 | requiresBuild: true
1091 | optionalDependencies:
1092 | '@esbuild/android-arm': 0.18.20
1093 | '@esbuild/android-arm64': 0.18.20
1094 | '@esbuild/android-x64': 0.18.20
1095 | '@esbuild/darwin-arm64': 0.18.20
1096 | '@esbuild/darwin-x64': 0.18.20
1097 | '@esbuild/freebsd-arm64': 0.18.20
1098 | '@esbuild/freebsd-x64': 0.18.20
1099 | '@esbuild/linux-arm': 0.18.20
1100 | '@esbuild/linux-arm64': 0.18.20
1101 | '@esbuild/linux-ia32': 0.18.20
1102 | '@esbuild/linux-loong64': 0.18.20
1103 | '@esbuild/linux-mips64el': 0.18.20
1104 | '@esbuild/linux-ppc64': 0.18.20
1105 | '@esbuild/linux-riscv64': 0.18.20
1106 | '@esbuild/linux-s390x': 0.18.20
1107 | '@esbuild/linux-x64': 0.18.20
1108 | '@esbuild/netbsd-x64': 0.18.20
1109 | '@esbuild/openbsd-x64': 0.18.20
1110 | '@esbuild/sunos-x64': 0.18.20
1111 | '@esbuild/win32-arm64': 0.18.20
1112 | '@esbuild/win32-ia32': 0.18.20
1113 | '@esbuild/win32-x64': 0.18.20
1114 | dev: true
1115 |
1116 | /escalade@3.1.1:
1117 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
1118 | engines: {node: '>=6'}
1119 | dev: true
1120 |
1121 | /escape-string-regexp@1.0.5:
1122 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
1123 | engines: {node: '>=0.8.0'}
1124 | dev: true
1125 |
1126 | /estree-walker@2.0.2:
1127 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
1128 | dev: true
1129 |
1130 | /execa@5.1.1:
1131 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
1132 | engines: {node: '>=10'}
1133 | dependencies:
1134 | cross-spawn: 7.0.3
1135 | get-stream: 6.0.1
1136 | human-signals: 2.1.0
1137 | is-stream: 2.0.1
1138 | merge-stream: 2.0.0
1139 | npm-run-path: 4.0.1
1140 | onetime: 5.1.2
1141 | signal-exit: 3.0.7
1142 | strip-final-newline: 2.0.0
1143 | dev: true
1144 |
1145 | /fast-glob@3.3.2:
1146 | resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
1147 | engines: {node: '>=8.6.0'}
1148 | dependencies:
1149 | '@nodelib/fs.stat': 2.0.5
1150 | '@nodelib/fs.walk': 1.2.8
1151 | glob-parent: 5.1.2
1152 | merge2: 1.4.1
1153 | micromatch: 4.0.5
1154 | dev: true
1155 |
1156 | /fastq@1.15.0:
1157 | resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
1158 | dependencies:
1159 | reusify: 1.0.4
1160 | dev: true
1161 |
1162 | /fill-range@7.0.1:
1163 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
1164 | engines: {node: '>=8'}
1165 | dependencies:
1166 | to-regex-range: 5.0.1
1167 | dev: true
1168 |
1169 | /find-up@5.0.0:
1170 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
1171 | engines: {node: '>=10'}
1172 | dependencies:
1173 | locate-path: 6.0.0
1174 | path-exists: 4.0.0
1175 | dev: true
1176 |
1177 | /fsevents@2.3.3:
1178 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
1179 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
1180 | os: [darwin]
1181 | requiresBuild: true
1182 | dev: true
1183 | optional: true
1184 |
1185 | /gensync@1.0.0-beta.2:
1186 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
1187 | engines: {node: '>=6.9.0'}
1188 | dev: true
1189 |
1190 | /get-stream@6.0.1:
1191 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
1192 | engines: {node: '>=10'}
1193 | dev: true
1194 |
1195 | /glob-parent@5.1.2:
1196 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
1197 | engines: {node: '>= 6'}
1198 | dependencies:
1199 | is-glob: 4.0.3
1200 | dev: true
1201 |
1202 | /globals@11.12.0:
1203 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
1204 | engines: {node: '>=4'}
1205 | dev: true
1206 |
1207 | /gzip-size@6.0.0:
1208 | resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==}
1209 | engines: {node: '>=10'}
1210 | dependencies:
1211 | duplexer: 0.1.2
1212 | dev: true
1213 |
1214 | /has-flag@3.0.0:
1215 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
1216 | engines: {node: '>=4'}
1217 | dev: true
1218 |
1219 | /html-entities@2.3.3:
1220 | resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
1221 | dev: true
1222 |
1223 | /human-signals@2.1.0:
1224 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
1225 | engines: {node: '>=10.17.0'}
1226 | dev: true
1227 |
1228 | /is-binary-path@2.1.0:
1229 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
1230 | engines: {node: '>=8'}
1231 | dependencies:
1232 | binary-extensions: 2.2.0
1233 | dev: true
1234 |
1235 | /is-extglob@2.1.1:
1236 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
1237 | engines: {node: '>=0.10.0'}
1238 | dev: true
1239 |
1240 | /is-glob@4.0.3:
1241 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
1242 | engines: {node: '>=0.10.0'}
1243 | dependencies:
1244 | is-extglob: 2.1.1
1245 | dev: true
1246 |
1247 | /is-number@7.0.0:
1248 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
1249 | engines: {node: '>=0.12.0'}
1250 | dev: true
1251 |
1252 | /is-stream@2.0.1:
1253 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
1254 | engines: {node: '>=8'}
1255 | dev: true
1256 |
1257 | /is-what@4.1.16:
1258 | resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
1259 | engines: {node: '>=12.13'}
1260 | dev: true
1261 |
1262 | /isexe@2.0.0:
1263 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1264 | dev: true
1265 |
1266 | /jiti@1.21.0:
1267 | resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
1268 | hasBin: true
1269 | dev: true
1270 |
1271 | /js-tokens@4.0.0:
1272 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
1273 | dev: true
1274 |
1275 | /jsesc@2.5.2:
1276 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
1277 | engines: {node: '>=4'}
1278 | hasBin: true
1279 | dev: true
1280 |
1281 | /json5@2.2.3:
1282 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
1283 | engines: {node: '>=6'}
1284 | hasBin: true
1285 | dev: true
1286 |
1287 | /jsonc-parser@3.2.0:
1288 | resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
1289 | dev: true
1290 |
1291 | /kolorist@1.8.0:
1292 | resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
1293 | dev: true
1294 |
1295 | /local-pkg@0.4.3:
1296 | resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
1297 | engines: {node: '>=14'}
1298 | dev: true
1299 |
1300 | /locate-path@6.0.0:
1301 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
1302 | engines: {node: '>=10'}
1303 | dependencies:
1304 | p-locate: 5.0.0
1305 | dev: true
1306 |
1307 | /lru-cache@5.1.1:
1308 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
1309 | dependencies:
1310 | yallist: 3.1.1
1311 | dev: true
1312 |
1313 | /magic-string@0.30.5:
1314 | resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==}
1315 | engines: {node: '>=12'}
1316 | dependencies:
1317 | '@jridgewell/sourcemap-codec': 1.4.15
1318 | dev: true
1319 |
1320 | /mdn-data@2.0.30:
1321 | resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
1322 | dev: true
1323 |
1324 | /merge-anything@5.1.7:
1325 | resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==}
1326 | engines: {node: '>=12.13'}
1327 | dependencies:
1328 | is-what: 4.1.16
1329 | dev: true
1330 |
1331 | /merge-stream@2.0.0:
1332 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
1333 | dev: true
1334 |
1335 | /merge2@1.4.1:
1336 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
1337 | engines: {node: '>= 8'}
1338 | dev: true
1339 |
1340 | /micromatch@4.0.5:
1341 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
1342 | engines: {node: '>=8.6'}
1343 | dependencies:
1344 | braces: 3.0.2
1345 | picomatch: 2.3.1
1346 | dev: true
1347 |
1348 | /mimic-fn@2.1.0:
1349 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
1350 | engines: {node: '>=6'}
1351 | dev: true
1352 |
1353 | /mlly@1.4.2:
1354 | resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==}
1355 | dependencies:
1356 | acorn: 8.11.2
1357 | pathe: 1.1.1
1358 | pkg-types: 1.0.3
1359 | ufo: 1.3.2
1360 | dev: true
1361 |
1362 | /mrmime@1.0.1:
1363 | resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==}
1364 | engines: {node: '>=10'}
1365 | dev: true
1366 |
1367 | /ms@2.1.2:
1368 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
1369 | dev: true
1370 |
1371 | /nanoid@3.3.7:
1372 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
1373 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1374 | hasBin: true
1375 | dev: true
1376 |
1377 | /node-fetch-native@1.4.1:
1378 | resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==}
1379 | dev: true
1380 |
1381 | /node-releases@2.0.13:
1382 | resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
1383 | dev: true
1384 |
1385 | /normalize-path@3.0.0:
1386 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
1387 | engines: {node: '>=0.10.0'}
1388 | dev: true
1389 |
1390 | /npm-run-path@4.0.1:
1391 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
1392 | engines: {node: '>=8'}
1393 | dependencies:
1394 | path-key: 3.1.1
1395 | dev: true
1396 |
1397 | /ofetch@1.3.3:
1398 | resolution: {integrity: sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==}
1399 | dependencies:
1400 | destr: 2.0.2
1401 | node-fetch-native: 1.4.1
1402 | ufo: 1.3.2
1403 | dev: true
1404 |
1405 | /onetime@5.1.2:
1406 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
1407 | engines: {node: '>=6'}
1408 | dependencies:
1409 | mimic-fn: 2.1.0
1410 | dev: true
1411 |
1412 | /p-limit@3.1.0:
1413 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
1414 | engines: {node: '>=10'}
1415 | dependencies:
1416 | yocto-queue: 0.1.0
1417 | dev: true
1418 |
1419 | /p-locate@5.0.0:
1420 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
1421 | engines: {node: '>=10'}
1422 | dependencies:
1423 | p-limit: 3.1.0
1424 | dev: true
1425 |
1426 | /path-exists@4.0.0:
1427 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
1428 | engines: {node: '>=8'}
1429 | dev: true
1430 |
1431 | /path-key@3.1.1:
1432 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
1433 | engines: {node: '>=8'}
1434 | dev: true
1435 |
1436 | /pathe@1.1.1:
1437 | resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==}
1438 | dev: true
1439 |
1440 | /perfect-debounce@1.0.0:
1441 | resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
1442 | dev: true
1443 |
1444 | /picocolors@1.0.0:
1445 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
1446 | dev: true
1447 |
1448 | /picomatch@2.3.1:
1449 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
1450 | engines: {node: '>=8.6'}
1451 | dev: true
1452 |
1453 | /pkg-types@1.0.3:
1454 | resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
1455 | dependencies:
1456 | jsonc-parser: 3.2.0
1457 | mlly: 1.4.2
1458 | pathe: 1.1.1
1459 | dev: true
1460 |
1461 | /postcss@8.4.31:
1462 | resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
1463 | engines: {node: ^10 || ^12 || >=14}
1464 | dependencies:
1465 | nanoid: 3.3.7
1466 | picocolors: 1.0.0
1467 | source-map-js: 1.0.2
1468 | dev: true
1469 |
1470 | /queue-microtask@1.2.3:
1471 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
1472 | dev: true
1473 |
1474 | /readdirp@3.6.0:
1475 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
1476 | engines: {node: '>=8.10.0'}
1477 | dependencies:
1478 | picomatch: 2.3.1
1479 | dev: true
1480 |
1481 | /reusify@1.0.4:
1482 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
1483 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
1484 | dev: true
1485 |
1486 | /rollup@3.29.4:
1487 | resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
1488 | engines: {node: '>=14.18.0', npm: '>=8.0.0'}
1489 | hasBin: true
1490 | optionalDependencies:
1491 | fsevents: 2.3.3
1492 | dev: true
1493 |
1494 | /run-parallel@1.2.0:
1495 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
1496 | dependencies:
1497 | queue-microtask: 1.2.3
1498 | dev: true
1499 |
1500 | /semver@6.3.1:
1501 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
1502 | hasBin: true
1503 | dev: true
1504 |
1505 | /seroval@0.12.4:
1506 | resolution: {integrity: sha512-JIsZHp98o+okpYN8HEPyI9Blr0gxAUPIGvg3waXrEMFjPz9obiLYMz0uFiUGezKiCK8loosYbn8WsqO8WtAJUA==}
1507 | engines: {node: '>=10'}
1508 |
1509 | /shebang-command@2.0.0:
1510 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
1511 | engines: {node: '>=8'}
1512 | dependencies:
1513 | shebang-regex: 3.0.0
1514 | dev: true
1515 |
1516 | /shebang-regex@3.0.0:
1517 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
1518 | engines: {node: '>=8'}
1519 | dev: true
1520 |
1521 | /signal-exit@3.0.7:
1522 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
1523 | dev: true
1524 |
1525 | /sirv@2.0.3:
1526 | resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==}
1527 | engines: {node: '>= 10'}
1528 | dependencies:
1529 | '@polka/url': 1.0.0-next.24
1530 | mrmime: 1.0.1
1531 | totalist: 3.0.1
1532 | dev: true
1533 |
1534 | /solid-apexcharts@0.3.2(apexcharts@3.44.0)(solid-js@1.8.5):
1535 | resolution: {integrity: sha512-4U80dk2e/YEghD903aitBrO0l5WjUv/IhRI6Pp8mfJNT6JPkYG4HTMjBrI+XHRU8uJICJl9ZwLtkvFZnKd2Shw==}
1536 | peerDependencies:
1537 | apexcharts: ^3.40.0
1538 | solid-js: ^1.6.0
1539 | dependencies:
1540 | apexcharts: 3.44.0
1541 | defu: 6.1.3
1542 | solid-js: 1.8.5
1543 | dev: false
1544 |
1545 | /solid-js@1.8.5:
1546 | resolution: {integrity: sha512-xvtJvzJzWbsn35oKFhW9kNwaxG1Z/YLMsDp4tLVcYZTMPzvzQ8vEZuyDQ6nt7xDArVgZJ7TUFrJUwrui/oq53A==}
1547 | dependencies:
1548 | csstype: 3.1.2
1549 | seroval: 0.12.4
1550 |
1551 | /solid-refresh@0.5.3(solid-js@1.8.5):
1552 | resolution: {integrity: sha512-Otg5it5sjOdZbQZJnvo99TEBAr6J7PQ5AubZLNU6szZzg3RQQ5MX04oteBIIGDs0y2Qv8aXKm9e44V8z+UnFdw==}
1553 | peerDependencies:
1554 | solid-js: ^1.3
1555 | dependencies:
1556 | '@babel/generator': 7.23.5
1557 | '@babel/helper-module-imports': 7.22.15
1558 | '@babel/types': 7.23.5
1559 | solid-js: 1.8.5
1560 | dev: true
1561 |
1562 | /source-map-js@1.0.2:
1563 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
1564 | engines: {node: '>=0.10.0'}
1565 | dev: true
1566 |
1567 | /strip-final-newline@2.0.0:
1568 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
1569 | engines: {node: '>=6'}
1570 | dev: true
1571 |
1572 | /supports-color@5.5.0:
1573 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
1574 | engines: {node: '>=4'}
1575 | dependencies:
1576 | has-flag: 3.0.0
1577 | dev: true
1578 |
1579 | /svg.draggable.js@2.2.2:
1580 | resolution: {integrity: sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==}
1581 | engines: {node: '>= 0.8.0'}
1582 | dependencies:
1583 | svg.js: 2.7.1
1584 | dev: false
1585 |
1586 | /svg.easing.js@2.0.0:
1587 | resolution: {integrity: sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==}
1588 | engines: {node: '>= 0.8.0'}
1589 | dependencies:
1590 | svg.js: 2.7.1
1591 | dev: false
1592 |
1593 | /svg.filter.js@2.0.2:
1594 | resolution: {integrity: sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==}
1595 | engines: {node: '>= 0.8.0'}
1596 | dependencies:
1597 | svg.js: 2.7.1
1598 | dev: false
1599 |
1600 | /svg.js@2.7.1:
1601 | resolution: {integrity: sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==}
1602 | dev: false
1603 |
1604 | /svg.pathmorphing.js@0.1.3:
1605 | resolution: {integrity: sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==}
1606 | engines: {node: '>= 0.8.0'}
1607 | dependencies:
1608 | svg.js: 2.7.1
1609 | dev: false
1610 |
1611 | /svg.resize.js@1.4.3:
1612 | resolution: {integrity: sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==}
1613 | engines: {node: '>= 0.8.0'}
1614 | dependencies:
1615 | svg.js: 2.7.1
1616 | svg.select.js: 2.1.2
1617 | dev: false
1618 |
1619 | /svg.select.js@2.1.2:
1620 | resolution: {integrity: sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==}
1621 | engines: {node: '>= 0.8.0'}
1622 | dependencies:
1623 | svg.js: 2.7.1
1624 | dev: false
1625 |
1626 | /svg.select.js@3.0.1:
1627 | resolution: {integrity: sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==}
1628 | engines: {node: '>= 0.8.0'}
1629 | dependencies:
1630 | svg.js: 2.7.1
1631 | dev: false
1632 |
1633 | /to-fast-properties@2.0.0:
1634 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
1635 | engines: {node: '>=4'}
1636 | dev: true
1637 |
1638 | /to-regex-range@5.0.1:
1639 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
1640 | engines: {node: '>=8.0'}
1641 | dependencies:
1642 | is-number: 7.0.0
1643 | dev: true
1644 |
1645 | /totalist@3.0.1:
1646 | resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
1647 | engines: {node: '>=6'}
1648 | dev: true
1649 |
1650 | /typescript@5.2.2:
1651 | resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==}
1652 | engines: {node: '>=14.17'}
1653 | hasBin: true
1654 | dev: true
1655 |
1656 | /ufo@1.3.2:
1657 | resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==}
1658 | dev: true
1659 |
1660 | /unconfig@0.3.11:
1661 | resolution: {integrity: sha512-bV/nqePAKv71v3HdVUn6UefbsDKQWRX+bJIkiSm0+twIds6WiD2bJLWWT3i214+J/B4edufZpG2w7Y63Vbwxow==}
1662 | dependencies:
1663 | '@antfu/utils': 0.7.6
1664 | defu: 6.1.3
1665 | jiti: 1.21.0
1666 | mlly: 1.4.2
1667 | dev: true
1668 |
1669 | /unocss@0.58.0(postcss@8.4.31)(vite@4.5.0):
1670 | resolution: {integrity: sha512-MSPRHxBqWN+1AHGV+J5uUy4//e6ZBK6O+ISzD0qrXcCD/GNtxk1+lYjOK2ltkUiKX539+/KF91vNxzhhwEf+xA==}
1671 | engines: {node: '>=14'}
1672 | peerDependencies:
1673 | '@unocss/webpack': 0.58.0
1674 | vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
1675 | peerDependenciesMeta:
1676 | '@unocss/webpack':
1677 | optional: true
1678 | vite:
1679 | optional: true
1680 | dependencies:
1681 | '@unocss/astro': 0.58.0(vite@4.5.0)
1682 | '@unocss/cli': 0.58.0
1683 | '@unocss/core': 0.58.0
1684 | '@unocss/extractor-arbitrary-variants': 0.58.0
1685 | '@unocss/postcss': 0.58.0(postcss@8.4.31)
1686 | '@unocss/preset-attributify': 0.58.0
1687 | '@unocss/preset-icons': 0.58.0
1688 | '@unocss/preset-mini': 0.58.0
1689 | '@unocss/preset-tagify': 0.58.0
1690 | '@unocss/preset-typography': 0.58.0
1691 | '@unocss/preset-uno': 0.58.0
1692 | '@unocss/preset-web-fonts': 0.58.0
1693 | '@unocss/preset-wind': 0.58.0
1694 | '@unocss/reset': 0.58.0
1695 | '@unocss/transformer-attributify-jsx': 0.58.0
1696 | '@unocss/transformer-attributify-jsx-babel': 0.58.0
1697 | '@unocss/transformer-compile-class': 0.58.0
1698 | '@unocss/transformer-directives': 0.58.0
1699 | '@unocss/transformer-variant-group': 0.58.0
1700 | '@unocss/vite': 0.58.0(vite@4.5.0)
1701 | vite: 4.5.0
1702 | transitivePeerDependencies:
1703 | - postcss
1704 | - rollup
1705 | - supports-color
1706 | dev: true
1707 |
1708 | /update-browserslist-db@1.0.13(browserslist@4.22.1):
1709 | resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
1710 | hasBin: true
1711 | peerDependencies:
1712 | browserslist: '>= 4.21.0'
1713 | dependencies:
1714 | browserslist: 4.22.1
1715 | escalade: 3.1.1
1716 | picocolors: 1.0.0
1717 | dev: true
1718 |
1719 | /validate-html-nesting@1.2.2:
1720 | resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==}
1721 | dev: true
1722 |
1723 | /vite-plugin-solid@2.7.2(solid-js@1.8.5)(vite@4.5.0):
1724 | resolution: {integrity: sha512-GV2SMLAibOoXe76i02AsjAg7sbm/0lngBlERvJKVN67HOrJsHcWgkt0R6sfGLDJuFkv2aBe14Zm4vJcNME+7zw==}
1725 | peerDependencies:
1726 | solid-js: ^1.7.2
1727 | vite: ^3.0.0 || ^4.0.0
1728 | dependencies:
1729 | '@babel/core': 7.23.5
1730 | '@babel/preset-typescript': 7.23.3(@babel/core@7.23.5)
1731 | '@types/babel__core': 7.20.5
1732 | babel-preset-solid: 1.8.6(@babel/core@7.23.5)
1733 | merge-anything: 5.1.7
1734 | solid-js: 1.8.5
1735 | solid-refresh: 0.5.3(solid-js@1.8.5)
1736 | vite: 4.5.0
1737 | vitefu: 0.2.5(vite@4.5.0)
1738 | transitivePeerDependencies:
1739 | - supports-color
1740 | dev: true
1741 |
1742 | /vite@4.5.0:
1743 | resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==}
1744 | engines: {node: ^14.18.0 || >=16.0.0}
1745 | hasBin: true
1746 | peerDependencies:
1747 | '@types/node': '>= 14'
1748 | less: '*'
1749 | lightningcss: ^1.21.0
1750 | sass: '*'
1751 | stylus: '*'
1752 | sugarss: '*'
1753 | terser: ^5.4.0
1754 | peerDependenciesMeta:
1755 | '@types/node':
1756 | optional: true
1757 | less:
1758 | optional: true
1759 | lightningcss:
1760 | optional: true
1761 | sass:
1762 | optional: true
1763 | stylus:
1764 | optional: true
1765 | sugarss:
1766 | optional: true
1767 | terser:
1768 | optional: true
1769 | dependencies:
1770 | esbuild: 0.18.20
1771 | postcss: 8.4.31
1772 | rollup: 3.29.4
1773 | optionalDependencies:
1774 | fsevents: 2.3.3
1775 | dev: true
1776 |
1777 | /vitefu@0.2.5(vite@4.5.0):
1778 | resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==}
1779 | peerDependencies:
1780 | vite: ^3.0.0 || ^4.0.0 || ^5.0.0
1781 | peerDependenciesMeta:
1782 | vite:
1783 | optional: true
1784 | dependencies:
1785 | vite: 4.5.0
1786 | dev: true
1787 |
1788 | /which@2.0.2:
1789 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
1790 | engines: {node: '>= 8'}
1791 | hasBin: true
1792 | dependencies:
1793 | isexe: 2.0.0
1794 | dev: true
1795 |
1796 | /yallist@3.1.1:
1797 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
1798 | dev: true
1799 |
1800 | /yocto-queue@0.1.0:
1801 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
1802 | engines: {node: '>=10'}
1803 | dev: true
1804 |
--------------------------------------------------------------------------------